[
  {
    "path": ".csscomb.json",
    "content": "{\n    \"always-semicolon\": true,\n    \"block-indent\": false,\n    \"color-case\": \"lower\",\n    \"color-shorthand\": true,\n    \"element-case\": false,\n    \"eof-newline\": false,\n    \"leading-zero\": false,\n    \"quotes\": \"single\",\n    \"space-after-colon\": false,\n    \"space-after-combinator\": \" \",\n    \"space-after-opening-brace\": false,\n    \"space-after-selector-delimiter\": false,\n    \"space-before-closing-brace\": false,\n    \"space-before-colon\": \"\",\n    \"space-before-combinator\": \" \",\n    \"space-before-opening-brace\": false,\n    \"space-before-selector-delimiter\": \"\",\n    \"space-between-declarations\": false,\n    \"strip-spaces\": true,\n    \"unitless-zero\": true,\n    \"vendor-prefix-align\": false,\n\n    \"sort-order\": [[\n        \"position\",\n        \"top\",\n        \"right\",\n        \"bottom\",\n        \"left\",\n        \"z-index\",\n        \"display\",\n        \"visibility\",\n        \"-webkit-flex-direction\",\n        \"-moz-flex-direction\",\n        \"-ms-flex-direction\",\n        \"-o-flex-direction\",\n        \"flex-direction\",\n        \"-webkit-flex-order\",\n        \"-moz-flex-order\",\n        \"-ms-flex-order\",\n        \"-o-flex-order\",\n        \"flex-order\",\n        \"-webkit-flex-pack\",\n        \"-moz-flex-pack\",\n        \"-ms-flex-pack\",\n        \"-o-flex-pack\",\n        \"flex-pack\",\n        \"float\",\n        \"clear\",\n        \"-webkit-flex-align\",\n        \"-moz-flex-align\",\n        \"-ms-flex-align\",\n        \"-o-flex-align\",\n        \"flex-align\",\n        \"overflow\",\n        \"-ms-overflow-x\",\n        \"-ms-overflow-y\",\n        \"overflow-x\",\n        \"overflow-y\",\n        \"-webkit-overflow-scrolling\",\n        \"clip\",\n        \"-webkit-box-sizing\",\n        \"-moz-box-sizing\",\n        \"box-sizing\",\n        \"margin\",\n        \"margin-top\",\n        \"margin-right\",\n        \"margin-bottom\",\n        \"margin-left\",\n        \"padding\",\n        \"padding-top\",\n        \"padding-right\",\n        \"padding-bottom\",\n        \"padding-left\",\n        \"min-width\",\n        \"min-height\",\n        \"max-width\",\n        \"max-height\",\n        \"width\",\n        \"height\",\n        \"outline\",\n        \"outline-width\",\n        \"outline-style\",\n        \"outline-color\",\n        \"outline-offset\",\n        \"border\",\n        \"border-spacing\",\n        \"border-collapse\",\n        \"border-width\",\n        \"border-style\",\n        \"border-color\",\n        \"border-top\",\n        \"border-top-width\",\n        \"border-top-style\",\n        \"border-top-color\",\n        \"border-right\",\n        \"border-right-width\",\n        \"border-right-style\",\n        \"border-right-color\",\n        \"border-bottom\",\n        \"border-bottom-width\",\n        \"border-bottom-style\",\n        \"border-bottom-color\",\n        \"border-left\",\n        \"border-left-width\",\n        \"border-left-style\",\n        \"border-left-color\",\n        \"-webkit-border-radius\",\n        \"-moz-border-radius\",\n        \"border-radius\",\n        \"-webkit-border-top-left-radius\",\n        \"-moz-border-radius-topleft\",\n        \"border-top-left-radius\",\n        \"-webkit-border-top-right-radius\",\n        \"-moz-border-radius-topright\",\n        \"border-top-right-radius\",\n        \"-webkit-border-bottom-right-radius\",\n        \"-moz-border-radius-bottomright\",\n        \"border-bottom-right-radius\",\n        \"-webkit-border-bottom-left-radius\",\n        \"-moz-border-radius-bottomleft\",\n        \"border-bottom-left-radius\",\n        \"-webkit-border-image\",\n        \"-moz-border-image\",\n        \"-o-border-image\",\n        \"border-image\",\n        \"-webkit-border-image-source\",\n        \"-moz-border-image-source\",\n        \"-o-border-image-source\",\n        \"border-image-source\",\n        \"-webkit-border-image-slice\",\n        \"-moz-border-image-slice\",\n        \"-o-border-image-slice\",\n        \"border-image-slice\",\n        \"-webkit-border-image-width\",\n        \"-moz-border-image-width\",\n        \"-o-border-image-width\",\n        \"border-image-width\",\n        \"-webkit-border-image-outset\",\n        \"-moz-border-image-outset\",\n        \"-o-border-image-outset\",\n        \"border-image-outset\",\n        \"-webkit-border-image-repeat\",\n        \"-moz-border-image-repeat\",\n        \"-o-border-image-repeat\",\n        \"border-image-repeat\",\n        \"-webkit-border-top-image\",\n        \"-moz-border-top-image\",\n        \"-o-border-top-image\",\n        \"border-top-image\",\n        \"-webkit-border-right-image\",\n        \"-moz-border-right-image\",\n        \"-o-border-right-image\",\n        \"border-right-image\",\n        \"-webkit-border-bottom-image\",\n        \"-moz-border-bottom-image\",\n        \"-o-border-bottom-image\",\n        \"border-bottom-image\",\n        \"-webkit-border-left-image\",\n        \"-moz-border-left-image\",\n        \"-o-border-left-image\",\n        \"border-left-image\",\n        \"-webkit-border-corner-image\",\n        \"-moz-border-corner-image\",\n        \"-o-border-corner-image\",\n        \"border-corner-image\",\n        \"-webkit-border-top-left-image\",\n        \"-moz-border-top-left-image\",\n        \"-o-border-top-left-image\",\n        \"border-top-left-image\",\n        \"-webkit-border-top-right-image\",\n        \"-moz-border-top-right-image\",\n        \"-o-border-top-right-image\",\n        \"border-top-right-image\",\n        \"-webkit-border-bottom-right-image\",\n        \"-moz-border-bottom-right-image\",\n        \"-o-border-bottom-right-image\",\n        \"border-bottom-right-image\",\n        \"-webkit-border-bottom-left-image\",\n        \"-moz-border-bottom-left-image\",\n        \"-o-border-bottom-left-image\",\n        \"border-bottom-left-image\",\n        \"background\",\n        \"filter:progid:DXImageTransform.Microsoft.AlphaImageLoader\",\n        \"background-color\",\n        \"background-image\",\n        \"background-attachment\",\n        \"background-position\",\n        \"-ms-background-position-x\",\n        \"-ms-background-position-y\",\n        \"background-position-x\",\n        \"background-position-y\",\n        \"-webkit-background-clip\",\n        \"-moz-background-clip\",\n        \"background-clip\",\n        \"background-origin\",\n        \"-webkit-background-size\",\n        \"-moz-background-size\",\n        \"-o-background-size\",\n        \"background-size\",\n        \"background-repeat\",\n        \"box-decoration-break\",\n        \"-webkit-box-shadow\",\n        \"-moz-box-shadow\",\n        \"box-shadow\",\n        \"color\",\n        \"table-layout\",\n        \"caption-side\",\n        \"empty-cells\",\n        \"list-style\",\n        \"list-style-position\",\n        \"list-style-type\",\n        \"list-style-image\",\n        \"quotes\",\n        \"content\",\n        \"counter-increment\",\n        \"counter-reset\",\n        \"-ms-writing-mode\",\n        \"vertical-align\",\n        \"text-align\",\n        \"-webkit-text-align-last\",\n        \"-moz-text-align-last\",\n        \"-ms-text-align-last\",\n        \"text-align-last\",\n        \"text-decoration\",\n        \"text-emphasis\",\n        \"text-emphasis-position\",\n        \"text-emphasis-style\",\n        \"text-emphasis-color\",\n        \"text-indent\",\n        \"-ms-text-justify\",\n        \"text-justify\",\n        \"text-outline\",\n        \"text-transform\",\n        \"text-wrap\",\n        \"-ms-text-overflow\",\n        \"text-overflow\",\n        \"text-overflow-ellipsis\",\n        \"text-overflow-mode\",\n        \"text-shadow\",\n        \"white-space\",\n        \"word-spacing\",\n        \"-ms-word-wrap\",\n        \"word-wrap\",\n        \"-ms-word-break\",\n        \"word-break\",\n        \"-moz-tab-size\",\n        \"-o-tab-size\",\n        \"tab-size\",\n        \"-webkit-hyphens\",\n        \"-moz-hyphens\",\n        \"hyphens\",\n        \"letter-spacing\",\n        \"font\",\n        \"font-weight\",\n        \"font-style\",\n        \"font-variant\",\n        \"font-size-adjust\",\n        \"font-stretch\",\n        \"font-size\",\n        \"font-family\",\n        \"src\",\n        \"line-height\",\n        \"opacity\",\n        \"-ms-filter:\\\\'progid:DXImageTransform.Microsoft.Alpha\",\n        \"filter:progid:DXImageTransform.Microsoft.Alpha(Opacity\",\n        \"-ms-interpolation-mode\",\n        \"-webkit-filter\",\n        \"-ms-filter\",\n        \"filter\",\n        \"resize\",\n        \"cursor\",\n        \"nav-index\",\n        \"nav-up\",\n        \"nav-right\",\n        \"nav-down\",\n        \"nav-left\",\n        \"-webkit-transition\",\n        \"-moz-transition\",\n        \"-ms-transition\",\n        \"-o-transition\",\n        \"transition\",\n        \"-webkit-transition-delay\",\n        \"-moz-transition-delay\",\n        \"-ms-transition-delay\",\n        \"-o-transition-delay\",\n        \"transition-delay\",\n        \"-webkit-transition-timing-function\",\n        \"-moz-transition-timing-function\",\n        \"-ms-transition-timing-function\",\n        \"-o-transition-timing-function\",\n        \"transition-timing-function\",\n        \"-webkit-transition-duration\",\n        \"-moz-transition-duration\",\n        \"-ms-transition-duration\",\n        \"-o-transition-duration\",\n        \"transition-duration\",\n        \"-webkit-transition-property\",\n        \"-moz-transition-property\",\n        \"-ms-transition-property\",\n        \"-o-transition-property\",\n        \"transition-property\",\n        \"-webkit-transform\",\n        \"-moz-transform\",\n        \"-ms-transform\",\n        \"-o-transform\",\n        \"transform\",\n        \"-webkit-transform-origin\",\n        \"-moz-transform-origin\",\n        \"-ms-transform-origin\",\n        \"-o-transform-origin\",\n        \"transform-origin\",\n        \"-webkit-animation\",\n        \"-moz-animation\",\n        \"-ms-animation\",\n        \"-o-animation\",\n        \"animation\",\n        \"-webkit-animation-name\",\n        \"-moz-animation-name\",\n        \"-ms-animation-name\",\n        \"-o-animation-name\",\n        \"animation-name\",\n        \"-webkit-animation-duration\",\n        \"-moz-animation-duration\",\n        \"-ms-animation-duration\",\n        \"-o-animation-duration\",\n        \"animation-duration\",\n        \"-webkit-animation-play-state\",\n        \"-moz-animation-play-state\",\n        \"-ms-animation-play-state\",\n        \"-o-animation-play-state\",\n        \"animation-play-state\",\n        \"-webkit-animation-timing-function\",\n        \"-moz-animation-timing-function\",\n        \"-ms-animation-timing-function\",\n        \"-o-animation-timing-function\",\n        \"animation-timing-function\",\n        \"-webkit-animation-delay\",\n        \"-moz-animation-delay\",\n        \"-ms-animation-delay\",\n        \"-o-animation-delay\",\n        \"animation-delay\",\n        \"-webkit-animation-iteration-count\",\n        \"-moz-animation-iteration-count\",\n        \"-ms-animation-iteration-count\",\n        \"-o-animation-iteration-count\",\n        \"animation-iteration-count\",\n        \"-webkit-animation-direction\",\n        \"-moz-animation-direction\",\n        \"-ms-animation-direction\",\n        \"-o-animation-direction\",\n        \"animation-direction\",\n        \"pointer-events\",\n        \"unicode-bidi\",\n        \"direction\",\n        \"-webkit-columns\",\n        \"-moz-columns\",\n        \"columns\",\n        \"-webkit-column-span\",\n        \"-moz-column-span\",\n        \"column-span\",\n        \"-webkit-column-width\",\n        \"-moz-column-width\",\n        \"column-width\",\n        \"-webkit-column-count\",\n        \"-moz-column-count\",\n        \"column-count\",\n        \"-webkit-column-fill\",\n        \"-moz-column-fill\",\n        \"column-fill\",\n        \"-webkit-column-gap\",\n        \"-moz-column-gap\",\n        \"column-gap\",\n        \"-webkit-column-rule\",\n        \"-moz-column-rule\",\n        \"column-rule\",\n        \"-webkit-column-rule-width\",\n        \"-moz-column-rule-width\",\n        \"column-rule-width\",\n        \"-webkit-column-rule-style\",\n        \"-moz-column-rule-style\",\n        \"column-rule-style\",\n        \"-webkit-column-rule-color\",\n        \"-moz-column-rule-color\",\n        \"column-rule-color\",\n        \"break-before\",\n        \"break-inside\",\n        \"break-after\",\n        \"page-break-before\",\n        \"page-break-inside\",\n        \"page-break-after\",\n        \"orphans\",\n        \"widows\",\n        \"-ms-zoom\",\n        \"zoom\",\n        \"max-zoom\",\n        \"min-zoom\",\n        \"user-zoom\",\n        \"orientation\",\n        \"...\"\n    ]]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig: https://EditorConfig.org\n\nroot = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.{js,ts,jsx,tsx,json,html,css,md,yml}]\ncharset = utf-8\n\n[*.{js,ts,jsx,tsx,json,html,css}]\nindent_style = space\nindent_size = 4\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"eslint:recommended\",\n  \"rules\": {\n    \"eqeqeq\": 0,\n    \"camelcase\": 2,\n    \"quotes\": [2, \"single\"],\n    \"no-mixed-spaces-and-tabs\": [2, \"smart-tabs\"],\n    \"space-before-function-paren\": [2, \"never\"],\n    \"space-in-parens\": 2,\n    \"object-curly-spacing\": 2,\n    \"array-bracket-spacing\": 2,\n    \"computed-property-spacing\": 2,\n    \"space-before-blocks\": 2,\n    \"keyword-spacing\": 2,\n    \"no-lonely-if\": 2,\n    \"comma-style\": 2,\n    \"indent\": [2, 4, {\"SwitchCase\": 1}],\n    \"no-underscore-dangle\": 0,\n    \"no-use-before-define\": 0,\n    \"no-constant-condition\": 0,\n    \"no-multi-spaces\": 0,\n    \"strict\": 0,\n    \"key-spacing\": 0,\n    \"no-shadow\": 0,\n    \"no-console\": 1,\n    \"no-useless-escape\": 0,\n    \"no-prototype-builtins\": 0\n  },\n  \"globals\": {\n    \"DG\": true,\n    \"L\": true,\n    \"baron\": true,\n    \"Promise\": true\n  },\n  \"env\": {\n    \"browser\": true,\n    \"node\": true\n  }\n}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\non: push\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout 🛎️\n        uses: actions/checkout@v2\n\n      - name: Set env var to fix the PhantomJS error\n        run: |\n          echo \"OPENSSL_CONF=/tmp/openssl.cnf\" >> \"$GITHUB_ENV\"\n\n      - name: Setup node 🔧\n        uses: actions/setup-node@v2\n        with:\n          node-version: 12\n\n      - name: Downgrade the Python version to fix the install errors\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.10'\n\n      - name: Test ✔️\n        env:\n          TEST_SECRET_KEY: ${{ secrets.TEST_SECRET_KEY }}\n        run: |\n          npm ci\n          npm test\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n\n.idea\n\nnode_modules\nnpm-debug.log\n\ndist\ngulp/tmp\n\n.tern-port\n\nconfig.local.json\n\nnohup.out\nvendors/leaflet/dist/leaflet-src.js\n\ncoverage\njsconfig.json\n.vscode\n\nyarn.lock\n"
  },
  {
    "path": ".npmignore",
    "content": ".DS_Store\n\n.idea\n\nnode_modules\nnpm-debug.log\n\ngulp/tmp\n\n.tern-port\n\nconfig.local.json\n\nnohup.out\nvendors/leaflet/dist/leaflet-src.js\n\ncoverage\njsconfig.json\n.vscode\n\nyarn.lock\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "## Содержание\n1. [Как принять участие в развитии API карт](#Как-принять-участие-в-развитии-api-карт)\n    * [Расскажите о нас](#Расскажите-о-нас)\n    * [Сообщайте об ошибках](#Сообщайте-об-ошибках)\n    * [Разрабатывайте собственные модули](#Разрабатывайте-собственные-модули)\n    * [Участвуйте в исправлении ошибок](#Участвуйте-в-исправлении-ошибок)\n    * [Участвуйте в улучшении документации](#Участвуйте-в-улучшении-документации)\n2. [Как разработать собственный модуль](#Как-разработать-собственный-модуль)\n    * [Инициализация](#Инициализация)\n    * [Код модуля](#Код-модуля)\n    * [Минификация и подключение](#Минификация-и-подключение)\n    * [Прочие рекомендации](#Прочие-рекомендации)\n3. [Как внести изменения в исходный код](#Как-внести-изменения-в-исходный-код)\n4. [Установка локальной сборки API карт](#Установка-локальной-сборки-api-карт)\n5. [Стандарты кодирования](#Стандарты-кодирования)\n    * [JavaScript](#javascript)\n    * [HTML и CSS](#html-и-css)\n\n## Как принять участие в развитии API карт\nКаждый из вас может повлиять на качество API карт и сделать продукт еще лучше. Ниже перечислено несколько способов того, как вы можете это сделать.\n### Расскажите о нас\nРеализовали качественный проект на API 2ГИС? Напишите об этом в своем блоге или социальной сети, поделитесь своим опытом использования API с другими разработчиками.\n### Сообщайте об ошибках\nЕсли вы нашли ошибку в работе API карт или столкнулись с проблемой, сообщите об этом на [форуме обратной связи](https://api2gis.uservoice.com) и мы обязательно поможем вам разобраться с проблемой. Как правило, хорошо локализованная ошибка&nbsp;&mdash; это уже половина работы по её исправлению, потому постарайтесь сделать максимально простой пример, на котором воспроизводится ошибка и разместите его в публичном доступе (например, используя [JSFiddle](http://jsfiddle.net/)), также не забудьте указать версию браузера и ОС, чтобы мы смогли воспроизвести ошибку.\n### Разрабатывайте собственные модули\nВы можете расширять функциональность API карт под свои потребности при помощи модулей. Прочтите [небольшую инструкцию](#Как-разработать-собственный-модуль), которая поможет написать ваш первый модуль. Если считаете, что модуль будет полезен другим разработчикам, обязательно сообщите нам об этом по адресу api@2gis.ru, мы разместим информацию о нем на официальном сайте 2ГИС, а возможно и включим в базовую поставку API карт.\n\n### Участвуйте в исправлении ошибок\nВы можете самостоятельно исправить найденные ошибки в работе API карт, для этого необходимо ознакомиться с [процессом внесения изменений в исходный код](#Как-внести-изменения-в-исходный-код) и прислать нам [pull request](https://help.github.com/articles/using-pull-requests).\n### Участвуйте в улучшении документации\nЕсли какой-то из разделов документации показался недостаточно полным и вы считаете, что его можно улучшить, вы можете сделать это самостоятельно. Для внесения изменений в документацию необходимо:\n* найти интересующий вас раздел документации в папке [src/doc/](https://github.com/2gis/maps-api-2.0/tree/master/src/doc/manual) и открыть его содержимое;\n* нажать кнопку Edit, отредактировать текст документации и нажать кнопку Propose File Change.\n\nМы рассмотрим ваш pull request с изменениями и при следующем релизе после их принятия они появятся на сайте API 2ГИС.\n\n## Как разработать собственный модуль\n\nНиже приведен пример разработки простого модуля. С помощью этого модуля мы покажем, как расширить функционал API карт таким образом, чтобы у пользователей появилась возможность кликнуть в любой дом на карте и увидеть вокруг него магазины в радиусе 500 метров.\n\nПеред началом разработки рекомендуется ознакомиться со [стандартами кодирования](#Стандарты-кодирования) и [документацией](http://api.2gis.ru/doc/maps/manual/loading/) API карт.\n\n### Инициализация\n\nПервое, что необходимо сделать&nbsp;&mdash; это создать отдельный [Github-репозиторий для нашего модуля](https://github.com/2gis/maps-api-2.0-plugin-demo).\n\nИ сформировать файловую структуру:\n\n    /src   - исходные JS файлы\n    /demo  - HTML файлы с примерами использования\n    /dist  - минифицированные JS и CSS файлы, а также изображения\n    README.md\n    LICENSE.md\n\n### Код модуля\nТак как наш модуль довольно простой, он будет состоять всего из одного исходного JS файла, назовем его DGDemoPlugin.js и напишем в нем необходимый для работы код:\n```javascript\n    DG.DemoPlugin = DG.Handler.extend({\n\n       _lastFirms: DG.layerGroup(),\n\n       addHooks: function() {\n           this._map.on('click', this._searchFirms, this);\n       },\n\n       removeHooks: function() {\n           this._map.off('click', this._searchFirms, this);\n       },\n\n       _searchFirms: function(e) { // (MouseEvent)\n           var latlng = e.latlng.wrap();\n\n           DG.ajax({\n               url: 'http://catalog.api.2gis.ru/2.0/search',\n               data: {\n                   what: 'магазин',\n                   point: latlng.lng + ',' + latlng.lat,\n                   radius: 500,\n                   page_size: 50,\n                   type: 'filial',\n                   key: '12345678'\n               },\n               success: DG.bind(this._showFirms, this),\n               error: DG.bind(this._logError, this)\n           });\n       },\n\n       _showFirms: function(data) { // (Object)\n           var firms, marker;\n\n           if (data.response.code > 200) {\n               this._logError(data);\n               return;\n           }\n\n           this._lastFirms.clearLayers();\n\n           firms = data.result.data;\n           firms.forEach(function(firmInfo) {\n               marker = DG.marker([firmInfo.geo.lat, firmInfo.geo.lon]);\n               marker.bindPopup(firmInfo.firm.name);\n               marker.addTo(this._lastFirms);\n           }, this);\n\n           this._lastFirms.addTo(this._map);\n       },\n\n       _logError: function(data) {\n           console.log('Error: ', data);\n       }\n   });\n\n   DG.Map.addInitHook('addHandler', 'demoPlugin', DG.DemoPlugin);\n```\n\nНаш модуль предполагает взаимодействие пользователя с картой, потому мы его отнаследовали от класса `DG.Handler`. Благодаря этому можно будет контролировать его поведение в процессе исполнения приложения (например, у разработчика будет возможность включить или выключить модуль).\n\nСвойство `_lastFirms` представляет собой группу, в которую мы добавляем маркеры. В нашем случае это необходимо для того, чтоб можно было одной командой удалить с карты маркеры всех магазинов, которые были добавлены после предыдущего клика пользователя, и отобразить новые.\n\nМетоды `addHooks` и `removeHooks` срабатывает в тот момент, когда разработчик конечного приложения включает или отключает наш модуль.\n\nМетод `_searchFirms` отправляет AJAX-запрос к [REST API справочника 2ГИС](http://catalog.api.2gis.ru/doc/2.0/catalog/filial/search-by-what-and-radius) и в случае успешного ответа вызывает метод `_showFirms`.\n\nМетод `_showFirms` удаляет с карты все предыдущие маркеры и показывает новые.\n\nМетод `_logError` при возникновении ошибки печатает в консоль браузера данные о ней.\n\nКонструкция `DG.Map.addInitHook('addHandler', 'demoPlugin', DG.DemoPlugin)` позволяет карте зарегистрировать написанный нами обработчик пользовательских действий, после чего к нему можно будет обратиться по соответствующему имени, например:\n\n    map.demoPlugin.enable();\n\n### Минификация и подключение\nДля минификации JS файлов существует множество популярных инструментов, вы можете воспользоваться любым из них, напрмиер [YUI Compressor](http://yui.github.io/yuicompressor/). Минифицированный JS файл необходимо положить в папку `dist` и предоставить к нему публичный доступ, после чего любой разработчик сможет подключить и использовать его вместе с API карт. Пример подключения модуля:\n\n    DG.then(function() {\n        //загрузка модуля\n        return DG.plugin('https://raw.github.com/2gis/maps-api-2.0-plugin-demo/master/dist/DGDemoPlugin.js');\n    })\n    .then(function() {\n        //инициализация карты\n        var map = new DG.Map('map', {\n            'center': new DG.LatLng(54.980206086231, 82.898068362003),\n            'zoom': 15,\n            'geoclicker': false\n        });\n        // включение модуля\n        map.demoPlugin.enable();\n    });\n\n### Прочие рекомендации\nВыше мы привели пример очень простого модуля, но модули могут быть более сложные, ниже перечислены некоторые рекомендации по их разработке.\n\nРекомендуемая файловая структура модуля:\n\n    /src       — исходные JS файлы\n    /doc       — документация\n    /lang      — языковые файлы\n    /skin      — изображения и CSS файлы разных тем API карт\n    /templates — шаблоны\n    /test      — тесты\n    /demo      — HTML файлы с примерами использования\n    /dist      — минифицированные JS и CSS файлы, а также изображения\n    README.md\n    LICENSE.md\n\nВ качестве примера модуля с описанной выше файловой структурой можно изучить [DGGeoclicker](https://github.com/2gis/maps-api-2.0/tree/master/src/DGGeoclicker).\n\nНе забывайте снабжать модули тестами, это позволит упростить их поддержку в будущем. В качестве тестового фреймворка в API карт используется [Mocha](http://visionmedia.github.io/mocha/).\n\nДелайте демонстрационные примеры. Как правило, это первое на что обращают внимание пользователи модуля при ознакомлении с его возможностями.\n\nСоставьте и положите в корневую папку модуля файл `README.md`, в котором будут описаны возможности модуля и примеры его использования.\n\nВыберите лицензию для своего модуля, ведь это неотъемлемая часть любого open-source проекта. Такие ресурсы, как [tldrlegal.com](http://www.tldrlegal.com/) и [opensource.org](http://opensource.org/licenses) могут вам в этом помочь.\n\n## Как внести изменения в исходный код\nДля внесения изменений в существующий исходный код API карт (например, для исправления ошибки) вам потребуется:\n* сделать [форк](https://help.github.com/articles/fork-a-repo) репозитория API карт;\n* [установить API карт локально](#Установка-локальной-сборки-api-карт) на своем компьютере;\n* сделать ветку, название которой будет соответствовать сути вашего изменения (ветку необходимо унаследовать от ветки `master`, так как в ней находится последняя стабильная версия API карт);\n* внести свои изменения в код (рекомендуется следовать принятым [стандартам кодирования](#Стандарты-кодирования));\n* прислать нам pull request.\n\nПосле изучения и тестирования pull request-а мы его примем (возможно с некоторыми доработками), после чего они попадут в релиз и станут доступны всем пользователям API карт.\n\nПожалуйста, не забывайте покрывать и проверять измененный код тестами.\n\nДля запуска тестов в PhantomJS (по умолчанию) необходимо из консоли выполнить команду:\n\n    gulp test\n\nДля запуска тестов в браузерах вашей операционной системы укажите названия браузеров с помощью параметров:\n\n    gulp test --ff --chrome\n\nСписок доступных параметров:\n\n    (default)   PhantomJS\n    --chrome    Chrome\n    --ff        Firefox\n    --opera     Opera\n    --safari    Safari\n    --ie        IE (только для Windows)\n\nЕсли вам необходимо выполнить тесты за несколько запусков браузера, то вы можете использовать параметр:\n    \n    --multiple-chunks\n    \nПо умолчанию при каждом запуске браузера будут выполняться тесты из 10ти модулей.\nИзменить это число можно параметром:\n\n    --items-in-chunk\n\nТакже вы можете проверить код на наличие синтаксических ошибок, для этого необходимо выполнить команду:\n\n    gulp lint\n\n## Установка локальной сборки API карт\nНиже перечислены шаги, которые необходимо выполнить для установки API карт локально на своем компьютере.\n\n* Склонируйте репозиторий:\n\n        git clone git@github.com:2gis/mapsapi.git\n\n    Примечание: если вы устанавливаете API карт не с текущего репозитория, а с его форка, тогда не забудьте указать первым параметром команды `clone` адрес форка вместо адреса репозитория 2ГИС.\n* Установите [Node.js](https://nodejs.org/)\n* Установите зависимости:\n\n        cd ~/mapsapi-folder\n        npm install\n\n* В файле `config.main.json` замените параметр `baseUrl` на пустую строку: `\"baseUrl\": \"\"`.\n* Выполните сборку API карт и запуск сервера:\n\n        npm run dev\n\nПосле выполнения описанных выше действий вы сможете открыть в браузере карту по адресу http://127.0.0.1:3000/2.0/\n\n## Стандарты кодирования\n\n### JavaScript\nОсновные требования к JavaScript коду обеспечиваются синтаксическим анализатором и описаны в конфигурационом файле [ESLint](https://github.com/2gis/maps-api-2.0/blob/master/.eslintrc). В процессе разработки мы стараемся придерживаться соглашений, схожими с [Airbnb style guide](https://github.com/airbnb/javascript), за исключением соглашений о [пробелах](https://github.com/airbnb/javascript#whitespace) и [комментариях](https://github.com/airbnb/javascript#comments).\n\n### HTML и CSS\n#### Определения\nДанные соглашения&nbsp;&mdash; набор правил разной степени обязательности исполнения. Используется три степени:\n* обязательно&nbsp;&mdash; нарушение правила не имеет смысла либо полностью запрещено. Нарушение должно обсуждаться заранее с командой;\n* должно&nbsp;&mdash; нарушение правила возможно при достаточном обосновании. Нарушение можно обсудить постфактум или оставить комментарий в коде;\n* рекомендуется&nbsp;&mdash; при прочих равных лучше использовать рекомендованный вариант.\n\nСоглашения являются расширением методологии [БЭМ](http://ru.bem.info/method/definitions/), поэтому используются следующие термины:\n* блок&nbsp;&mdash; синоним понятий &laquo;плагин&raquo;, &laquo;модуль&raquo;&nbsp;&mdash; неразрывная независимая часть ветки DOM-дерева (или ветка целиком), и связанных с ней CSS-правил, которая может быть переиспользована на любом проекте, в любом контексте. Блоком так же называется корневой тег такой структуры;\n* элемент&nbsp;&mdash; структурная единица блока. Элемент всегда принадлежит одной копии блока. Элемент не имеет смысла вне блока. Элемент не может принадлежать одновременно нескольким блокам, или нескольким копиям одного блока. При движении от элемента вверх по DOM дереву можно встретить любое число других элементов того же блока, либо сам блок. Нельзя встретить элементы других блоков или другие блоки;\n* модификатор&nbsp;&mdash; синоним понятия &laquo;состояние&raquo;. Модификатор реализует наследование блоков&nbsp;&mdash; когда нам нужен второй блок, очень похожий на первый. Модификатор всегда относится к какому-то конкретному блоку или элементу. У любого блока и элемента может быть несколько модификаторов, по несколько значений у каждого.\n\n#### Область применения\n\nДанное соглашение применяется для вновь создаваемых блоков (модулей). Сюда относится замена блока при рефакторинге. Соглашение имеет слабое влияние при небольших работах со старым кодом, а также при переиспользовании сторонних модулей.\n\n#### HTML\n* вёрстка должна быть [валидным](http://validator.w3.org/#validate_by_input+with_options) html5 кодом;\n* код должен быть максимально семантичным;\n* код должен быть в нижнем регистре;\n* рекомендуется не указывать типы для тегов `script` и `link`;\n* рекомендуется пропускать строку перед блоками, списками, таблицами и т.д.;\n* должны использоваться двойные кавычки в атрибутах HTML.\n\n##### Рекомендуется использовать теги html5\n* `article`&nbsp;&mdash; выделение смысловой самостоятельной единицы (обычно блока);\n* `address`&nbsp;&mdash; тег для адреса;\n* `aside`&nbsp;&mdash; тег для сопутствующей информации, например &laquo;конкуренты&raquo;;\n* `time`&nbsp;&mdash; тег для любого времени или даты;\n* `header` и `footer` для явно выраженной шапки и футера блока, если такие есть;\n* а также: `summary`, `nav` и другие.\n\nСуществующие теги и их назначение: http://www.w3.org/TR/html-markup/elements.html#elements\n\n* рекомендуется использовать атрибуты [schema.org](http://schema.org/docs/gs.html#microdata_how);\n* запрещено использовать &laquo;табличные&raquo; теги: `table`, `thead`, `tbody`, `tfoot`, `tr`, `th`, `td` кроме как по их прямому назначению&nbsp;&mdash; т.е. для отображения табличных данных;\n* запрещено использование устаревших тегов: `font`, `blink` и прочее;\n* у каждого тега, который будет иметь визуальное представление на странице, должен быть CSS-класс (полное покрытие тегов классами).\n\n##### Структура\n* должна использоваться методология БЭМ;\n* любая визуальная HTML нода должна быть покрыта CSS-классом;\n* структура HTML должна быть семантичной и минимально зависеть от дизайна. Иными словами, по HTML-коду должно быть всё понятно о содержимом страницы, но ничего не понятно о её дизайне.\n\nПлохо:\n\n    <div class=\"outer-wrapper\">\n        <div class=\"inner-wrapper\">\n            <div class=\"right clerafix\">Какой-то <span class=\"red\">текст</span></div>\n        </div>\n    </div>\n\nХорошо:\n\n    <article class=\"dg-card dg-card_type_org dg-card_spec_edu\" itemscope itemtype=\"http://schema.org/EducationalOrganization\">\n        <header class=\"dg-card__header\">\n            <h1 class=\"dg-card__name\" itemprop=\"name\">Школа №176</h1>\n        </header>\n        <address class=\"dg-card__address\" itemprop=\"streetAddress\">Красный проспект, д. 348</address>\n    </article>\n\nПриветствуется минимизация DOM-дерева (исключение различных оберток, оболочек, разделителей, однопиксельных GIF-файлов и т.п.).\n\n##### Общий пример\n\n    <div class=\"dg-board\">\n        <div class=\"dg-board__list\">\n            <div class=\"dg-filters\">...</div>\n            <article class=\"dg-card\" itemscope itemtype=\"http://schema.org/EducationalOrganization\">\n                <header class=\"dg-card__header\">\n                    <h1 class=\"dg-card__name\" itemprop=\"name\">Школа №176</h1>\n                </header>\n                <address class=\"dg-card__address\" itemprop=\"streetAddress\">Красный проспект, д. 348</address>\n            </article>\n            <article class=\"dg-card\">...</article>\n            <article class=\"dg-card\">...</article>\n        </div>\n    </div>\n\n#### CSS\n##### Именование классов\n* обязательно используется методология БЭМ для именования всех CSS-классов;\n* для блоков должен использоваться префикс .dg-, например: `.dg-fullscreen`;\n* любой CSS-класс должен начинаться с имени блока;\n* любой класс по своему предназначению и правилам составления имени должен быть блоком, элементом, или модификатором;\n* модификатор обязан иметь четкое описание-комментарий;\n* запрещено использовать в имени блока любые символы, кроме a-z, 0-9 и &laquo;-&raquo;, а в качестве первого символа любые, кроме a-z. То же касается составных частей элементов и модификаторов;\n* должны использоваться одинарные кавычки;\n* должны использоваться короткие 16-тиричные числа, когда это возможно (#ffffff → #fff);\n* рекомендуется использовать сокращенные названия свойств CSS;\n* не рекомендуется указывать единицы измерений после нулевых значений. Плохо: `margin: 0px 10px;` Хорошо: `margin: 0 10px;`.\n\nПримеры классов блоков: `.dg-search`, `.dg-popup`, `.dg-card`, `.dg-firm-list`.\n\n* имя любого элемента обязательно имеет префикс `.block__`, где &laquo;block&raquo;&nbsp;&mdash; имя блока, которому принадлежит этот элемент.\n\nПримеры классов элементов: `.dg-card__name`, `.dg-search__query`, `.dg-popup__close`.\n\n* имя модификатора обязательно имеет префикс `block_` или `block__elem_` и состоит из двух частей: имя модификатора и значение модификатора.\n\nПримеры классов модификаторов:\n* `.dg-card_type_firm`&nbsp;&mdash; тип карточки &laquo;фирма&raquo;;\n* `.dg-search_mode_metro`&nbsp;&mdash; режим строки поиска &laquo;метро&raquo;;\n* `.dg-popup_state_hidden`&nbsp;&mdash; состояние коллаута &laquo;скрыт&raquo;;\n* `.dg-board__list_state_minimized`&nbsp;&mdash; состояние элемента &laquo;список&raquo; равно &laquo;свёрнут&raquo;.\n\nМодификаторы:\n\n* любой модификатор обязательно относится только к какому-то конкретному элементу или блоку;\n* разрешено использовать несколько разных модификаторов блока или элемента одновременно (например `.dg-card_state_visible` и `.dg-card_type_building`);\n* запрещено использовать несколько разных значений одного модификатора или элемента одновременно (например `.dg-card_state_hidden` и `.dg-card_state_visible`).\n\n##### Селекторы\n* селектор должен состоять только из одного имени класса;\n* селекторы по тегам крайне не желательны;\n* запрещено использовать селекторы по id;\n* одно состояние одного селектора должно встречаться в CSS 0 или 1 раз;\n* селекторы через запятую не желательны. Если такая необходимость сильно выражена, то стоит подумать о создании нового элемента с общими стилями, и его примешиванию к уже существующим в HTML коде;\n* классы должны быть сгруппированы вокруг своего блока в порядке: блок, элементы, модификаторы блока. То есть, в потоке CSS одним выделением можно выделить все стили блока и его элементов;\n* состояния класса должны быть также сгруппированы: класс, его псевдоклассы, его псевдоэлементы;\n* модификаторы блока должны быть сгруппированы по названию модификатора и по его значениям;\n* псевдоэлементы before и after должны отделяться от селектора одинарным двоеточием.\n\n##### Свойства\n* запрещено использование `!important`;\n* стили, предназначенные для IE 8, должны находиться в отдельных файлах;\n* файлы со стилями для IE 8 должны иметь суффикс &laquo;ie&raquo;. Пример: `dg-fullscreen.ie.less`;\n* наличие невалидного CSS должно быть строго обосновано. Используем [CSS валидатор](http://jigsaw.w3.org/css-validator/#validate_by_input);\n* любое неочевидное свойство или значение должно поясняться `/* комментарием */` на английском языке.\n"
  },
  {
    "path": "LICENSE",
    "content": "НАСТОЯЩИЙ ДОКУМЕНТ ЯВЛЯЕТСЯ ЮРИДИЧЕСКИМ ДОГОВОРОМ («Договор») между ООО «ДубльГИС» («Мы», «Нас»,\n«2ГИС») И ВАМИ («Вы») В ОТНОШЕНИИ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ API («Программное обеспечение»).\n\nКОГДА ВЫ СКАЧИВАЕТЕ, УСТАНАВЛИВАЕТЕ, КОПИРУЕТЕ ИЛИ ИНЫМ ОБРАЗОМ ИСПОЛЬЗУЕТЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ,\nВЫ ТЕМ САМЫМ ПРИНИМАЕТЕ УСЛОВИЯ ДОГОВОРА, ИЗЛОЖЕННЫЕ НИЖЕ. ЕСЛИ ВЫ НЕ СОГЛАСНЫ С НИЖЕСЛЕДУЮЩИМИ\nУСЛОВИЯМИ, ВЫ НЕ ИМЕЕТЕ ПРАВА СКАЧИВАТЬ, УСТАНАВЛИВАТЬ, КОПИРОВАТЬ ИЛИ ИНЫМ ОБРАЗОМ ИСПОЛЬЗОВАТЬ\nПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ИЛИ КАКУЮ-ЛИБО ЕГО ЧАСТЬ. НАСТОЯЩИЙ ЛИЦЕНЗИОННЫЙ ДОГОВОР ОПИСЫВАЕТ ВАШИ\nПРАВА И ОГРАНИЧЕНИЯ В ОТНОШЕНИИ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ И ЕГО КОМПОНЕНТОВ.\n\n1. ОПРЕДЕЛЕНИЯ\n\n«Приложение» означает любое программное обеспечение, приложение или элементы, которые Вы\n«разрабатываете или которыми управляете, используя Программное обеспечение или Модификации в\n«соответствии с настоящим Договором.\n\n«Конечный пользователь» означает конечного пользователя Вашего Приложения, который приобрел лицензию\n«на Приложение для собственного внутреннего использования, но не для распространения, перепродажи,\n«разработки пользовательского интерфейса или иных целей, связанных с разработкой.\n\n«Модификация» означает: а) любое дополнение или удаление из контента файла, включенного в\n«первоначальную версию Программного обеспечения или предшествующие Модификации, созданные вами,\n«и/или b) любой новый файл, который использует любую часть первоначальной версии Программного\n«обеспечения или предшествующих Модификаций.\n\n«Исходная» форма означает предпочтительную форму для внесения изменений, включая, в том числе,\n«исходный код программного обеспечения, исходную документацию и конфигурационные файлы.\n\n«Объектная» форма означает любую форму, полученную в результате механической трансформации или\n«перевода из Исходной формы, включая, в том числе, скомпилированный объектный код, генерируемую\n«документацию и конвертирование в иные форматы.\n\n«Код счетчика посещений» означает часть Исходной формы, которая требуется для отслеживания,\n«мониторинга и регистрации деятельности Конечных пользователей.\n\n«Программное обеспечение API» (Программное обеспечение») означает программный интерфейс приложения\n«ООО ДубльГИС»  версии 2.0 в форме, предоставляемой Вам ООО ДубльГИС», включая библиотеки, исходный\n«код, документацию, набор инструментальных средств разработчика и иные материалы, размещаемый на\n«https://github.com/2gis/maps-api-2.0 и http://api.2gis.ru/, предназначенный для модификаций,\n«адаптаций и иных изменений программного обеспечения.\n\nПрограммное обеспечение включает любые изменения, обновления, исправления ошибок или\nмодифицированные версии Программного обеспечения, при условии, что Мы имеем право изменять\nПрограммное обеспечение, а также изменять или отзывать настоящую лицензию на использование\nПрограммного обеспечения по Нашему исключительному усмотрению и в любое время без направления Вам\nпредварительного уведомления. Новая версия Договора вступает в силу в день ее размещения на сайте\nhttp://law.2gis.ru, если иное не предусмотрено новой версией договора. В случае Вашего несогласия с\nизмененной или обновленной версией Программного обеспечения, применяется раздел 7 настоящего\nДоговора.\n\n«Средства индивидуализации» означает в совокупности товарные знаки, торговые марки, знаки\n«обслуживания, логотипы, уведомления об авторском праве, доменные имена ООО ДубльГИС», а также иные\n«Наши средства индивидуализации.\n\n«Базы данных» означает в совокупности, общедоступные размещаемые и принадлежащие ООО ДубльГИС» Базы\n«данных электронных карт, включающие, в том числе, ГИС данные о географических объектах и населенных\n«пунктах в пределах территории, ограниченной определенными географическими координатами.\n\n «Контент» означает данные, включая, в том числе, любые фрагменты информации, хранящиеся и/или\n «извлекаемые из Баз данных, и/или любые иные данные или информацию, которую ОООДубльГИС» включило в\n «свое Программное обеспечение. Использование Вами Контента ограничено одновременным использованием\n «Программного обеспечения.\n\n \n\n2. ПРЕДОСТАВЛЕНИЕ ЛИЦЕНЗИИ\n\n2.1. При условии соблюдения условий настоящего Договора, Мы предоставляем на срок защиты авторского\nправа, действующую по всему миру, неисключительную, бесплатную и не подлежащую сублицензированию\nлицензию (i) Вам — на использование, копирование, модификацию, объединение Программного обеспечения\nв исходной и объектной формах для создания Модификаций и Приложений; (ii) Вам — на публичный показ,\nпубличное исполнение и бесплатное распространение Конечным пользователям Программного обеспечения\nи/или Модификаций в исходной или объектной форме, включенных в Приложения; и (iii) Конечным\nпользователям — на использование Программного обеспечения, включенного в Ваши Приложения в\nсоответствии с условиями настоящего Договора; (iv) Вам — на право осуществления коммуникации между\nВашим Приложением и Базами данных и извлечение из Баз данных информации, необходимой для\nиспользования способами, разрешенными настоящим Договором; (v) Вам — на изготовление ограниченного\nчисла промежуточных копий Контента исключительно для совершение действий, разрешенных настоящим\nДоговором, и на изменение (исключительно в целях реорганизации или упорядочивания) Контента в\nпределах Приложения; (vi) Вам — на раскрытие для всеобщего ознакомления структуры Программного\nобеспечения и Исходного кода, при условии, что Вы надлежащим образом идентифицируете их путем\nиспользования Средств индивидуализации.\n\nМы сохраняем за собой право модифицировать, изменять, обновлять и/или улучшать Программное\nобеспечение, Базы данных, Исходный код и Контент в любое время с уведомлением Вас или без такого\nуведомления по Нашему исключительному усмотрению.\n\n2.2. Вы можете модифицировать Исходный код исключительно в целях проектирования, разработки и\nтестирования Ваших собственных Приложений. Тем не менее, Вам разрешается использовать, копировать,\nвоспроизводить, распространять и перераспределять Ваш модифицированный Исходный код при соблюдении\nследующих условий: (a) Вы включаете Наше уведомление об авторском праве (его текст содержится в\nДополнении А к настоящему Договору) в Ваше Приложение, в том числе в любом месте, где в таком\nПриложении появляется любое иное уведомление об авторском праве; и (b) Вы не используете иным\nобразом Наше наименование, Средства индивидуализации и иные Наши торговые марки для реализации\nВашего Приложения, кроме случаев когда Мы в письменном виде согласовали иное. Кроме случаев,\nуказанных выше, Вы не можете иным образом модифицировать, удалять или изменять Код счетчика\nпосещений, включенный в Программное обеспечение.\n\n2.3. На Вас не возлагается обязанность по уплате Нам каких-либо роялти в за осуществляемое Вами\nраспространение Программного обеспечения в соответствии с настоящим Договором, а также по уплате Нам\nкаких-либо комиссий за использование или распространение Приложений в соответствии с настоящим\nДоговором.\n\n3. ПРАВО СОБСТВЕННОСТИ\n\n3.1. Настоящий Договор является лицензионным договором, а не договором купли- продажи. Мы сохраняем\nза собой все права интеллектуальной собственности на Программное обеспечение или связанные с\nПрограммным обеспечением, включая, в том числе, авторское право, патентные права, все права на\nзарегистрированные и не зарегистрированные товарные знаки (знаки обслуживания), конфиденциальную\nинформацию (включая секреты производства и ноу-хау) и все иные права, кроме тех, которые в прямо\nвыраженной форме предоставляются по настоящему Договору.\n\n3.2. Мы предоставляем Вам Исходный код, что позволяет Вам создавать Модификации и Приложения. В то\nвремя как Вы сохраняете за собой все права на любые оригинальные произведения в составе Модификаций,\nавтором которых Вы являетесь, мы сохраняем все права авторства и интеллектуальной собственности в\nотношении Программного обеспечения, Исходного кода, Баз данных, Контента, Кода счетчика посещений.\n\n3.3. Вы не вправе удалять, скрывать или изменять любые уведомления об авторском праве,\nудостоверения, ссылки на источник, товарные знаки, предупреждения или заявление об отказе от\nответственности, прикрепленные, включенные или иным образом применимые к Программному обеспечению.\n\n4. ОБРАТНАЯ СВЯЗЬ\n\n4.1. ООО «ДубльГИС» владеет бесплатной, действующей по всему миру, бессрочной лицензией на\nиспользование и включение в состав Программного обеспечения или Контента любых предложений, идей,\nзаявок на расширение, откликов, рекомендаций и иной информации и ее производных, предоставляемых\nВами.\n\n5. ЗАПРЕЩЕННОЕ ИСПОЛЬЗОВАНИЕ\n\n5.1. Вы не вправе повторно распространять Программное обеспечение или Модификации иным образом,\nкроме как путем включения Программного обеспечения или его части в Ваше Приложение. Вы не вправе\nизменять или удалять уведомление об авторском праве с файлов, включенных в Программное обеспечение\nили Модификации.\n\n5.2. Разрешение по настоящему Договору предоставляется любому лицу на использование данного\nПрограммного обеспечения для любой цели, исключая коммерческое использование, которое ограничивается\nв соответствии с настоящим Договором. Программное обеспечение или Модификации должны использоваться\nисключительно в составе Приложений, доступных для бесплатного общедоступного использования.\nИспользование Программного обеспечения или Модификаций для платных проектов или иных проектов,\nпредполагающих ограничение доступа Конечных пользователей к Базам данных и/или Контенту, строго\nзапрещается. В случае необходимости коммерческого использования, пожалуйста, обратитесь к Нам по\nследующему адресу api@2gis.ru.\n\n5.3. Версии Программного обеспечения с открытым кодом («GPL Версия») могут лицензироваться в\nсоответствии с Универсальной общедоступной лицензией версии 3.0., созданной в рамках проекта GNU\n(«GPL»), а не в соответствии с настоящим Договором. Если Вы или иное третье лицо разработали\nполностью (или любую часть) Приложения(ий), используя GPL Версию, Вы не вправе объединять такое\nразработанное произведение с Программным обеспечением и обязаны лицензировать такое(ие)\nПриложение(я) (или любую их часть) в соответствии с Универсальной общедоступной лицензией версии\n3.0., созданной в рамках проекта GNU, с которой можно ознакомиться по адресу\nhttp://www.gnu.org/copyleft/gpl.html.\n\n6. ОГРАНИЧЕНИЯ\n\n6.1. Кроме случаев, прямо разрешенных настоящим Договором, Лицензиат не вправе:\n\n(i) использовать Программное обеспечение, Базы данных, Исходный код или Контент любым способом,\n(который прямо не разрешен или не предоставлен по настоящему Договору;\n\n(ii) копировать Контент для целей, лежащих вне сферы действия лицензии, предоставленной по\n(настоящему Договору;\n\n(iii) использовать Контент для создания баз данных или любых компиляций Контента без Нашего\n(предварительного письменного разрешения;\n\n(iv) распространять, публиковать, продвигать, предоставлять право или разрешать доступ или\n(предоставлять ссылку на Контент или Базы данных из любого места или источника, кроме Вашего\n(Приложения;\n\n(v) использовать Контент для создания приложения, которое предлагает или рекламирует услуги, которые\n(порочат Наши услуги, наносят ущерб или являются конкурирующими по отношению к Нашим услугам или\n(иным образом вредят Нашим услугам;\n\n(vi) обходить, устанавливать спайдеры и индексы или любым способом сохранять информацию, полученную\n(из Контента кроме способов, предусмотренных настоящей ограниченной лицензией) или распространять\n(любые вирусы, «червей», троянские программы или иные программы, направленные на причинение вреда\n(любым системам или данным, отправлять или сохранять наносящие вред или незаконные материалы с\n(использованием Программного обеспечения;\n\n(vii) предоставлять Контент или Базы данных любым третьим сторонам способом, противоречащим условиям\n(использования, предусмотренным для пользователей нашего сайта;\n\n(viii) осуществлять коммерческое использование т.е. продавать, сдавать в аренду), копировать,\n(хранить или кэшировать Контент или Базы данных для иных целей, кроме разрешенных настоящим\n(Договором.\n\n6.2. Ограничение сублицензирования. Кроме случаев, предусмотренных в настоящем разделе, все\nлицензионные права (в соответствии с применимым правом интеллектуальной собственности),\nпредоставленные по настоящему Договору, не подлежат сублицензированию, передаче или уступке. При\nусловии соблюдения положений ниже, Вы вправе сублицензировать Ваше право на показ Контента и Средств\nиндивидуализации, как предусмотрено настоящим Договором, Конечным пользователям исключительно для\nтого, чтобы они имели возможность показа Контента и Средств индивидуализации на экранах своих\nкомпьютеров и/или вебсайтах посредством Вашего Приложения.\n\n7. ПРЕКРАЩЕНИЕ\n\n7.1. Настоящий Договор и Ваше право на использование Программного обеспечения и Модификаций\nнемедленно прекращается в случае Вашего несоблюдения любых условий настоящего Договора. После\nпрекращения Вы должны немедленно прекратить использование и уничтожить Программное обеспечение и\nМодификации, включая все сопроводительные документы.\n\n8. ОТКАЗ ОТ ПРЕДОСТАВЛЕНИЯ ГАРАНТИЙ\n\n8.1. В МАКСИМАЛЬНОЙ СТЕПЕНИ, ДОПУСТИМОЙ ПРИМЕНИМЫМ ЗАКОНОДАТЕЛЬСТВОМ, МЫ ОТКАЗЫВАЕМСЯ ОТ\nПРЕДОСТАВЛЕНИЯ ЛЮБЫХ ГАРАНТИЙ И УСЛОВИЙ, ПРЯМО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, В ТОМ ЧИСЛЕ,\nПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ПРОДАЖИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ, НАЛИЧИЯ ПРАВА\nСОБСТВЕННОСТИ И ОТСУТСТВИЯ НАРУШЕНИЙ В ОТНОШЕНИИ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ. МЫ НЕ ГАРАНТИРУЕМ, ЧТО\nРАБОТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ЕГО КОДА, БУДЕТ БЕСПЕРЕБОЙНОЙ И БЕЗОШИБОЧНОЙ, И ВЫ ПРИЗНАЕТЕ,\nЧТО ПРЕДОСТАВЛЕНИЕ ТАКИХ ГАРАНТИЙ ЯВЛЯЕТСЯ ТЕХНИЧЕСКИ НЕОСУЩЕСТВИМЫМ ДЛЯ НАС.\n\n9. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ\n\n9.1. В МАКСИМАЛЬНОЙ СТЕПЕНИ, ДОПУСТИМОЙ ПРИМЕНИМЫМ ЗАКОНОДАТЕЛЬСТВОМ, МЫ НИ ПРИ КАКИХ\nОБСТОЯТЕЛЬСТВАХ НЕ ОТВЕЧАЕМ, НА ОСНОВАНИИ КАКИХ-ЛИБО ЗАКОНОВ, ЗА ЛЮБЫЕ ОСОБЫЕ, СЛУЧАЙНЫЕ, КОСВЕННЫЕ\nИЛИ ВТОРИЧНЫЕ УБЫТКИ (ВКЛЮЧАЯ, В ТОМ ЧИСЛЕ, УБЫТКИ В ФОРМЕ УПУЩЕННОЙ ВЫГОДЫ, ПРИОСТАНОВЛЕНИЯ\nДЕЯТЕЛЬНОСТИ, ПОТЕРИ КОММЕРЧЕСКОЙ ИНФОРМАЦИИ ИЛИ ЛЮБОЙ ИНОЙ ИМУЩЕСТВЕННЫЙ УЩЕРБ), ВОЗНИКШИЕ В\nРЕЗУЛЬТАТЕ ИСПОЛЬЗОВАНИЯ ИЛИ НЕВОЗМОЖНОСТИ ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ЕГО КОДА, ИЛИ\nПО ЛЮБОЙ ПРИЧИНЕ, СВЯЗАННОЙ С ПРЕДМЕТОМ НАСТОЯЩЕГО ДОГОВОРА, ДАЖЕ В СЛУЧАЕ ЕСЛИ МЫ БЫЛИ\nПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ВОЗНИКНОВЕНИЯ ТАКИХ УБЫТКОВ.\n\n10. БЕСПЛАТНОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ\n\n10.1. Независимо от указанного выше, Мы признаем, что некоторые компоненты Программного обеспечения\nмогут подпадать под действие лицензии на так называемое «программное обеспечение с открытым исходным\nкодом» («Компоненты с открытым кодом»). Мы обязуемся подготовить обзор соответствующего бесплатного\nпрограммного обеспечения и предоставить Вам полный соответствующий исходный код, включая все\nизменения, произведенные нами (при наличии). Обзор будет включен в Дополнение А, вместе с копией\nусловий лицензии, регулирующих предоставление соответствующего бесплатного программного обеспечения.\n\n10.2. В степени, требуемой лицензиями, касающимися Компонентов с открытым кодом, условия таких\nлицензий будут применяться вместо условий настоящего Договора, и мы настоящим заявляем, что только\nКомпоненты с открытым кодом, лицензируемые на основании лицензий, предоставляющих объем прав не уже,\nчем лицензия, предоставляемая по настоящему Договору, включены в Программное обеспечение. В той\nмере, в какой лицензии, применимые в отношении Компонентов с открытым кодом, запрещают какие-либо\nограничения, содержащиеся в настоящем Договоре, такие ограничения не будут применяться в отношении\nКомпонентов.\n\n11. ИНТЕЛЛЕКТУАЛЬНАЯ СОБСТВЕННОСТЬ\n\n11.1. Программное обеспечение содержит Наши товарные знаки, логотипы, патенты, секреты производства\nи/или материалы, охраняемые авторским правом. Вы обязуетесь не раскрывать и не предоставлять такие\nсекреты производства и/или ноу-хау в любой форме любым третьим сторонам, не удалять уведомления о\nтоварных знаках, уведомления об авторском праве, условия лицензии с Программного обеспечения или\nлюбых его компонентов. Право собственности и права интеллектуальной собственности на Наши товарные\nзнаки или в отношении Наших товарных знаков и материалов, охраняемых авторским правом, которые\nотображаются или доступны посредством Программного обеспечения, принадлежат нам.\n\n11.2. При условии соблюдения положений настоящего Договора и на период действия Договора Мы\nпредоставляем Вам ограниченную, неисключительную, отзывную, сублицензируемую лицензию на отображение\nтоварных знаков, торговых марок, знаков обслуживания, логотипов, уведомлений об авторских правах,\nдоменных имен и иных Средств индивидуализации в соответствии с настоящим Договором и исключительно в\nцелях указания на источник Программного обеспечения и для продвижения и/или рекламирования того\nфакта, что Вы используете Программное обеспечение в Вашем Приложении, разработанном на его основе.\n\n11.3. Никогда, в течение срока действия настоящего Договора или после его завершения, Вы не вправе\nоспаривать права на Средства индивидуализации или содействовать другим лицам в оспаривании таких\nправ, а также не вправе содействовать в регистрации любых Средств индивидуализации или\nопознавательных черт бренда (включая доменные имена), которые в любом виде схожи до степени смешения\nв любыми Средствами индивидуализации.\n\n12. ГАРАНТИИ СТОРОН В ОТНОШЕНИИ ВОЗМЕЩЕНИЯ УБЫТКОВ\n\n12.1. При условии соблюдения положений настоящего Договора, Вы обязаны защищать, освобождать от\nответственности и возмещать убытки Нам, нашим аффилированным лицам, лицензиарам, каждому из наших\nсотрудников, должностных лиц, директоров, в отношении любых исков, ущерба, ответственности, затрат и\nсборов (включая разумные затраты за юридические услуги), возникших в результате или в связи с\nиспользованием Вами Программного обеспечения (включая любой Контент, предоставляемый по настоящему\nДоговору) или в связи с нарушением настоящего Договора и/или любых заявлений или гарантий,\nвключенных в настоящий Договор. Вы соглашаетесь с тем, что Мы не принимаем на себя обязательств по\nвозмещению Вам убытков в связи с Вашим использованием Программного обеспечения или Контента.\n\n13. ПРОЧИЕ УСЛОВИЯ\n\n13.1. Лицензия, предоставляемая по настоящему Договору, применяется исключительно к версии\nПрограммного обеспечения, предоставляемой в соответствии с настоящим Договором, а также в отношении\nлюбых изменений и/или обновлений, на получение которых Вы можете иметь право. Во избежание сомнений,\nМы не обязаны предоставлять Вам какую-либо поддержку, средства устранения ошибок, изменения и\nобновления Программного обеспечения.\n\n13.2. Вы согласны соблюдать все применимые законы и подзаконные акты, относящиеся к Программному\nобеспечению.\n\n13.3. При дальнейшем распространении Программного обеспечения или Модификаций в рамках Вашего\nПриложения, Вы вправе предлагать поддержку, гарантии, гарантии возмещения убытков и иные\nобязательства и/или права, соответствующие условиям настоящего Договора. Тем не менее, при принятии\nтаких обязательств Вы вправе действовать исключительно от собственного имени и под свою\nответственность, но не от нашего имени. Вы должны возмещать Нам убытки или, по нашему выбору,\nзащищать нас от любых исков, претензий или судебных процессов, возбужденных против Нас (i) в связи с\nтем, что Вы приняли на себя такую поддержку, гарантии, гарантии возмещения убытков или\nдополнительную ответственность; или (ii) в связи с использованием, воспроизведением или\nраспространением Вашего Приложения, кроме случаев когда такой иск основывается исключительно на\nвключении Программного обеспечения в такое Приложение.\n\n13.4. Более того, Вы должны распространять Программное обеспечение исключительно в соответствии с\nсоглашением, которое включает все ограничения, предусмотренные настоящим Договором, и в той же\nстепени защищает Нас и Программное обеспечение, как это делает настоящий Договор.\n\n13.5. Вы признаете, что настоящий Договор является полным и единственным выражением нашего\nсоглашения. Никакая устная или письменная информация, предоставленная Нами или предоставленная иным\nобразом от Нашего имени, не создает каких-либо гарантий или дополнительных соглашений и никоим\nобразом не расширяет сферу действия настоящего Договора, и Вы не вправе полагаться на любую такую\nустную или письменную информацию.\n\n13.6. Настоящий Договор не предоставляет никаких подразумеваемых лицензий или подразумеваемых прав,\nи все иные права, кроме прямо предоставленных по настоящему Договору, сохраняются за Нами и нашими\nлицензиарами. Кроме того, никакие лицензии и привилегии не предоставляются в отношении\nкомбинирования Программного обеспечения и/или Модификаций, в зависимости от ситуации, с любым иным\nпрограммным обеспечением или аппаратными средствами, которые не были предоставлены Нами Вам по\nнастоящему Договору. Ваши права по настоящему Договору применяются только в отношении Программного\nобеспечения, Модификаций и/или Приложений.\n\n13.7. Если какие-либо положения настоящего Договора будут признаны недействительными, такие\nположения считаются исключенными из настоящего Договора; остальные условия сохраняют полную силу и\nдействие.\n\n13.8. Настоящий Договор регулируется законодательством соответствующей юрисдикции, в которой\nлицензия исполняется. Если набор прав по суперимперативным нормам применимого законодательства в\nсоответствующей юрисдикции включает дополнительные права, не предусмотренные настоящей Лицензией,\nтакие дополнительные права считаются предоставленными по настоящей Лицензии в соответствии с\nусловиями настоящей Лицензии.\n\nРедакция от 30.06.2014 г.\n\n\nДополнение А\n\nУведомление об авторском праве\n\nCopyright © 2014 2GIS. Эксперт по городу. www.2gis.ru\n\nНиже предоставляется перечень компонентов с открытым кодом, как предусмотрено настоящим документом.\nДанный перечень предоставляется для вашего удобства; пожалуйста, читайте далее, если желаете\nознакомиться с уведомлением(ями) об авторском праве и полным текстом лицензии, связанной с каждым\nкомпонентом.\n\nhttps://github.com/Leaflet/Leaflet/blob/master/LICENSE\nhttps://github.com/linkedin/dustjs/blob/master/LICENSE\nhttps://github.com/gulpjs/gulp/blob/master/LICENSE\nhttps://github.com/mapbox/wellknown/blob/master/LICENSE\n"
  },
  {
    "path": "LICENSE_EN",
    "content": "THIS DOCUMENT IS A LEGAL AGREEMENT (the “Agreement”) BETWEEN DoubleGIS LLC (\"We\", \"Us\", \"2GIS\") AND\nYOU (\"You\") IN RELATION TO API SOFTWARE (the \"Software\").\n\nBY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING THE SOFTWARE, YOU ACCEPT THE FOLLOWING TERMS\nAND CONDITIONS. IF YOU DO NOT AGREE WITH ANY OF THE TERMS OR CONDITIONS OF THIS LICENSE AGREEMENT,\nDO NOT PROCEED WITH THE DOWNLOADING, COPYING, INSTALLATION OR ANY OTHER USE OF THE SOFTWARE OR ANY\nPORTION THEREOF AS YOU HAVE NO RIGHTS TO DO SO. THIS LICENSE AGREEMENT DESCRIBES YOUR RIGHTS AND\nRESTRICTIONS WITH RESPECT TO THE SOFTWARE AND ITS COMPONENTS.\n\n1.DEFINITIONS\n\n\"Application\" means any software, application, or elements that You develop and operate using the\nSoftware or Modifications in accordance with this Agreement.\n\n\"End User\" means an end user of Your Application who acquires a license to such solely for their own\ninternal use and not for distribution, resale, user interface design or software development\npurposes.\n\n\"Modification\" means: a) any addition to or deletion from the contents of a file included in the\noriginal Software or previous Modifications created by You, and/or b) any new file that leverages\nany part of the original Software or previous Modifications.\n\n\"Source\" form shall mean the preferred form for making modifications, including but not limited to\nsoftware source code, documentation source, and configuration files.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or translation of a\nSource form, including but not limited to compiled object code, generated documentation, and\nconversions to other media types.\n\n\"Hit Counter Script Code\" means part of Source that is required for tracking, monitoring and\nregistration of End Users activity.\n\n\"API Software\" (\"Software\") means DoubleGIS LLC application programming interface 2.0 version in the\nform provided by DoubleGIS LLC to You, including any libraries, source code, documentation,\ndeveloper tools kit and other materials provided at https://github.com/2gis/maps-api-2.0 and\nhttp://api.2gis.ru/ designated for modification, adaptation and any other software changes. Software\nshall include any upgrades, updates, bug fixes or modified versions of the Software provided that We\nare entitled to change the Software, as well as to modify or revoke this license agreement to use\nthe Software at Our sole discretion and at any time without giving You prior notice. The new version\nof the Agreement shall enter into force on the date of its posting on the http://law.2gis.ru/,\nunless otherwise provided in the new version of the agreement. In case of Your disagreement with the\nuse of a modified or updated version of the Software, the Section 7 of the Agreement shall apply.\n\n\"Logos\" collectively means the DoubleGIS LLC trade names, trademarks, service marks, logos,\ncopyright notices, domain names and other Our distinctive brands.\n\n\"Databases\" collectively means publicly accessible and displayed DoubleGIS LLC Databases of an\nelectronic map, which includes GIS data on geographical locations and settlements within an area\nbounded by certain geographical coordinates.\n\n\"Content\" means included, but is not limited to any piece of information stored in and/or retrieved\nfrom the Databases and/or any other data or information DoubleGIS LLC chooses to include in its\nSoftware. The use of any Content by You is limited to concurrent use with the Software.\n\n2. LICENSE GRANT\n\n2.1. Subject to your compliance with all of the terms and conditions of this Agreement, We grant a\nperpetual for the duration of the applicable copyright, worldwide, non-exclusive, royalty-free and\nnot-sublicensable license (i) for You to use, copy, modify, merge the Software in source and object\nforms to create Modifications and Applications; (ii) for You to publicly display, publicly perform\nand at no-charge distribute the Software and/or Modifications in source and object forms to End\nUsers solely as integrated into the Applications; and (iii) for End Users to use the Software as\nintegrated into Your Applications in accordance with the terms of this Agreement; (iv) for You to be\nenable Your Application to interact with the Databases and retrieve therefrom information necessary\nto facilitate the use permitted under this Agreement; (v) for You to make limited intermediate\ncopies of the Content only as necessary to perform an activity permitted under this Agreement and to\nmodify (solely in order to rearrange or reorganize) the Content within Application; (vi)  for You to\ndisclose to the public the structure of the Software and the Source Code, provided that You properly\nidentify these by reference to Logo.\n\nWe reserve the right to modify, change, update and/or enhance the Software, the Databases, the\nSource Code, and the Content at any time with or without notice to You Our sole and exclusive\ndiscretion.\n\n2.2. You may modify the Source Code solely for the purposes of designing, developing and testing\nYour own Applications. However, You are permitted to use, copy, reproduce, distribute and\nredistribute Your modified Source Code only if all of the following conditions are met: (a) You\ninclude Our copyright notice (text is available in Exhibit A to this Agreement) with Your\nApplication, including every location in which any other copyright notice appears in such\nApplication; and (b) You do not otherwise use Our name, Logos or other of Our trademarks to market\nYour Application, unless otherwise agree by Us in writing. Except to the above, You may not modify\nremove or alter the Hit Counter Script Code contained in Software.\n\n2.3. You will not owe Us any royalties for Your distribution of the Software in accordance with this\nAgreement. You will not owe Us any fees for Your use or distribution of Applications in accordance\nwith this Agreement.\n\n3.OWNERSHIP\n\n3.1. This is a license agreement and not an agreement for sale. We reserve ownership of all\nintellectual property rights inherent in or relating to the Software, which include, but are not\nlimited to, all copyright, patent rights, all rights in relation to registered and unregistered\ntrademarks (service marks), confidential information (including trade secrets and know-how) and all\nrights other than those expressly granted by this Agreement.\n\n3.2. We provide You with Source code so that You can create Modifications and Applications. While\nYou retain all rights to any original work authored by You as part of the Modifications, We continue\nto own all copyright and other intellectual property rights in the Software, Source Code, Databases,\nContent, Hit Counter script code.\n\n3.3. You must not remove, obscure or interfere with any copyright, acknowledgment, attribution,\ntrademark, warning or disclaimer statement affixed to, incorporated in or otherwise applied in\nconnection with the Software.\n\n4.FEEDBACK\n\n4.1. DoubleGIS shall have a royalty-free, worldwide, perpetual license to use or incorporate into\nthe Software or Content any suggestions, ideas, enhancement requests, feedback, recommendations or\nother information and derivatives thereof provided by You.\n\n5.PROHIBITED USES\n\n5.1. You may not redistribute the Software or Modifications other than by including the Software or\na portion thereof within Your Application. You may not change or remove the copyright notice from\nany of the files included in the Software or Modifications. 5.2. The permission hereby is granted to\nanyone to use this Software for any purpose,   excluding commercial applications, which is subject\nto the restrictions of present Agreement. Software or Modifications shall be used only as integrated\ninto the Applications available for free public use.  Using of Software or Modifications for\nprojects intending payment or otherwise restricted access of the End Users to Databases or/and\nContent are strictly prohibited. In case of commercial use is required, please contact us at\napi@2gis.ru.\n\n5.3. Open Source versions of the Software (“GPL Version”) may be licensed under the terms of the GNU\nGeneral Public License versions 3.0 (“GPL”) and not under this Agreement. If You, or another third\nparty, has, at any time, developed all (or any portions of) the Application(s) using a GPL Version,\nYou may not combine such development work with the Software and must license such Application(s) (or\nany portions derived there from) under the terms of the GNU General Public License version 3, a copy\nof which is located at http://www.gnu.org/copyleft/gpl.html.\n\n6. RESTRICTIONS\n\n6.1. Except as expressly authorized under this Agreement, Licensee shall not (i) use the Software,\nthe Databases, the Source Code, or the Content in any way not expressly permitted or granted under\nthis Agreement; (ii) copy the Content for purposes outside the scope of the license granted herein;\n(iii) use the Content to create databases or any other compilations of Content, without Our prior\nwritten consent; (iv)You shall not distribute, publish, facilitate, enable or allow access or\nlinking to the Content or Database from any location or source other than Your Application; (v) use\nthe Content to create an application that offers or promotes services that may be competitive with,\ndamaging to, disparaging of or otherwise detrimental to the Our service; (vi) crawl, spider, index\nor in any way store information obtained from the Content (except for the limited license granted\nherein), or propagate any virus, worms, Trojan horses, or other programming routine intended to\ndamage any system or data,  send or store infringing or unlawful material using the Software; (vii)\nprovide Content or Databases to any third parties in a manner contrary to the terms of use\napplicable to users of the our web site; (viii) commercialize (i.e., sell, rent, or lease), copy,\nstore or cache the Content or Databases, other than for the purposes allowed by this Agreement.\n\n6.2. Limits on Sublicensing. Except as set forth in this section, all license rights (under any\napplicable intellectual property right) granted herein are not sublicenseable, transferable or\nassignable. Subject to the terms and conditions below, You may sublicense Your right to display the\nContent and the Logos, as provided in this Agreement, to End Users solely to enable End Users to\ndisplay Content and the Logos on their computer screens and/or websites through Your Application.\n\n7.TERMINATION\n\n7.1. This Agreement and Your right to use the Software and Modifications will terminate immediately\nif You fail to comply with any of the terms and conditions of this Agreement. Upon termination, You\nagree to immediately cease using and destroy the Software or Modifications, including all\naccompanying documents.\n\n8.DISCLAIMER OF WARRANTIES\n\n8.1. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, WE DISCLAIM ALL WARRANTIES AND CONDITIONS,\nEITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, AND TITLE AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE. WE DO\nNOT GUARANTEE THAT THE OPERATION OF THE SOFTWARE OR THE CODE IT PRODUCES WILL BE UNINTERRUPTED OR\nERROR-FREE, AND YOU ACKNOWLEDGE THAT IT IS NOT TECHNICALLY PRACTICABLE FOR US TO DO SO.\n\n9.LIMITATION OF LIABILITIES\n\n9.1. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL WE BE LIABLE UNDER ANY\nLEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING,\nWITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS\nINFORMATION OR ANY OTHER PECUNIARY LOSSES) ARISING OUT OF THE USE OF OR INABILITY TO USE THE\nSOFTWARE OR THE CODE IT PRODUCES OR ANY OTHER SUBJECT MATTER RELATING TO THIS AGREEMENT, EVEN IF WE\nHAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n\n10.FREE SOFTWARE\n\n10.1. Notwithstanding the foregoing, We acknowledges that certain components of the Software may be\ncovered by so-called \"open source\" software licenses (\"Open Source Components\"). We will prepare an\noverview of the relevant free software and provide You with the complete corresponding source code,\nincluding any modification We have made to that code if so. The overview shall be included in\nExhibit A, together with a copy of the license terms governing the relevant free software.\n\n10.2. To the extent required by the licenses covering Open Source Components, the terms of such\nlicenses will apply in lieu of the terms of this Agreement, and We hereby represent that only Open\nSource Components with licenses that intend to grant permissions no less broad than the license\ngranted in this Agreement are included in the Software. To the extent which the licenses applicable\nto an Open Source Component prohibit any of the restrictions in this Agreement with respect to such\nOpen Source Component, such restrictions will not apply regarding to these Components.\n\n11. INTELLECTUAL PROPERTY\n\n11.1. The Software contain Our trademarks, logos, patents, trade secrets and/or copyrighted\nmaterials. You shall not disclose or make available such trade secrets and/or know-how in any form\nto any third party nor remove any trademark notices, copyright notices, or licensing terms from the\nSoftware or any components therein. Title and intellectual property rights in and to Our trademarks\nand Our copyrighted material which appears in content displayed by or accessed through the Software\nbelongs to Us.\n\n11.2. Subject to the terms and conditions in, and during the term of, this Agreement, We grant you a\nlimited, nonexclusive, revocable, sublicensable license to display the trade names, trademarks,\nservice marks, logos, copyright notices, domain names and other Logos in accordance with this\nAgreement and solely for attributing the source of the Software and for the purpose of promoting\nand/or advertising that You use the Software and in your resulting Application.\n\n11.3. At no time during or after the term of this Agreement shall you challenge or assist others to\nchallenge the Logos or, nor shall you attempt to register any Logos or brand identifiers (including\ndomain names) that are confusingly similar in any way to any of the Logos.\n\n12.PARTIES INDEMNITY OBLIGATIONS\n\n12.1 Subject to this Agreement, You shall defend, indemnify and hold Us, our affiliates, and\nlicensors, and each of Our respective employees, officers, directors, harmless from and against any\nclaims, damages, liabilities, costs and fees (including reasonable attorneys' fees) arising out of\nor related to Your use of the Software (including all Content provided therein) or for any breach of\nthis Agreement and/or any of the representations and warranties made herein. You agrees that We\nshall have no indemnity obligations for any use You make of the Software or the Content.\n\n13.MISCELANEOUS\n\n13.1. The license granted herein applies only to the version of the Software available in connection\nwith the terms of this Agreement, and to any updates and/or upgrades to which you may be entitled.\nFor the avoidance of doubt, We are not obligated to provide You with any support, bug fixes,\nupgrades, or updates and/or upgrades to the Software.\n\n13.2. You agree that you will comply with all applicable laws and regulations with respect to the\nSoftware.\n\n13.3. While redistributing the Software or Modifications thereof as part of Your Application, You\nmay choose to offer acceptance of support, warranty, indemnity, or other liability obligations\nand/or rights consistent with this Agreement. However, in accepting such obligations, You may act\nonly on Your own behalf and on Your sole responsibility, not on our behalf. You shall indemnify Us,\nor at Our option, defend Us against any claim, suit or proceeding brought against Us (i) arising by\nreason of Your accepting any such support, warranty, indemnity or additional liability; or (ii)\narising out of the use, reproduction or distribution of Your Application, except to the extent such\nclaim is solely based on the inclusion of the Software therein.\n\n13.4. Further, You agree only to distribute the Software pursuant agreement that includes all the\nlimitations and restrictions of this Agreement and is as protective of Us and Software as is this\nAgreement.\n\n13.5. You acknowledge that this Agreement is complete and is the exclusive representation of our\nagreement. No oral or written information given by Us, or otherwise on Our behalf shall create a\nwarranty or collateral contract, or in any way increase the scope of this Agreement in any way, and\nYou may not rely on any such oral or written information.\n\n13.6. There are no implied licenses or other implied rights granted under this Agreement, and all\nrights, save for those expressly granted hereunder, shall remain with Us and our licensors. In\naddition, no licenses or immunities are granted to the combination of the Software and/or\nModifications, as applicable, with any other software or hardware not delivered by Us to You under\nthis Agreement. Your rights under this Agreement apply only to Software, Modifications, and/or\nApplications.\n\n13.7. If any provision in this Agreement shall be determined to be invalid, such provision shall be\ndeemed omitted; the remainder of this Agreement shall continue in full force and effect.\n\n13.8. This Agreement will be governed by the law s of the relevant jurisdiction in which the license\nterms are sought to be enforced. If the suite of rights granted under super imperative rules of\napplicable law in the relevant jurisdiction includes additional rights not granted under this\nLicense, these additional rights are granted in this License in order to meet the terms of this\nLicense.\n\nDate: 30.06.2014 Exhibit A Copyright notice Copyright © 2014 2GIS. The City Expert. www.2gis.ru\n\nThe following is a listing of the open source components detailed in this document. This list is\nprovided for your convenience; please read further if you wish to review the copyright notice(s) and\nthe full text of the license associated with each component.\nhttps://github.com/Leaflet/Leaflet/blob/master/LICENSE\nhttps://github.com/linkedin/dustjs/blob/master/LICENSE\nhttps://github.com/gulpjs/gulp/blob/master/LICENSE\nhttps://github.com/mapbox/wellknown/blob/master/LICENSE\n"
  },
  {
    "path": "README.md",
    "content": "# API карт 2GIS [![npm][npm-badge]][npm-link]\n\n[npm-badge]: https://img.shields.io/npm/v/2gis-maps.svg\n[npm-link]: https://www.npmjs.com/package/2gis-maps\n\nПри помощи API карт вы сможете:\n* создавать интерактивные карты на веб-странице;\n* показывать на карте различные объекты (маркеры, балуны, геометрические фигуры);\n* производить поиск на карте: определять координаты геообъектов по их названиям и названия по координатам.\n\nЧтобы начать использовать API карт нужно получить ключ, для этого напишите на почту api@2gis.com, далее перейдите в раздел [Быстрый старт](https://docs.2gis.com/ru/maps/others/rasterjs/).\n\nЕсли вы решили внести свой вклад в развитие продукта, ознакомьтесь с [инструкцией для контрибьюторов](https://github.com/2gis/maps-api-2.0/blob/master/CONTRIBUTING.md).\n\nТакже мы открыты для общения и готовы ответить на ваши вопросы, чтобы связаться с нами перейдите в раздел [Обратная связь](https://help.2gis.ru/feedback/).\n\nДополнительная информация:\n* текущая версия API карт — 2.0;\n* работает с использованием библиотеки [Leaflet](http://leafletjs.com);\n* правовая информация доступна [на сайте 2ГИС](http://law.2gis.ru/api-rules/#kart2).\n"
  },
  {
    "path": "app/config.js",
    "content": "/**\n * Build config\n */\nvar fs = require('fs');\nvar _ = require('lodash');\nvar basePath = __dirname + '/..'; // Set root application path\n\nvar config = {\n    mainAppConfig: basePath + '/config.main.json',\n    localAppConfig: basePath + '/config.local.json',\n\n    packages: require(basePath + '/gulp/deps/packs.js'),\n\n    skins: ['dark', 'light'],\n\n    source: {\n        deps: require(basePath + '/gulp/deps/deps.js'),\n        path: basePath + '/src/'\n    },\n\n    testSource: {\n        deps: require(basePath + '/gulp/deps/deps.js'),\n        path: basePath + '/gulp/tmp/testJS/src/'\n    },\n\n    leaflet: {\n        deps: require(basePath + '/node_modules/leaflet/build/deps.js').deps,\n        path: basePath + '/node_modules/leaflet/src/'\n    },\n\n    tmpl: {\n        dir: 'templates',\n        pattern: '*.dust',\n        ext: '.dust',\n        varPostfix: '_TMPL'\n    },\n\n    doc: {\n        menu: './src/menu.json',\n        input: './src/doc/',\n        output: './dist/doc'\n    },\n\n    copyright: fs.readFileSync('./src/copyright.js'),\n\n    coreModules: ['DGCore', 'DGCustomization', 'DGAjax']\n};\n\nfunction getMainConfig() {\n    return require(config.mainAppConfig);\n}\n\nfunction getLocalConfig() {\n    try {\n        return require(config.localAppConfig);\n    } catch (e) {\n        return {};\n    }\n}\n\nfunction getAppConfig() {\n    return _.assign({}, getMainConfig(), getLocalConfig());\n}\n\nconfig.mainConfig = getMainConfig();\nconfig.localConfig = getLocalConfig();\nconfig.appConfig = getAppConfig();\n\nmodule.exports = config;\n"
  },
  {
    "path": "app/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>API карт 2ГИС</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n    <script src=\"__BASE_URL__/loader.js\"></script>\n\n    <style>\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n        .leaflet-touch .leaflet-bottom .dg-attribution { margin-top: 70px; }\n        .leaflet-touch .leaflet-bottom .dg-zoom {margin: 40px 10px 40px 0; }\n    </style>\n</head>\n<body>\n\n<div id=\"map\"></div>\n\n<script>\n    DG.then(function () {\n        // change control position on touch devices\n        var options = {\n            center: [54.980156831455, 82.897440725094],\n            zoom: 13,\n            geoclicker: true,\n            worldCopyJump: true,\n            zoomControl: false,\n            fullscreenControl: false,\n            key: DG.config.key || 'Your API access key',\n        };\n        var query = parseQuery();\n        var map = window.map = DG.map('map', getMapOptions(query, options));\n\n        var controlOptions = DG.Browser.mobile ? {position: 'bottomright'} : {};\n        DG.control.zoom(controlOptions).addTo(map);\n        DG.control.traffic(controlOptions).addTo(map);\n        DG.control.location(controlOptions).addTo(map);\n        DG.control.ruler(controlOptions).addTo(map);\n        if (DG.screenfull.isAvailable()) {\n            DG.control.fullscreen(controlOptions).addTo(map);\n        }\n        var balloonHTML = '<a href=\"http://www.2gis.ru/\" target=\"_blank\">\\n\\\n        <img src=\"__BASE_URL__/img/2gis-logo.png\" alt=\"2GIS\" title=\"2GIS\" width=\"154\" height=\"66\" style=\"border: none\"></a>\\n\\\n        <p>Компания «ДубльГИС»</p>Тел.: (383) 363-05-55<br />Адрес: г. Новосибирск, Карла Маркса площадь, 7<br />\\n\\\n        (МФК «Сан Сити»), 13 этаж';\n\n        var marker = DG.marker([54.980156831455, 82.897440725094]).addTo(map).bindPopup(balloonHTML);\n\n        if (query.lng === undefined && query.lat === undefined) {\n            // only open popup when no coordinates specified because it moves map to popup\n            marker.openPopup();\n        }\n\n        map.on('moveend', function() {\n            if (!history.replaceState) {\n                return; // ie <= 9\n            }\n\n            var center = map.getCenter();\n            history.replaceState({}, document.title,\n                '?lng=' + center.lng.toFixed(5) +\n                '&lat=' + center.lat.toFixed(5) +\n                '&zoom=' + map.getZoom()\n            );\n        });\n    });\n\n    function parseQuery() {\n        var res = {};\n        location.search.slice(1).split('&')\n            .map(function(str) {\n                return str.split('=')\n            })\n            .forEach(function(couple) {\n                res[couple[0]] = couple[1];\n            });\n        return res;\n    }\n\n    function getMapOptions(query, options) {\n        if (query.lng !== undefined && query.lat !== undefined) {\n            options.center = [parseFloat(query.lat), parseFloat(query.lng)];\n        }\n        if (query.zoom !== undefined) {\n            options.zoom = parseInt(query.zoom, 10);\n        }\n        return options;\n    }\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "app/index.js",
    "content": "//Web app of 2GIS Maps API 2.0\nvar express = require('express');\nvar cors = require('cors');\nvar config = require('./config.js');\nvar _ = require('lodash');\nvar fs = require('fs');\n\n// Init application\nvar app = express();\napp.disable('x-powered-by');\napp.use(cors());\n\n// Serve loader\nvar loader = fs.readFileSync('./dist/loader.js', {encoding: 'utf8'});\napp.get('/loader.js', function(req, res) {\n    var localConfig = _.cloneDeep(config.localConfig);\n    var protocol = config.appConfig.protocol;\n\n    localConfig.protocol = protocol;\n\n    res.set('Content-Type', 'application/javascript; charset=utf-8');\n\n    var result = loader\n        .replace(/__LOCAL_CONFIG__/g, JSON.stringify(localConfig))\n        .replace(/__BASE_URL__/g, protocol + config.appConfig.baseUrl)\n        .replace(/__QUERY__/g, JSON.stringify(req.query));\n\n    // Send loader with injected params\n    res.send(result);\n});\n\n// Load index file and inject base URL\nvar indexFile = fs.readFileSync('./dist/index.html', {encoding: 'utf8'});\nindexFile = indexFile.replace(/__BASE_URL__/g, config.appConfig.baseUrl);\n\n// Serve index file\nfunction serveIndexFile(req, res) {\n    res.send(indexFile);\n}\napp.get('/', serveIndexFile);\napp.get('/index.html', serveIndexFile);\napp.get('/healthcheck', function(req, res) {\n    res.sendStatus(200);\n});\n\nfunction getParams(req) {\n    var pkg = req.query.pkg;\n    var skin = req.query.skin;\n    var ie8 = req.query.ie8 === 'true';\n\n    if (Object.keys(config.packages).indexOf(pkg) === -1) {\n        pkg = 'full';\n    }\n\n    if (config.skins.indexOf(skin) === -1) {\n        skin = config.appConfig.defaultSkin;\n    }\n\n    return {\n        pkg: pkg,\n        skin: skin,\n        ie8: ie8\n    }\n}\n\nfunction loadDir(dirPath) {\n    var files = {};\n\n    fs.readdirSync(dirPath).forEach(function(fileName) {\n        files[fileName] = fs.readFileSync(dirPath + '/' + fileName);\n    });\n\n    return files;\n}\n\n// Load and serve JS files\nvar jsFiles = loadDir('./dist/js');\napp.get('/js', function(req, res) {\n    var params = getParams(req);\n    var fileName = 'script.' + params.pkg + '.js';\n\n    res.set('Content-Type', 'application/javascript; charset=utf-8');\n    res.set('Cache-Control', 'public, max-age=84000');\n\n    res.send(jsFiles[fileName]);\n});\n\n// Load and serve CSS files\nvar cssFiles = loadDir('./dist/css');\napp.get('/css', function(req, res) {\n    var params = getParams(req);\n\n    var fileName = 'styles.' +\n        params.pkg + '.' +\n        params.skin + '.' +\n        (params.ie8 ? 'ie8' + '.' : '') +\n        'css';\n\n    res.set('Content-Type', 'text/css');\n    res.set('Cache-Control', 'public, max-age=84000');\n\n    res.send(cssFiles[fileName]);\n});\n\n// Serve everything else\napp.use(express.static(__dirname + '/../dist'));\n\n// Start server\nvar host = config.appConfig.host;\nvar port = config.appConfig.port;\n\napp.listen(port, host, function() {\n    console.log('Maps API 2.0 server listening on ' + (host ? host + ':' : '') + port);\n});\n"
  },
  {
    "path": "app/loader.js",
    "content": "(function() {\n    'use strict';\n\n    var isJSRequested = false;\n    var rejects = [];\n    var version = 'v4.0.12';\n    var baseURL = '__BASE_URL__';\n    var query = __QUERY__;\n    var isLazy = query.lazy === 'true';\n    var qs = getQueryString();\n\n    function getQueryString() {\n        var params = {\n            skin: query.skin,\n            pkg: query.pkg,\n            version: version\n        };\n\n        if (/MSIE\\x20(\\d+\\.\\d+);/.test(navigator.userAgent) && parseInt(RegExp.$1, 10) < 9) {\n            params.ie8 = true;\n        }\n\n        var qsComponents = [];\n\n        for (var key in params) {\n            var value = params[key];\n\n            if (value) {\n                qsComponents.push(key + '=' + value);\n            }\n        }\n\n        if (!qsComponents.length) {\n            return '';\n        }\n\n        return '?' + qsComponents.join('&');\n    }\n\n    function requestJS() {\n        isJSRequested = true;\n\n        var script = document.createElement('script');\n        script.setAttribute('type', 'text/javascript');\n        script.setAttribute('src', baseURL + '/js/' + qs);\n\n        script.onerror = function(evt) {\n            runRejects(evt);\n        };\n\n        document.getElementsByTagName('head')[0].appendChild(script);\n    }\n\n    // Returns a promise that resolves once the DOM is ready. Based on\n    // https://github.com/addyosmani/jquery.parts/blob/master/jquery.documentReady.js\n    function ensureDOMReady() {\n        return new Promise(function(resolve, reject) {\n            var isResolved = false;\n\n            function resolveOnce() {\n                // Clean up all listeners we added\n                if (document.addEventListener) {\n                    document.removeEventListener('DOMContentLoaded', resolveOnce, false);\n                    window.removeEventListener('load', resolveOnce, false);\n                } else {\n                    document.detachEvent('onreadystatechange', resolveOnce);\n                    window.detachEvent('onload', resolveOnce);\n                }\n\n                if (isResolved) {\n                    return;\n                }\n\n                isResolved = true;\n                resolve();\n            }\n\n            // Scroll check hack for IE8\n            function doScrollCheck() {\n                if (isResolved) {\n                    return;\n                }\n\n                try {\n                    document.documentElement.doScroll('left');\n                } catch (e) {\n                    setTimeout(doScrollCheck, 50);\n                    return;\n                }\n\n                resolveOnce();\n            }\n\n            // If the DOM is already ready, load JS immediately\n            if (document.readyState !== 'loading') {\n                return resolveOnce();\n            }\n\n            // Adding event listeners. We also listen to window load event as a\n            // 'better late than never' fallback.\n            if (document.addEventListener) {\n                document.addEventListener('DOMContentLoaded', resolveOnce, false);\n                window.addEventListener('load', resolveOnce, false);\n            } else if (document.attachEvent) { // IE8\n                document.attachEvent('onreadystatechange', resolveOnce);\n                window.attachEvent('onload', resolveOnce);\n\n                // Scroll check hack for IE8\n                var isTopLevel = false;\n                try {\n                    isTopLevel = window.frameElement == null;\n                } catch (e) {}\n                if (document.documentElement.doScroll && isTopLevel) {\n                    doScrollCheck();\n                }\n            }\n        });\n    }\n\n    function loadStylesheet() {\n        var url = baseURL + '/css/' + qs;\n        var style = document.createElement('style');\n        style.type = 'text/css';\n\n        return new Promise(function(resolve, reject) {\n            DG.ajax(url, {\n                type: 'get',\n\n                dataType: 'html',\n\n                success: function(data) {\n                    var head = document.getElementsByTagName('head')[0];\n\n                    // Replace urls in CSS in case local config was changed\n                    // after build. originalBaseUrl contains URL value at the\n                    // moment application was built. baseUrl contains current\n                    // value.\n                    var originalBaseUrl = '__ORIGINAL_BASE_URL__';\n\n                    // Replace if they don't match\n                    if (baseURL !== originalBaseUrl) {\n                        data = data.replace(\n                            new RegExp(originalBaseUrl, 'g'),\n                            baseURL\n                        );\n                    }\n\n                    if (style.styleSheet) {\n                        head.appendChild(style);\n                        style.styleSheet.cssText = data;\n                    } else {\n                        style.appendChild(document.createTextNode(data));\n                        head.appendChild(style);\n                    }\n\n                    resolve();\n                },\n\n                error: function() {\n                    reject();\n                }\n            });\n        });\n    }\n\n    function loadProjectList() {\n        var url = DG.config.protocol +\n            DG.config.webApiServer + '/' +\n            DG.config.webApiVersion + '/region/list';\n\n        return new Promise(function(resolve) {\n            DG.ajax(url, {\n                type: DG.ajax.corsSupport ? 'get' : 'jsonp',\n\n                data: {\n                    format: DG.ajax.corsSupport ? 'json' : 'jsonp',\n                    key: DG.config.webApiKey,\n                    fields: DG.config.regionListFields\n                },\n\n                timeout: DG.config.loadProjectListTimeout,\n\n                success: function(data) {\n                    var result = data.result;\n\n                    if (result && result.items && result.items.length) {\n                        DG.projectsList = result.items;\n                    }\n\n                    resolve();\n                },\n\n                error: function(err) {\n                    resolve();\n                }\n            });\n        });\n    }\n\n    function extendConfig() {\n        DG.extend(DG.config, __LOCAL_CONFIG__);\n\n        if (DG.customConfig) {\n            DG.extend(DG.config, DG.customConfig);\n        }\n    }\n\n    function prepareForInit() {\n        return Promise.all([\n            loadStylesheet(),\n            loadProjectList(),\n            ensureDOMReady()\n        ]);\n    }\n\n    function setReady() {\n        DG.ready = true;\n    }\n\n    function runRejects() {\n        for (var i = 0, l = rejects.length; i < l; i++) {\n            if (typeof rejects[i] === 'function') {\n                rejects[i]();\n            }\n        }\n    }\n\n    window.DG = window.DG || {};\n    window.DG.ready = false;\n\n    window.__dgApi__ = {\n        callbacks: [\n            [extendConfig, undefined],\n            [prepareForInit, undefined],\n            [setReady, undefined]\n        ],\n        version: version\n    };\n\n    var loaderDgThen = window.DG.then = function(resolve, reject) {\n        if (DG.then !== loaderDgThen) {\n            return DG.then(resolve, reject);\n        }\n\n        window.__dgApi__.callbacks.push([resolve, reject]);\n\n        if (isLazy && !isJSRequested) {\n            requestJS();\n        }\n\n        if (reject) {\n            rejects.push(reject);\n        }\n\n        return this;\n    };\n\n    if (!isLazy) {\n        requestJS();\n    }\n})();\n"
  },
  {
    "path": "assets/cluster_realworld.js",
    "content": "//An extract of address points from the LINZ bulk extract: http://www.linz.govt.nz/survey-titles/landonline-data/landonline-bde\n//Should be this data set: http://data.linz.govt.nz/#/layer/779-nz-street-address-electoral/\nvar addressPoints = [\n[54.9210922667, 82.8209316333, \"2\"],\n[54.9210819833, 82.8213903167, \"3\"],\n[54.9210881833, 82.8215004833, \"3A\"],\n[54.9211946833, 82.8213655333, \"1\"],\n[54.9209458667, 82.8214051333, \"5\"],\n[54.9208292333, 82.8214374833, \"7\"],\n[54.9325816, 82.8238798667, \"537\"],\n[54.9315855167, 82.8279767, \"454\"],\n[54.9096336833, 82.8223743833, \"176\"],\n[54.90970685, 82.8221815833, \"178\"],\n[54.9102146667, 82.8211562833, \"190\"],\n[54.9088037167, 82.8242227, \"156\"],\n[54.9112330167, 82.8193425667, \"210\"],\n[54.9116368667, 82.8193005167, \"212\"],\n[54.90812645, 82.8255449333, \"146\"],\n[54.9080231333, 82.8286383167, \"125\"],\n[54.9089538667, 82.8222222333, \"174\"],\n[54.9080905833, 82.8275400667, \"129\"],\n[54.908811, 82.8227592833, \"172\"],\n[54.90832975, 82.8276898167, \"131\"],\n[54.9089395333, 82.8281710333, \"133\"],\n[54.9093421, 82.8274883167, \"135\"],\n[54.9084820833, 82.82601925, \"137\"],\n[54.90881015, 82.82622865, \"139\"],\n[54.9090947667, 82.8263585667, \"141\"],\n[54.9092962333, 82.8244872333, \"147\"],\n[54.9091016667, 82.8249140167, \"145\"],\n[54.9088785167, 82.8253611667, \"143\"],\n[54.90825965, 82.82530115, \"148\"],\n[54.90995685, 82.8238554333, \"153\"],\n[54.90975435, 82.8238417833, \"151\"],\n[54.90950755, 82.8237912, \"149\"],\n[54.9092772667, 82.8231980833, \"170\"],\n[54.9082753833, 82.80672975, \"4\"],\n[54.9078434833, 82.811822, \"56\"],\n[54.9083775667, 82.8090812333, \"30B\"],\n[54.9084588, 82.8058838167, \"174\"],\n[54.9088788333, 82.8062702833, \"175\"],\n[54.9091632833, 82.80514875, \"182A\"],\n[54.9094891167, 82.80384695, \"202\"],\n[54.9156715667, 82.8034881667, \"277\"],\n[54.9109189333, 82.8024631, \"220\"],\n[54.9108164333, 82.8039622, \"219\"],\n[54.9125773667, 82.8026079667, \"238\"],\n[54.9125799333, 82.8032824, \"241A\"],\n[54.9125869, 82.8037423833, \"241C\"],\n[54.9140266833, 82.8025706, \"256\"],\n[54.90932, 82.8051094333, \"182B\"],\n[54.9098799667, 82.8040444167, \"197\"],\n[54.9094298833, 82.80561245, \"189\"],\n[54.9172409333, 82.8035291167, \"287\"],\n[54.9232166667, 82.82452865, \"2028\"],\n[54.9225024333, 82.8249944667, \"2022\"],\n[54.92334135, 82.8244748667, \"2030\"],\n[54.9229725333, 82.8246809333, \"2026\"],\n[54.9224034667, 82.82507345, \"2020\"],\n[54.9227806, 82.8248285833, \"2024\"],\n[54.9178801, 82.8181871667, \"6\"],\n[54.91811315, 82.8180543667, \"4\"],\n[54.9181739833, 82.81851995, \"1\"],\n[54.91797515, 82.8186312, \"3\"],\n[54.9181787, 82.8176995, \"2A\"],\n[54.9183385333, 82.81812895, \"2\"],\n[54.9293053167, 82.8105357833, \"31\"],\n[54.9309444333, 82.81208735, \"16\"],\n[54.9306726667, 82.8115020833, \"19\"],\n[54.9300903, 82.8120791, \"26\"],\n[54.9289416167, 82.8113778333, \"33\"],\n[54.9274969167, 82.8113355167, \"53\"],\n[54.9199192667, 82.8173622833, \"5A\"],\n[54.9200392833, 82.8174100167, \"3\"],\n[54.9196328, 82.8167642, \"18\"],\n[54.91752585, 82.8155467667, \"22C\"],\n[54.91766615, 82.8153714167, \"22B\"],\n[54.9179022667, 82.8151616833, \"22A\"],\n[54.9191980333, 82.81664245, \"20A\"],\n[54.91799325, 82.81565925, \"20C\"],\n[54.9187486333, 82.8165228667, \"20B\"],\n[54.91964875, 82.8172874167, \"7\"],\n[54.91925545, 82.8171617, \"11\"],\n[54.9190491667, 82.8170928333, \"13\"],\n[54.9194515667, 82.8172147167, \"9\"],\n[54.91981045, 82.81733245, \"5B\"],\n[54.91876595, 82.8172445167, \"15B\"],\n[54.9185999167, 82.8172441, \"17A\"],\n[54.91816745, 82.81725905, \"21B\"],\n[54.9182157167, 82.8164626333, \"24\"],\n[54.9180109667, 82.8173984167, \"23A\"],\n[54.9179918, 82.817159, \"23B\"],\n[54.9188473167, 82.8170330333, \"15\"],\n[54.9186481333, 82.8169800667, \"17\"],\n[54.9184132, 82.8169327333, \"19\"],\n[54.9202288333, 82.8174746333, \"1\"],\n[54.918193, 82.8169955667, \"21\"],\n[54.9178000833, 82.81733275, \"25\"],\n[54.9176839, 82.8168488333, \"26\"],\n[54.9198172, 82.8204960667, \"5\"],\n[54.919986, 82.82049635, \"3\"],\n[54.9197666, 82.8200825, \"4\"],\n[54.9193835833, 82.8191669667, \"10\"],\n[54.9193426333, 82.8198626667, \"11\"],\n[54.9192171667, 82.8191711, \"12\"],\n[54.9192621333, 82.8196364167, \"13\"],\n[54.9195289667, 82.8193943167, \"8\"],\n[54.91946, 82.8201499167, \"9\"],\n[54.9196037833, 82.819674, \"6\"],\n[54.9194712, 82.8204032, \"7A\"],\n[54.9196381, 82.8203709333, \"7\"],\n[54.9200137667, 82.8201364333, \"2\"],\n[54.9191725167, 82.8193772833, \"14\"],\n[54.9214417333, 82.8256822167, \"4\"],\n[54.9210291, 82.8259429667, \"8\"],\n[54.9212328333, 82.8258132, \"6\"],\n[54.9216819833, 82.8253209, \"3\"],\n[54.9334697167, 82.8038651667, \"326\"],\n[54.9322603667, 82.8028621167, \"317\"],\n[54.9322013667, 82.8046802667, \"1/341\"],\n[54.9320576167, 82.8165535833, \"435\"],\n[54.9319540333, 82.80506915, \"2/341\"],\n[54.9316975667, 82.8053442333, \"3/341\"],\n[54.9328229833, 82.8062598, \"346\"],\n[54.93161565, 82.8074915, \"355\"],\n[54.93219305, 82.80629425, \"347\"],\n[54.9328549, 82.8080619667, \"362\"],\n[54.9321289667, 82.8084019333, \"367\"],\n[54.9322225167, 82.8120427667, \"397\"],\n[54.9321649, 82.81119325, \"393\"],\n[54.9321458833, 82.8131246333, \"407\"],\n[54.9327043833, 82.81377405, \"416\"],\n[54.9321267167, 82.8144058167, \"417\"],\n[54.93212555, 82.8096521333, \"373\"],\n[54.9331028667, 82.80928495, \"366\"],\n[54.92866875, 82.82177625, \"563\"],\n[54.9295602, 82.81924335, \"582\"],\n[54.9304707833, 82.8182986167, \"590\"],\n[54.93086, 82.8180687667, \"592\"],\n[54.9328604833, 82.8172892167, \"618\"],\n[54.9342575667, 82.8168357833, \"638\"],\n[54.9239713, 82.8245693667, \"504\"],\n[54.9365260167, 82.8170911, \"673\"],\n[54.9233928833, 82.8249669167, \"492\"],\n[54.9248650167, 82.8246300833, \"509\"],\n[54.9191798333, 82.8265331667, \"435\"],\n[54.9143243333, 82.8310940167, \"368\"],\n[54.91459255, 82.8320046, \"363\"],\n[54.91127515, 82.8356499167, \"311\"],\n[54.9126359667, 82.8340855167, \"333\"],\n[54.9096158333, 82.8375218167, \"293\"],\n[54.9315868667, 82.8177722833, \"604\"],\n[54.9160177667, 82.8299268333, \"391\"],\n[54.9204715667, 82.8265481833, \"456\"],\n[54.9206352, 82.8265670333, \"458\"],\n[54.9208412667, 82.8265323333, \"460\"],\n[54.9210184333, 82.82648325, \"462\"],\n[54.9212643833, 82.8270422167, \"465\"],\n[54.92119945, 82.8264274333, \"464\"],\n[54.92136485, 82.8263145667, \"466\"],\n[54.9215261, 82.82684075, \"467\"],\n[54.9215301833, 82.8262078, \"468\"],\n[54.9217701667, 82.8266360167, \"1/471\"],\n[54.9218376833, 82.82686725, \"2/471\"],\n[54.9217084667, 82.8260839667, \"472\"],\n[54.9219782333, 82.8265028333, \"475\"],\n[54.9218988833, 82.8259723, \"476\"],\n[54.9223939333, 82.8262447, \"479\"],\n[54.9223048667, 82.8256582833, \"480\"],\n[54.9226657, 82.8261230833, \"481\"],\n[54.9224199, 82.8255487833, \"482\"],\n[54.9229134167, 82.8259527833, \"485\"],\n[54.9226937833, 82.8253693167, \"486\"],\n[54.9231509667, 82.8258170333, \"487\"],\n[54.92295265, 82.8252571167, \"488\"],\n[54.9233779, 82.8256743833, \"489\"],\n[54.9232052667, 82.8251109333, \"490\"],\n[54.9236200333, 82.82553395, \"493\"],\n[54.92385775, 82.8253390833, \"495\"],\n[54.9203220167, 82.82650925, \"454\"],\n[54.9179795333, 82.8262826, \"428\"],\n[54.91038215, 82.8365298167, \"303\"],\n[54.9161746667, 82.8297239833, \"393\"],\n[54.9083635333, 82.833955, \"294\"],\n[54.92029495, 82.8214968167, \"39\"],\n[54.9204754333, 82.8247793333, \"12B\"],\n[54.9205440833, 82.82344905, \"23\"],\n[54.9195974333, 82.8254019333, \"2\"],\n[54.9210801, 82.8237748667, \"20A\"],\n[54.9209057333, 82.82389775, \"18\"],\n[54.9208016833, 82.8221582833, \"32\"],\n[54.9209372667, 82.8236919, \"20\"],\n[54.9210586833, 82.82351925, \"22B\"],\n[54.92092905, 82.8234855333, \"22\"],\n[54.9208587333, 82.8231887667, \"24\"],\n[54.9210241167, 82.8230882, \"24B\"],\n[54.9208547833, 82.8229410667, \"26\"],\n[54.9209917, 82.8228447667, \"26B\"],\n[54.92097645, 82.8227176167, \"28B\"],\n[54.9208099167, 82.8226765167, \"28\"],\n[54.9207666833, 82.8224338833, \"30\"],\n[54.9209508833, 82.8222094167, \"32B\"],\n[54.92076515, 82.8219195167, \"34A\"],\n[54.9207399667, 82.8218131667, \"34B\"],\n[54.9203075833, 82.8240482833, \"19\"],\n[54.9205368167, 82.8237746667, \"21\"],\n[54.9205025833, 82.8231658, \"25A\"],\n[54.920465, 82.8229733667, \"27\"],\n[54.92043535, 82.8227387, \"29\"],\n[54.9204582, 82.8225319667, \"31\"],\n[54.92024115, 82.8224347833, \"31B\"],\n[54.9203792333, 82.8222631667, \"33\"],\n[54.92034095, 82.8219843, \"35\"],\n[54.9201566167, 82.8219446, \"35B\"],\n[54.92030575, 82.8217594333, \"37\"],\n[54.9202966833, 82.8233158167, \"25\"],\n[54.9192714167, 82.8253842667, \"1\"],\n[54.91969695, 82.82516645, \"4\"],\n[54.9194904667, 82.82468815, \"5\"],\n[54.9198524333, 82.8249096667, \"6\"],\n[54.9200581833, 82.8247122, \"8\"],\n[54.9193447, 82.8244639667, \"5C\"],\n[54.9208238, 82.8241340167, \"16\"],\n[54.9193183667, 82.82515695, \"1A\"],\n[54.91940575, 82.8249383333, \"3\"],\n[54.9211855167, 82.8242545333, \"18A\"],\n[54.9207094833, 82.82430275, \"14\"],\n[54.92027725, 82.82488135, \"10A\"],\n[54.9202305833, 82.8245652667, \"10\"],\n[54.9205049667, 82.8244201333, \"12\"],\n[54.9196320333, 82.8255586, \"22\"],\n[54.9209711, 82.8250444667, \"8\"],\n[54.92120665, 82.8252942833, \"5\"],\n[54.9210184, 82.8254290333, \"7\"],\n[54.9213430333, 82.8252086167, \"3\"],\n[54.9207887833, 82.8251555667, \"10\"],\n[54.92060805, 82.8257042333, \"13\"],\n[54.9208330333, 82.82553905, \"9\"],\n[54.9216988833, 82.8249665667, \"1\"],\n[54.9215665833, 82.8246573333, \"2\"],\n[54.9213729, 82.8247789333, \"4\"],\n[54.9211700667, 82.8249324333, \"6\"],\n[54.9205967667, 82.8252867, \"12\"],\n[54.9204008833, 82.8254234667, \"14\"],\n[54.92043265, 82.82582195, \"15\"],\n[54.9202037333, 82.8255415833, \"16\"],\n[54.9200154333, 82.8256547667, \"18\"],\n[54.9197443167, 82.8256164833, \"20\"],\n[54.9202814333, 82.82590955, \"17\"],\n[54.9202967667, 82.81462555, \"98\"],\n[54.92204485, 82.81819735, \"61B\"],\n[54.9224241, 82.8179326667, \"61C\"],\n[54.9215043167, 82.8227943833, \"24\"],\n[54.9219082, 82.8255408167, \"8\"],\n[54.9216963, 82.8240856667, \"14\"],\n[54.9213418333, 82.8188135667, \"55\"],\n[54.9204966333, 82.8183406333, \"54A\"],\n[54.9221799833, 82.81122085, \"139\"],\n[54.9217387, 82.82431625, \"12\"],\n[54.9218650167, 82.8149734167, \"107\"],\n[54.9214083333, 82.8220152667, \"30\"],\n[54.9213738333, 82.8217301, \"32\"],\n[54.9221598167, 82.8247839333, \"9\"],\n[54.9216356, 82.8235610667, \"18\"],\n[54.9212188167, 82.8221387333, \"30B\"],\n[54.9200466667, 82.8166111, \"84A\"],\n[54.9216679333, 82.8238393333, \"16\"],\n[54.9211582833, 82.82031685, \"34\"],\n[54.9221918667, 82.8250378333, \"7\"],\n[54.9187410167, 82.8067290167, \"170C\"],\n[54.9206532, 82.8170745667, \"81\"],\n[54.9212348667, 82.8181024167, \"67\"],\n[54.9213057667, 82.8185351167, \"57\"],\n[54.9214571, 82.8145877333, \"110\"],\n[54.92207085, 82.8136727167, \"121\"],\n[54.92190125, 82.8123493, \"130\"],\n[54.9207519667, 82.8102467333, \"150\"],\n[54.9212159, 82.8096407, \"159\"],\n[54.9208313833, 82.8067756, \"172\"],\n[54.9214413333, 82.8222779833, \"28\"],\n[54.9206921333, 82.8182549, \"54\"],\n[54.92043975, 82.8181215, \"56\"],\n[54.9218791, 82.8252452167, \"10\"],\n[54.92029435, 82.8169818, \"84\"],\n[54.9215885167, 82.82308725, \"22\"],\n[54.9215897333, 82.8233113167, \"20\"],\n[54.92167455, 82.8183345, \"61A\"],\n[54.9217164667, 82.8179857333, \"63\"],\n[54.92147385, 82.82253565, \"26\"],\n[54.9206765333, 82.8160304333, \"86\"],\n[54.9188941, 82.8069437, \"170A\"],\n[54.9188068333, 82.8068104833, \"170B\"],\n[54.9193742667, 82.8085580333, \"170\"],\n[54.9214388167, 82.8200072, \"45\"],\n[54.9209547167, 82.8157149167, \"92\"],\n[54.92088565, 82.8164849333, \"85\"],\n[54.92136235, 82.8159546667, \"97\"],\n[54.9219607333, 82.8232987, \"19\"],\n[54.9210501, 82.8179753833, \"69\"],\n[54.9212466667, 82.8222175833, \"28A\"],\n[54.9213836167, 82.82300555, \"22A\"],\n[54.921339, 82.8227439167, \"24A\"],\n[54.9208144333, 82.8173117167, \"77\"],\n[54.9189363667, 82.8211582333, \"25\"],\n[54.9196676167, 82.8209947333, \"26B\"],\n[54.9194113, 82.8211991, \"26\"],\n[54.91883205, 82.8209747, \"27\"],\n[54.9186925833, 82.8207728833, \"29\"],\n[54.9199931833, 82.8240802167, \"2\"],\n[54.9191759333, 82.8208279333, \"30\"],\n[54.91835395, 82.8196571667, \"39\"],\n[54.9198807333, 82.8235938167, \"6\"],\n[54.9194567833, 82.82349015, \"7\"],\n[54.9200507833, 82.81933875, \"58\"],\n[54.9197902167, 82.8182408, \"59A\"],\n[54.91991635, 82.81797195, \"59B\"],\n[54.9198223833, 82.8179361833, \"59C\"],\n[54.9201049333, 82.8197347167, \"60\"],\n[54.9199380333, 82.81836645, \"61A\"],\n[54.92003775, 82.8182443833, \"61B\"],\n[54.9200944167, 82.81803015, \"61C\"],\n[54.9201259667, 82.8185610667, \"63\"],\n[54.92026275, 82.8188001167, \"65\"],\n[54.9188917833, 82.8203729333, \"34\"],\n[54.9184921333, 82.8203832, \"33\"],\n[54.9190387167, 82.8206181333, \"32\"],\n[54.91968705, 82.8224253667, \"16\"],\n[54.91981205, 82.823119, \"10\"],\n[54.9193882833, 82.8229798333, \"11\"],\n[54.9190901167, 82.8227829833, \"13B\"],\n[54.9193593, 82.8227247833, \"13\"],\n[54.91993935, 82.8226893333, \"14B\"],\n[54.91842725, 82.8201474167, \"35\"],\n[54.9187965833, 82.8200475333, \"36\"],\n[54.9183878167, 82.8198735667, \"37\"],\n[54.9188702167, 82.8196982333, \"38B\"],\n[54.92027885, 82.8209890667, \"82\"],\n[54.9199839667, 82.8190668, \"56\"],\n[54.9187008333, 82.81973745, \"38A\"],\n[54.9196820167, 82.82262455, \"14\"],\n[54.9186528333, 82.8191018, \"42\"],\n[54.9182912167, 82.81915535, \"43\"],\n[54.91870525, 82.81945675, \"40\"],\n[54.9195044333, 82.8214081833, \"24\"],\n[54.91857075, 82.8205925167, \"31\"],\n[54.9195656167, 82.8181396, \"57\"],\n[54.9198411667, 82.8213911167, \"24A\"],\n[54.9195851667, 82.8240869667, \"3\"],\n[54.9192829167, 82.8239720167, \"3A\"],\n[54.9193257, 82.8224725667, \"15\"],\n[54.9197290167, 82.8224129833, \"16A\"],\n[54.9196499333, 82.8221262667, \"18\"],\n[54.9196755333, 82.8243193333, \"1\"],\n[54.9192091667, 82.82166805, \"21\"],\n[54.91957585, 82.82166585, \"22\"],\n[54.9199106833, 82.8238436, \"4\"],\n[54.91953715, 82.82372785, \"5A\"],\n[54.9193377833, 82.82378105, \"5\"],\n[54.9189702833, 82.8184597333, \"46\"],\n[54.9185876167, 82.81821495, \"47A\"],\n[54.9185706333, 82.8178869167, \"47B\"],\n[54.9191945667, 82.81845965, \"48\"],\n[54.9188482167, 82.8176680833, \"49\"],\n[54.9194043667, 82.81852395, \"50\"],\n[54.9196233333, 82.8186248333, \"52\"],\n[54.91920055, 82.8179787167, \"53\"],\n[54.9198255, 82.8188011167, \"54\"],\n[54.9205994333, 82.8207248667, \"81\"],\n[54.9193045333, 82.8222075667, \"17\"],\n[54.9205621167, 82.8204520167, \"79\"],\n[54.9180799333, 82.8194407, \"41A\"],\n[54.9208301833, 82.8206735833, \"81A\"],\n[54.9202558, 82.8206809333, \"80\"],\n[54.91941275, 82.81804965, \"55\"],\n[54.9190239, 82.8179808833, \"51\"],\n[54.9187854, 82.8180712167, \"47\"],\n[54.9187476667, 82.8186516333, \"44\"],\n[54.9182977, 82.81889655, \"45\"],\n[54.91831675, 82.8194069833, \"41\"],\n[54.9192735167, 82.8219502167, \"19\"],\n[54.9196219167, 82.82189825, \"20\"],\n[54.91962665, 82.8216432667, \"22A\"],\n[54.9192782833, 82.8209942, \"28\"],\n[54.9208129833, 82.8209176833, \"83A\"],\n[54.9206351167, 82.8209705667, \"83\"],\n[54.9203109333, 82.8212402667, \"84\"],\n[54.91909575, 82.82139795, \"23\"],\n[54.9197787167, 82.8228814, \"12\"],\n[54.9195628333, 82.81791605, \"57A\"],\n[54.9198373833, 82.8233606833, \"8\"],\n[54.9194342167, 82.82322975, \"9\"]\n];"
  },
  {
    "path": "assets/heat_realworld.js",
    "content": "//An extract of address points from the LINZ bulk extract: http://www.linz.govt.nz/survey-titles/landonline-data/landonline-bde\n//Should be this data set: http://data.linz.govt.nz/#/layer/779-nz-street-address-electoral/\nvar addressPoints1 = [\n[54.8839, 82.3745188667, \"571\"],\n[54.8869090667, 82.3657417333, \"486\"],\n[54.8894207167, 82.4015351167, \"807\"],\n[54.8927369333, 82.4087452333, \"899\"],\n[54.90585105, 82.4453463833, \"1273\"],\n[54.9064188833, 82.4441556833, \"1258\"],\n[54.90584715, 82.4463564333, \"1279\"],\n[54.9033391333, 82.4244005667, \"1078\"],\n[54.9061991333, 82.4492620333, \"1309\"],\n[54.9058955167, 82.4445613167, \"1261\"],\n[54.88888045, 82.39146475, \"734\"],\n[54.8950811333, 82.4107982, \"928\"],\n[54.88909235, 82.3922956333, \"740\"],\n[54.8889259667, 82.3938591667, \"759\"],\n[54.8876576333, 82.3859563833, \"687\"],\n[54.89027155, 82.3973178833, \"778\"],\n[54.8864473667, 82.3806136833, \"631\"],\n[54.9000262833, 82.4183242167, \"1012\"],\n[54.90036495, 82.4189457, \"1024\"],\n[54.9000976833, 82.4197312167, \"1027\"],\n[54.90239975, 82.42371165, \"1067\"],\n[54.9043379667, 82.42430325, \"1080\"],\n[54.9026441, 82.4231055167, \"1068\"],\n[54.8883536333, 82.3888573833, \"718\"],\n[54.9029948833, 82.4237386167, \"1070\"],\n[54.89824135, 82.4150421667, \"982\"],\n[54.8976067833, 82.41510265, \"983\"],\n[54.9023491333, 82.4225495, \"1066\"],\n[54.8856157167, 82.3775632833, \"608\"],\n[54.8963032667, 82.4132068, \"951\"],\n[54.8922813667, 82.4073402333, \"1/898\"],\n[54.88933345, 82.3956084333, \"769\"],\n[54.8936148833, 82.4090577, \"906\"],\n[54.8939398, 82.4094444833, \"914\"],\n[54.8857355333, 82.3722297667, \"542\"],\n[54.8931092167, 82.4083014, \"898\"],\n[54.9008253167, 82.4198128, \"1030\"],\n[54.9045052333, 82.4260735, \"1100\"],\n[54.9053927167, 82.42822265, \"1130\"],\n[54.90507935, 82.4313065, \"1147\"],\n[54.9055749667, 82.4319092167, \"1154\"],\n[54.9039034833, 82.4274736667, \"1/1105\"],\n[54.9037633, 82.4261181833, \"1093\"],\n[54.9038755, 82.42871045, \"3/1105\"],\n[54.90369555, 82.4285285, \"2/1105\"],\n[54.9056626, 82.4341078833, \"1170\"],\n[54.9018736833, 82.438852, \"1/1213\"],\n[54.9057596167, 82.4356650167, \"1180\"],\n[54.9053502, 82.4361049333, \"1185\"],\n[54.9053379167, 82.4366986167, \"1195\"],\n[54.9058892333, 82.4381450333, \"1204\"],\n[54.9060264167, 82.4400763167, \"1220\"],\n[54.9056766833, 82.4412592, \"1233\"],\n[54.9057312167, 82.4418380333, \"1235\"],\n[54.9061575833, 82.4421068667, \"1242\"],\n[54.9063946167, 82.4438004667, \"1256\"],\n[54.8996027667, 82.43995055, \"4/1215\"],\n[54.9006449667, 82.4395556833, \"3/1215\"],\n[54.9009138167, 82.4394061333, \"2/1215\"],\n[54.9034547, 82.4396315, \"1219\"],\n[54.9055243, 82.4396033, \"1221\"],\n[54.89952325, 82.4406619167, \"5/1215\"],\n[54.90561525, 82.4404853167, \"1225\"],\n[54.9045602333, 82.4477690333, \"1285\"],\n[54.9040051667, 82.4388491833, \"1213\"],\n[54.90588145, 82.4440349167, \"1257\"],\n[54.90595915, 82.4389286833, \"1212\"],\n[54.9059939667, 82.4398068833, \"1218\"],\n[54.8868631833, 82.37991055, \"630\"],\n[54.8878744833, 82.382179, \"650\"],\n[54.8880764, 82.3839845667, \"670\"],\n[54.8850457333, 82.3759821, \"594\"],\n[54.88446045, 82.3762872667, \"587\"],\n[54.8880782667, 82.38423415, \"1/670\"],\n[54.8863533833, 82.3690698667, \"515\"],\n[54.8861783167, 82.3710009833, \"530\"],\n[54.885424, 82.3716677833, \"541\"],\n[54.88524065, 82.3722141167, \"547\"],\n[54.9022371333, 82.47991035, \"10\"],\n[54.9020014833, 82.4799581667, \"1\"],\n[54.9020824, 82.4802630167, \"2\"],\n[54.9018589833, 82.4804760833, \"3\"],\n[54.9018211333, 82.4806769667, \"4\"],\n[54.9021543667, 82.4805538833, \"5\"],\n[54.9022658, 82.4807579333, \"6\"],\n[54.9024517833, 82.4806480667, \"7\"],\n[54.9024251167, 82.48041985, \"8\"],\n[54.9023317833, 82.4802119667, \"9\"],\n[54.9321212167, 82.4555088, \"39\"],\n[54.8956185167, 82.4719458667, \"4\"],\n[54.8954566, 82.4728120333, \"20\"],\n[54.8957231833, 82.4727906, \"22A\"],\n[54.8956085833, 82.4726702, \"22\"],\n[54.8956460167, 82.4718485167, \"2\"],\n[54.8953487167, 82.47202915, \"5\"],\n[54.8800121167, 82.4865467167, \"9\"],\n[54.8803487833, 82.48595255, \"3\"],\n[54.8802064167, 82.4861004, \"5\"],\n[54.8800705167, 82.4862671167, \"7\"],\n[54.8798887333, 82.4863712333, \"7A\"],\n[54.8801676667, 82.4866722667, \"10\"],\n[54.88029245, 82.4868499667, \"8\"],\n[54.8803302167, 82.4865822167, \"6\"],\n[54.88038715, 82.4864004167, \"4\"],\n[54.8805029333, 82.4862314167, \"2\"],\n[54.9127148667, 82.4710607833, \"51\"],\n[54.9118609667, 82.4668648, \"20\"],\n[54.9122010667, 82.47078695, \"49A\"],\n[54.91191245, 82.4682913833, \"29\"],\n[54.9112774333, 82.4668027333, \"17A\"],\n[54.91244995, 82.4700709833, \"41\"],\n[54.9149636, 82.4772568333, \"98\"],\n[54.9128421833, 82.4702103167, \"42\"],\n[54.91130515, 82.4650217667, \"2\"],\n[54.9140405333, 82.4754503833, \"85\"],\n[54.91155815, 82.4670938833, \"21\"],\n[54.9144416167, 82.4754564, \"86\"],\n[54.91149715, 82.4668828667, \"19\"],\n[54.9155068167, 82.4784839167, \"116\"],\n[54.9135311667, 82.4736794833, \"69\"],\n[54.9146717667, 82.4773664833, \"103\"],\n[54.913582667, 82.4724437333, \"62\"],\n[54.9117463, 82.4676612167, \"23\"],\n[54.9136108833, 82.47263915, \"64\"],\n[54.9118005167, 82.46788515, \"25\"],\n[54.9142630167, 82.4748833333, \"80\"],\n[54.9118481833, 82.4680930167, \"27\"],\n[54.91519165, 82.47727755, \"100\"],\n[54.9121701, 82.4679073167, \"28\"],\n[54.9152358167, 82.4780924833, \"112\"],\n[54.9122425667, 82.4681859167, \"30\"],\n[54.9150027167, 82.47843285, \"107\"],\n[54.91196865, 82.4684916833, \"31\"],\n[54.9132330333, 82.4726685333, \"61\"],\n[54.9123722, 82.4685087667, \"32\"],\n[54.915824667, 82.4790262, \"113\"],\n[54.9120319833, 82.46868985, \"33\"],\n[54.9151328167, 82.4788729, \"111\"],\n[54.9124617167, 82.4687799833, \"34\"],\n[54.9150617167, 82.4786454167, \"109\"],\n[54.9120926, 82.4688931667, \"35\"],\n[54.9132881333, 82.47285965, \"63\"],\n[54.9119984333, 82.4691844, \"37A\"],\n[54.9120311, 82.4673706667, \"24\"],\n[54.91214925, 82.46909885, \"37\"],\n[54.91408025, 82.4759690833, \"91B\"],\n[54.9125366, 82.4691343, \"38\"],\n[54.9134794833, 82.4739836167, \"71A\"],\n[54.9122081167, 82.4674649333, \"26A\"],\n[54.9140814333, 82.4736708667, \"72A\"],\n[54.9120801, 82.4675947333, \"26\"],\n[54.9113324167, 82.46512405, \"4\"],\n[54.91185795, 82.4686138167, \"31A\"],\n[54.9144403167, 82.4767387667, \"101\"],\n[54.9125054167, 82.46896025, \"36A\"],\n[54.9151334833, 82.4778022667, \"106\"],\n[54.9126167833, 82.4688409667, \"36B\"],\n[54.9111576, 82.4663765167, \"13A\"],\n[54.9112960833, 82.4662379, \"13\"],\n[54.9116252167, 82.46602135, \"14\"],\n[54.9113666167, 82.4664507833, \"15\"],\n[54.9117068333, 82.466336, \"16\"],\n[54.9114338333, 82.4666576, \"17\"],\n[54.9119338667, 82.4665694167, \"18A\"],\n[54.9117808333, 82.4665752, \"18\"],\n[54.9110205, 82.4652438667, \"3\"],\n[54.9110742833, 82.4654501167, \"5\"],\n[54.9111370833, 82.4656566833, \"7\"],\n[54.9111865833, 82.4658542667, \"9\"],\n[54.9112390333, 82.46602075, \"11\"],\n[54.9118135167, 82.46543705, \"6A\"],\n[54.9118572167, 82.46556135, \"6B\"],\n[54.91145615, 82.4655286, \"6\"],\n[54.9115389167, 82.4657957167, \"8\"],\n[54.9127748333, 82.4699760667, \"40\"],\n[54.9125127167, 82.4703133, \"43\"],\n[54.9129274, 82.4704172833, \"44\"],\n[54.9125759833, 82.4705303667, \"45\"],\n[54.9129758667, 82.4706118, \"46\"],\n[54.9126359667, 82.4707644, \"47\"],\n[54.91226225, 82.47106665, \"49\"],\n[54.9130937833, 82.4709588833, \"50\"],\n[54.9131644667, 82.4711523, \"52\"],\n[54.9132299667, 82.4713462167, \"60\"],\n[54.9127690833, 82.4712279667, \"53\"],\n[54.9133607167, 82.4730695833, \"65\"],\n[54.91367805, 82.4728816667, \"66\"],\n[54.9134211, 82.4732760667, \"67\"],\n[54.9137477833, 82.4731176, \"68\"],\n[54.9138932333, 82.4736511667, \"70\"],\n[54.9135950667, 82.4738879833, \"71\"],\n[54.9139430167, 82.4737982333, \"72\"],\n[54.9136486, 82.4740868667, \"73\"],\n[54.91400415, 82.4740125833, \"74\"],\n[54.9140350333, 82.4741693833, \"76\"],\n[54.91432385, 82.475081, \"82\"],\n[54.9139975333, 82.47523055, \"83\"],\n[54.9143889667, 82.47526065, \"84\"],\n[54.9137640333, 82.47575135, \"87\"],\n[54.91449875, 82.4756521167, \"88\"],\n[54.9141123, 82.4756848833, \"89\"],\n[54.9145492167, 82.4758458667, \"90\"],\n[54.9141779667, 82.4758650667, \"91\"],\n[54.9146104833, 82.4760345, \"92\"],\n[54.9142320333, 82.4760478833, \"93\"],\n[54.9146642167, 82.47621125, \"94\"],\n[54.9142896667, 82.4762277667, \"95\"],\n[54.9147136833, 82.4764402833, \"96\"],\n[54.9143434167, 82.47639805, \"97\"],\n[54.9143937167, 82.4765685, \"99\"],\n[54.91501315, 82.4774403667, \"102\"],\n[54.9154860667, 82.4774428167, \"104\"],\n[54.9149432667, 82.4782801, \"105\"],\n[54.9152651667, 82.47833035, \"114\"],\n[54.9299333167, 82.55909085, \"128\"],\n[54.9286782833, 82.5545978, \"181\"],\n[54.9300747333, 82.5497311333, \"3/193\"],\n[54.9276611167, 82.5543011333, \"192\"],\n[54.9305557833, 82.5594630333, \"129\"],\n[54.9280362, 82.5517895, \"2/193\"],\n[54.9284764, 82.5616764333, \"103\"],\n[54.93143935, 82.55390345, \"165\"],\n[54.9288132, 82.5647016167, \"61\"],\n[54.9275235, 82.5619954833, \"94\"],\n[54.93081245, 82.5577222333, \"149\"],\n[54.9300416667, 82.5566331333, \"161\"],\n[54.92921255, 82.5684947, \"16\"],\n[54.9304111667, 82.5673126333, \"35\"],\n[54.9291729667, 82.5653647333, \"55\"],\n[54.9289266333, 82.5656691333, \"56\"],\n[54.92751825, 82.5531413167, \"1/193\"],\n[54.9323321667, 82.5512635167, \"1/165\"],\n[54.9045377667, 82.4827770167, \"3\"],\n[54.9051343333, 82.4829339167, \"10\"],\n[54.9045625, 82.4832139167, \"4\"],\n[54.9052854167, 82.4828661667, \"12\"],\n[54.9045012833, 82.4825234, \"3A\"],\n[54.9054383, 82.4831963, \"14\"],\n[54.9048575167, 82.4826078167, \"7\"],\n[54.9050790667, 82.4825558167, \"9A\"],\n[54.90496205, 82.4830191667, \"8\"],\n[54.9050431833, 82.4823803833, \"9B\"],\n[54.9047063167, 82.4826914667, \"5\"],\n[54.9051649333, 82.4825182667, \"11\"],\n[54.9047697333, 82.4831092667, \"6\"],\n[54.9044120833, 82.4828407333, \"1\"],\n[54.8987653333, 82.4845873667, \"12\"],\n[54.89849935, 82.4843253333, \"8\"],\n[54.8989808833, 82.4835699333, \"13\"],\n[54.8982670333, 82.4839818167, \"5\"],\n[54.89792805, 82.4841291833, \"1\"],\n[54.8990696333, 82.48395625, \"18\"],\n[54.8983429167, 82.4837488833, \"7A\"],\n[54.8986908667, 82.4846387167, \"10\"],\n[54.8985086333, 82.48330895, \"9A\"],\n[54.8980756833, 82.4840675333, \"3\"],\n[54.8984572667, 82.4838707, \"7\"],\n[54.8988333833, 82.48411825, \"16\"],\n[54.89797735, 82.4845139167, \"2\"],\n[54.8988639833, 82.4832473, \"9B\"],\n[54.8985740667, 82.4844548333, \"8A\"],\n[54.8983953667, 82.4832022167, \"9\"],\n[54.898132, 82.48448765, \"4\"],\n[54.8983169333, 82.48441905, \"6\"],\n[54.898835, 82.4848386, \"12A\"],\n[54.8982524667, 82.4837739667, \"5A\"],\n[54.7992683667, 82.4068494, \"44D\"],\n[54.7973138333, 82.40680895, \"37\"],\n[54.79798795, 82.4063265667, \"41\"],\n[54.7983426667, 82.4060350833, \"38\"],\n[54.7981863, 82.40728095, \"45\"],\n[54.7985252667, 82.4070533167, \"46\"],\n[54.7991710833, 82.4079073667, \"44A\"],\n[54.7994488333, 82.4084595333, \"44B\"],\n[54.7998703833, 82.4089765833, \"44C\"],\n[54.7969343667, 82.4040572333, \"15\"],\n[54.7991115833, 82.406026, \"44E\"],\n[54.9108972667, 82.4737860333, \"1\"],\n[54.9109227833, 82.4740157167, \"3\"],\n[54.9110122167, 82.47419315, \"5\"],\n[54.91133475, 82.4740478833, \"6\"],\n[54.91125305, 82.4738936667, \"4\"],\n[54.9111422333, 82.4736767667, \"2\"],\n[54.9110952167, 82.47448295, \"7\"],\n[54.9112131667, 82.4741245667, \"8\"],\n[54.8804519333, 82.4809153167, \"16A\"],\n[54.8808188333, 82.4804471833, \"8\"],\n[54.8805619667, 82.4804252833, \"10\"],\n[54.8810451833, 82.4809865167, \"11\"],\n[54.8806955167, 82.4806394, \"12\"],\n[54.8808969, 82.48108405, \"13\"],\n[54.8806416, 82.4807763833, \"14\"],\n[54.8807567, 82.48110125, \"15\"],\n[54.8806444167, 82.4809707333, \"16\"],\n[54.8805414833, 82.4812062167, \"17\"],\n[54.8812994167, 82.4798864833, \"1\"],\n[54.8810411333, 82.4798769333, \"2\"],\n[54.8812669, 82.4801150167, \"3\"],\n[54.8810092333, 82.4800721333, \"4\"],\n[54.8811867333, 82.48041535, \"5\"],\n[54.8809235, 82.4802776833, \"6\"],\n[54.8811437833, 82.4806999667, \"7\"],\n[54.8811760167, 82.4808741333, \"9\"],\n[54.8778504833, 82.5246844167, \"102\"],\n[54.8819230667, 82.52038225, \"37\"],\n[54.8838481333, 82.5190955, \"15\"],\n[54.8825636667, 82.5211268, \"42\"],\n[54.8789988, 82.528298167, \"79\"],\n[54.8729074667, 82.5286693667, \"167\"],\n[54.8760724333, 82.52502585, \"127\"],\n[54.8745184833, 82.5278637167, \"148\"],\n[54.8744641, 82.5268869667, \"145\"],\n[54.8971449, 82.3967563, \"82\"],\n[54.8943781833, 82.3977300667, \"44\"],\n[54.9004613, 82.47640765, \"13\"],\n[54.9004093667, 82.4762205333, \"11\"],\n[54.9002790833, 82.4769703167, \"16\"],\n[54.9003597167, 82.4772565, \"20\"],\n[54.90090275, 82.4763007167, \"15\"],\n[54.90094715, 82.4764403167, \"17\"],\n[54.9006751333, 82.4771785333, \"27\"],\n[54.90107225, 82.4768541333, \"25\"],\n[54.9001119667, 82.4749271333, \"1\"],\n[54.9006160667, 82.4769211667, \"23\"],\n[54.9002628, 82.4757354, \"3\"],\n[54.9005473333, 82.4767056, \"19\"],\n[54.9002167333, 82.4750815167, \"2\"],\n[54.8998862167, 82.4772123833, \"18\"],\n[54.9003037333, 82.47596475, \"9\"],\n[54.9000952167, 82.4752010833, \"2A\"],\n[54.9006044167, 82.475943, \"9A\"],\n[54.9085414, 82.47102025, \"1\"],\n[54.90831215, 82.4705452333, \"4\"],\n[54.9085338333, 82.4706769667, \"2\"],\n[54.90815565, 82.470603, \"5\"],\n[54.9082244667, 82.4708460167, \"6\"],\n[54.9083062, 82.4711227667, \"7\"],\n[54.9084509833, 82.47045035, \"3\"],\n[54.8911392333, 82.4583220667, \"8\"],\n[54.891127, 82.4585561667, \"10\"],\n[54.8912095833, 82.4581187333, \"7\"],\n[54.8910674833, 82.4575599333, \"2\"],\n[54.8913220333, 82.4574411833, \"1\"],\n[54.89159775, 82.4573200333, \"1A\"],\n[54.8910451833, 82.4580652333, \"6\"],\n[54.8913072667, 82.4576702667, \"3\"],\n[54.8913322, 82.4579054333, \"5\"],\n[54.8910210167, 82.45784865, \"4\"],\n[54.8853014, 82.4629564833, \"3\"],\n[54.88554135, 82.4629736, \"2\"],\n[54.88541785, 82.46296925, \"1\"],\n[54.9193531833, 82.54385725, \"354\"],\n[54.9188882667, 82.5420886333, \"355\"],\n[54.9192738333, 82.5435102833, \"356\"],\n[54.9192985333, 82.5429392833, \"358\"],\n[54.9193181167, 82.54233135, \"360\"],\n[54.9192005, 82.5403558833, \"130\"],\n[54.9186817333, 82.5404104667, \"109\"],\n[54.9199342167, 82.5412764833, \"260\"],\n[54.9193768333, 82.5412782167, \"223\"],\n[54.91831485, 82.5400403333, \"103\"],\n[54.91961875, 82.5408546833, \"200\"],\n[54.9176805, 82.5413459167, \"105\"],\n[54.9190955, 82.5408870167, \"171\"],\n[54.9182861833, 82.5408937167, \"107\"],\n[54.9195153, 82.5433797, \"352\"],\n[54.92030865, 82.54192075, \"264\"],\n[54.920463, 82.5417725, \"262\"],\n[54.9197269667, 82.5432480167, \"350\"],\n[54.9197592167, 82.5415707667, \"266\"],\n[54.9195913167, 82.54231935, \"348\"],\n[54.9183186167, 82.5393124667, \"2\"],\n[54.9187989667, 82.53988695, \"70\"],\n[54.9185694, 82.5418133, \"353\"],\n[54.8994012, 82.3657659333, \"821\"],\n[54.89971895, 82.3645648833, \"835\"],\n[54.9139332167, 82.4090271667, \"332\"],\n[54.8988464667, 82.3659825667, \"828\"],\n[54.9022981, 82.38067085, \"685\"],\n[54.9065350333, 82.4018221167, \"434\"],\n[54.90028885, 82.3798328667, \"697\"],\n[54.9084945333, 82.4050759167, \"410\"],\n[54.89922135, 82.3740981833, \"747\"],\n[54.9232422167, 82.4145657333, \"185\"],\n[54.9245097667, 82.41242555, \"187\"],\n[54.9159503333, 82.40778185, \"303\"],\n[54.9094665, 82.4069157667, \"388\"],\n[54.9231998333, 82.4170489, \"158\"],\n[54.9102601, 82.4072221667, \"383\"],\n[54.9207001, 82.4065603167, \"257\"],\n[54.9102264, 82.4082195, \"372\"],\n[54.928280667, 82.4087488, \"233\"],\n[54.9021599833, 82.3911428167, \"598\"],\n[54.9229502667, 82.4127942667, \"197\"],\n[54.90296435, 82.3924815167, \"583\"],\n[54.9255960833, 82.4136194333, \"2/187\"],\n[54.9245176, 82.4278129833, \"59\"],\n[54.9249067167, 82.4263146667, \"75\"],\n[54.92534045, 82.4130770333, \"1/187\"],\n[54.9077678, 82.4038107833, \"424\"],\n[54.9244162333, 82.4258990667, \"76\"],\n[54.9237273333, 82.4194401833, \"138\"],\n[54.9019339833, 82.3879181167, \"625\"],\n[54.90920365, 82.4053418167, \"397\"],\n[54.9057407667, 82.39478875, \"540\"],\n[54.9243174333, 82.4220341833, \"112\"],\n[54.8992012333, 82.3666729333, \"815\"],\n[54.9110874833, 82.4102195833, \"360\"],\n[54.9027096, 82.3913196333, \"591\"],\n[54.9011183833, 82.38410915, \"655\"],\n[54.9234701333, 82.4155696333, \"181\"],\n[54.9025482, 82.3926162167, \"582\"],\n[54.92450575, 82.4246711167, \"90\"],\n[54.9242924167, 82.4289432833, \"47\"],\n[54.8986079833, 82.3685293333, \"801\"],\n[54.9030857, 82.3932839, \"577\"],\n[54.90235535, 82.3894401667, \"613\"],\n[54.9008578833, 82.3826145667, \"675\"],\n[54.90071405, 82.3818195, \"681\"],\n[54.8820639667, 82.4856738333, \"4\"],\n[54.8811382833, 82.4847224333, \"17\"],\n[54.8820705, 82.4859065167, \"2\"],\n[54.8822594167, 82.4854946333, \"5\"],\n[54.88230695, 82.4860176667, \"1\"],\n[54.8816572833, 82.4846057667, \"14\"],\n[54.8822931167, 82.4857413833, \"3\"],\n[54.8820614833, 82.4849636833, \"10\"],\n[54.8814784167, 82.4853259333, \"20\"],\n[54.8820341167, 82.4854254, \"6\"],\n[54.8814562667, 82.4855579, \"22\"],\n[54.8820407667, 82.4852060167, \"8\"],\n[54.88139725, 82.4857370167, \"24\"],\n[54.8819474, 82.4846312, \"12\"],\n[54.8812179833, 82.4855291833, \"23\"],\n[54.8811665833, 82.4849644, \"19\"],\n[54.8822871333, 82.4850344167, \"9\"],\n[54.8822664667, 82.4852611, \"7\"],\n[54.8813914667, 82.4847524, \"16\"],\n[54.8812347667, 82.4852638167, \"21\"],\n[54.8814556, 82.48509055, \"18\"],\n[54.8811484833, 82.4844946, \"15\"],\n[54.8823244833, 82.4848154333, \"11\"],\n[54.8823452833, 82.4845833667, \"13\"],\n[54.9599893167, 82.5018972167, \"82\"],\n[54.9618358833, 82.4874459667, \"18\"],\n[54.9618619, 82.50776785, \"90\"],\n[54.9616283333, 82.4929460167, \"64\"],\n[54.9611726167, 82.4984393667, \"80\"],\n[54.9607851, 82.5016190333, \"86\"],\n[54.9608416167, 82.4971466, \"78\"],\n[54.9614436333, 82.5080607667, \"92\"],\n[54.9643050333, 82.4953529167, \"2/84\"],\n[54.9610803, 82.4864609, \"7\"],\n[54.9606146667, 82.4939399, \"83\"],\n[54.9609926167, 82.4857235333, \"3\"],\n[54.96113465, 82.4948554, \"84\"],\n[54.9613254333, 82.5047791833, \"88\"],\n[54.8593059833, 82.5330650333, \"10\"],\n[54.8596072333, 82.533587, \"19\"],\n[54.90423375, 82.4844148, \"107B\"],\n[54.9020309333, 82.4769959167, \"49A\"],\n[54.9029281167, 82.4805014167, \"81A\"],\n[54.9016197667, 82.4756437833, \"37\"],\n[54.90101005, 82.4735379833, \"21\"],\n[54.9016823667, 82.4760847833, \"39A\"],\n[54.90178185, 82.4761837333, \"41\"],\n[54.9011922667, 82.4725514167, \"8\"],\n[54.9015593833, 82.4738315333, \"26\"],\n[54.9015446833, 82.473388, \"18A\"],\n[54.9024291, 82.4783928, \"57\"],\n[54.9010319, 82.4736316167, \"23\"],\n[54.9039576333, 82.4835641667, \"103\"],\n[54.9011953333, 82.4741573333, \"29A\"],\n[54.9042121, 82.4828802833, \"100\"],\n[54.9010152, 82.4741578667, \"29B\"],\n[54.9019761833, 82.4752665167, \"34\"],\n[54.90256225, 82.4788024667, \"71\"],\n[54.9031558833, 82.4793385, \"68\"],\n[54.9043412833, 82.48477025, \"109A-109D\"],\n[54.9030168667, 82.4803624833, \"81\"],\n[54.9054432333, 82.48740955, \"114\"],\n[54.9032955667, 82.4821555167, \"93B\"],\n[54.9052043, 82.4875160667, \"118\"],\n[54.9040282167, 82.4838154167, \"105\"],\n[54.90498365, 82.4875592167, \"120\"],\n[54.90388715, 82.4833244, \"101\"],\n[54.90156105, 82.47306285, \"1/14-5/14\"],\n[54.9028688, 82.4798400167, \"77\"],\n[54.908212, 82.4730746667, \"16A\"],\n[54.9034353833, 82.48239905, \"95A\"],\n[54.9018501333, 82.47294875, \"16B\"],\n[54.9065120667, 82.4873521833, \"114A\"],\n[54.9027523, 82.47799015, \"58\"],\n[54.9029325833, 82.4801074833, \"79\"],\n[54.9032525167, 82.4811784, \"87\"],\n[54.9031822833, 82.4809204, \"85\"],\n[54.9033394667, 82.4814522333, \"89\"],\n[54.9011077167, 82.4738625833, \"25\"],\n[54.9024641, 82.4756984333, \"40\"],\n[54.9044449, 82.4836965167, \"104\"],\n[54.9023471833, 82.47810245, \"55\"],\n[54.9029669667, 82.4787094167, \"62\"],\n[54.90442275, 82.4850982, \"115\"],\n[54.9026089, 82.47587495, \"44\"],\n[54.90264365, 82.4790681667, \"73\"],\n[54.9035878333, 82.4823534, \"95\"],\n[54.9024915, 82.4786270833, \"67\"],\n[54.9031010167, 82.4812452667, \"87A\"],\n[54.9030982, 82.47913305, \"66\"],\n[54.9035099167, 82.4821307, \"93A\"],\n[54.90079465, 82.4741973833, \"33\"],\n[54.9040185667, 82.48229025, \"96\"],\n[54.9023384167, 82.4765524833, \"50\"],\n[54.9022154167, 82.4786401833, \"59\"],\n[54.9018837333, 82.4765543333, \"45\"],\n[54.9029163333, 82.4785064167, \"60\"],\n[54.9022748167, 82.4763478167, \"48\"],\n[54.9041422, 82.4826398833, \"98\"],\n[54.9022017333, 82.4761212333, \"46A\"],\n[54.9034542333, 82.4818904, \"91\"],\n[54.9019505833, 82.4767386667, \"47\"],\n[54.9018310833, 82.4763711167, \"43\"],\n[54.9022245, 82.4761991, \"46B\"],\n[54.9022058833, 82.4776710667, \"51\"],\n[54.9011141167, 82.4738904667, \"31\"],\n[54.90381365, 82.48307595, \"99\"],\n[54.9013508667, 82.4731568833, \"14\"],\n[54.9026744667, 82.4776618667, \"54\"],\n[54.9013012667, 82.4729456, \"12\"],\n[54.9016709167, 82.4758279833, \"39\"],\n[54.9012509333, 82.4727291833, \"10\"],\n[54.902262, 82.4778573167, \"53\"],\n[54.9011626167, 82.4723885667, \"6\"],\n[54.9015607167, 82.4753714333, \"35\"],\n[54.9007910667, 82.47417145, \"27\"],\n[54.9020738833, 82.47565455, \"36\"],\n[54.9010502667, 82.4719555, \"4\"],\n[54.9036689667, 82.4826166, \"97\"],\n[54.90165275, 82.4742215833, \"28\"],\n[54.9043576, 82.4834127, \"102\"],\n[54.9014172833, 82.4734044167, \"18\"],\n[54.90310965, 82.4806441333, \"83\"],\n[54.90305305, 82.4810779, \"85A\"],\n[54.9041825833, 82.4842419667, \"107A\"],\n[54.9018864667, 82.4749266667, \"32\"],\n[54.9018503333, 82.47696095, \"49\"],\n[54.9030326167, 82.47892515, \"64\"],\n[54.9017621333, 82.4733169667, \"20\"],\n[54.89705485, 82.4732848667, \"5\"],\n[54.8972060833, 82.4727957833, \"1A\"],\n[54.8950392167, 82.47373745, \"28B\"],\n[54.8965514333, 82.4726139833, \"6\"],\n[54.8952181167, 82.4744414833, \"33B\"],\n[54.8952637167, 82.47354965, \"26A\"],\n[54.8951086667, 82.4742331167, \"33A\"],\n[54.8966904333, 82.4729455, \"11A\"],\n[54.8962754333, 82.4733100167, \"17\"],\n[54.8968641333, 82.4728138667, \"1/3-5/3\"],\n[54.8949580667, 82.4743396167, \"35\"],\n[54.8973106167, 82.4729746, \"1B\"],\n[54.8949376167, 82.47388345, \"30\"],\n[54.89572315, 82.4732895, \"18\"],\n[54.8958303167, 82.4731749333, \"16\"],\n[54.8969656167, 82.4732634, \"7\"],\n[54.896495, 82.4731159833, \"13\"],\n[54.8968125667, 82.4731199333, \"11B\"],\n[54.89640605, 82.4732035667, \"15\"],\n[54.8952445667, 82.4736735667, \"26\"],\n[54.8960091167, 82.47303035, \"14\"],\n[54.896205, 82.47289145, \"10\"],\n[54.8956152, 82.4738212833, \"29\"],\n[54.8950829667, 82.4737896, \"28A\"],\n[54.8955509167, 82.4734385333, \"22\"],\n[54.8972144833, 82.4729756, \"1C\"],\n[54.8970069167, 82.4727237833, \"1D\"],\n[54.8964112667, 82.4727309333, \"8\"],\n[54.89685155, 82.4723649167, \"2\"],\n[54.8959909833, 82.4735371333, \"19\"],\n[54.8968653333, 82.4732429833, \"9\"],\n[54.8952936, 82.4740853667, \"31\"],\n[54.8956491833, 82.47335855, \"20\"],\n[54.8971588833, 82.4725988, \"1\"],\n[54.95948505, 82.3813743167, \"3/362\"],\n[54.9267924667, 82.3947664833, \"790\"],\n[54.95374205, 82.3785110333, \"417\"],\n[54.9270906333, 82.3962139333, \"802\"],\n[54.95208085, 82.3790772833, \"435\"],\n[54.9537863833, 82.37916715, \"418\"],\n[54.9336977167, 82.3872475333, \"660\"],\n[54.9370890667, 82.3861055333, \"610\"],\n[54.9632177167, 82.37745245, \"310\"],\n[54.9552044167, 82.3775981, \"391\"],\n[54.95356905, 82.3785904167, \"419\"],\n[54.9658669167, 82.3737947167, \"273\"],\n[54.9591853, 82.37834395, \"360\"],\n[54.95818485, 82.3776341167, \"1/362\"],\n[54.9264044, 82.3933694833, \"770\"],\n[54.94279195, 82.3830579333, \"541\"],\n[54.9358610167, 82.3856405, \"623\"],\n[54.92604605, 82.39188825, \"762\"],\n[54.95893715, 82.3798225167, \"2/362\"],\n[54.9257693333, 82.3904065167, \"750\"],\n[54.9654268167, 82.3769618333, \"308\"],\n[54.9323014833, 82.3868321333, \"743\"],\n[54.93764955, 82.3850314, \"599\"],\n[54.9095889, 82.4694829333, \"13\"],\n[54.9099912333, 82.4694063167, \"4\"],\n[54.9101332, 82.4693430167, \"2\"],\n[54.90943375, 82.4691617333, \"9\"],\n[54.90960705, 82.46916755, \"7\"],\n[54.9100405, 82.4689760667, \"1\"],\n[54.9095270167, 82.4693311, \"11\"],\n[54.9098948167, 82.4690437, \"3\"],\n[54.9097340167, 82.4696952667, \"10\"],\n[54.9095571, 82.4697117833, \"12\"],\n[54.90975285, 82.4691024667, \"5\"],\n[54.9018515667, 82.47956045, \"10\"],\n[54.9025733333, 82.4796073833, \"1A\"],\n[54.90234615, 82.4792779, \"4\"],\n[54.9027908167, 82.4795601333, \"1\"],\n[54.9024103667, 82.47967745, \"3\"],\n[54.90205615, 82.4794369167, \"8\"],\n[54.89827985, 82.4664433333, \"25\"],\n[54.8990345167, 82.4670508, \"11\"],\n[54.8989251667, 82.4664513667, \"17\"],\n[54.8990204833, 82.4665540333, \"15\"],\n[54.8996123667, 82.4678836167, \"10\"],\n[54.89873215, 82.4672828, \"18\"],\n[54.89858465, 82.4666028667, \"21\"],\n[54.8990743833, 82.4675788, \"12A\"],\n[54.8984592, 82.4665057, \"23\"],\n[54.89889965, 82.467451, \"12\"],\n[54.9002081667, 82.46756315, \"1\"],\n[54.9001357167, 82.4679316667, \"4\"],\n[54.898277, 82.46726385, \"24\"],\n[54.89978315, 82.46793515, \"8\"],\n[54.8983929667, 82.4669553667, \"26\"],\n[54.8991940667, 82.4672154167, \"9\"],\n[54.8980936167, 82.4664998167, \"27\"],\n[54.8995042, 82.4674747167, \"7\"],\n[54.898334, 82.46731845, \"22\"],\n[54.8999632833, 82.4679440333, \"6\"],\n[54.89794665, 82.4665422333, \"29\"],\n[54.8988821167, 82.4669019167, \"13\"],\n[54.8980275167, 82.4668801333, \"30\"],\n[54.89871525, 82.4676048667, \"14\"],\n[54.8977558667, 82.4665362333, \"31\"],\n[54.8986535, 82.4675602667, \"16\"],\n[54.8979195833, 82.4667739667, \"32\"],\n[54.89979585, 82.4675336833, \"5\"],\n[54.8974943167, 82.46652485, \"33\"],\n[54.8987147333, 82.46672835, \"19\"],\n[54.8977257333, 82.4666500833, \"34\"],\n[54.8985690333, 82.4671123833, \"20\"],\n[54.9003081667, 82.46791995, \"2\"],\n[54.8981989167, 82.4668991, \"28\"],\n[54.8999918333, 82.4675733167, \"3\"],\n[54.9085979, 82.47228295, \"6\"],\n[54.9082979333, 82.4727952, \"1\"],\n[54.9084415, 82.4723396833, \"4\"],\n[54.9085185333, 82.4726990667, \"3\"],\n[54.90870765, 82.4724272833, \"8\"],\n[54.9082453167, 82.4725341667, \"2\"],\n[54.9087162, 82.4725830333, \"5\"],\n[54.8992527333, 82.4614825, \"5A\"],\n[54.8974537333, 82.4597499, \"30\"],\n[54.8990513167, 82.461357, \"5\"],\n[54.89854655, 82.4618827833, \"2\"],\n[54.8962418167, 82.4614646667, \"69\"],\n[54.89729515, 82.4597868833, \"32\"],\n[54.8986072, 82.4598125833, \"18\"],\n[54.8990041, 82.4601224, \"17\"],\n[54.8986801, 82.46007825, \"16\"],\n[54.8976013667, 82.4596983333, \"28\"],\n[54.8987992333, 82.4607934667, \"10\"],\n[54.8961486, 82.4612296167, \"65\"],\n[54.8987145333, 82.4602998667, \"14\"],\n[54.8986250667, 82.4616027833, \"6\"],\n[54.8985372, 82.4606703, \"12A\"],\n[54.8990944833, 82.4618171167, \"3A\"],\n[54.8987547833, 82.4605145833, \"12\"],\n[54.8989327667, 82.46174375, \"3\"],\n[54.89940475, 82.4614229833, \"5B\"],\n[54.8981109833, 82.4595815167, \"22\"],\n[54.8992761667, 82.4612548833, \"7A\"],\n[54.89858635, 82.4617420167, \"4\"],\n[54.89615355, 82.4610093667, \"63\"],\n[54.8960633167, 82.4614357, \"67\"],\n[54.8970480833, 82.4594701667, \"47\"],\n[54.8964719167, 82.4610726, \"46\"],\n[54.89942805, 82.4612639, \"7B\"],\n[54.8969129333, 82.4595048833, \"49\"],\n[54.8983810333, 82.4595983, \"20\"],\n[54.8966503, 82.4601548, \"40\"],\n[54.8965228167, 82.4605625667, \"42\"],\n[54.8979410167, 82.4596252, \"24\"],\n[54.89698365, 82.45986105, \"36\"],\n[54.89909445, 82.46094265, \"9\"],\n[54.8990747, 82.4611943333, \"7\"],\n[54.8968194333, 82.4598978167, \"38\"],\n[54.8990957833, 82.4607578667, \"11\"],\n[54.8993121167, 82.4605309833, \"13A\"],\n[54.8993347667, 82.4606526667, \"11A\"],\n[54.8977427333, 82.4596749667, \"26\"],\n[54.8964422833, 82.4608866833, \"44\"],\n[54.897148, 82.4598171667, \"34\"],\n[54.8964457667, 82.4614839667, \"50\"],\n[54.8965226, 82.4613232333, \"48\"],\n[54.89666225, 82.4616268167, \"50A\"],\n[54.8967215667, 82.4614938667, \"48A\"],\n[54.8961699833, 82.4606764833, \"61\"],\n[54.8990274167, 82.4594845333, \"21A\"],\n[54.8978044833, 82.4592938, \"37\"],\n[54.89765145, 82.45932785, \"39\"],\n[54.8972011167, 82.4594360833, \"45\"],\n[54.89748945, 82.45936165, \"41\"],\n[54.8973585333, 82.4594078333, \"43\"],\n[54.8989135833, 82.4593674167, \"23A\"],\n[54.8982502167, 82.4591910333, \"31\"],\n[54.8980929167, 82.4592136833, \"33\"],\n[54.8979576667, 82.4592540667, \"35\"],\n[54.8987865, 82.459442, \"23\"],\n[54.8983624667, 82.4591781333, \"29\"],\n[54.89859365, 82.4592542667, \"25\"],\n[54.8984648833, 82.4592043833, \"27\"],\n[54.89599285, 82.4605853833, \"61A\"],\n[54.8967193667, 82.4595488167, \"51\"],\n[54.89895945, 82.45991735, \"19\"],\n[54.8988903667, 82.4596039833, \"21\"],\n[54.8991762833, 82.4598346833, \"19A\"],\n[54.8990309833, 82.4603212, \"15\"],\n[54.8992306667, 82.4600061667, \"17A\"],\n[54.8990798333, 82.46053775, \"13\"],\n[54.8960234, 82.46042255, \"59A\"],\n[54.8961819167, 82.4595465333, \"55A\"],\n[54.8965562167, 82.4596334167, \"53\"],\n[54.8962467833, 82.4604475, \"59\"],\n[54.8961687167, 82.459936, \"57A\"],\n[54.8963601167, 82.4599881167, \"57\"],\n[54.8964266, 82.4598209333, \"55\"],\n[54.89876895, 82.4610164333, \"8\"],\n[54.89888655, 82.46191985, \"1\"],\n[54.8992657, 82.4618445667, \"3B\"],\n[54.89942775, 82.46177925, \"3C\"],\n[54.8994213333, 82.461939, \"3D\"],\n[54.8877845667, 82.4769104167, \"15A\"],\n[54.8884691333, 82.47652905, \"9\"],\n[54.8876236833, 82.4762465333, \"14\"],\n[54.8881092667, 82.4765359833, \"11\"],\n[54.8870282333, 82.47689615, \"21\"],\n[54.8878168667, 82.4761862, \"12\"],\n[54.8869641167, 82.4766908333, \"20\"],\n[54.88876965, 82.4761694167, \"7\"],\n[54.8866340667, 82.4762948167, \"20D\"],\n[54.8875209833, 82.4767726667, \"17\"],\n[54.8878835333, 82.4766054, \"13\"],\n[54.8870823167, 82.4763955, \"18\"],\n[54.8885070833, 82.4758756667, \"6\"],\n[54.8880108, 82.4760921833, \"10\"],\n[54.8888735667, 82.4758855333, \"5\"],\n[54.8879635, 82.4768245333, \"13A\"],\n[54.8890102, 82.4753934667, \"1\"],\n[54.887397, 82.4763382, \"16\"],\n[54.8867165333, 82.4763817833, \"20C\"],\n[54.8881819, 82.4760513167, \"8\"],\n[54.886801, 82.4764408667, \"20B\"],\n[54.8873439167, 82.4769787167, \"19A\"],\n[54.88688675, 82.47651985, \"20A\"],\n[54.8872187, 82.4769650667, \"19\"],\n[54.8874603333, 82.4770461667, \"19B\"],\n[54.8877107667, 82.4766732833, \"15\"],\n[54.9028793667, 82.4694345, \"9\"],\n[54.9027742, 82.4691508167, \"5\"],\n[54.9027706333, 82.46934705, \"7\"],\n[54.9030670833, 82.4689651833, \"4\"],\n[54.903068, 82.4692231333, \"6\"],\n[54.90282975, 82.4689251167, \"2\"],\n[54.9030033, 82.4694327333, \"8\"],\n[54.7979216167, 82.3709623333, \"40\"],\n[54.7901529, 82.3755824, \"144\"],\n[54.7907598333, 82.3744419, \"134\"],\n[54.7937929667, 82.3664199167, \"59C\"],\n[54.79439395, 82.3674624167, \"59B\"],\n[54.7944289667, 82.3725634167, \"82A\"],\n[54.7904513167, 82.3738425333, \"131\"],\n[54.794607, 82.3745403833, \"82B\"],\n[54.7921551167, 82.3768403, \"132\"],\n[54.7926399833, 82.3722763, \"102\"],\n[54.7967557, 82.3729791333, \"60A\"],\n[54.7921326333, 82.37322975, \"110\"],\n[54.8012874, 82.3703331, \"14\"],\n[54.7948232167, 82.3716246, \"74\"],\n[54.7979944667, 82.3703715167, \"35\"],\n[54.7956465, 82.3714636167, \"66\"],\n[54.7911951833, 82.3732412833, \"123B\"],\n[54.7987651833, 82.3708161667, \"32\"],\n[54.79171095, 82.3736367667, \"112\"],\n[54.7976371833, 82.3704513833, \"41\"],\n[54.7911877333, 82.3732945667, \"123A\"],\n[54.7913029167, 82.37306835, \"121\"],\n[54.7906186667, 82.3755869, \"140\"],\n[54.7931244667, 82.3712613167, \"93A\"],\n[54.7974290667, 82.3711039667, \"42\"],\n[54.7936148167, 82.3719375667, \"84\"],\n[54.8005517667, 82.3700387, \"9\"],\n[54.7938986667, 82.3710440333, \"77\"],\n[54.7965492333, 82.3713085167, \"54\"],\n[54.8001176167, 82.3701064333, \"13\"],\n[54.7930191667, 82.37129215, \"93B\"],\n[54.7926151667, 82.37155955, \"99A\"],\n[54.7950692833, 82.3686159167, \"59A\"],\n[54.7969088, 82.37462925, \"60B\"],\n[54.7951773167, 82.37087185, \"75\"],\n[54.7921505, 82.3713529333, \"99B\"],\n[54.7904565167, 82.3749809333, \"138\"],\n[54.8006982167, 82.3700011, \"7\"],\n[54.7991912, 82.3699700833, \"29\"],\n[54.7967847667, 82.3705662167, \"47\"],\n[54.792296, 82.3720602333, \"99C\"],\n[54.7980087167, 82.36967245, \"31\"],\n[54.7982152833, 82.3709274, \"34\"],\n[54.9155702167, 82.4723301167, \"4\"],\n[54.9159029, 82.4721897167, \"8\"],\n[54.9157610833, 82.4726929667, \"3\"],\n[54.9160956333, 82.4725375333, \"7\"],\n[54.9153328, 82.4724436667, \"2\"],\n[54.9164312667, 82.4723669167, \"11\"],\n[54.9165995, 82.4722833833, \"13\"],\n[54.9162671833, 82.4724523333, \"9\"],\n[54.9162124833, 82.4720273, \"12\"],\n[54.9160704833, 82.4720950333, \"10\"],\n[54.9170187667, 82.4717177667, \"22\"],\n[54.9164956667, 82.4718994167, \"16\"],\n[54.9163615667, 82.4719599333, \"14\"],\n[54.9155396833, 82.4728079667, \"1\"],\n[54.9157325833, 82.4722579833, \"6\"],\n[54.9159316, 82.47261835, \"5\"],\n[54.8914888167, 82.4620999667, \"21\"],\n[54.8837548, 82.4623328, \"77B\"],\n[54.8930618833, 82.4622745, \"11\"],\n[54.8852888667, 82.46116795, \"76\"],\n[54.8913069667, 82.4621727167, \"23\"],\n[54.8839160167, 82.4615298167, \"75\"],\n[54.8883285167, 82.4618738833, \"47\"],\n[54.8858521667, 82.46093185, \"68B\"],\n[54.8853005333, 82.4610670333, \"76A\"],\n[54.88383285, 82.4621270167, \"75A\"],\n[54.8823235167, 82.4605504833, \"110A\"],\n[54.8914899333, 82.46174725, \"22\"],\n[54.8818567333, 82.4608746167, \"116\"],\n[54.88353235, 82.4618320333, \"77A\"],\n[54.8813482, 82.4613161333, \"95\"],\n[54.8879809, 82.4618373667, \"49\"],\n[54.88152115, 82.46131485, \"93\"],\n[54.8885148667, 82.4618976167, \"45\"],\n[54.8872325667, 82.4613256333, \"54\"],\n[54.8877582, 82.4620199, \"51A\"],\n[54.8837208833, 82.4615252, \"77\"],\n[54.8879695167, 82.4611445833, \"50A\"],\n[54.8933130333, 82.46192685, \"6\"],\n[54.88794035, 82.46146015, \"50\"],\n[54.8911399667, 82.4621445, \"25\"],\n[54.8927127, 82.4625991167, \"15\"],\n[54.8898722833, 82.4620120667, \"37\"],\n[54.8817498333, 82.4605830833, \"118A\"],\n[54.8856498167, 82.4611874667, \"70\"],\n[54.8818152333, 82.4605837833, \"118B\"],\n[54.8834546167, 82.4619323333, \"1/79-3/79\"],\n[54.8817077833, 82.46087495, \"120\"],\n[54.88566165, 82.4608763667, \"70B\"],\n[54.8881064833, 82.4614714667, \"48\"],\n[54.8883276833, 82.4614909, \"46\"],\n[54.8900726, 82.4616307167, \"34\"],\n[54.8824921167, 82.4614109333, \"85\"],\n[54.8902574, 82.4620445833, \"33\"],\n[54.8821857333, 82.4613799, \"89\"],\n[54.8909901, 82.4620973667, \"27\"],\n[54.8906249333, 82.4624066333, \"31A\"],\n[54.8909031667, 82.4623998167, \"27A\"],\n[54.8823715333, 82.4609577, \"110\"],\n[54.8885618333, 82.4615104, \"44\"],\n[54.8907907, 82.4624375833, \"29A\"],\n[54.8911051167, 82.4615235333, \"26A\"],\n[54.8912843667, 82.46171725, \"24\"],\n[54.88775155, 82.4618187333, \"51\"],\n[54.88202465, 82.4608939, \"114\"],\n[54.8877833167, 82.4614137, \"52\"],\n[54.8907810833, 82.462108, \"29\"],\n[54.8910314667, 82.4617401833, \"26\"],\n[54.882292, 82.4613977333, \"87\"],\n[54.8906141333, 82.4621064667, \"31\"],\n[54.8892757667, 82.4615758167, \"38\"],\n[54.8904495, 82.4624898833, \"33B\"],\n[54.8868235333, 82.461296, \"58\"],\n[54.8904039167, 82.4622297, \"33A\"],\n[54.8826623167, 82.4609461833, \"106\"],\n[54.89295465, 82.4615430167, \"14B\"],\n[54.8907016, 82.46165145, \"28\"],\n[54.89291045, 82.4618812167, \"14\"],\n[54.8854757, 82.461181, \"74\"],\n[54.8930916667, 82.46189575, \"12\"],\n[54.8856999, 82.4605845, \"70A\"],\n[54.8928368667, 82.4622630833, \"13\"],\n[54.8899615833, 82.4616178167, \"36\"],\n[54.8925096667, 82.4618395167, \"16A\"],\n[54.8927205667, 82.4618461, \"16\"],\n[54.8925576333, 82.4622484333, \"17\"],\n[54.8887964167, 82.4615352, \"42\"],\n[54.8887897667, 82.4619157667, \"43\"],\n[54.8813160833, 82.46082205, \"124\"],\n[54.88148945, 82.46084125, \"122\"],\n[54.8822301, 82.4605952667, \"112B\"],\n[54.8821928667, 82.4609133167, \"112A\"],\n[54.8825255, 82.4609447167, \"108\"],\n[54.886356, 82.4607633833, \"62A\"],\n[54.88384855, 82.46107535, \"84\"],\n[54.8844810833, 82.46111955, \"78\"],\n[54.8865957833, 82.4612863167, \"60\"],\n[54.8870465333, 82.4613338333, \"56\"],\n[54.8840136833, 82.4610932, \"82\"],\n[54.8840612333, 82.4615617667, \"73\"],\n[54.8858403667, 82.4612416667, \"68A\"],\n[54.8863992833, 82.4612464333, \"62\"],\n[54.88602145, 82.4612203, \"66\"],\n[54.8862464, 82.4607918667, \"64A\"],\n[54.8859472, 82.4606057333, \"66A\"],\n[54.88617885, 82.4612264667, \"64\"],\n[54.8841155833, 82.4606926667, \"82A\"],\n[54.8842170667, 82.46156725, \"71\"],\n[54.8843494167, 82.4615815167, \"69\"],\n[54.8845482333, 82.4615789, \"61\"],\n[54.8832313667, 82.4614822, \"81\"],\n[54.8833854333, 82.46147585, \"79\"],\n[54.8842273333, 82.4610982667, \"80\"],\n[54.8842230833, 82.4607088333, \"80A\"],\n[54.88898595, 82.4619261, \"41\"],\n[54.8836924167, 82.4610583833, \"86\"],\n[54.88897595, 82.4615556167, \"40\"],\n[54.8835485833, 82.4610374, \"88\"],\n[54.8812029, 82.4608328833, \"126\"],\n[54.8834193333, 82.4610251833, \"90\"],\n[54.8174314833, 82.3761889833, \"28\"],\n[54.882173333, 82.3745060667, \"41A\"],\n[54.8189801, 82.3767644333, \"19\"],\n[54.81721685, 82.3746944667, \"40A\"],\n[54.8184217833, 82.3785756333, \"7\"],\n[54.81727655, 82.3739209, \"41C\"],\n[54.8169354333, 82.3751527667, \"40B\"],\n[54.8183142667, 82.3745782, \"39\"],\n[54.8177220333, 82.3774063833, \"18\"],\n[54.8181192333, 82.3734650333, \"41B\"],\n[54.8182567, 82.37774445, \"15\"],\n[54.8177787833, 82.3756114, \"31\"],\n[54.8171698, 82.37896375, \"14\"],\n[54.8179103833, 82.3762068167, \"27\"],\n[54.81816045, 82.3773152167, \"17\"],\n[54.8187562833, 82.3765890167, \"21\"],\n[54.81804885, 82.3788571, \"6\"],\n[54.8184971667, 82.3750758833, \"49\"],\n[54.8173303, 82.3796556667, \"12\"],\n[54.8177653667, 82.3776830167, \"16\"],\n[54.81610655, 82.3744603333, \"40C\"],\n[54.882659833, 82.3767630167, \"24\"],\n[54.8857427167, 82.4668167833, \"6\"],\n[54.8842291667, 82.46713325, \"21\"],\n[54.88552105, 82.46728075, \"7\"],\n[54.8822557833, 82.4671910833, \"41A\"],\n[54.88573115, 82.4665300333, \"6A\"],\n[54.8841256167, 82.4667261, \"22\"],\n[54.8855689, 82.4668563667, \"8\"],\n[54.8833609167, 82.4664140667, \"30A\"],\n[54.8819612833, 82.4662849167, \"42A\"],\n[54.8854916667, 82.4665621167, \"8A\"],\n[54.88355305, 82.4666830167, \"28\"],\n[54.8858997833, 82.46683345, \"2\"],\n[54.88529365, 82.4675717333, \"9A\"],\n[54.8853087167, 82.46724515, \"9\"],\n[54.8858362167, 82.4668311, \"4\"],\n[54.88501735, 82.4672261167, \"13\"],\n[54.88173245, 82.4665125833, \"44\"],\n[54.8819903833, 82.4669395333, \"43\"],\n[54.8819599, 82.46652035, \"42\"],\n[54.8821801667, 82.4669412, \"41\"],\n[54.8820951, 82.4665340833, \"40\"],\n[54.8822636667, 82.4665534167, \"36\"],\n[54.8836934333, 82.4671131833, \"27\"],\n[54.8817733333, 82.4669241, \"45\"],\n[54.8811819833, 82.46709535, \"49A\"],\n[54.8812991667, 82.4664858167, \"48\"],\n[54.8815565333, 82.4668967167, \"47\"],\n[54.8815367, 82.46651585, \"46\"],\n[54.8837635333, 82.4667121, \"26\"],\n[54.8811047333, 82.466856, \"51\"],\n[54.8810985833, 82.4664679167, \"50\"],\n[54.8813315833, 82.46687885, \"49\"],\n[54.8838189667, 82.4665006, \"26A\"],\n[54.8840672667, 82.46711675, \"23\"],\n[54.8838811667, 82.4670993333, \"25\"],\n[54.8839458833, 82.4667205667, \"24\"],\n[54.8832529, 82.4673047167, \"33A\"],\n[54.8835982, 82.4664604333, \"28A\"],\n[54.8830642667, 82.4666342167, \"32\"],\n[54.8835364167, 82.4675321, \"29\"],\n[54.8834683333, 82.4670743667, \"31\"],\n[54.883317, 82.4666640833, \"30\"],\n[54.8851499333, 82.4667468, \"12\"],\n[54.8851338167, 82.46723935, \"11\"],\n[54.8828958667, 82.4666283167, \"34\"],\n[54.88325825, 82.46707095, \"33\"],\n[54.8853570333, 82.4667731167, \"10\"],\n[54.88494775, 82.4672146833, \"15\"],\n[54.8854012333, 82.466548, \"10A\"],\n[54.88298215, 82.4670794667, \"35\"],\n[54.9137448167, 82.4769976167, \"9\"],\n[54.9139995, 82.4769421167, \"1\"],\n[54.9137195833, 82.4762766333, \"5\"],\n[54.9136874333, 82.4768144167, \"8\"],\n[54.9138555833, 82.4762229167, \"4\"],\n[54.9139553833, 82.4765034, \"3\"],\n[54.9139429833, 82.4767303, \"2\"],\n[54.91357485, 82.4763857833, \"6\"],\n[54.91363055, 82.47658545, \"7\"],\n[54.9070534333, 82.4673664667, \"26\"],\n[54.9051596, 82.4668419167, \"13\"],\n[54.9107910167, 82.4652498167, \"70\"],\n[54.9049454167, 82.4681745833, \"8\"],\n[54.9086697833, 82.466192, \"46A\"],\n[54.9049889333, 82.4680154333, \"8A\"],\n[54.90506145, 82.4674941833, \"7\"],\n[54.9106372333, 82.4652995167, \"68\"],\n[54.9083611333, 82.4663507667, \"42\"],\n[54.9062177333, 82.4681393167, \"16B\"],\n[54.91076535, 82.46463305, \"71\"],\n[54.90610465, 82.46785555, \"16A\"],\n[54.9054751167, 82.4677389667, \"12\"],\n[54.9058089833, 82.4680032167, \"14A\"],\n[54.9054853667, 82.4672854833, \"17\"],\n[54.90856345, 82.4665805333, \"44\"],\n[54.9088263, 82.4661217333, \"48\"],\n[54.9101238833, 82.4655415667, \"62\"],\n[54.908529, 82.4662483167, \"46\"],\n[54.9056721833, 82.46797, \"12A\"],\n[54.9057461833, 82.4675941167, \"14\"],\n[54.90600145, 82.4670439167, \"23\"],\n[54.9076178833, 82.4673104167, \"34A\"],\n[54.90463895, 82.46807945, \"3\"],\n[54.9049602667, 82.4669330833, \"9\"],\n[54.90673685, 82.4671040833, \"22\"],\n[54.907098, 82.4676191667, \"32\"],\n[54.9076081833, 82.46671515, \"38\"],\n[54.90916225, 82.4659552667, \"52\"],\n[54.90454345, 82.4684433, \"1\"],\n[54.90512805, 82.4671995667, \"11A\"],\n[54.9059193, 82.4674994, \"16\"],\n[54.9073133167, 82.4668277667, \"34\"],\n[54.9102952667, 82.4654520833, \"64\"],\n[54.9092774833, 82.46591125, \"52A\"],\n[54.9052165167, 82.4674315333, \"11\"],\n[54.9053672, 82.4671046, \"17B\"],\n[54.9048409833, 82.46859545, \"4\"],\n[54.905671, 82.46720995, \"19\"],\n[54.9048928333, 82.4683727167, \"6\"],\n[54.9058366833, 82.4671128, \"21\"],\n[54.9071612667, 82.4678683, \"30\"],\n[54.9089840667, 82.4660592667, \"50\"],\n[54.90527545, 82.4667925333, \"15\"],\n[54.90715615, 82.466917, \"32A\"],\n[54.9061779167, 82.4669647333, \"25\"],\n[54.9077133333, 82.4674576833, \"36A\"],\n[54.9104661667, 82.4653805167, \"66\"],\n[54.9051668667, 82.4678703167, \"10\"],\n[54.89370395, 82.47271155, \"11\"],\n[54.8921716167, 82.4721017, \"26\"],\n[54.8935424167, 82.4728224833, \"13A\"],\n[54.8935212, 82.4727174167, \"13\"],\n[54.8937888333, 82.4722797667, \"12\"],\n[54.8944482, 82.4723851667, \"2\"],\n[54.89426415, 82.4731979833, \"8/7\"],\n[54.8944458167, 82.4722873333, \"1/2\"],\n[54.8940236833, 82.4722967667, \"8\"],\n[54.8944464167, 82.47217745, \"2/2\"],\n[54.89289535, 82.4722046, \"20\"],\n[54.8940564, 82.4721777667, \"1/8\"],\n[54.89387485, 82.47305145, \"9A\"],\n[54.8941962833, 82.4734008333, \"7/7\"],\n[54.8940251167, 82.4729672167, \"3/7\"],\n[54.8940147167, 82.4733695833, \"5/7\"],\n[54.8927664833, 82.4726649, \"21\"],\n[54.8940957833, 82.4733820167, \"6/7\"],\n[54.8942063833, 82.47275275, \"11/7\"],\n[54.8938730167, 82.4727318667, \"9\"],\n[54.8940384833, 82.4727499833, \"1/7\"],\n[54.8916949833, 82.47255425, \"29\"],\n[54.8940345667, 82.4728609333, \"2/7\"],\n[54.8920309, 82.4720907167, \"28\"],\n[54.8942669167, 82.4723162, \"6\"],\n[54.8920657333, 82.4725813667, \"27\"],\n[54.8924789, 82.4721364167, \"22\"],\n[54.89162635, 82.4720620167, \"34\"],\n[54.89420475, 82.4728706, \"10/7\"],\n[54.8924279, 82.4726186167, \"25\"],\n[54.8942782, 82.4730613833, \"9/7\"],\n[54.8917478833, 82.4720685333, \"32\"],\n[54.89359425, 82.4722612333, \"14\"],\n[54.8919238167, 82.4717851167, \"30A\"],\n[54.89358685, 82.47297855, \"11A\"],\n[54.8917815667, 82.4717468667, \"32A\"],\n[54.8940195667, 82.4730878667, \"4/7\"],\n[54.89188475, 82.4720793833, \"30\"],\n[54.8766258167, 82.453827333, \"63\"],\n[54.8793250667, 82.4531694667, \"33\"],\n[54.87557575, 82.4531778333, \"71\"],\n[54.8649285167, 82.4537918667, \"194\"],\n[54.8758193333, 82.4536709167, \"72\"],\n[54.8730099333, 82.4536885167, \"104\"],\n[54.87537995, 82.4536875833, \"76\"],\n[54.866365, 82.4537908667, \"182\"],\n[54.8773983, 82.4531370667, \"53\"],\n[54.8663474333, 82.4540325167, \"182A\"],\n[54.8765353, 82.4536952667, \"68\"],\n[54.8633266833, 82.4532383833, \"213\"],\n[54.8748418833, 82.4536900667, \"86\"],\n[54.8723979667, 82.4536811667, \"112\"],\n[54.8789557167, 82.4531799167, \"37\"],\n[54.8744338333, 82.45543435, \"88\"],\n[54.8780606333, 82.4531695167, \"49\"],\n[54.8613876667, 82.4533495833, \"1/233\"],\n[54.8779126333, 82.449236, \"4/51\"],\n[54.86132765, 82.4526138667, \"2/233\"],\n[54.8779974333, 82.45063155, \"3/51\"],\n[54.8629783167, 82.4532700667, \"215\"],\n[54.8777104167, 82.4515755167, \"2/51\"],\n[54.8811745, 82.4555028167, \"4\"],\n[54.8779778833, 82.4521171, \"1/51\"],\n[54.8619675333, 82.4532946667, \"227\"],\n[54.8786639833, 82.4493194167, \"5/51\"],\n[54.88057795, 82.4544579, \"18\"],\n[54.86531615, 82.4531001833, \"191\"],\n[54.8655207167, 82.4536965333, \"186\"],\n[54.8646614333, 82.4537639667, \"198\"],\n[54.8647871333, 82.4541422833, \"196\"],\n[54.86771765, 82.4537268, \"162\"],\n[54.8711387333, 82.4536879167, \"124\"],\n[54.8611343167, 82.45330145, \"235\"],\n[54.8624900167, 82.4532548833, \"221\"],\n[54.86872715, 82.4532476, \"151\"],\n[54.8703843667, 82.4532525, \"131\"],\n[54.8692643833, 82.45371825, \"150\"],\n[54.8699453833, 82.4537083667, \"142\"],\n[54.88075845, 82.4546889, \"14\"],\n[54.8810108833, 82.45510075, \"8\"],\n[54.8808800833, 82.45486695, \"12\"],\n[54.8810951, 82.4553182, \"6\"],\n[54.8812414333, 82.4557114167, \"2\"],\n[54.8737279833, 82.4537149833, \"90\"],\n[54.8804315833, 82.4547993833, \"2/16\"],\n[54.8806571333, 82.4551276833, \"2/10\"],\n[54.8807296667, 82.4552756333, \"1/10\"],\n[54.8805078333, 82.4548978667, \"1/16\"],\n[54.8305417667, 82.4407137167, \"106\"],\n[54.8305758833, 82.4444438667, \"78\"],\n[54.8305754, 82.45156825, \"18\"],\n[54.83063965, 82.45322105, \"2\"],\n[54.8305728333, 82.4437875667, \"82\"],\n[54.8690497667, 82.4740093167, \"7\"],\n[54.86952375, 82.4790699, \"60\"],\n[54.8713118667, 82.4763685667, \"42\"],\n[54.8690602667, 82.4767549167, \"47\"],\n[54.8957648333, 82.4773709167, \"4A\"],\n[54.8971239167, 82.47716665, \"16\"],\n[54.89663135, 82.4774846833, \"10\"],\n[54.8972863333, 82.4770748833, \"18\"],\n[54.8969474167, 82.4772745667, \"14\"],\n[54.8963529167, 82.4776375333, \"8\"],\n[54.8982169667, 82.4746382667, \"44\"],\n[54.8958142, 82.4771743333, \"4B\"],\n[54.89577995, 82.4770061667, \"4C\"],\n[54.8956352667, 82.4772386167, \"4\"],\n[54.89679325, 82.4773878, \"12\"],\n[54.8956875333, 82.4769206, \"4D\"],\n[54.8955368, 82.4771246333, \"2\"],\n[54.9075869833, 82.4681207167, \"5\"],\n[54.9076935833, 82.4688911, \"1\"],\n[54.9078046833, 82.4683225333, \"7\"],\n[54.9077261333, 82.4681354833, \"6\"],\n[54.9078473333, 82.4685627833, \"8\"],\n[54.9075310167, 82.46846565, \"3\"],\n[54.9079180333, 82.46879245, \"9\"],\n[54.90762245, 82.4686683, \"2\"],\n[54.9074934833, 82.4682448, \"4\"],\n[54.8065385167, 82.3969116167, \"26\"],\n[54.8052316167, 82.3947853833, \"1\"],\n[54.8054979333, 82.3951090333, \"5\"],\n[54.8061355333, 82.3955903667, \"12\"],\n[54.8057016167, 82.3950258333, \"6\"],\n[54.8059893667, 82.3953958833, \"10\"],\n[54.8068311167, 82.3965807, \"22\"],\n[54.80583815, 82.3952011167, \"8\"],\n[54.8067129833, 82.3967156, \"24\"],\n[54.8062816833, 82.39578495, \"14\"],\n[54.8056595, 82.3953378, \"7\"],\n[54.80642775, 82.3959857667, \"16\"],\n[54.8067297167, 82.39640035, \"20\"],\n[54.8063663, 82.3962931167, \"13\"],\n[54.8053626333, 82.3949338333, \"3\"],\n[54.8065366, 82.3965265333, \"15\"],\n[54.80539065, 82.394573, \"2\"],\n[54.8065884, 82.39621225, \"18\"],\n[54.8055506833, 82.39481855, \"4\"],\n[54.8062047667, 82.3961045, \"11\"],\n[54.91218215, 82.4768794167, \"8\"],\n[54.9120288167, 82.4765747, \"7B\"],\n[54.9122875167, 82.4765784167, \"3\"],\n[54.9123338833, 82.4771329833, \"6B\"],\n[54.9120254167, 82.4764380167, \"5\"],\n[54.91246155, 82.4769255333, \"4\"],\n[54.9125897333, 82.4768015, \"2\"],\n[54.9121711333, 82.4767164667, \"7\"],\n[54.9122827167, 82.4769958667, \"6A\"],\n[54.8527505833, 82.53393255, \"617\"],\n[54.8826752167, 82.5025520333, \"9\"],\n[54.81291845, 82.5447496, \"1161\"],\n[54.8788362167, 82.510149, \"1/88\"],\n[54.81259405, 82.5447376, \"1163\"],\n[54.8763215167, 82.5110032333, \"115\"],\n[54.8751193167, 82.51276665, \"134\"],\n[54.86748695, 82.5219444167, \"272\"],\n[54.8793489167, 82.5093666167, \"80\"],\n[54.8249454833, 82.5459290333, \"1021\"],\n[54.87870795, 82.5090378667, \"81\"],\n[54.8802461667, 82.5019911, \"1/37\"],\n[54.8790009333, 82.5095332, \"84\"],\n[54.8675435167, 82.51850165, \"243\"],\n[54.8783544, 82.5094524833, \"97\"],\n[54.8785864667, 82.5105412333, \"2/88\"],\n[54.8565379167, 82.5340265667, \"567\"],\n[54.8790696167, 82.5117932, \"98\"],\n[54.8579882167, 82.5332226833, \"557\"],\n[54.8228546333, 82.5478497667, \"1043\"],\n[54.8111895167, 82.5446341667, \"1177\"],\n[54.8670294, 82.5209776667, \"265\"],\n[54.8111449, 82.5438866, \"1179\"],\n[54.8810532167, 82.50530935, \"39\"],\n[54.8107934667, 82.5438973833, \"1183\"],\n[54.8766940333, 82.51263885, \"2/110\"],\n[54.8094178833, 82.5439488333, \"1195\"],\n[54.8484587833, 82.5342090667, \"663\"],\n[54.81064835, 82.5445837167, \"1187\"],\n[54.8744863, 82.5115857333, \"139\"],\n[54.8099838, 82.54453645, \"1191\"],\n[54.8787071333, 82.5051437667, \"2/39\"],\n[54.8092644167, 82.54453125, \"1199\"],\n[54.8361982667, 82.5463852167, \"890\"],\n[54.8389412667, 82.5464548, \"858\"],\n[54.8789616667, 82.5121996833, \"100\"],\n[54.8336715167, 82.5454231, \"919\"],\n[54.8289189, 82.5478054833, \"986\"],\n[54.8323492833, 82.5460591, \"928\"],\n[54.8320521833, 82.5459855, \"930\"],\n[54.8251348833, 82.5480670667, \"1016\"],\n[54.8561845167, 82.5327450833, \"581\"],\n[54.8262207333, 82.5482595333, \"996\"],\n[54.8083614833, 82.5449377833, \"1211\"],\n[54.8172147667, 82.5457622333, \"1107\"],\n[54.8461716667, 82.5348015333, \"688\"],\n[54.8159882, 82.5454072833, \"1119\"],\n[54.8801261, 82.5011647833, \"37\"],\n[54.8788507333, 82.5071659, \"5/39\"],\n[54.86353225, 82.5262979167, \"392\"],\n[54.8087557667, 82.5460182, \"1208\"],\n[54.8799249, 82.50989025, \"70\"],\n[54.8087391167, 82.5453725167, \"1206\"],\n[54.8368114333, 82.5449542167, \"881\"],\n[54.8278101833, 82.5479474667, \"990\"],\n[54.8144593833, 82.5446729333, \"1143\"],\n[54.8763691667, 82.51261455, \"1/110\"],\n[54.8141157667, 82.5446296, \"1145\"],\n[54.8675668333, 82.5223205667, \"276\"],\n[54.86875635, 82.5151021667, \"207\"],\n[54.8785670167, 82.5058547667, \"3/39\"],\n[54.8766803833, 82.5140811167, \"6/110\"],\n[54.86696285, 82.5258656667, \"302\"],\n[54.81135475, 82.5425439833, \"1/1181\"],\n[54.8809864833, 82.5057107, \"8/39\"],\n[54.8788209, 82.5065659833, \"4/39\"],\n[54.8792938833, 82.5065692167, \"7/39\"],\n[54.8139674667, 82.5456240667, \"1146\"],\n[54.8611906333, 82.5269748, \"432\"],\n[54.8402324, 82.5411414667, \"809\"],\n[54.82010205, 82.5480512333, \"1070\"],\n[54.8771378833, 82.51029235, \"1/103\"],\n[54.8213269333, 82.54882125, \"1052\"],\n[54.8089942, 82.5452704833, \"1202\"],\n[54.8212039667, 82.5500653333, \"1/1052\"],\n[54.86704345, 82.5199686167, \"257\"],\n[54.8211860833, 82.55188125, \"2/1052\"],\n[54.8732234167, 82.51193365, \"151\"],\n[54.8231706667, 82.5483519, \"1040\"],\n[54.8129427333, 82.54544965, \"1158\"],\n[54.8398410833, 82.5429798, \"817\"],\n[54.8774619667, 82.5081401333, \"4/103\"],\n[54.8413094333, 82.5414880333, \"796\"],\n[54.8734242333, 82.5114266833, \"149\"],\n[54.8116329167, 82.54465065, \"1173\"],\n[54.8790814667, 82.505419, \"6/39\"],\n[54.8402537, 82.54399925, \"830\"],\n[54.87415495, 82.5111152667, \"1/139\"],\n[54.8090223833, 82.5446570333, \"1201\"],\n[54.8809561333, 82.5036574833, \"35\"],\n[54.8085440167, 82.5454961667, \"1210\"],\n[54.8413132, 82.5395747333, \"773\"],\n[54.87539025, 82.5146704167, \"1/138\"],\n[54.83847385, 82.54218775, \"2/815\"],\n[54.87580405, 82.5118973167, \"126\"],\n[54.86917495, 82.5157794167, \"1/208\"],\n[54.8082772667, 82.5455867333, \"1212\"],\n[54.8096694667, 82.5450804833, \"1194\"],\n[54.8787073667, 82.5083375, \"79\"],\n[54.8763409333, 82.51340955, \"3/110\"],\n[54.8080369167, 82.5450349667, \"1213\"],\n[54.8093666167, 82.5451384833, \"1196\"],\n[54.82245505, 82.5477440333, \"1047\"],\n[54.8775422667, 82.5104792, \"2/103\"],\n[54.8236463333, 82.5474525, \"1033\"],\n[54.8814960667, 82.50479415, \"33\"],\n[54.8245330667, 82.5471272667, \"1023\"],\n[54.8403625, 82.5402170167, \"1/809\"],\n[54.8678366667, 82.5195366167, \"254\"],\n[54.8790242333, 82.5103504333, \"4/88\"],\n[54.8218208, 82.5477814333, \"1049\"],\n[54.8789700833, 82.5084782833, \"77/1\"],\n[54.8704926333, 82.5137601667, \"188\"],\n[54.87878565, 82.5106821667, \"3/88\"],\n[54.871913, 82.5121444333, \"163\"],\n[54.87933595, 82.5101975333, \"6/88\"],\n[54.8748227833, 82.5121225, \"136\"],\n[54.87947495, 82.5108712167, \"5/88\"],\n[54.8753615167, 82.5127019833, \"132\"],\n[54.8109761333, 82.5426080167, \"1181\"],\n[54.8773393667, 82.5116264833, \"104\"],\n[54.8370667667, 82.5458885833, \"879\"],\n[54.8765559833, 82.5101962833, \"103\"],\n[54.8253379167, 82.5472683, \"989\"],\n[54.8793315833, 82.5086546167, \"77\"],\n[54.8661602, 82.52487915, \"316\"],\n[54.8776637333, 82.50929225, \"3/103\"],\n[54.8092819667, 82.5456565833, \"2/1200\"],\n[54.87534805, 82.5120049833, \"128\"],\n[54.81204605, 82.5446423333, \"1169\"],\n[54.8752625833, 82.5140794833, \"138\"],\n[54.8766464333, 82.5134206667, \"4/110\"],\n[54.8770230167, 82.5108992333, \"113\"],\n[54.8406207, 82.5394538167, \"2/809\"],\n[54.8770699833, 82.5116503167, \"106\"],\n[54.8122078667, 82.5440270833, \"1165\"],\n[54.87518925, 82.5112472667, \"129\"],\n[54.8507412333, 82.5347013833, \"633\"],\n[54.8759461833, 82.5110732833, \"117\"],\n[54.8210931833, 82.5477387333, \"1055\"],\n[54.87555235, 82.511829667, \"127\"],\n[54.8180744833, 82.5471867333, \"1092\"],\n[54.8761638, 82.5118200833, \"120\"],\n[54.8714445, 82.5188348833, \"2/208\"],\n[54.8738533, 82.5117649, \"141\"],\n[54.8083899, 82.5443001833, \"1209\"],\n[54.8672468667, 82.5243000167, \"295\"],\n[54.8395333333, 82.54262905, \"1/815\"],\n[54.8093977833, 82.5456164833, \"1/1200\"],\n[54.86778915, 82.5240579167, \"290\"],\n[54.8151683, 82.5450954333, \"1133\"],\n[54.8676913333, 82.5179285833, \"235\"],\n[54.87977015, 82.5090145833, \"66\"],\n[54.8785379333, 82.5043763, \"1/39\"],\n[54.8764341333, 82.51407215, \"5/110\"],\n[54.8740516, 82.5125295667, \"146\"],\n[54.87401495, 82.47760185, \"16\"],\n[54.8739528333, 82.4764705667, \"31\"],\n[54.8739846167, 82.4768385667, \"33\"],\n[54.8748585167, 82.4767720333, \"11\"],\n[54.8736880333, 82.4772042167, \"37\"],\n[54.8747492333, 82.4769483667, \"9\"],\n[54.87503235, 82.4775088667, \"3\"],\n[54.87489515, 82.4779213833, \"6\"],\n[54.8748158667, 82.4774378, \"5\"],\n[54.8750760667, 82.4779026, \"4\"],\n[54.8746501167, 82.4773401167, \"7\"],\n[54.8741460667, 82.4765724167, \"27\"],\n[54.8739166167, 82.477184, \"35\"],\n[54.8741975833, 82.4778215, \"23\"],\n[54.8738094, 82.47760075, \"18\"],\n[54.8749257833, 82.4765688833, \"13\"],\n[54.8741402667, 82.4763856, \"29\"],\n[54.8742506833, 82.4775977, \"14\"],\n[54.8741505, 82.47681925, \"25\"],\n[54.8747261167, 82.4778583667, \"8\"],\n[54.8745555, 82.4777541667, \"10\"],\n[54.8743982667, 82.4777232, \"12\"],\n[54.87440735, 82.4772111833, \"21\"],\n[54.8745958667, 82.47674675, \"19\"],\n[54.8747628333, 82.47645865, \"15\"],\n[54.8745715333, 82.4764928667, \"17\"],\n[54.9116880667, 82.4711713833, \"3\"],\n[54.9116604333, 82.4715114333, \"1\"],\n[54.9118500667, 82.4714183, \"5\"],\n[54.9122240667, 82.4713923, \"11\"],\n[54.9118788833, 82.4710693167, \"7\"],\n[54.9123174667, 82.4714676167, \"10\"],\n[54.91227905, 82.4716167167, \"8\"],\n[54.9117270667, 82.4718080667, \"2\"],\n[54.91205, 82.4713633167, \"9\"],\n[54.912161, 82.4717712, \"6\"],\n[54.8859179333, 82.4582119667, \"1\"],\n[54.8865885333, 82.4581321667, \"6A\"],\n[54.88640305, 82.45807455, \"6\"],\n[54.8860451667, 82.4578916833, \"4D\"],\n[54.8863091167, 82.45790615, \"5\"],\n[54.8861527, 82.4579021833, \"4A\"],\n[54.8859058833, 82.4578780333, \"3\"],\n[54.8861333333, 82.4577295167, \"4B\"],\n[54.8859079333, 82.45834695, \"1A\"],\n[54.8861985, 82.4582370667, \"7\"],\n[54.8860742333, 82.4577260833, \"4C\"],\n[54.8858135, 82.4580266333, \"2\"],\n[54.8856798, 82.4576616167, \"3B\"],\n[54.8857954333, 82.45773405, \"3A\"],\n[54.8039755167, 82.3924264333, \"588\"],\n[54.8024268333, 82.3891336167, \"555\"],\n[54.80621375, 82.3790952, \"476A\"],\n[54.8035793667, 82.3898201333, \"565\"],\n[54.8041731333, 82.3674844, \"348\"],\n[54.8035751833, 82.38904805, \"559\"],\n[54.8013125167, 82.390194, \"569A\"],\n[54.8039518333, 82.3880558333, \"550\"],\n[54.7993036333, 82.3774681, \"447B\"],\n[54.80163095, 82.39138825, \"577\"],\n[54.8035939833, 82.3922268667, \"583\"],\n[54.8034719167, 82.3864473333, \"535A\"],\n[54.80612815, 82.3786574833, \"476C\"],\n[54.80604375, 82.3653441833, \"320\"],\n[54.8030940833, 82.3837668333, \"515\"],\n[54.8017065167, 82.37966555, \"471\"],\n[54.8032808167, 82.3824573833, \"496C\"],\n[54.8023511333, 82.3675479833, \"361\"],\n[54.8029974167, 82.38875325, \"553B\"],\n[54.8013158, 82.3713298333, \"400\"],\n[54.8069269167, 82.38494245, \"522A\"],\n[54.8041518333, 82.3666512333, \"342\"],\n[54.8035926, 82.3904181, \"569B\"],\n[54.8022781333, 82.3782524667, \"450A\"],\n[54.8010726667, 82.3710681167, \"395\"],\n[54.80130715, 82.37668905, \"445\"],\n[54.8010362667, 82.3712212667, \"399\"],\n[54.8032196333, 82.36794415, \"358\"],\n[54.80095265, 82.3727210333, \"409\"],\n[54.8021615667, 82.3808655833, \"481B\"],\n[54.80149165, 82.3733540167, \"418\"],\n[54.8010327833, 82.3739455167, \"419\"],\n[54.8037261333, 82.3859318333, \"530\"],\n[54.8019531333, 82.36978095, \"382\"],\n[54.8035854333, 82.3674296167, \"352\"],\n[54.8035820667, 82.3681635, \"358B\"],\n[54.8044532833, 82.3898220167, \"562A\"],\n[54.8030543167, 82.3681729333, \"360\"],\n[54.80023085, 82.3753558333, \"429B\"],\n[54.8029366333, 82.3683441833, \"362\"],\n[54.8046987, 82.38796795, \"548\"],\n[54.80282455, 82.3684962, \"364\"],\n[54.8016347167, 82.3738360667, \"420\"],\n[54.8031052333, 82.3689649333, \"366\"],\n[54.8026689, 82.3687241167, \"368\"],\n[54.8025527333, 82.3689042333, \"370\"],\n[54.8037381333, 82.3672040667, \"350B\"],\n[54.8015959333, 82.37030475, \"384\"],\n[54.8037429667, 82.3861631667, \"532\"],\n[54.8056256, 82.3854121, \"522D\"],\n[54.8074032833, 82.37890055, \"476D\"],\n[54.8033627833, 82.3941313, \"601\"],\n[54.8035645833, 82.3885777333, \"553A\"],\n[54.8037265833, 82.3751864333, \"438\"],\n[54.80393295, 82.3820938333, \"496B\"],\n[54.8039961667, 82.3937407167, \"600\"],\n[54.8016335, 82.3785741333, \"455B\"],\n[54.8028840667, 82.3674978, \"357\"],\n[54.8009541833, 82.3783785, \"455C\"],\n[54.8061105, 82.3849712833, \"518\"],\n[54.8041071, 82.3675672667, \"350A\"],\n[54.8039732667, 82.3922047667, \"586\"],\n[54.7970054833, 82.3806949833, \"475B\"],\n[54.80154115, 82.3776200833, \"455A\"],\n[54.7968634833, 82.3813122667, \"475C\"],\n[54.8040230333, 82.3951761833, \"610\"],\n[54.8004082667, 82.3807690333, \"475D\"],\n[54.8020559, 82.3804593667, \"481A\"],\n[54.8029026667, 82.3814678667, \"490\"],\n[54.79877225, 82.3804673833, \"475A\"],\n[54.8024990833, 82.3803016, \"478\"],\n[54.80798195, 82.3848864167, \"522B\"],\n[54.8032268667, 82.3820611833, \"496A\"],\n[54.8039424333, 82.3900004667, \"566\"],\n[54.8055885667, 82.3849529667, \"508\"],\n[54.8039439833, 82.3902647333, \"568\"],\n[54.8044673167, 82.3791537667, \"476B\"],\n[54.8034701, 82.3861407833, \"531\"],\n[54.80394855, 82.3905212833, \"570\"],\n[54.8033434667, 82.3677650667, \"356\"],\n[54.8039541167, 82.3897445, \"564\"],\n[54.8044864833, 82.3894950833, \"562B\"],\n[54.8023883667, 82.3792474, \"468\"],\n[54.8037905667, 82.3868461833, \"538\"],\n[54.80376065, 82.3848380167, \"516\"],\n[54.8037788333, 82.3866195333, \"536\"],\n[54.8013236667, 82.3867703833, \"535B\"],\n[54.80376085, 82.3863884, \"534\"],\n[54.8038128667, 82.38531645, \"524\"],\n[54.8038359, 82.3875590667, \"546\"],\n[54.8053126, 82.3651698, \"328\"],\n[54.8038053833, 82.3870689, \"540\"],\n[54.80589585, 82.3892222167, \"560\"],\n[54.8035248667, 82.3876434167, \"545\"],\n[54.8037198, 82.3949872, \"609\"],\n[54.80381955, 82.3872982, \"542\"],\n[54.8075598333, 82.3855587, \"522C\"],\n[54.8039602167, 82.3917614333, \"582\"],\n[54.80139505, 82.3727005667, \"414\"],\n[54.8036690667, 82.3910398667, \"575\"],\n[54.8039518833, 82.3910117167, \"574\"],\n[54.80395405, 82.3914879333, \"580\"],\n[54.8002672167, 82.3771908, \"447A\"],\n[54.8039521833, 82.3907747167, \"572\"],\n[54.8036402667, 82.3914460167, \"579\"],\n[54.803952, 82.3912312333, \"578\"],\n[54.8015263667, 82.3694650333, \"383\"],\n[54.80400045, 82.3949203833, \"608\"],\n[54.8039955333, 82.3935219167, \"598\"],\n[54.8039738167, 82.3926465167, \"590\"],\n[54.8034657167, 82.3675994, \"354\"],\n[54.8039642833, 82.3919945, \"584\"],\n[54.8039832667, 82.3932899167, \"596\"],\n[54.7988289, 82.3754860833, \"429C\"],\n[54.80369095, 82.3927310167, \"591\"],\n[54.80233225, 82.3911433833, \"571\"],\n[54.8039846667, 82.3930810833, \"594\"],\n[54.8013068333, 82.37155805, \"402\"],\n[54.80397775, 82.3928504167, \"592\"],\n[54.8040068833, 82.3948069833, \"608A\"],\n[54.8037325167, 82.3941101167, \"603\"],\n[54.8021858833, 82.3685292167, \"369\"],\n[54.8039958, 82.3939723167, \"602\"],\n[54.8048039833, 82.3657911, \"336\"],\n[54.80368355, 82.39362055, \"599\"],\n[54.8039906833, 82.3668667833, \"344\"],\n[54.8037408333, 82.39457725, \"607\"],\n[54.8040022167, 82.3941957, \"604\"],\n[54.80357305, 82.3683457167, \"358A\"],\n[54.80400475, 82.3944321167, \"606\"],\n[54.8037340667, 82.3943487167, \"605\"],\n[54.8021156667, 82.3876556833, \"543\"],\n[54.8012321, 82.3754553833, \"429A\"],\n[54.8018551667, 82.3752511, \"430\"],\n[54.8038677333, 82.3670357333, \"346\"],\n[54.8037207167, 82.3857282667, \"528\"],\n[54.89186715, 82.4802623167, \"40\"],\n[54.8923304833, 82.4777135167, \"13\"],\n[54.8929612833, 82.4756593333, \"1\"],\n[54.8918642, 82.4800987833, \"38\"],\n[54.8926700333, 82.4763031833, \"5\"],\n[54.89194195, 82.47893395, \"28A\"],\n[54.8924575833, 82.4767435167, \"9\"],\n[54.8918917333, 82.47938125, \"32\"],\n[54.8922351667, 82.4796796333, \"27\"],\n[54.8916363333, 82.47957795, \"34A\"],\n[54.8922002833, 82.48006775, \"29\"],\n[54.8918962833, 82.4796114333, \"34\"],\n[54.8923002333, 82.4783952667, \"21\"],\n[54.89225505, 82.4790280833, \"25\"],\n[54.8920123333, 82.4773945167, \"10\"],\n[54.8919046167, 82.4791651833, \"30\"],\n[54.89170475, 82.4789158833, \"28B\"],\n[54.89166225, 82.4793545667, \"32A\"],\n[54.8919418833, 82.4787236, \"26\"],\n[54.89187395, 82.4798382833, \"36\"],\n[54.89226945, 82.4788097167, \"23\"],\n[54.8919833667, 82.47800955, \"14\"],\n[54.88193185, 82.4866305833, \"1\"],\n[54.8812478, 82.4878395, \"20\"],\n[54.8819307, 82.48686775, \"3\"],\n[54.8823734333, 82.4877629833, \"8B\"],\n[54.8821842833, 82.48700355, \"4\"],\n[54.8818976833, 82.4871309333, \"5\"],\n[54.8821982333, 82.4867615167, \"2\"],\n[54.8821772, 82.48722635, \"6\"],\n[54.8809340667, 82.4875154, \"24\"],\n[54.8815621333, 82.4870228333, \"11B\"],\n[54.88080855, 82.4873367167, \"26\"],\n[54.8810877167, 82.4876951, \"22\"],\n[54.8806647833, 82.4872178, \"25\"],\n[54.8815580667, 82.4875735333, \"9\"],\n[54.88050695, 82.48709835, \"23\"],\n[54.8823652833, 82.48799725, \"10B\"],\n[54.8817490333, 82.4878626667, \"12\"],\n[54.88214405, 82.4874454833, \"8\"],\n[54.8816923833, 82.4878766167, \"14\"],\n[54.8823520667, 82.4875880667, \"8A\"],\n[54.8814424167, 82.48790665, \"16\"],\n[54.8819485333, 82.48774405, \"10\"],\n[54.8813723833, 82.4878899, \"18\"],\n[54.8822010167, 82.4879131167, \"10A\"],\n[54.8825377667, 82.48796795, \"8C\"],\n[54.8808839, 82.4866251333, \"17\"],\n[54.8807889, 82.4868384833, \"19\"],\n[54.8806788833, 82.4869695333, \"21\"],\n[54.8818035, 82.48743315, \"7\"],\n[54.8810684667, 82.4871791, \"13\"],\n[54.8809503667, 82.4869225, \"15\"],\n[54.8812931167, 82.4874573167, \"11\"],\n[54.8812351167, 82.4869114833, \"13A\"],\n[54.8814375667, 82.4871747, \"11A\"],\n[54.8813577333, 82.4869692333, \"13B\"],\n[54.9359592833, 82.5576784333, \"1/21\"],\n[54.9380472167, 82.5564234833, \"20\"],\n[54.9388147833, 82.5583222333, \"2/21\"],\n[54.9370746333, 82.55679275, \"21\"],\n[54.9396807833, 82.5590516333, \"4/21\"],\n[54.9321653667, 82.5586632333, \"15\"],\n[54.93777925, 82.5607732333, \"3/21\"],\n[54.93261665, 82.5577030167, \"22\"],\n[54.9350610667, 82.5544772, \"18\"],\n[54.9324680333, 82.55825425, \"17\"],\n[54.93286725, 82.5580919667, \"19\"],\n[54.9655341, 82.48344125, \"228\"],\n[54.9662557833, 82.4823937167, \"238\"],\n[54.9551121167, 82.4819800167, \"74\"],\n[54.97145005, 82.4810869667, \"298\"],\n[54.96511045, 82.4842071167, \"226\"],\n[54.9597843, 82.4837558833, \"1/144\"],\n[54.9542875333, 82.4787352833, \"46\"],\n[54.96095, 82.4848569, \"156\"],\n[54.9608395667, 82.4825922167, \"144\"],\n[54.9665397, 82.4859805667, \"227\"],\n[54.9546337667, 82.4780326167, \"44\"],\n[54.9662588833, 82.48466365, \"229\"],\n[54.9774811333, 82.4827824167, \"367\"],\n[54.9532187667, 82.4778035833, \"25\"],\n[54.9779600167, 82.4820124333, \"380\"],\n[54.96688945, 82.4825700833, \"244\"],\n[54.9724996333, 82.4816797, \"317\"],\n[54.9551293333, 82.4882803333, \"2/81\"],\n[54.9544212167, 82.4829611333, \"79\"],\n[54.9552378333, 82.4835594, \"3/81\"],\n[54.9551674833, 82.4873534333, \"1/81\"],\n[54.8177678333, 82.36481165, \"23\"],\n[54.8176856667, 82.36528815, \"21\"],\n[54.81793065, 82.36431665, \"24\"],\n[54.8188466, 82.3655251167, \"13\"],\n[54.8183913167, 82.3654774833, \"14\"],\n[54.8186506667, 82.3663757833, \"8\"],\n[54.9091586833, 82.4806199667, \"8\"],\n[54.9097846667, 82.4804238833, \"5\"],\n[54.9095970833, 82.4803937333, \"6\"],\n[54.90949585, 82.48088805, \"2\"],\n[54.9097125667, 82.4807851667, \"3\"],\n[54.9090767333, 82.4810419167, \"1\"],\n[54.9098378, 82.4806015167, \"4\"],\n[54.9094125333, 82.48047265, \"7\"],\n[54.8987957167, 82.4867648167, \"4\"],\n[54.8993040833, 82.48608325, \"13A\"],\n[54.8986618667, 82.4863548, \"3\"],\n[54.8990157167, 82.4866799667, \"8\"],\n[54.8988486167, 82.48625515, \"11\"],\n[54.89940275, 82.48652375, \"12\"],\n[54.8990940333, 82.4857358333, \"15\"],\n[54.8994477, 82.4860294167, \"13\"],\n[54.8984905333, 82.4864897167, \"1\"],\n[54.8910458667, 82.4604486167, \"4A\"],\n[54.8909012833, 82.4603024667, \"1\"],\n[54.8912700667, 82.4604892667, \"4B\"],\n[54.8909202167, 82.4608893333, \"3C\"],\n[54.8912779333, 82.4605982333, \"4C\"],\n[54.8909172, 82.4610096, \"3D\"],\n[54.8910309833, 82.46058295, \"4D\"],\n[54.8909275167, 82.4607770667, \"3B\"],\n[54.8908830667, 82.46040695, \"2\"],\n[54.8907294667, 82.4603703, \"2B\"],\n[54.8909360167, 82.4606728333, \"3A\"],\n[54.8910318, 82.46011345, \"5\"],\n[54.9038995167, 82.4740167833, \"1\"],\n[54.9040010833, 82.4744881, \"3\"],\n[54.9039700667, 82.4742456667, \"2\"],\n[54.9041160333, 82.4738995667, \"9\"],\n[54.9042205, 82.4746609667, \"5\"],\n[54.90408835, 82.4746666167, \"4\"],\n[54.9043300333, 82.4745611833, \"6\"],\n[54.9042862667, 82.47435, \"7\"],\n[54.9041895, 82.4741327333, \"8\"],\n[54.8412972333, 82.51498905, \"2/370\"],\n[54.85380915, 82.5048969, \"197\"],\n[54.8393792167, 82.5185004833, \"4/370\"],\n[54.8356004, 82.5155473833, \"1/446\"],\n[54.8516975167, 82.5088596333, \"230\"],\n[54.83493705, 82.5162245, \"2/446\"],\n[54.8630868833, 82.5013258667, \"77\"],\n[54.8341336333, 82.5147212667, \"454\"],\n[54.838285167, 82.511789, \"495\"],\n[54.8378645667, 82.51179665, \"422\"],\n[54.8482979667, 82.5057717167, \"2/277\"],\n[54.8384529, 82.5107566, \"1/413\"],\n[54.8543168833, 82.5057733167, \"200\"],\n[54.8382859, 82.51004915, \"2/413\"],\n[54.8302591667, 82.51099635, \"520\"],\n[54.8430264833, 82.5117441667, \"361\"],\n[54.8569890167, 82.50014995, \"145\"],\n[54.8546612333, 82.51046255, \"4/210\"],\n[54.8291138167, 82.5100652833, \"537\"],\n[54.8644712, 82.5010749167, \"57\"],\n[54.8537165667, 82.5061015667, \"1/210\"],\n[54.8561494333, 82.5002218833, \"151\"],\n[54.8531273167, 82.50591205, \"207\"],\n[54.8661337333, 82.50044185, \"39\"],\n[54.8572501333, 82.50068855, \"142\"],\n[54.86749845, 82.4999983667, \"31\"],\n[54.8311046167, 82.5124198667, \"504\"],\n[54.8610681167, 82.5009140667, \"99\"],\n[54.86009745, 82.5013829333, \"110\"],\n[54.8635882333, 82.5025296333, \"2/72\"],\n[54.8381455333, 82.5095623833, \"415\"],\n[54.86345265, 82.5022295333, \"1/72\"],\n[54.8535591333, 82.5063429, \"3/210\"],\n[54.8428438667, 82.5239404333, \"8/370\"],\n[54.8425296667, 82.5133880833, \"1/370\"],\n[54.8415704667, 82.5230515333, \"7/370\"],\n[54.8607450167, 82.5008543833, \"101\"],\n[54.8402798167, 82.5220041667, \"6/370\"],\n[54.8540611833, 82.5052768833, \"198\"],\n[54.8457524833, 82.5094666, \"314\"],\n[54.8379597667, 82.51065885, \"417\"],\n[54.83947605, 82.5206863, \"5/370\"],\n[54.8301105, 82.5103759, \"521\"],\n[54.84097385, 82.5217665167, \"9/370\"],\n[54.8408829167, 82.5157633333, \"3/370\"],\n[54.8540650833, 82.5067036667, \"2/210\"],\n[54.8541100167, 82.5042267333, \"191\"],\n[54.8426532167, 82.5117339667, \"365\"],\n[54.8483104167, 82.50609355, \"1/277\"],\n[54.8610126167, 82.5014974, \"98\"],\n[54.8409556, 82.5110372667, \"383\"],\n[54.8563855167, 82.4999012333, \"149\"],\n[54.8591389167, 82.5012515167, \"118\"],\n[54.8622922667, 82.5017081, \"86\"],\n[54.8279955333, 82.5107170333, \"548\"],\n[54.8293633667, 82.5100288667, \"535\"],\n[54.87412315, 82.36871325, \"20\"],\n[54.8741985167, 82.3678984333, \"25\"],\n[54.8744552833, 82.36791385, \"23\"],\n[54.82354435, 82.3645601333, \"31\"],\n[54.81426245, 82.3697857667, \"140B\"],\n[54.8249820167, 82.36436295, \"18A\"],\n[54.8247545333, 82.3644630667, \"18B\"],\n[54.8196718, 82.3690864167, \"74B\"],\n[54.8141992167, 82.3685047667, \"140D\"],\n[54.8202965167, 82.3688420833, \"74C\"],\n[54.8180317333, 82.3670563833, \"97\"],\n[54.8166606, 82.3680389833, \"116\"],\n[54.81378495, 82.3674693667, \"143\"],\n[54.8140329833, 82.36750105, \"141\"],\n[54.8230129333, 82.36477085, \"33\"],\n[54.8181065333, 82.367528, \"96A\"],\n[54.822355, 82.3651528333, \"43\"],\n[54.8207430167, 82.37001735, \"72\"],\n[54.882852333, 82.36768535, \"104\"],\n[54.8240652167, 82.3643383167, \"25\"],\n[54.8208649167, 82.3708165167, \"72C\"],\n[54.8158759333, 82.3699935167, \"124A\"],\n[54.81611735, 82.3726213833, \"124D\"],\n[54.8141102833, 82.3710208167, \"140E\"],\n[54.8158552833, 82.3725671, \"126C\"],\n[54.8172870667, 82.3672759333, \"105\"],\n[54.8149043167, 82.3680942, \"126A\"],\n[54.8156860667, 82.3714600667, \"126B\"],\n[54.82234555, 82.3676551167, \"58C\"],\n[54.8229201, 82.3663306333, \"42B\"],\n[54.8217244667, 82.36615365, \"56\"],\n[54.82168065, 82.3671740333, \"58A\"],\n[54.8226533, 82.3656960667, \"42A\"],\n[54.81969495, 82.3671185, \"74A\"],\n[54.8139910833, 82.3680670333, \"142\"],\n[54.8222810667, 82.36812165, \"58B\"],\n[54.8160942833, 82.3717498333, \"124C\"],\n[54.8210101167, 82.3697359333, \"72D\"],\n[54.8199424667, 82.3700336667, \"72A\"],\n[54.8162840333, 82.36763115, \"115\"],\n[54.8169082, 82.3674243667, \"109\"],\n[54.8231334167, 82.3666729833, \"42C\"],\n[54.8211535833, 82.3664307, \"66\"],\n[54.8159958, 82.3710006, \"124B\"],\n[54.8230926333, 82.3654223667, \"40\"],\n[54.8142580167, 82.3692795333, \"140C\"],\n[54.8184104667, 82.3677529833, \"96B\"],\n[54.8232137667, 82.3664941667, \"42D\"],\n[54.8238653167, 82.3649438333, \"30\"],\n[54.8210668833, 82.3659746167, \"59\"],\n[54.8204322833, 82.3668945833, \"70\"],\n[54.814820667, 82.3703629167, \"140A\"],\n[54.8203761167, 82.3663, \"69\"],\n[54.8190875, 82.3666263, \"83\"],\n[54.8206303833, 82.37079745, \"72B\"],\n[54.8159921167, 82.36829495, \"120\"],\n[54.8702900833, 82.4823576, \"129\"],\n[54.8691575833, 82.4875552167, \"174\"],\n[54.8752810167, 82.4785701333, \"29\"],\n[54.8739353333, 82.4787035333, \"71\"],\n[54.8694349833, 82.4853619333, \"150\"],\n[54.86819925, 82.4904272667, \"203\"],\n[54.8739757333, 82.4791716, \"36\"],\n[54.8743164833, 82.47849545, \"69\"],\n[54.8764327833, 82.4784211167, \"18\"],\n[54.8772371, 82.47724965, \"11\"],\n[54.8711581167, 82.4812798, \"99\"],\n[54.8774015333, 82.4771253167, \"9\"],\n[54.8747281, 82.4786202833, \"35\"],\n[54.8769075, 82.47753225, \"15\"],\n[54.8764091, 82.4779333667, \"21\"],\n[54.8751066833, 82.47903655, \"28\"],\n[54.8755713333, 82.4789569333, \"24\"],\n[54.8767426833, 82.4776735667, \"17\"],\n[54.87754365, 82.4769945167, \"7\"],\n[54.8749176, 82.4790524, \"30\"],\n[54.86789545, 82.4922832833, \"215\"],\n[54.8762449333, 82.4780463833, \"23\"],\n[54.8746104333, 82.4786632333, \"37\"],\n[54.87535045, 82.4789887, \"26\"],\n[54.8690190833, 82.4889257667, \"188\"],\n[54.8766569, 82.4782477833, \"16\"],\n[54.8777791667, 82.4743660833, \"3F\"],\n[54.8760992833, 82.4781375667, \"25\"],\n[54.8735414833, 82.4792975667, \"40\"],\n[54.8749123833, 82.4786099333, \"33\"],\n[54.8778868667, 82.4755309333, \"3B\"],\n[54.8757382667, 82.4789290833, \"22\"],\n[54.8690839, 82.4882992333, \"182\"],\n[54.8778719167, 82.4752090167, \"3C\"],\n[54.8692440333, 82.487114, \"168\"],\n[54.87786735, 82.4759980333, \"3A\"],\n[54.8750885833, 82.4785857167, \"31\"],\n[54.8778593, 82.4767417, \"1\"],\n[54.8770541, 82.4774016167, \"13\"],\n[54.8693264333, 82.4864033167, \"160\"],\n[54.8776720667, 82.47687455, \"5\"],\n[54.87418305, 82.4791450333, \"34\"],\n[54.8772782167, 82.4778079333, \"12\"],\n[54.8694907, 82.48387845, \"139\"],\n[54.8737682833, 82.4792036833, \"38\"],\n[54.8780202167, 82.4743749, \"3E\"],\n[54.87657365, 82.4778033833, \"19\"],\n[54.8769227, 82.4780192833, \"14\"],\n[54.8778372, 82.4747625833, \"3D\"],\n[54.9058634167, 82.4818391833, \"11\"],\n[54.90651765, 82.4816564, \"7\"],\n[54.90600205, 82.4817922833, \"10\"],\n[54.9065382667, 82.4819836667, \"6\"],\n[54.9064549667, 82.48231495, \"4\"],\n[54.9065751, 82.4821868667, \"5\"],\n[54.9062895, 82.4822382667, \"3\"],\n[54.9061909, 82.4817668, \"9\"],\n[54.9058636333, 82.4821877667, \"1\"],\n[54.90609375, 82.48208955, \"2\"],\n[54.9063477667, 82.4818540833, \"8\"],\n[54.9028285, 82.4830620667, \"10\"],\n[54.9033403333, 82.4828242833, \"4\"],\n[54.9026557833, 82.4836036833, \"11\"],\n[54.9026651667, 82.4831392167, \"12\"],\n[54.9024793, 82.4836898833, \"13\"],\n[54.9024864833, 82.4832286333, \"14\"],\n[54.9022771167, 82.4837931167, \"15\"],\n[54.9023275333, 82.48331475, \"16\"],\n[54.9021481167, 82.4833864333, \"18\"],\n[54.9034164167, 82.48324155, \"3\"],\n[54.9020819667, 82.4837508833, \"17\"],\n[54.9032251, 82.4833323833, \"5\"],\n[54.9031833833, 82.4829241667, \"6\"],\n[54.9030398667, 82.4834288667, \"7\"],\n[54.9030060333, 82.4827531167, \"8A\"],\n[54.90303195, 82.4830065, \"8\"],\n[54.90285465, 82.48352545, \"9\"],\n[54.9030180333, 82.4855010667, \"50\"],\n[54.90297345, 82.4847805333, \"52\"],\n[54.90302055, 82.4852138333, \"50A\"],\n[54.9006098833, 82.4854521833, \"33\"],\n[54.9029307667, 82.485268, \"48\"],\n[54.9014686667, 82.48551475, \"36\"],\n[54.9017719833, 82.4853557833, \"40\"],\n[54.9016177667, 82.4854306833, \"38\"],\n[54.9023493667, 82.48468465, \"47\"],\n[54.9027064667, 82.4842364667, \"51A\"],\n[54.9019256667, 82.4852900333, \"42\"],\n[54.9016388667, 82.4849819167, \"41\"],\n[54.9014681667, 82.485061, \"39\"],\n[54.9033233167, 82.48461845, \"56\"],\n[54.9037893833, 82.4839462667, \"63\"],\n[54.9031498833, 82.4846976667, \"54\"],\n[54.9026018, 82.48495995, \"44\"],\n[54.9030769833, 82.4842938, \"55\"],\n[54.9027864167, 82.4848613, \"46\"],\n[54.9037959667, 82.4843982667, \"62\"],\n[54.90251565, 82.4845560333, \"49\"],\n[54.9039613167, 82.4843144, \"64\"],\n[54.9027125667, 82.4844694167, \"51\"],\n[54.9034637167, 82.4841226, \"59\"],\n[54.9028946833, 82.4843869, \"53\"],\n[54.9036489333, 82.4840298833, \"61\"],\n[54.90327315, 82.4842082833, \"57\"],\n[54.90046945, 82.4855198667, \"29\"],\n[54.9010344833, 82.4856939833, \"34\"],\n[54.9013283667, 82.4851346333, \"37\"],\n[54.9017672167, 82.4849186, \"43\"],\n[54.8611247, 82.4102509167, \"82\"],\n[54.8499004667, 82.4102191667, \"47\"],\n[54.86802365, 82.4100161, \"251\"],\n[54.8527479167, 82.4097375667, \"82\"],\n[54.84663775, 82.41026955, \"13\"],\n[54.8556193, 82.4102112167, \"113\"],\n[54.8623374833, 82.4096021667, \"188\"],\n[54.8570313833, 82.4097304667, \"128\"],\n[54.8508672833, 82.4096890333, \"58\"],\n[54.8633539667, 82.4102016833, \"197\"],\n[54.8624295167, 82.4113314833, \"187\"],\n[54.8643999167, 82.4142555167, \"211A\"],\n[54.8674836667, 82.4109264333, \"245A\"],\n[54.8645949333, 82.4142231333, \"211B\"],\n[54.863722, 82.4116543667, \"203\"],\n[54.8652689, 82.4102405667, \"217\"],\n[54.8674028167, 82.4119272333, \"245B\"],\n[54.8688986, 82.4071594333, \"283\"],\n[54.8626189667, 82.4102669333, \"191\"],\n[54.86890705, 82.4066821333, \"285\"],\n[54.8638613833, 82.4102196333, \"205\"],\n[54.8520415333, 82.4096858833, \"74\"],\n[54.85366185, 82.4103740333, \"91\"],\n[54.8541498167, 82.4102157, \"99\"],\n[54.8481882167, 82.4096517333, \"32\"],\n[54.8998180833, 82.4671585833, \"1\"],\n[54.8994876333, 82.46689395, \"4\"],\n[54.8995568833, 82.4671854, \"2\"],\n[54.89982245, 82.4669492, \"3\"],\n[54.8997823167, 82.4667780333, \"5\"],\n[54.8993499, 82.4665456333, \"6\"],\n[54.8994541, 82.4664421167, \"8\"],\n[54.8996415, 82.4667272333, \"7\"],\n[54.8916384833, 82.4630697, \"40\"],\n[54.8913306, 82.4610441333, \"24\"],\n[54.89161595, 82.4716677667, \"133\"],\n[54.8914569167, 82.4754211833, \"149\"],\n[54.89160835, 82.4718250167, \"135\"],\n[54.89234715, 82.4585814667, \"9\"],\n[54.8915247667, 82.4732450833, \"137\"],\n[54.8916493667, 82.4628682, \"36\"],\n[54.89127365, 82.4608001667, \"1/20-3/20\"],\n[54.8922152167, 82.4605929667, \"17\"],\n[54.89145415, 82.4607833333, \"4/20-7/20\"],\n[54.8917261333, 82.4624021, \"32\"],\n[54.8919335167, 82.45821125, \"4C\"],\n[54.8922107833, 82.4609609833, \"21\"],\n[54.8919453667, 82.4579664333, \"4B\"],\n[54.8915077, 82.4658864333, \"66\"],\n[54.8919506333, 82.4577320333, \"4A\"],\n[54.8916613167, 82.4626608667, \"34\"],\n[54.8919576833, 82.4575137, \"2C\"],\n[54.89126035, 82.4701749167, \"92\"],\n[54.8922950667, 82.4588386, \"11\"],\n[54.8921412333, 82.4623956833, \"31\"],\n[54.8918877167, 82.4588751167, \"10\"],\n[54.8912372, 82.4708680333, \"98\"],\n[54.8920993333, 82.4636887167, \"43\"],\n[54.89223965, 82.4603451, \"15\"],\n[54.8920777333, 82.4638900667, \"43A\"],\n[54.89235135, 82.4580704, \"5\"],\n[54.8916213667, 82.4634083333, \"44\"],\n[54.8913535, 82.4751499333, \"147\"],\n[54.8911645667, 82.4634580167, \"46\"],\n[54.89154565, 82.460355, \"16A\"],\n[54.8916286667, 82.4636265667, \"48\"],\n[54.8914890667, 82.4661530833, \"68\"],\n[54.8916243333, 82.46377045, \"50A\"],\n[54.8921945667, 82.4613726833, \"25\"],\n[54.8916212333, 82.4638566667, \"50\"],\n[54.898285833, 82.4617233333, \"28\"],\n[54.8916201, 82.4640203, \"52\"],\n[54.89219925, 82.46119465, \"23\"],\n[54.891597, 82.46425765, \"54\"],\n[54.8918353, 82.46017655, \"14\"],\n[54.8919748667, 82.4649644667, \"53\"],\n[54.8917905667, 82.4608055333, \"22\"],\n[54.89131955, 82.4756406, \"153\"],\n[54.8923704333, 82.4576240833, \"3\"],\n[54.8905614333, 82.4758690167, \"154\"],\n[54.8916816167, 82.4707503, \"97\"],\n[54.8913018667, 82.4759012333, \"155\"],\n[54.89253265, 82.4612154167, \"23B\"],\n[54.8909466833, 82.4760167333, \"156\"],\n[54.8920906167, 82.4634921, \"41\"],\n[54.8912217, 82.4774480833, \"165\"],\n[54.8921237833, 82.46277795, \"35\"],\n[54.8908697333, 82.477294, \"162\"],\n[54.8920948667, 82.4632665833, \"39\"],\n[54.8912003333, 82.47770905, \"167\"],\n[54.8914414833, 82.4678414, \"76\"],\n[54.8908453833, 82.4777106667, \"168\"],\n[54.8912160667, 82.4629456833, \"38\"],\n[54.8911874, 82.4779408167, \"169\"],\n[54.8919186333, 82.4584176833, \"6\"],\n[54.89118215, 82.4781761167, \"171\"],\n[54.8916446833, 82.4632172667, \"42\"],\n[54.8911654333, 82.4784059833, \"173\"],\n[54.8918217333, 82.4603906, \"16\"],\n[54.8911525333, 82.47862755, \"82\"],\n[54.8924511333, 82.4606313, \"17B\"],\n[54.8907954, 82.4784089, \"176\"],\n[54.8915381333, 82.46524225, \"58\"],\n[54.8911355667, 82.478864, \"177\"],\n[54.892167, 82.4617876833, \"29\"],\n[54.8911190667, 82.4790793167, \"179\"],\n[54.89148925, 82.47413605, \"141\"],\n[54.891102, 82.4793148833, \"181\"],\n[54.89174025, 82.4622023, \"30\"],\n[54.8910930167, 82.4795416333, \"183\"],\n[54.8923048, 82.4605938667, \"17A\"],\n[54.8907614, 82.4793265833, \"184\"],\n[54.8919164833, 82.45868485, \"8\"],\n[54.89108015, 82.4797723833, \"185\"],\n[54.8905659667, 82.4757830667, \"152\"],\n[54.8910595667, 82.4800169167, \"187\"],\n[54.8923372333, 82.4582542, \"7\"],\n[54.8917307333, 82.46930505, \"83\"],\n[54.8909663333, 82.4756883833, \"150\"],\n[54.8909111167, 82.47660485, \"160\"],\n[54.8916525667, 82.47116215, \"129\"],\n[54.8909366167, 82.4762755333, \"158\"],\n[54.8911956, 82.4715676333, \"104\"],\n[54.8915429, 82.4650714667, \"56\"],\n[54.8916859833, 82.45866365, \"8A\"],\n[54.8919523, 82.4651683833, \"55\"],\n[54.8915248667, 82.4654342167, \"60\"],\n[54.8917482, 82.4613051333, \"26\"],\n[54.89101255, 82.4753879, \"148\"],\n[54.8925110833, 82.4608349833, \"19\"],\n[54.89179885, 82.4605882333, \"18\"],\n[54.8918582667, 82.4680386, \"79\"],\n[54.8921763167, 82.461584, \"27\"],\n[54.8914747833, 82.4665362167, \"70\"],\n[54.8923905833, 82.4611956167, \"23A\"],\n[54.8919975333, 82.4651655, \"55A-55E\"],\n[54.8920026167, 82.45729865, \"2B\"],\n[54.8920162667, 82.4570673, \"2A\"],\n[54.8916384333, 82.4713722, \"131\"],\n[54.8912288333, 82.4711408333, \"102\"],\n[54.8915248167, 82.4656389833, \"62\"],\n[54.8917611667, 82.46114545, \"26A\"],\n[54.8921091, 82.4630288167, \"37\"],\n[54.8209873167, 82.3760669333, \"191C\"],\n[54.8249917, 82.3656036667, \"91A\"],\n[54.8190006167, 82.3860204167, \"254B\"],\n[54.818206, 82.38533, \"254C\"],\n[54.8061591667, 82.3983436, \"462\"],\n[54.8056489333, 82.3937574167, \"423\"],\n[54.79713005, 82.40084965, \"545\"],\n[54.79324805, 82.4048036667, \"601\"],\n[54.8186617833, 82.3815952, \"248A\"],\n[54.8090422833, 82.3906621333, \"383B\"],\n[54.8183971667, 82.3818555667, \"248B\"],\n[54.8027335833, 82.3963706167, \"471\"],\n[54.8167087, 82.380828333, \"267D\"],\n[54.7975265333, 82.4015703333, \"548\"],\n[54.8190651167, 82.3786646333, \"229\"],\n[54.7903981, 82.4069922833, \"639B\"],\n[54.8253436333, 82.3662536, \"91B\"],\n[54.8085089, 82.3916918167, \"406\"],\n[54.82507135, 82.36734685, \"107A\"],\n[54.8243141667, 82.3677190167, \"107B\"],\n[54.8240930167, 82.3684544333, \"107C\"],\n[54.82428045, 82.3692349, \"107D\"],\n[54.79320855, 82.4054745333, \"606\"],\n[54.8210957833, 82.3758549, \"191A\"],\n[54.8220672667, 82.3711244167, \"155B\"],\n[54.7905658333, 82.40715725, \"639A\"],\n[54.8219987167, 82.37182365, \"155C\"],\n[54.79282425, 82.4050586, \"605\"],\n[54.8217745833, 82.37222335, \"155D\"],\n[54.80515685, 82.3938695, \"437\"],\n[54.8076407333, 82.3900775, \"397\"],\n[54.8237106, 82.3712966333, \"131\"],\n[54.8015971, 82.3955181667, \"479\"],\n[54.8227929, 82.3730921167, \"157\"],\n[54.7961391167, 82.4003037, \"549\"],\n[54.8233609833, 82.37310895, \"152\"],\n[54.8219492667, 82.3745148667, \"167\"],\n[54.8247903833, 82.3685883333, \"109\"],\n[54.8248283, 82.3705193167, \"126\"],\n[54.8109710333, 82.3856751167, \"341\"],\n[54.82605485, 82.3651553667, \"80\"],\n[54.8107359, 82.3894516833, \"368\"],\n[54.8120085667, 82.3845064, \"321\"],\n[54.8128636833, 82.38379265, \"310\"],\n[54.81208235, 82.3843228, \"319\"],\n[54.8046513333, 82.3956590833, \"452\"],\n[54.8144067333, 82.3816008667, \"275\"],\n[54.8102773, 82.3874213, \"345B\"],\n[54.8144369, 82.38227185, \"280\"],\n[54.8164895333, 82.3782892333, \"267C\"],\n[54.8182382167, 82.3800216667, \"240\"],\n[54.8173681833, 82.3806125, \"248C\"],\n[54.8181792333, 82.3832736333, \"254A\"],\n[54.8095723, 82.3899326833, \"383A\"],\n[54.81761125, 82.3835261667, \"254D\"],\n[54.8028805167, 82.3962506667, \"469\"],\n[54.8185789, 82.3845444, \"254\"],\n[54.8163547167, 82.3812859833, \"258\"],\n[54.7930282167, 82.40572125, \"608\"],\n[54.821138, 82.38039485, \"216D\"],\n[54.81606355, 82.3793317167, \"267B\"],\n[54.81934515, 82.3785087833, \"225\"],\n[54.8050155667, 82.3943832667, \"443A\"],\n[54.81861015, 82.379036, \"235A\"],\n[54.8121421833, 82.3842917833, \"317\"],\n[54.7913696833, 82.4063793, \"623\"],\n[54.8205651167, 82.3768472333, \"201\"],\n[54.8205108, 82.37795785, \"212\"],\n[54.8231057, 82.3725295333, \"155A\"],\n[54.8046846167, 82.3939956333, \"443B\"],\n[54.7964915667, 82.40187745, \"559\"],\n[54.80485815, 82.39453205, \"443C\"],\n[54.8060723667, 82.3939798167, \"428\"],\n[54.8047227, 82.3946713167, \"445\"],\n[54.8048381667, 82.3949814667, \"448\"],\n[54.8045786833, 82.3947850833, \"449\"],\n[54.7981357, 82.3900883333, \"461B\"],\n[54.8099047, 82.39060605, \"388\"],\n[54.8043014333, 82.3950148, \"453\"],\n[54.8043075833, 82.3954701167, \"456\"],\n[54.79168895, 82.4068591833, \"626\"],\n[54.8021525833, 82.39678165, \"481\"],\n[54.8034197833, 82.39575665, \"463\"],\n[54.8032362167, 82.3959217833, \"467\"],\n[54.80216475, 82.3974925167, \"484\"],\n[54.8203596833, 82.3755115833, \"191B\"],\n[54.7993380667, 82.3999904667, \"522\"],\n[54.8085763833, 82.3912222, \"391\"],\n[54.7981168833, 82.4004628, \"533\"],\n[54.7969743333, 82.4013795333, \"553\"],\n[54.7970796333, 82.4021227667, \"554\"],\n[54.7943688833, 82.404582833, \"590\"],\n[54.8073738833, 82.39222815, \"419\"],\n[54.7955603667, 82.4027828667, \"569\"],\n[54.8102608, 82.3842148333, \"345A\"],\n[54.7958160167, 82.4031990833, \"570\"],\n[54.7924329333, 82.4084768167, \"630\"],\n[54.7956436833, 82.4033528333, \"572\"],\n[54.7960458333, 82.4022678, \"563\"],\n[54.8030297833, 82.3966600167, \"472\"],\n[54.7963875, 82.4000470667, \"547\"],\n[54.8052467, 82.39419005, \"439\"],\n[54.8103165333, 82.38810555, \"345C\"],\n[54.7987565833, 82.3998819167, \"531A\"],\n[54.7982830833, 82.40023825, \"531B\"],\n[54.79918855, 82.4000808833, \"524\"],\n[54.7944693667, 82.4027557167, \"577\"],\n[54.7950937833, 82.4031431333, \"575\"],\n[54.7927918333, 82.4046828167, \"603\"],\n[54.7947576333, 82.4034387833, \"579\"],\n[54.8117228167, 82.38764085, \"346B\"],\n[54.7911496667, 82.40664935, \"629\"],\n[54.81588535, 82.3807131667, \"267A\"],\n[54.7912028, 82.40724595, \"634\"],\n[54.7908960167, 82.4074944, \"638\"],\n[54.8108278167, 82.3873807333, \"346A\"],\n[54.8109458667, 82.3868272333, \"346\"],\n[54.8861902333, 82.4912457, \"146\"],\n[54.8868429667, 82.4923818, \"242\"],\n[54.8863162333, 82.4914635667, \"150\"],\n[54.8866134167, 82.4930928167, \"281\"],\n[54.8857069333, 82.49160115, \"115\"],\n[54.88701045, 82.4928565167, \"282\"],\n[54.8865745167, 82.4918085333, \"196\"],\n[54.8847997667, 82.49160355, \"1\"],\n[54.88530765, 82.49159645, \"65\"],\n[54.8858858, 82.4924325333, \"195\"],\n[54.88625505, 82.4922030167, \"201\"],\n[54.8858815167, 82.49117815, \"140\"],\n[54.8870972167, 82.4937585167, \"370\"],\n[54.8871422667, 82.4932273333, \"330\"],\n[54.8867199333, 82.4935654, \"331\"],\n[54.88711285, 82.4670386167, \"6\"],\n[54.8867336333, 82.4670516667, \"3\"],\n[54.8867436833, 82.4669519, \"1\"],\n[54.8869533833, 82.4669386667, \"2\"],\n[54.8869398667, 82.46704125, \"4\"],\n[54.887182, 82.46692505, \"5\"],\n[54.9008030333, 82.4861118167, \"2\"],\n[54.90075285, 82.4859038833, \"1\"],\n[54.9009336167, 82.4865805833, \"4\"],\n[54.9008800167, 82.4863431167, \"3\"],\n[54.90100455, 82.4868142, \"5\"],\n[54.9014235667, 82.4873154667, \"7B\"],\n[54.9010728, 82.4870406333, \"6\"],\n[54.9012685833, 82.4873578833, \"7A\"],\n[54.9011401833, 82.4872876833, \"7\"],\n[54.8158733667, 82.37666665, \"18A\"],\n[54.8161566833, 82.3760580333, \"16\"],\n[54.8161400333, 82.3766246833, \"18B\"],\n[54.81564025, 82.3760005833, \"20\"],\n[54.9147940667, 82.4781293167, \"2\"],\n[54.91445275, 82.477954, \"5\"],\n[54.91432165, 82.4780204333, \"7\"],\n[54.9142254833, 82.4781627667, \"9\"],\n[54.9142594833, 82.4783362167, \"11\"],\n[54.9140805833, 82.4785308167, \"11A\"],\n[54.9141151333, 82.47861905, \"10A\"],\n[54.91436635, 82.4784698833, \"10\"],\n[54.9144396667, 82.4784653667, \"8\"],\n[54.9147089667, 82.47783895, \"1\"],\n[54.9145894, 82.4778914333, \"3\"],\n[54.9146597833, 82.4781811833, \"4\"],\n[54.9145286, 82.4783673833, \"6\"],\n[54.9030873667, 82.47210575, \"3\"],\n[54.9032704833, 82.472054, \"5\"],\n[54.9032275333, 82.4724681, \"4\"],\n[54.9029155167, 82.4722868333, \"1\"],\n[54.9029878333, 82.4725947167, \"2\"],\n[54.9033794333, 82.4723403167, \"6\"],\n[54.9033877, 82.4721768833, \"8\"],\n[54.9026622333, 82.5342312833, \"2/60\"],\n[54.8962902167, 82.5377237833, \"3/157\"],\n[54.9056577833, 82.5300138, \"24\"],\n[54.8978118667, 82.53526435, \"1/157\"],\n[54.9036869333, 82.5324068, \"46\"],\n[54.8976678167, 82.5356030833, \"2/157\"],\n[54.9025187, 82.53438235, \"3/60\"],\n[54.8981575333, 82.5358635, \"1/158\"],\n[54.9027801667, 82.5340282833, \"1/60\"],\n[54.8979776333, 82.536204, \"2/158\"],\n[54.9023776667, 82.5345600167, \"4/60\"],\n[54.8853151833, 82.4743354167, \"6\"],\n[54.8839096667, 82.4747028, \"17\"],\n[54.8826408833, 82.4741236667, \"44\"],\n[54.8835314167, 82.4746655333, \"21\"],\n[54.88308945, 82.4737775333, \"28\"],\n[54.8814453833, 82.4749238167, \"41\"],\n[54.8829200333, 82.4741641167, \"40\"],\n[54.8804728833, 82.4739323833, \"66\"],\n[54.8824228667, 82.47455335, \"33\"],\n[54.8849254333, 82.4748141333, \"9\"],\n[54.8815074833, 82.4735321333, \"54A\"],\n[54.8829310333, 82.4736918167, \"38\"],\n[54.8836627167, 82.47426195, \"20\"],\n[54.8818192, 82.4745435833, \"35\"],\n[54.8816592833, 82.4740403, \"48\"],\n[54.8816905333, 82.4745296167, \"37\"],\n[54.8835084, 82.47420785, \"22\"],\n[54.8810922833, 82.4739643833, \"58\"],\n[54.8814526, 82.4737812167, \"52\"],\n[54.8813118333, 82.4739949167, \"56\"],\n[54.88347125, 82.4749025167, \"21A\"],\n[54.88493785, 82.4743158, \"10\"],\n[54.88273915, 82.4748604167, \"29A\"],\n[54.8837637667, 82.4746886167, \"19\"],\n[54.8833199667, 82.47417425, \"24\"],\n[54.8838467, 82.4742672333, \"18\"],\n[54.8833191167, 82.4746548333, \"23\"],\n[54.8845514833, 82.4742861, \"14\"],\n[54.8853397, 82.4748736833, \"5\"],\n[54.8847559333, 82.4748089167, \"11\"],\n[54.8829521167, 82.47379525, \"36\"],\n[54.88450605, 82.4747736667, \"13\"],\n[54.8851099333, 82.4747525667, \"7\"],\n[54.8847199, 82.4743100333, \"12\"],\n[54.8831416, 82.4741727333, \"26\"],\n[54.8808951333, 82.47394745, \"60\"],\n[54.8808293167, 82.4744251333, \"49\"],\n[54.8806857667, 82.4739440333, \"62\"],\n[54.8815219, 82.4745206667, \"39\"],\n[54.88054725, 82.47393465, \"64\"],\n[54.8851369667, 82.4743293333, \"8\"],\n[54.8829415167, 82.4735765833, \"34\"],\n[54.8813163167, 82.4745132667, \"45\"],\n[54.8825621, 82.4745672, \"31\"],\n[54.882743, 82.4745888, \"29\"],\n[54.8849588833, 82.4740735333, \"10A\"],\n[54.8830033833, 82.47362085, \"32\"],\n[54.8814134833, 82.4735401, \"54\"],\n[54.8829174167, 82.4746101833, \"27\"],\n[54.881329, 82.4749196167, \"43\"],\n[54.8818477833, 82.4741495167, \"46\"],\n[54.8806645833, 82.474444, \"51\"],\n[54.8835542, 82.4740686833, \"22A\"],\n[54.8815817333, 82.4735421833, \"54B\"],\n[54.884082333, 82.4742836, \"16\"],\n[54.8827733167, 82.4741382833, \"42\"],\n[54.8831040167, 82.4746167333, \"25\"],\n[54.88152945, 82.47402335, \"50\"],\n[54.8810197, 82.4744641667, \"47\"],\n[54.90035815, 82.4810595167, \"6\"],\n[54.9004626167, 82.4814882, \"5\"],\n[54.9004783333, 82.4807893167, \"8\"],\n[54.90053035, 82.48110305, \"10\"],\n[54.9001194333, 82.4813414167, \"1\"],\n[54.9002854167, 82.4813794, \"3\"],\n[54.9005929833, 82.4812279167, \"12\"],\n[54.9005808667, 82.4813900667, \"7\"],\n[54.90019795, 82.4810457333, \"4\"],\n[54.9000177833, 82.4810738667, \"2\"],\n[54.8970709833, 82.471412, \"47\"],\n[54.8962267, 82.4699139833, \"25\"],\n[54.8957546, 82.46976195, \"14\"],\n[54.8960248333, 82.4695108167, \"15\"],\n[54.8958360833, 82.4699171167, \"16\"],\n[54.8960595667, 82.4695834167, \"17\"],\n[54.8956411833, 82.46957925, \"12\"],\n[54.8955700333, 82.46945925, \"10\"],\n[54.8957725, 82.4690580833, \"13\"],\n[54.8957180833, 82.4689838167, \"11\"],\n[54.89593735, 82.4700870667, \"18\"],\n[54.8960019667, 82.4702152333, \"20\"],\n[54.8960897167, 82.4696367833, \"21\"],\n[54.8960816667, 82.4703379833, \"22\"],\n[54.8961728667, 82.4698312667, \"23\"],\n[54.89611545, 82.4703987167, \"24\"],\n[54.89616535, 82.4704619, \"26\"],\n[54.8965143333, 82.4704345833, \"31\"],\n[54.8965995, 82.4706005, \"33\"],\n[54.8952596167, 82.46889415, \"2\"],\n[54.8954856333, 82.4693051333, \"8\"],\n[54.8953389167, 82.4690297167, \"4\"],\n[54.8953875833, 82.469136, \"6\"],\n[54.9194040167, 82.4783079, \"10\"],\n[54.9197726333, 82.4782003, \"12\"],\n[54.9194026167, 82.4796128167, \"133\"],\n[54.9197761667, 82.47866625, \"40\"],\n[54.9199951833, 82.4798155667, \"148\"],\n[54.91981195, 82.47907645, \"78\"],\n[54.9194262833, 82.4788171833, \"59\"],\n[54.9196759333, 82.4798573833, \"154\"],\n[54.9193148667, 82.48000435, \"155\"],\n[54.9194418667, 82.479248, \"95\"],\n[54.91985945, 82.47946575, \"114\"],\n[54.8948282, 82.4632178833, \"7\"],\n[54.8948541333, 82.4634539, \"11\"],\n[54.8946653333, 82.46382725, \"6A\"],\n[54.8942238167, 82.4629336667, \"1A\"],\n[54.8942486167, 82.4635523667, \"2\"],\n[54.8942641667, 82.4631693, \"1\"],\n[54.8950186, 82.4640242, \"8C\"],\n[54.8944589, 82.4631798333, \"3\"],\n[54.8946294333, 82.4631902, \"5\"],\n[54.89450815, 82.4635785333, \"4\"],\n[54.8946479, 82.4635948, \"6\"],\n[54.89498065, 82.4637099667, \"8B\"],\n[54.8948863333, 82.4637035833, \"8A\"],\n[54.89496985, 82.46325115, \"9\"],\n[54.8947899667, 82.4637024167, \"8\"],\n[54.89513905, 82.4640248667, \"8D\"],\n[54.9428737167, 82.4654487167, \"80\"],\n[54.9435976167, 82.4662367333, \"85\"],\n[54.9406954, 82.4650713667, \"60\"],\n[54.9443210167, 82.466494, \"91\"],\n[54.9430113833, 82.4661685167, \"79\"],\n[54.9423613, 82.4660200167, \"73\"],\n[54.9217937167, 82.54130465, \"1\"],\n[54.9214646833, 82.5409056667, \"41\"],\n[54.9210630667, 82.5409307333, \"86\"],\n[54.9211853667, 82.5410841, \"66\"],\n[54.92096145, 82.5405598333, \"83\"],\n[54.9206217333, 82.54086065, \"133\"],\n[54.9216795, 82.5411416833, \"21\"],\n[54.9213075167, 82.5412473167, \"48\"],\n[54.9214208167, 82.54139905, \"26\"],\n[54.9204421, 82.5405807833, \"127\"],\n[54.8771340667, 82.4766456167, \"17\"],\n[54.87582545, 82.4764970667, \"2\"],\n[54.8772717167, 82.47651465, \"19\"],\n[54.87616025, 82.47643495, \"6\"],\n[54.87713215, 82.4761358333, \"20\"],\n[54.8763702833, 82.4764765, \"10\"],\n[54.8768617333, 82.4759845333, \"18A\"],\n[54.87599415, 82.4764346167, \"4\"],\n[54.8767086, 82.4760073, \"18B\"],\n[54.8762125167, 82.4761083833, \"8\"],\n[54.8771747, 82.4758428833, \"22\"],\n[54.8774091, 82.4763950167, \"21\"],\n[54.8764912333, 82.4760901, \"18C\"],\n[54.8775394167, 82.47599195, \"25\"],\n[54.8765312333, 82.47650495, \"12\"],\n[54.8774804667, 82.47621635, \"23\"],\n[54.8767157833, 82.4764832833, \"14\"],\n[54.8776499, 82.4754748667, \"26B\"],\n[54.8769073667, 82.4763486167, \"16\"],\n[54.8774781667, 82.4755253167, \"26A\"],\n[54.8769741333, 82.4767701, \"15\"],\n[54.8761039, 82.4768351333, \"3\"],\n[54.8767738333, 82.4768931333, \"13\"],\n[54.8775332833, 82.4757816833, \"27\"],\n[54.87661205, 82.4769204667, \"11\"],\n[54.8773297333, 82.4756777167, \"24\"],\n[54.8761442833, 82.47743145, \"5B\"],\n[54.8761289667, 82.4772156167, \"5A\"],\n[54.87642575, 82.47690055, \"7\"],\n[54.87587225, 82.4768522667, \"1\"],\n[54.8762655667, 82.4774301667, \"5C\"],\n[54.8765258167, 82.4771421167, \"9\"],\n[54.8775364167, 82.48049705, \"9\"],\n[54.87721065, 82.48073405, \"3\"],\n[54.8773645167, 82.48035315, \"6\"],\n[54.8769231833, 82.4805237833, \"2\"],\n[54.8776686, 82.4807239333, \"7\"],\n[54.87711275, 82.4803929167, \"4\"],\n[54.8774604167, 82.4807430667, \"5\"],\n[54.87709625, 82.4808098667, \"1\"],\n[54.8775519167, 82.48027995, \"8\"],\n[54.8028734167, 82.5544968333, \"64\"],\n[54.7908094, 82.55717225, \"231\"],\n[54.8020794667, 82.5538755, \"79\"],\n[54.8025875667, 82.5538326167, \"73\"],\n[54.8788754667, 82.4246207833, \"26\"],\n[54.8579076333, 82.423369, \"257A\"],\n[54.8799908833, 82.4247353667, \"14\"],\n[54.8576267333, 82.4217187, \"257D\"],\n[54.8792310833, 82.4241302167, \"21\"],\n[54.8560683833, 82.4248801833, \"278\"],\n[54.8737989833, 82.42415875, \"79\"],\n[54.8813433667, 82.42936065, \"8/8\"],\n[54.8734102333, 82.4246495, \"86\"],\n[54.8605645333, 82.42419905, \"229\"],\n[54.8719786333, 82.4241769, \"91\"],\n[54.8781270333, 82.4246374167, \"34\"],\n[54.8720274833, 82.4248217833, \"94\"],\n[54.8578687167, 82.4212873833, \"257C\"],\n[54.87800375, 82.4263720167, \"40\"],\n[54.8618965833, 82.4242119333, \"213\"],\n[54.8801869167, 82.42773835, \"1/8\"],\n[54.8779240167, 82.42463595, \"36\"],\n[54.8743793333, 82.4246104667, \"76\"],\n[54.8578661, 82.4218172, \"257B\"],\n[54.8539269833, 82.4240546833, \"293\"],\n[54.8767564, 82.4218264667, \"49\"],\n[54.8598008833, 82.4242299667, \"235\"],\n[54.8584386667, 82.42421145, \"249\"],\n[54.8570034667, 82.4213275, \"265\"],\n[54.8800888, 82.42631445, \"10\"],\n[54.8771395667, 82.4240152, \"43\"],\n[54.8781435167, 82.4240972, \"33\"],\n[54.8767499333, 82.4247563, \"52\"],\n[54.87567625, 82.42459055, \"60\"],\n[54.8807013, 82.4246087167, \"6\"],\n[54.8764337167, 82.42402455, \"55\"],\n[54.8645742, 82.4242096833, \"183\"],\n[54.88046835, 82.4241622833, \"7\"],\n[54.8700695833, 82.4241415, \"109\"],\n[54.87820565, 82.4227695333, \"31\"],\n[54.86436995, 82.42472575, \"184\"],\n[54.8712348833, 82.4199563167, \"129\"],\n[54.8655708833, 82.4241920833, \"163\"],\n[54.866108, 82.4247113333, \"168\"],\n[54.85758825, 82.4248484667, \"258\"],\n[54.8806747167, 82.4289119667, \"3/8\"],\n[54.8808697333, 82.429829167, \"5/8\"],\n[54.8805498667, 82.4315314333, \"7/8\"],\n[54.8805142333, 82.4283195667, \"8\"],\n[54.8642561, 82.4211131, \"185B\"],\n[54.8642016333, 82.4241768167, \"185C\"],\n[54.8584019167, 82.4247333, \"254\"],\n[54.8579075, 82.4247216333, \"256\"],\n[54.85733205, 82.4242334, \"261\"],\n[54.8572177833, 82.4231895, \"263\"],\n[54.8643650167, 82.4220877667, \"185A\"],\n[54.89998625, 82.4831132833, \"33\"],\n[54.9028015, 82.4824331833, \"62A\"],\n[54.9027069833, 82.4824823167, \"60A\"],\n[54.8999237833, 82.48395105, \"28\"],\n[54.8998797667, 82.4835940667, \"30\"],\n[54.9000587333, 82.4835154167, \"32\"],\n[54.9016412667, 82.48230395, \"51\"],\n[54.901574, 82.4827421167, \"52\"],\n[54.90194355, 82.4826111667, \"54\"],\n[54.90215485, 82.4824878833, \"56\"],\n[54.9003890667, 82.48224575, \"41\"],\n[54.9005753833, 82.4833095667, \"42\"],\n[54.9004801833, 82.4824322, \"43\"],\n[54.9007382, 82.48323555, \"44\"],\n[54.9007203833, 82.4827551667, \"45\"],\n[54.9008984833, 82.4831199, \"46\"],\n[54.9010707, 82.4830293333, \"48\"],\n[54.9010407167, 82.4825866833, \"49\"],\n[54.90236485, 82.4823782167, \"58\"],\n[54.9025425, 82.4818774167, \"59\"],\n[54.9025757167, 82.4822757667, \"60\"],\n[54.9029402833, 82.4816723667, \"61\"],\n[54.90278895, 82.4821800333, \"62\"],\n[54.9031374667, 82.4822319333, \"64A\"],\n[54.9030315833, 82.4820359667, \"64\"],\n[54.9032178667, 82.4819789333, \"66\"],\n[54.9019434, 82.48286115, \"54A\"],\n[54.8818104333, 82.4707039833, \"12\"],\n[54.8814851833, 82.4704820167, \"9\"],\n[54.8810768333, 82.4699034, \"5B\"],\n[54.8818488, 82.4702216, \"1\"],\n[54.8816215667, 82.47092875, \"11\"],\n[54.8816941833, 82.4701273667, \"2\"],\n[54.8811842333, 82.4704525667, \"7\"],\n[54.8813522667, 82.47002245, \"4\"],\n[54.88194605, 82.4707180167, \"13\"],\n[54.8813308, 82.4704956333, \"8\"],\n[54.88115305, 82.4702513333, \"6\"],\n[54.8811936167, 82.4700739, \"5A\"],\n[54.8815373167, 82.4700831, \"3\"],\n[54.8816521333, 82.4705540833, \"10\"],\n[54.8088981167, 82.36906915, \"77\"],\n[54.8088042833, 82.3655253833, \"80\"],\n[54.8066999167, 82.3689073333, \"52\"],\n[54.8042113, 82.3710341667, \"21\"],\n[54.8035833, 82.3699288833, \"17\"],\n[54.8043107833, 82.3697591667, \"23\"],\n[54.8108776667, 82.3698460833, \"87B\"],\n[54.8045451333, 82.3697163333, \"25\"],\n[54.8104246167, 82.365628, \"94B\"],\n[54.8047750833, 82.3692679333, \"30\"],\n[54.80400095, 82.3716803333, \"19B\"],\n[54.8025388833, 82.3693096833, \"2\"],\n[54.8032552333, 82.3718025, \"19A\"],\n[54.8027435333, 82.3695240333, \"4\"],\n[54.8105842, 82.3663406667, \"94A\"],\n[54.8028778167, 82.3696653833, \"6\"],\n[54.8095059667, 82.37026555, \"81\"],\n[54.8055475667, 82.3691296833, \"36\"],\n[54.8101165833, 82.3695157, \"87A\"],\n[54.8055532333, 82.3695431833, \"41\"],\n[54.8068988, 82.3688744333, \"54\"],\n[54.8059911667, 82.3690365333, \"44\"],\n[54.8074588333, 82.36921695, \"59\"],\n[54.8075005667, 82.3687474667, \"60\"],\n[54.80836585, 82.3685797833, \"64\"],\n[54.8060896833, 82.3724944167, \"67A\"],\n[54.8079139, 82.3722770833, \"67B\"],\n[54.8089385167, 82.3721465167, \"67C\"],\n[54.81012905, 82.3782445, \"67D\"],\n[54.8110090333, 82.3680073333, \"96\"],\n[54.8103251, 82.3687031333, \"89\"],\n[54.8101581667, 82.36820355, \"88\"],\n[54.8097519333, 82.36879765, \"85\"],\n[54.8084821, 82.37132025, \"69\"],\n[54.8818073167, 82.4679643, \"6\"],\n[54.8823003833, 82.4676866167, \"1\"],\n[54.8818464333, 82.4675593, \"5\"],\n[54.8822481333, 82.4679646833, \"2\"],\n[54.8817913833, 82.4677682167, \"7\"],\n[54.8821612333, 82.4674131167, \"3A\"],\n[54.8821403, 82.46766325, \"3\"],\n[54.8821458833, 82.4679535, \"4\"],\n[54.9077193667, 82.4708605833, \"32\"],\n[54.9105951, 82.4793621667, \"98A\"],\n[54.9066916333, 82.4685963, \"19\"],\n[54.9104376833, 82.4794448167, \"98\"],\n[54.9064596833, 82.4678557333, \"11\"],\n[54.9103041333, 82.479528, \"100\"],\n[54.9090584167, 82.477976, \"83\"],\n[54.9088679, 82.4779112, \"81B\"],\n[54.90751235, 82.4701317833, \"26\"],\n[54.9085779167, 82.4748978833, \"57B\"],\n[54.9077844167, 82.4710735, \"34\"],\n[54.9088840833, 82.4747589333, \"60\"],\n[54.9063916833, 82.4676261333, \"9\"],\n[54.9091791167, 82.47510015, \"64A\"],\n[54.9090063, 82.4778273167, \"81\"],\n[54.9094076667, 82.4749288167, \"66\"],\n[54.9104649333, 82.4812665333, \"111\"],\n[54.9094658167, 82.47513735, \"66A\"],\n[54.9106371667, 82.4806045833, \"108\"],\n[54.9085164667, 82.47469955, \"57A\"],\n[54.9065306333, 82.4680931667, \"13B\"],\n[54.90744655, 82.46992735, \"24\"],\n[54.90669875, 82.4675042833, \"10\"],\n[54.9063321167, 82.467451, \"7\"],\n[54.9068232667, 82.4690555333, \"23\"],\n[54.9064476333, 82.4682054167, \"13A\"],\n[54.90728695, 82.4687101167, \"20A\"],\n[54.90564665, 82.4665080833, \"1B\"],\n[54.9095425167, 82.4780996, \"87\"],\n[54.9055099333, 82.4665785667, \"1C\"],\n[54.9064278333, 82.4685453667, \"17\"],\n[54.9087755667, 82.4730346, \"48A\"],\n[54.9092946833, 82.4772395333, \"77\"],\n[54.9089289833, 82.4729708, \"48B\"],\n[54.9070766, 82.4680242167, \"14A\"],\n[54.9099299333, 82.4794760167, \"97\"],\n[54.9060196667, 82.4664193167, \"3\"],\n[54.9093701833, 82.4764340333, \"78\"],\n[54.9088882, 82.4759446333, \"71\"],\n[54.9071022833, 82.4688659833, \"20\"],\n[54.9087805333, 82.4732292667, \"50A\"],\n[54.9101438333, 82.4802177167, \"103\"],\n[54.9100409167, 82.4805634167, \"105A\"],\n[54.9103943, 82.4797851, \"102\"],\n[54.9097405333, 82.4787679167, \"95\"],\n[54.9093126667, 82.4762224667, \"76\"],\n[54.9076596, 82.4706490167, \"30\"],\n[54.9090636667, 82.4764674667, \"75\"],\n[54.9091701167, 82.47836235, \"89\"],\n[54.9089457333, 82.4761631167, \"73\"],\n[54.9085522833, 82.4736826, \"52\"],\n[54.9092411833, 82.4760100667, \"74\"],\n[54.9079714833, 82.4729381333, \"45\"],\n[54.9080979833, 82.4733453333, \"49\"],\n[54.9069515333, 82.4683180833, \"16\"],\n[54.9066421833, 82.4673182, \"8\"],\n[54.90937045, 82.47757155, \"79\"],\n[54.9081895333, 82.47364565, \"51\"],\n[54.9086237333, 82.4750583333, \"59\"],\n[54.9091840167, 82.4757918333, \"72\"],\n[54.9087522333, 82.47547835, \"63\"],\n[54.90689515, 82.46927105, \"25\"],\n[54.9078795, 82.4713550833, \"36\"],\n[54.9056039, 82.4664057333, \"1A\"],\n[54.9106886833, 82.4808305833, \"110\"],\n[54.9059434167, 82.4661582833, \"1\"],\n[54.90686465, 82.4680447333, \"14\"],\n[54.9100754167, 82.4799441333, \"101\"],\n[54.9096307667, 82.4784052167, \"93\"],\n[54.9103163333, 82.4807391667, \"107\"],\n[54.9099907833, 82.47967445, \"99\"],\n[54.9102545333, 82.4804980667, \"105\"],\n[54.9067854667, 82.46778495, \"12\"],\n[54.9087875, 82.4761555333, \"73A\"],\n[54.9088226667, 82.4757288667, \"69\"],\n[54.90860015, 82.4738656333, \"54\"],\n[54.9084004667, 82.4731332667, \"48\"],\n[54.9086524, 82.4734778333, \"52A\"],\n[54.9070271167, 82.4685905333, \"18\"],\n[54.9075912333, 82.47002045, \"26A\"],\n[54.9089373833, 82.4749522333, \"62\"],\n[54.90542545, 82.4648276667, \"2\"],\n[54.9075973667, 82.4703872167, \"28\"],\n[54.9084245, 82.4757077667, \"65\"],\n[54.90912645, 82.4755800667, \"70\"],\n[54.90927015, 82.4751967833, \"68A\"],\n[54.9094690167, 82.4778629667, \"85\"],\n[54.90713625, 82.4682970167, \"16A\"],\n[54.9084881667, 82.4734576333, \"50\"],\n[54.9071228167, 82.4684523333, \"18A\"],\n[54.9066047833, 82.4683209, \"15\"],\n[54.9086888833, 82.4752875667, \"61\"],\n[54.9092166833, 82.4785048333, \"91\"],\n[54.90675295, 82.4688188167, \"21\"],\n[54.9089505167, 82.4731089667, \"50B\"],\n[54.9090581667, 82.4753575833, \"68\"],\n[54.9086879167, 82.47334805, \"50C\"],\n[54.91039185, 82.48101575, \"109\"],\n[54.9091127833, 82.4786399833, \"91A\"],\n[54.90897975, 82.4751060667, \"64\"],\n[54.8717186833, 82.4615598167, \"102\"],\n[54.8620697167, 82.4558799667, \"224\"],\n[54.8767515, 82.4619986833, \"42\"],\n[54.8664140333, 82.4578848167, \"168\"],\n[54.8778354833, 82.46234395, \"32\"],\n[54.8624631167, 82.456142, \"216\"],\n[54.8639001667, 82.4568719667, \"194\"],\n[54.8719572167, 82.4602589, \"100\"],\n[54.87530725, 82.46140325, \"60\"],\n[54.86265385, 82.4563095333, \"214\"],\n[54.8736987167, 82.46078595, \"80\"],\n[54.8899623167, 82.4632323, \"57A\"],\n[54.8891142333, 82.4571846167, \"4\"],\n[54.8896277, 82.4633464833, \"59\"],\n[54.88913275, 82.4644998167, \"60\"],\n[54.8891977, 82.46335, \"1/52\"],\n[54.8902417, 82.4604661, \"25A\"],\n[54.8892224667, 82.4630494333, \"50\"],\n[54.8904468333, 82.4604248, \"25\"],\n[54.8899309167, 82.45755835, \"7\"],\n[54.8893669667, 82.4601698, \"26\"],\n[54.8891862667, 82.4573128833, \"4B\"],\n[54.8897543167, 82.4603741167, \"27A\"],\n[54.8895259333, 82.4573211667, \"4A\"],\n[54.8899523167, 82.4603841667, \"27B\"],\n[54.8887959333, 82.4610821833, \"34\"],\n[54.8901048833, 82.4603943833, \"27C\"],\n[54.8891028833, 82.4650312333, \"64\"],\n[54.88868315, 82.4633466833, \"52B\"],\n[54.8896881, 82.4624856667, \"43\"],\n[54.8899772333, 82.46296325, \"53\"],\n[54.8893557167, 82.4604985333, \"28\"],\n[54.8887644667, 82.46359225, \"54A\"],\n[54.8887913667, 82.46338915, \"52A\"],\n[54.8891714, 82.4635651833, \"54B\"],\n[54.8898920167, 82.4582737, \"13\"],\n[54.8891619167, 82.46382635, \"56\"],\n[54.8902644667, 82.4602963, \"23B\"],\n[54.8903580333, 82.4578762167, \"9A\"],\n[54.8895457333, 82.4571203833, \"2\"],\n[54.8899171667, 82.4577745667, \"9\"],\n[54.8891239833, 82.4610409833, \"32\"],\n[54.8886105167, 82.4627844833, \"48A\"],\n[54.8897850667, 82.4601521667, \"23\"],\n[54.8885782833, 82.4630716, \"48B\"],\n[54.8895879667, 82.4639701, \"65\"],\n[54.88875245, 82.4628892667, \"48C\"],\n[54.8897637667, 82.46090555, \"29\"],\n[54.8898831667, 82.4584686167, \"15\"],\n[54.8900645833, 82.4630566333, \"57\"],\n[54.8894477833, 82.4587900667, \"20\"],\n[54.8898162, 82.4597956833, \"21\"],\n[54.8903147667, 82.4585830833, \"15A\"],\n[54.8899451, 82.4573311, \"5\"],\n[54.8892625, 82.46226515, \"42\"],\n[54.88959655, 82.4636994833, \"63\"],\n[54.8888289, 82.4626433167, \"46B\"],\n[54.8897502167, 82.4611882333, \"31\"],\n[54.8890874833, 82.4653801667, \"66\"],\n[54.8896453667, 82.4629410333, \"51\"],\n[54.88871155, 82.4626789833, \"46A\"],\n[54.8889027, 82.4648962833, \"64A\"],\n[54.8888759167, 82.4633533167, \"2/52\"],\n[54.8903299167, 82.4581553, \"13A\"],\n[54.8890716, 82.4657335833, \"68\"],\n[54.8894647167, 82.4584316167, \"16\"],\n[54.8889404333, 82.4574026, \"6B\"],\n[54.8896737667, 82.4626918667, \"45\"],\n[54.8899074, 82.4580168, \"11\"],\n[54.8898575333, 82.4588148833, \"17\"],\n[54.8896982167, 82.46224375, \"1/41-7/41\"],\n[54.8895164167, 82.4575203, \"6\"],\n[54.8899765333, 82.4602187333, \"23A\"],\n[54.8891143, 82.4647213833, \"62\"],\n[54.8892440667, 82.46252665, \"46\"],\n[54.88890735, 82.4607073833, \"30A\"],\n[54.88930945, 82.4612971, \"36\"],\n[54.8892202667, 82.4574350833, \"6A\"],\n[54.8891678667, 82.4639653333, \"58\"],\n[54.8898663667, 82.4589170833, \"19\"],\n[54.88937355, 82.4599354833, \"24\"],\n[54.8893259833, 82.4609626833, \"32A\"],\n[54.8899845333, 82.4624851, \"49\"],\n[54.8700170667, 82.4425962167, \"35\"],\n[54.87002395, 82.4440538333, \"45\"],\n[54.8703417167, 82.4408183833, \"19\"],\n[54.8704475833, 82.44446245, \"48\"],\n[54.8705703667, 82.44211805, \"32\"],\n[54.8712876167, 82.4401329, \"8\"],\n[54.8706072, 82.4431831333, \"40\"],\n[54.88103245, 82.43996055, \"74\"],\n[54.8810238833, 82.44054185, \"144\"],\n[54.8819540833, 82.44341985, \"444\"],\n[54.8810368167, 82.4414257833, \"218\"],\n[54.8836569833, 82.4449454, \"695\"],\n[54.8805499, 82.44146635, \"219\"],\n[54.88153545, 82.4435217, \"409\"],\n[54.8805337667, 82.4422020167, \"277\"],\n[54.8810820333, 82.4423189667, \"302\"],\n[54.8826985333, 82.4431283833, \"503\"],\n[54.8825451667, 82.4439081167, \"533\"],\n[54.8834376, 82.4454858167, \"694\"],\n[54.8806721167, 82.44412345, \"397\"],\n[54.81387095, 82.45409265, \"1\"],\n[54.821195, 82.4616223833, \"104\"],\n[54.8211624833, 82.4682833, \"181\"],\n[54.8178846167, 82.4588240333, \"65\"],\n[54.8149536667, 82.4553629333, \"15\"],\n[54.8197732667, 82.4671436, \"167\"],\n[54.8161526333, 82.4563465, \"35\"],\n[54.8209648833, 82.4674674, \"178\"],\n[54.820487, 82.4606511167, \"86\"],\n[54.9711954833, 82.3673120333, \"66\"],\n[54.8927382667, 82.4630076, \"2A\"],\n[54.8930191833, 82.4631100333, \"1\"],\n[54.89302745, 82.4629626333, \"1A\"],\n[54.8927669333, 82.46308965, \"2\"],\n[54.8929038667, 82.46322235, \"5\"],\n[54.8926603333, 82.4633015, \"3A\"],\n[54.89273305, 82.4631913833, \"3\"],\n[54.8928261167, 82.4632172333, \"4\"],\n[54.8863257333, 82.3892431333, \"29\"],\n[54.8828649833, 82.3942711333, \"76\"],\n[54.88740485, 82.3880108167, \"3\"],\n[54.8816477833, 82.39495895, \"85\"],\n[54.9193026667, 82.46865615, \"27\"],\n[54.9191047667, 82.4689871, \"21\"],\n[54.9190031667, 82.4685222, \"29\"],\n[54.9191244667, 82.4666619167, \"55\"],\n[54.9187559333, 82.4673880833, \"43\"],\n[54.9191856, 82.4667804333, \"49\"],\n[54.9183846667, 82.4653317833, \"75\"],\n[54.9186045833, 82.46662185, \"59\"],\n[54.9191840167, 82.4678865167, \"35\"],\n[54.9191584333, 82.4662006333, \"61\"],\n[54.9188624, 82.4676419833, \"39\"],\n[54.9184419667, 82.4657698, \"69\"],\n[54.9178364167, 82.4627168667, \"111\"],\n[54.9185242667, 82.4661814167, \"63\"],\n[54.9191998, 82.4694479333, \"17\"],\n[54.9190388167, 82.4654450833, \"71\"],\n[54.91796485, 82.4632720833, \"103\"],\n[54.91880005, 82.4653678333, \"73\"],\n[54.9182357167, 82.4645811, \"93\"],\n[54.9177229333, 82.4619539, \"119\"],\n[54.91802955, 82.4624559167, \"115\"],\n[54.9176650833, 82.4616779667, \"123\"],\n[54.91870075, 82.4670770833, \"45\"],\n[54.9176143667, 82.4613274, \"125\"],\n[54.9189086667, 82.468155, \"33\"],\n[54.9174097167, 82.4613318833, \"127\"],\n[54.9190924, 82.4675234333, \"41\"],\n[54.8068523167, 82.3939250833, \"5\"],\n[54.8144720167, 82.4032648333, \"122\"],\n[54.8070121667, 82.3941206333, \"7\"],\n[54.8135841833, 82.40160315, \"114\"],\n[54.8071723, 82.39433025, \"9\"],\n[54.8073319667, 82.3945375, \"13\"],\n[54.8088248333, 82.39658935, \"35\"],\n[54.8150867, 82.4041908167, \"138\"],\n[54.8087098667, 82.39797025, \"45\"],\n[54.8153430833, 82.4043867333, \"140\"],\n[54.8113713333, 82.3997835833, \"77\"],\n[54.8128633667, 82.4026050333, \"103\"],\n[54.8153182333, 82.404702, \"142\"],\n[54.8136947667, 82.4026962667, \"113\"],\n[54.8146717833, 82.4042277167, \"133\"],\n[54.8132897167, 82.40224345, \"105\"],\n[54.87318525, 82.5752061, \"783\"],\n[54.87086625, 82.5605686167, \"3/668\"],\n[54.8736095333, 82.5759500667, \"791\"],\n[54.8846973333, 82.5128454333, \"105\"],\n[54.882909, 82.5284399, \"295\"],\n[54.8854251167, 82.50715345, \"42\"],\n[54.8730277, 82.5735052333, \"768\"],\n[54.8852305667, 82.5138063667, \"116\"],\n[54.8765950833, 82.5441586167, \"457\"],\n[54.8854819167, 82.51593135, \"130\"],\n[54.8793962333, 82.5400538, \"398\"],\n[54.8856814667, 82.5176310333, \"146\"],\n[54.8850541667, 82.5122725, \"94\"],\n[54.8859048, 82.5196622667, \"158\"],\n[54.8839926333, 82.5070946667, \"44\"],\n[54.8828246833, 82.5299873833, \"300\"],\n[54.8835640333, 82.5073463, \"47\"],\n[54.8812550167, 82.53308795, \"338\"],\n[54.87624165, 82.5468433, \"472\"],\n[54.8735672333, 82.5726554167, \"2/766\"],\n[54.8756854833, 82.5468615167, \"483\"],\n[54.8855889333, 82.5069699, \"1/42\"],\n[54.8764352833, 82.55027325, \"508\"],\n[54.88626155, 82.5222170833, \"2/182\"],\n[54.8739916667, 82.5532237833, \"537\"],\n[54.8790302167, 82.5397931667, \"396\"],\n[54.8750138, 82.5530649833, \"542\"],\n[54.8839209333, 82.5106114167, \"79\"],\n[54.8790556833, 82.5364847667, \"371\"],\n[54.8804106667, 82.5347674167, \"348\"],\n[54.8843208, 82.50806425, \"50\"],\n[54.8835448667, 82.50621025, \"37\"],\n[54.8789683667, 82.5407611667, \"400\"],\n[54.8819428333, 82.5302822333, \"307\"],\n[54.8838573833, 82.5041196833, \"26\"],\n[54.8728271833, 82.5730276667, \"1/766\"],\n[54.8862517333, 82.5218569167, \"1/182\"],\n[54.88592065, 82.52030825, \"170\"],\n[54.8804488333, 82.5336723833, \"345\"],\n[54.8724145667, 82.5722238833, \"756\"],\n[54.8710689167, 82.5600702167, \"2/668\"],\n[54.8749418667, 82.5762505333, \"808\"],\n[54.88330185, 82.5037989167, \"25\"],\n[54.8742985667, 82.5709469667, \"766\"],\n[54.8855461833, 82.5169524167, \"138\"],\n[54.8840771833, 82.5086316, \"57\"],\n[54.8799641333, 82.5345286833, \"351\"],\n[54.8747767833, 82.5703700833, \"4/766\"],\n[54.8712547, 82.5595212, \"1/668\"],\n[54.8852620333, 82.5203346333, \"167\"],\n[54.87846535, 82.5402971, \"407\"],\n[54.87451705, 82.5722616833, \"3/766\"],\n[54.8865716667, 82.5064284333, \"2/42\"],\n[54.8699697833, 82.5701625667, \"725\"],\n[54.8850022833, 82.5119347333, \"92\"],\n[54.9141589833, 82.4676254, \"19\"],\n[54.9155973833, 82.46772575, \"11/2\"],\n[54.91552955, 82.4660865, \"36/2\"],\n[54.9156190333, 82.4673462667, \"9/2\"],\n[54.9154039167, 82.4660434167, \"35/2\"],\n[54.9155738333, 82.4664463167, \"5/2\"],\n[54.91535915, 82.4658985167, \"34/2\"],\n[54.9155678833, 82.4667106333, \"6/2\"],\n[54.91544365, 82.4658299, \"33/2\"],\n[54.9160503333, 82.4675822, \"21/2\"],\n[54.9156064333, 82.4657751333, \"32/2\"],\n[54.9147495167, 82.4662775167, \"5\"],\n[54.9157566167, 82.46569785, \"31/2\"],\n[54.9154667667, 82.4679029167, \"12/2\"],\n[54.91585185, 82.4657343333, \"30/2\"],\n[54.9152016333, 82.4653091167, \"1\"],\n[54.9153522167, 82.4663997833, \"4\"],\n[54.9156452333, 82.4675400833, \"10/2\"],\n[54.9153521167, 82.4665981833, \"4A\"],\n[54.91558475, 82.4671245833, \"8/2\"],\n[54.9153486333, 82.4667996333, \"6\"],\n[54.9155721333, 82.4669092, \"7/2\"],\n[54.9152996667, 82.4669875833, \"6A\"],\n[54.9150243, 82.46636625, \"5A\"],\n[54.9162041333, 82.4675381333, \"22/2\"],\n[54.9162005, 82.4673120333, \"23/2\"],\n[54.9161440167, 82.4671061, \"24/2\"],\n[54.9160962667, 82.4669004667, \"25/2\"],\n[54.9160486333, 82.4666893333, \"26/2\"],\n[54.9159963833, 82.46648905, \"27/2\"],\n[54.91591785, 82.4662933333, \"28/2\"],\n[54.9157758667, 82.4662000667, \"38/2\"],\n[54.9157248667, 82.4659447167, \"37/2\"],\n[54.9158606, 82.46592755, \"29/2\"],\n[54.9159540833, 82.4673968833, \"20/2\"],\n[54.91578295, 82.4674348167, \"17/2\"],\n[54.91584205, 82.4677180167, \"18/2\"],\n[54.9156962333, 82.4664396833, \"13/2\"],\n[54.915699, 82.4667043333, \"14/2\"],\n[54.9157030167, 82.4669139, \"15/2\"],\n[54.9157118833, 82.4671016, \"16/2\"],\n[54.9158802833, 82.4671848, \"19/2\"],\n[54.9146419333, 82.4678385333, \"16\"],\n[54.9149667, 82.46605435, \"3\"],\n[54.9150279333, 82.4667922833, \"7\"],\n[54.9141704333, 82.4678512833, \"21\"],\n[54.9142653, 82.4673118833, \"15\"],\n[54.91450075, 82.4674330833, \"13\"],\n[54.9147242667, 82.46734925, \"11\"],\n[54.9148913167, 82.4671297667, \"9\"],\n[54.9151929833, 82.4672369167, \"8\"],\n[54.9144812833, 82.4679524833, \"18\"],\n[54.9149502167, 82.4675873667, \"12\"],\n[54.9147979333, 82.4677301167, \"14\"],\n[54.9140953833, 82.4682407667, \"22\"],\n[54.9143135333, 82.4679806667, \"20\"],\n[54.9139027667, 82.4673990667, \"17\"],\n[54.91508455, 82.46743825, \"10\"],\n[54.8207364833, 82.3925286333, \"110\"],\n[54.8140913167, 82.3867786167, \"31\"],\n[54.82388165, 82.3961648833, \"164\"],\n[54.8149241833, 82.3869723167, \"38\"],\n[54.8341317167, 82.4133935833, \"364\"],\n[54.8244762167, 82.39859475, \"186\"],\n[54.82108675, 82.3928284333, \"112\"],\n[54.8257318, 82.4028302167, \"236\"],\n[54.8213587333, 82.3930749333, \"114\"],\n[54.8245402667, 82.3979335833, \"184\"],\n[54.8216469333, 82.3939728667, \"129\"],\n[54.8287610333, 82.4083265833, \"302\"],\n[54.82049075, 82.3882675333, \"92\"],\n[54.8209210167, 82.3876718333, \"90B\"],\n[54.8243807167, 82.4009181, \"207\"],\n[54.8210754833, 82.3869467167, \"90A\"],\n[54.8142259167, 82.3862871667, \"26\"],\n[54.8142241, 82.3891889667, \"43\"],\n[54.8355967167, 82.4144058667, \"382\"],\n[54.8263508333, 82.4048937333, \"251\"],\n[54.8237985833, 82.3972016667, \"173\"],\n[54.82187925, 82.3941376333, \"137\"],\n[54.8159891667, 82.3862058833, \"42\"],\n[54.8233059333, 82.3950369833, \"156\"],\n[54.8224871333, 82.3939314167, \"148\"],\n[54.8194135833, 82.3914179833, \"100\"],\n[54.8149244, 82.38763835, \"41\"],\n[54.8192395667, 82.3919598167, \"103\"],\n[54.8202387167, 82.3879586, \"90D\"],\n[54.81610515, 82.3888637333, \"59\"],\n[54.8282481667, 82.4077297, \"290\"],\n[54.81714775, 82.3892465833, \"68\"],\n[54.8196078, 82.3887699667, \"90\"],\n[54.817284, 82.39001715, \"77\"],\n[54.81837465, 82.39045065, \"86\"],\n[54.8277749, 82.4071191667, \"272\"],\n[54.8265916333, 82.4056707167, \"251A\"],\n[54.8128841167, 82.3855143833, \"11\"],\n[54.8291297, 82.4098336167, \"313\"],\n[54.8329969667, 82.4126325333, \"358\"],\n[54.8322266, 82.4129321167, \"347\"],\n[54.8348266833, 82.4139054, \"372\"],\n[54.9099726167, 82.4757886667, \"71\"],\n[54.9101903333, 82.4760631833, \"73\"],\n[54.9152217167, 82.47371395, \"131\"],\n[54.9059390167, 82.47854405, \"32\"],\n[54.9097995667, 82.4753924833, \"71B\"],\n[54.9044269833, 82.4792423333, \"12\"],\n[54.9084252667, 82.4764496833, \"49\"],\n[54.9086711167, 82.4772269833, \"52\"],\n[54.9116987, 82.4759278667, \"92\"],\n[54.9098638167, 82.47581795, \"69\"],\n[54.9117964333, 82.4757621167, \"94\"],\n[54.90989485, 82.47559865, \"71A\"],\n[54.9073590833, 82.4778494167, \"40A\"],\n[54.91330765, 82.47552755, \"108\"],\n[54.9057401833, 82.4781938167, \"25\"],\n[54.911296, 82.4748848167, \"89\"],\n[54.9121108667, 82.4758530667, \"98A\"],\n[54.9043787833, 82.4787889167, \"13\"],\n[54.9083076667, 82.4766785667, \"47A\"],\n[54.9036909333, 82.4791402667, \"3\"],\n[54.91220345, 82.4755294, \"100\"],\n[54.9053728833, 82.4783509333, \"1/23\"],\n[54.90519915, 82.4784179, \"21\"],\n[54.9052690667, 82.4783896667, \"21A\"],\n[54.9114245, 82.4759148333, \"88\"],\n[54.9081505833, 82.4774655, \"46\"],\n[54.9142982833, 82.4745833, \"120\"],\n[54.9131166, 82.4751412333, \"106\"],\n[54.9083510667, 82.47694365, \"47\"],\n[54.9065192667, 82.4778253667, \"31\"],\n[54.9083240333, 82.47739375, \"48\"],\n[54.9149526833, 82.4742867833, \"126\"],\n[54.9103091667, 82.476032, \"75\"],\n[54.9118749833, 82.4749764833, \"101A\"],\n[54.9042161667, 82.4788623333, \"11\"],\n[54.9129278167, 82.4752157333, \"104\"],\n[54.9121256667, 82.4751926333, \"103\"],\n[54.9112547, 82.4755432667, \"85\"],\n[54.9142550667, 82.4741810667, \"121\"],\n[54.9106238667, 82.4759059667, \"77A\"],\n[54.9104479, 82.4759570167, \"77\"],\n[54.9114070667, 82.4754850833, \"87\"],\n[54.9113298833, 82.47516835, \"87A\"],\n[54.9148737833, 82.4738503833, \"127\"],\n[54.9112868667, 82.4759815833, \"86\"],\n[54.9111339667, 82.4760538, \"82\"],\n[54.91156375, 82.4758556833, \"90\"],\n[54.9151142, 82.4742192667, \"128\"],\n[54.9151403167, 82.4737436, \"129\"],\n[54.915375, 82.4740628167, \"130\"],\n[54.9144834167, 82.4745128333, \"122\"],\n[54.9144913, 82.4737651167, \"123A\"],\n[54.9144983167, 82.4740186167, \"123\"],\n[54.9146270167, 82.4744201833, \"124\"],\n[54.9126748, 82.4749461833, \"105\"],\n[54.9128134833, 82.4748703333, \"107\"],\n[54.9129492333, 82.4747718167, \"109\"],\n[54.9131005833, 82.4746998, \"111\"],\n[54.9132571833, 82.4746269833, \"113\"],\n[54.9135018833, 82.4749717, \"114\"],\n[54.91340395, 82.4745515, \"115\"],\n[54.9136698, 82.4748826167, \"116\"],\n[54.91356065, 82.4744797, \"117\"],\n[54.91379245, 82.4748357, \"118\"],\n[54.9136715833, 82.4744300167, \"119\"],\n[54.9085906833, 82.4768593, \"53\"],\n[54.9089448167, 82.47752235, \"54A\"],\n[54.9088353, 82.4771584333, \"54\"],\n[54.9087287167, 82.4767663333, \"55\"],\n[54.9090036667, 82.4770825167, \"56\"],\n[54.9065108833, 82.4773228833, \"33\"],\n[54.90671225, 82.4781606833, \"34\"],\n[54.90673975, 82.4777032, \"35\"],\n[54.9068835, 82.4780653833, \"36\"],\n[54.9067380833, 82.4772301167, \"37\"],\n[54.9070569167, 82.47798485, \"38\"],\n[54.9070025333, 82.4775753333, \"39\"],\n[54.90721945, 82.47790165, \"40\"],\n[54.9072522667, 82.4774842833, \"41\"],\n[54.9073576167, 82.47744775, \"43\"],\n[54.9055054167, 82.4782415167, \"23\"],\n[54.9146826833, 82.4739228, \"125\"],\n[54.9048823167, 82.4785375333, \"17\"],\n[54.9120084333, 82.4756561667, \"98\"],\n[54.9086973167, 82.4775292833, \"52A\"],\n[54.90495545, 82.4780925667, \"19A\"],\n[54.9115964667, 82.4754098667, \"91\"],\n[54.9117456333, 82.4753338667, \"93\"],\n[54.9047131167, 82.47861435, \"15\"],\n[54.9166350333, 82.47304345, \"141\"],\n[54.9119624833, 82.4752623, \"101\"],\n[54.9039384833, 82.4785719, \"9A\"],\n[54.9040451, 82.4789520667, \"9\"],\n[54.9159567333, 82.4733394833, \"133\"],\n[54.9133416833, 82.4750525833, \"112\"],\n[54.9164713167, 82.4731105667, \"139\"],\n[54.9162964833, 82.4731911, \"137\"],\n[54.91611805, 82.4732665833, \"135\"],\n[54.9050444167, 82.4785102333, \"19\"],\n[54.9084974833, 82.47730975, \"50\"],\n[54.9168131667, 82.4729816333, \"143\"],\n[54.9088890667, 82.47665875, \"51\"],\n[54.9169769833, 82.47291525, \"145\"],\n[54.91109855, 82.4756779833, \"83\"],\n[54.9036883833, 82.47891485, \"5\"],\n[54.9038746333, 82.4790332667, \"7\"],\n[54.9098547333, 82.4762237333, \"67\"],\n[54.9134471167, 82.47558925, \"110\"],\n[54.9091846167, 82.4769739333, \"58\"],\n[54.9041253333, 82.47834505, \"67\"],\n[54.9031156667, 82.47324245, \"30\"],\n[54.9039179333, 82.4771832667, \"57\"],\n[54.9027583833, 82.4732321833, \"31\"],\n[54.9039296333, 82.4759913167, \"1/48-5/48\"],\n[54.9031900333, 82.4735082833, \"32\"],\n[54.9034018667, 82.4743276167, \"36\"],\n[54.9023766833, 82.47196845, \"7\"],\n[54.9032458833, 82.47560575, \"49A\"],\n[54.9020863667, 82.4722218833, \"9\"],\n[54.9043371833, 82.4768388333, \"56B\"],\n[54.902459, 82.47222945, \"15\"],\n[54.9037351, 82.47533715, \"44\"],\n[54.9034826333, 82.4756647333, \"51\"],\n[54.9036591, 82.47507465, \"42\"],\n[54.90418945, 82.4769539167, \"56\"],\n[54.9032979333, 82.4750164, \"45\"],\n[54.9034232167, 82.47544545, \"49\"],\n[54.9033578, 82.4752311833, \"47\"],\n[54.9038201667, 82.4756474167, \"46\"],\n[54.9022973167, 82.4729606, \"25\"],\n[54.90414875, 82.4768183, \"52\"],\n[54.90349885, 82.4745345833, \"38\"],\n[54.9026894, 82.4730117167, \"29\"],\n[54.9021493667, 82.47246275, \"17\"],\n[54.9026062167, 82.47272955, \"23\"],\n[54.9025311667, 82.4725057, \"21\"],\n[54.9030380667, 82.47297935, \"28\"],\n[54.9024547167, 82.4734671, \"33\"],\n[54.9025374333, 82.4713386333, \"2\"],\n[54.9032365, 82.4747976667, \"43\"],\n[54.903545, 82.4758786333, \"53\"],\n[54.9036348667, 82.47615225, \"55\"],\n[54.9040838167, 82.4777189667, \"61\"],\n[54.9044308, 82.4778047833, \"62A\"],\n[54.9045770833, 82.4776408667, \"62\"],\n[54.9041435833, 82.4779421667, \"63\"],\n[54.9045395167, 82.4780827833, \"64\"],\n[54.9042280667, 82.4782127, \"65\"],\n[54.9046025833, 82.4783325333, \"66\"],\n[54.9027241, 82.4719824833, \"6\"],\n[54.9031429167, 82.4744526833, \"41\"],\n[54.90234395, 82.4730909833, \"27\"],\n[54.9035807667, 82.474814, \"40\"],\n[54.9024965667, 82.4735884667, \"35\"],\n[54.9028375333, 82.4735153, \"37\"],\n[54.90263765, 82.4716923333, \"4\"],\n[54.9021975, 82.47257235, \"19\"],\n[54.9043748667, 82.4775318, \"60\"],\n[54.90399325, 82.4774612167, \"59\"],\n[54.9042882333, 82.4772585333, \"58\"],\n[54.8844172167, 82.4672121, \"84\"],\n[54.88526725, 82.4677498167, \"89\"],\n[54.88475025, 82.4713889167, \"129A\"],\n[54.8850106, 82.4704196167, \"119B\"],\n[54.8848693167, 82.4653303833, \"67A\"],\n[54.8849946167, 82.47052095, \"119A\"],\n[54.8853588667, 82.4594981667, \"21A\"],\n[54.8840973667, 82.4733293833, \"140\"],\n[54.88468505, 82.4712750833, \"127B\"],\n[54.8848600667, 82.47296205, \"141\"],\n[54.8846001333, 82.4600292833, \"26A\"],\n[54.8836016167, 82.4733639667, \"142\"],\n[54.8834011333, 82.4735009333, \"144A\"],\n[54.8836620833, 82.4735234, \"144\"],\n[54.8836292333, 82.4677762333, \"92A\"],\n[54.8848011, 82.4732428833, \"145\"],\n[54.8848537, 82.4655050667, \"67B\"],\n[54.8840610333, 82.4737371333, \"146\"],\n[54.884338, 82.4684939, \"106\"],\n[54.8844335167, 82.4733986333, \"147\"],\n[54.88444615, 82.4731180167, \"1/143\"],\n[54.8840384, 82.4739760167, \"148\"],\n[54.8846361, 82.4730721, \"2/143\"],\n[54.8847583667, 82.4735201333, \"149\"],\n[54.8847493833, 82.4736688167, \"151\"],\n[54.8846399333, 82.4737421667, \"153A\"],\n[54.8844193833, 82.4737101333, \"153\"],\n[54.8844016, 82.4739577167, \"155\"],\n[54.8846051, 82.4703118167, \"117\"],\n[54.8842630167, 82.4702309167, \"118\"],\n[54.8845899833, 82.4706008833, \"119\"],\n[54.8839889, 82.4702975, \"120\"],\n[54.8845767833, 82.4708850333, \"121\"],\n[54.8848939667, 82.471153, \"125\"],\n[54.8845648, 82.4711997833, \"127A\"],\n[54.8845397333, 82.4714559833, \"129\"],\n[54.8845394, 82.4715708167, \"131\"],\n[54.88370185, 82.4681742833, \"100A\"],\n[54.8839465, 82.4681139833, \"100\"],\n[54.8839286333, 82.4682708, \"102\"],\n[54.8847414667, 82.4683697167, \"101\"],\n[54.8843311333, 82.4683495167, \"104\"],\n[54.8850005167, 82.468632, \"105\"],\n[54.8847132167, 82.4687043167, \"107\"],\n[54.88432375, 82.4686693, \"108A\"],\n[54.8841027333, 82.4686521333, \"108B\"],\n[54.8837668333, 82.4686217667, \"108C\"],\n[54.8843156167, 82.4690232667, \"110\"],\n[54.8844019333, 82.4676185833, \"88\"],\n[54.8839683, 82.4676575, \"90\"],\n[54.8839636333, 82.4677862833, \"92\"],\n[54.8847523333, 82.4678389667, \"93\"],\n[54.8843878667, 82.4678844833, \"94\"],\n[54.8843912, 82.46807835, \"96\"],\n[54.88488445, 82.4681411333, \"97A\"],\n[54.8847461167, 82.4681295167, \"97\"],\n[54.8850594333, 82.46849965, \"103\"],\n[54.88521615, 82.46866015, \"105A\"],\n[54.8852093833, 82.4680692333, \"95B\"],\n[54.8844562, 82.4666664667, \"82\"],\n[54.8844693167, 82.4664959833, \"80\"],\n[54.8850079167, 82.4663639833, \"77\"],\n[54.8850347667, 82.4662661667, \"75A\"],\n[54.8845094, 82.46511225, \"70\"],\n[54.8848360833, 82.46580235, \"71\"],\n[54.8845048333, 82.4652718333, \"72\"],\n[54.88484705, 82.4659848667, \"73\"],\n[54.8846077667, 82.4632926667, \"56\"],\n[54.8849583, 82.4636067667, \"57\"],\n[54.8849358667, 82.46389605, \"59\"],\n[54.8846143167, 82.4635059, \"60\"],\n[54.8849265833, 82.4640693333, \"61\"],\n[54.88458485, 82.4638039167, \"62\"],\n[54.8846887167, 82.4620028833, \"40\"],\n[54.8846763667, 82.4622161, \"42\"],\n[54.88439555, 82.46253885, \"50A\"],\n[54.8843140667, 82.4625245333, \"50B\"],\n[54.8846659833, 82.4626401167, \"50\"],\n[54.8843395, 82.4756649667, \"165\"],\n[54.8843288167, 82.4758768167, \"167\"],\n[54.8847458167, 82.4759882, \"169\"],\n[54.8839907333, 82.4754077667, \"154\"],\n[54.8832283833, 82.4761336167, \"158A\"],\n[54.8834749667, 82.4760305, \"158\"],\n[54.8839257333, 82.4761204333, \"160\"],\n[54.8839105, 82.4763266167, \"162\"],\n[54.8839068667, 82.4765393833, \"164\"],\n[54.8839006667, 82.4766556333, \"166A\"],\n[54.8838300333, 82.4766482833, \"166B\"],\n[54.8837648667, 82.4766430667, \"166C\"],\n[54.88370985, 82.4766495333, \"166D\"],\n[54.88450305, 82.4759053833, \"167A\"],\n[54.8843063833, 82.47627465, \"173\"],\n[54.88481905, 82.4593686833, \"20\"],\n[54.8848109, 82.4595419, \"22\"],\n[54.8847686333, 82.4602303333, \"28\"],\n[54.8847849, 82.4600010333, \"26\"],\n[54.8847695, 82.4604640833, \"30\"],\n[54.8847524167, 82.4606697667, \"32A\"],\n[54.8846032167, 82.4607054667, \"32\"],\n[54.8847437, 82.4609159, \"34\"],\n[54.8847367167, 82.4610480333, \"36\"],\n[54.8846226, 82.4597085, \"24A\"],\n[54.88480055, 82.4597682833, \"24\"],\n[54.8849988, 82.45680165, \"4\"],\n[54.88498305, 82.4570515667, \"6\"],\n[54.8852893167, 82.45737525, \"9A\"],\n[54.8856279667, 82.4573165333, \"9\"],\n[54.8852346167, 82.4583441167, \"17\"],\n[54.8846999, 82.46184155, \"38\"],\n[54.8842668333, 82.4699965667, \"116\"],\n[54.8849434, 82.4633167, \"55\"],\n[54.8849201333, 82.4582107833, \"14\"],\n[54.8841963333, 82.4680842833, \"98\"],\n[54.8850626333, 82.4680435333, \"95A\"],\n[54.8849265167, 82.4579232, \"12\"],\n[54.8849416333, 82.4576479667, \"10\"],\n[54.88464885, 82.4628154667, \"52\"],\n[54.88495495, 82.4630154, \"53\"],\n[54.8841566, 82.46306945, \"54C\"],\n[54.8843828833, 82.4631118167, \"54B\"],\n[54.8846277833, 82.4630559167, \"54A\"],\n[54.8852737333, 82.4576375667, \"11\"],\n[54.8849684, 82.4572897333, \"8\"],\n[54.8842156, 82.4664696, \"80A\"],\n[54.8852629167, 82.4609307833, \"31A\"],\n[54.88407215, 82.4664618, \"80B\"],\n[54.8853292833, 82.4658178167, \"69D\"],\n[54.8845638833, 82.4761256667, \"171A\"],\n[54.8843256167, 82.4761031333, \"171\"],\n[54.88461985, 82.4700835333, \"115\"],\n[54.8852249667, 82.4591643, \"19\"],\n[54.8850024667, 82.4655843667, \"69A\"],\n[54.8853347667, 82.4565859833, \"3\"],\n[54.8849291167, 82.4710324667, \"123\"],\n[54.8850487333, 82.46776055, \"91\"],\n[54.88518005, 82.4657751833, \"69B\"],\n[54.8847597, 82.4703240833, \"117A\"],\n[54.8838148667, 82.4733438, \"140A\"],\n[54.8852627, 82.4581414167, \"15\"],\n[54.8852686333, 82.4578723833, \"13\"],\n[54.8843833333, 82.4628765333, \"52A\"],\n[54.8846312667, 82.47258135, \"135A\"],\n[54.8841268, 82.4727441333, \"134\"],\n[54.8841223833, 82.4729087, \"136\"],\n[54.8844595167, 82.4725233833, \"135\"],\n[54.8844608, 82.4728356, \"139\"],\n[54.88411085, 82.4730945167, \"138\"],\n[54.8844061, 82.4674269333, \"86\"],\n[54.8846697, 82.4623996833, \"44\"],\n[54.8843516833, 82.4624326667, \"46\"],\n[54.8845218833, 82.4609426833, \"34A\"],\n[54.8845623833, 82.4649360333, \"68\"],\n[54.8852556667, 82.46580475, \"69C\"],\n[54.8853163833, 82.4638318667, \"57A\"],\n[54.8841402833, 82.4725588333, \"132\"],\n[54.8845058, 82.46627115, \"78\"],\n[54.88520865, 82.4594427, \"21\"],\n[54.88518675, 82.4597238, \"23\"],\n[54.88516405, 82.4602253833, \"27A\"],\n[54.8851860333, 82.4600092, \"25\"],\n[54.8851601667, 82.4603894167, \"27B\"],\n[54.8851518333, 82.4606064167, \"29\"],\n[54.8851348833, 82.4608605667, \"31\"],\n[54.8850809, 82.4610533333, \"33\"],\n[54.8856552, 82.4571406667, \"7A\"],\n[54.8853045167, 82.4571108167, \"7\"],\n[54.88540295, 82.4658220667, \"69E\"],\n[54.8853268167, 82.459619, \"23A\"],\n[54.8836866, 82.4760956667, \"160A\"],\n[54.8847632333, 82.4673442, \"83\"],\n[54.8847711333, 82.4675412167, \"85\"],\n[54.8848386167, 82.4661800667, \"75\"],\n[54.8845198, 82.4660549333, \"76\"],\n[54.8848257667, 82.46637395, \"79\"],\n[54.88481345, 82.4665570333, \"81\"],\n[54.8850432333, 82.4640734333, \"61A\"],\n[54.8854814333, 82.46382035, \"57B\"],\n[54.8853202, 82.45681275, \"5\"],\n[54.88467615, 82.4756712, \"165A\"],\n[54.8843590833, 82.4753791667, \"163\"],\n[54.8854775, 82.4568292667, \"5A\"],\n[54.8846230833, 82.4699498, \"113\"],\n[54.8840125667, 82.47500995, \"150\"],\n[54.8840018667, 82.4752078667, \"152\"],\n[54.8846837667, 82.4753169, \"163A\"],\n[54.8843619333, 82.4750396667, \"161\"],\n[54.8840304667, 82.4794188333, \"2A\"],\n[54.8807723833, 82.4785762167, \"38\"],\n[54.8832733667, 82.4785025167, \"14\"],\n[54.8805087833, 82.4795802, \"39\"],\n[54.8825106167, 82.4792898667, \"22\"],\n[54.8807048667, 82.4788063333, \"40\"],\n[54.88040735, 82.47993645, \"41\"],\n[54.8802707, 82.4795716333, \"43\"],\n[54.8806401833, 82.4791473833, \"46\"],\n[54.8805187667, 82.4791179667, \"48\"],\n[54.8803874167, 82.47910085, \"52A\"],\n[54.8832278833, 82.4793638667, \"16\"],\n[54.8830907167, 82.4793476833, \"18\"],\n[54.8821391833, 82.4796965667, \"27\"],\n[54.8822759, 82.4797246333, \"25\"],\n[54.88156645, 82.4792199667, \"26\"],\n[54.88154905, 82.4796941667, \"29\"],\n[54.8814046333, 82.4791842167, \"28\"],\n[54.8841534, 82.4798770333, \"1\"],\n[54.88124075, 82.47917795, \"30\"],\n[54.8811993833, 82.4787023, \"32\"],\n[54.8809580167, 82.4791391833, \"34\"],\n[54.8809750667, 82.4788466833, \"34A\"],\n[54.8835383667, 82.4798388, \"9\"],\n[54.8831311167, 82.4801495667, \"15\"],\n[54.88322745, 82.47980485, \"13\"],\n[54.8806638833, 82.4795858667, \"37\"],\n[54.88084555, 82.4786213833, \"36\"],\n[54.88399585, 82.4798779833, \"3\"],\n[54.8839041667, 82.4794138833, \"2\"],\n[54.8837673333, 82.4794031833, \"4\"],\n[54.8837132667, 82.4798593833, \"7\"],\n[54.8808555833, 82.47961625, \"35\"],\n[54.8835850167, 82.47938365, \"8\"],\n[54.8838495167, 82.4798612, \"5\"],\n[54.8837031833, 82.4801284167, \"7A\"],\n[54.8836938167, 82.47892395, \"6\"],\n[54.8833948833, 82.4788199167, \"12\"],\n[54.8832576167, 82.4787911, \"14A\"],\n[54.8834012333, 82.4798226333, \"11\"],\n[54.8834290167, 82.4793790167, \"10\"],\n[54.9152153667, 82.5551235833, \"3/5\"],\n[54.91650135, 82.5636650667, \"82\"],\n[54.9161045333, 82.5591854333, \"41\"],\n[54.9154124667, 82.5548626, \"2/5\"],\n[54.9166862333, 82.55784235, \"32\"],\n[54.91602365, 82.5560715, \"21\"],\n[54.91628925, 82.5653876833, \"94\"],\n[54.9160243833, 82.55493095, \"1/5\"],\n[54.9158285, 82.5660481167, \"109\"],\n[54.91440645, 82.5544777167, \"9\"],\n[54.9154713667, 82.56556335, \"105\"],\n[54.9123841333, 82.5769109, \"1/239\"],\n[54.9138841833, 82.5671444, \"127\"],\n[54.916035, 82.5569371167, \"25\"],\n[54.91497065, 82.5671545333, \"1/114\"],\n[54.9146378167, 82.5673035, \"2/114\"],\n[54.9176808667, 82.5727210167, \"192\"],\n[54.91296825, 82.57312245, \"1/192\"],\n[54.9165331, 82.56259155, \"70\"],\n[54.9128700167, 82.5676242167, \"135\"],\n[54.9127302333, 82.5677905167, \"137\"],\n[54.9138889, 82.57603805, \"212\"],\n[54.8834204167, 82.4653173333, \"2/67\"],\n[54.8829550167, 82.4680045, \"93A\"],\n[54.8815600333, 82.4786609667, \"164C\"],\n[54.8830218167, 82.4623102, \"41\"],\n[54.8817898333, 82.47891525, \"166A\"],\n[54.8827127167, 82.46177765, \"40\"],\n[54.8822979167, 82.4663795167, \"74A\"],\n[54.8828493167, 82.4591475, \"16\"],\n[54.88142475, 82.4786348833, \"164D\"],\n[54.88306005, 82.4616891167, \"37\"],\n[54.8820609167, 82.4740814833, \"122\"],\n[54.8826992167, 82.4619383167, \"42\"],\n[54.8821519667, 82.4815448333, \"209A\"],\n[54.883041, 82.4620756167, \"39\"],\n[54.8832654167, 82.4652926667, \"1/67\"],\n[54.88272565, 82.4616287, \"38\"],\n[54.8830076333, 82.4626069, \"43\"],\n[54.8831357, 82.4601246167, \"27\"],\n[54.8817307, 82.4761582, \"146A\"],\n[54.8831685833, 82.4596908, \"25\"],\n[54.8815906167, 82.4788964667, \"166B\"],\n[54.88278065, 82.4602865167, \"26\"],\n[54.8835589833, 82.4653321833, \"3/67\"],\n[54.8825282667, 82.4646378, \"60\"],\n[54.8813641333, 82.4755528333, \"136A\"],\n[54.8823392167, 82.4748610333, \"155\"],\n[54.8833277833, 82.46261325, \"43A\"],\n[54.8815676833, 82.4731547, \"114B\"],\n[54.8819471167, 82.4816728, \"211\"],\n[54.8829108333, 82.4730159, \"139\"],\n[54.8831197, 82.4654452, \"69A\"],\n[54.8827723, 82.4605280167, \"28\"],\n[54.8829114, 82.4647714833, \"59\"],\n[54.88250115, 82.4649823, \"64\"],\n[54.8829076, 82.46497065, \"61\"],\n[54.88293875, 82.4727218, \"135\"],\n[54.8824690167, 82.4726854833, \"133\"],\n[54.88310945, 82.4604659833, \"31\"],\n[54.8831059, 82.4608415833, \"35\"],\n[54.8827654333, 82.4607287333, \"30\"],\n[54.8831227667, 82.4602889167, \"29\"],\n[54.8825220833, 82.4621568833, \"44A\"],\n[54.88299765, 82.4628680167, \"45\"],\n[54.8832516833, 82.4628885167, \"45A\"],\n[54.8826944667, 82.46216875, \"44\"],\n[54.8825202167, 82.46254835, \"48A\"],\n[54.8833442667, 82.45699385, \"5\"],\n[54.8829708667, 82.4632570667, \"51\"],\n[54.8824811, 82.4725087833, \"131\"],\n[54.8829959833, 82.4630565833, \"49\"],\n[54.8826675833, 82.4625577, \"48\"],\n[54.88331805, 82.45745235, \"9\"],\n[54.8824531333, 82.47297485, \"141\"],\n[54.8827041833, 82.45734235, \"8\"],\n[54.8833336167, 82.4572248667, \"7\"],\n[54.8829612, 82.4728780167, \"137\"],\n[54.8823318333, 82.4686371167, \"86\"],\n[54.8824054833, 82.4672578333, \"78\"],\n[54.8823379667, 82.4683863333, \"84A-84D\"],\n[54.8823962167, 82.4674496167, \"80\"],\n[54.8824414833, 82.46633525, \"74\"],\n[54.8827537667, 82.4672953, \"85\"],\n[54.8822319333, 82.4661475333, \"72\"],\n[54.8824802, 82.4658691833, \"70\"],\n[54.8827660833, 82.4671242167, \"83\"],\n[54.8823372667, 82.47505315, \"157\"],\n[54.8826545167, 82.4751218167, \"157A\"],\n[54.8820193333, 82.4750065167, \"128\"],\n[54.8818626167, 82.4777718333, \"152\"],\n[54.8819736, 82.47592125, \"140\"],\n[54.8819698, 82.4757241667, \"138\"],\n[54.8823149, 82.4754510833, \"165\"],\n[54.8823264833, 82.4752907833, \"163\"],\n[54.8827581167, 82.4752805833, \"161\"],\n[54.8829257833, 82.4751779333, \"159\"],\n[54.8822762, 82.4760006333, \"167\"],\n[54.8821834, 82.4777217333, \"177\"],\n[54.8822236833, 82.4803508667, \"199\"],\n[54.8815487833, 82.4799515, \"172A\"],\n[54.8821390333, 82.4785808167, \"185\"],\n[54.8821657167, 82.4779489667, \"179\"],\n[54.8821615, 82.47814015, \"181\"],\n[54.8821482167, 82.4783480833, \"183\"],\n[54.88205545, 82.4801785, \"197\"],\n[54.8817139833, 82.48044315, \"176\"],\n[54.8817403667, 82.4799308667, \"172\"],\n[54.8817075, 82.4806324333, \"176A\"],\n[54.8816647167, 82.4814856333, \"184\"],\n[54.8817027333, 82.4808254167, \"178\"],\n[54.8816651167, 82.48128865, \"182\"],\n[54.8816775833, 82.4810764167, \"180\"],\n[54.8821253667, 82.4788135833, \"187\"],\n[54.88211265, 82.4790205167, \"189\"],\n[54.88210465, 82.4792012833, \"191\"],\n[54.8820355, 82.4804062667, \"201\"],\n[54.88222755, 82.4806704167, \"203A\"],\n[54.8820247167, 82.4806337333, \"203\"],\n[54.8821983833, 82.4809817, \"205A\"],\n[54.8820063, 82.4808974, \"205\"],\n[54.8819872, 82.4811870167, \"207\"],\n[54.88197265, 82.4814592667, \"209\"],\n[54.8831150167, 82.4606360833, \"33\"],\n[54.8827381667, 82.4614688333, \"36\"],\n[54.88168275, 82.4731685667, \"114A\"],\n[54.8825469333, 82.4624433, \"46A\"],\n[54.8827017167, 82.4623766, \"46\"],\n[54.8828950667, 82.4652071, \"65\"],\n[54.88223365, 82.4708144, \"98\"],\n[54.8826632333, 82.46886835, \"99\"],\n[54.88294545, 82.4574472333, \"10\"],\n[54.8820008, 82.47545635, \"132\"],\n[54.8815931167, 82.4754940333, \"134\"],\n[54.8815807333, 82.4756172833, \"136\"],\n[54.8820043167, 82.4752607833, \"130\"],\n[54.88218895, 82.4774782333, \"82\"],\n[54.88172165, 82.4801884, \"174\"],\n[54.8830567667, 82.4618380833, \"37A\"],\n[54.88330235, 82.4576792167, \"11\"],\n[54.8818654333, 82.4775383667, \"150\"],\n[54.8826391333, 82.4630505, \"50C\"],\n[54.8826306167, 82.4631781333, \"50D\"],\n[54.8822323333, 82.46476475, \"62\"],\n[54.8818249833, 82.4749363833, \"128A\"],\n[54.8826051333, 82.4701299167, \"109\"],\n[54.8822580667, 82.47622145, \"169\"],\n[54.8821165333, 82.4729660833, \"112\"],\n[54.8826087833, 82.4699331333, \"107\"],\n[54.8819629, 82.4761853, \"146\"],\n[54.882082833, 82.4748403667, \"126\"],\n[54.8825933333, 82.4704919167, \"113\"],\n[54.8825976, 82.4703054667, \"111\"],\n[54.8815316833, 82.4759537667, \"142\"],\n[54.8815485667, 82.4760951167, \"144\"],\n[54.8826667167, 82.4685696833, \"97A\"],\n[54.8823006, 82.4698174167, \"90\"],\n[54.8822800167, 82.4702989667, \"96\"],\n[54.8819513333, 82.47633525, \"148\"],\n[54.8828277833, 82.4687268667, \"97\"],\n[54.8822974333, 82.469983, \"92\"],\n[54.8828276667, 82.4593929667, \"18\"],\n[54.8823263167, 82.4688898, \"88\"],\n[54.8832137, 82.4589384833, \"17\"],\n[54.8822883667, 82.4701519667, \"94\"],\n[54.8826732, 82.4684589667, \"97B\"],\n[54.8822189833, 82.47111545, \"100\"],\n[54.8820588, 82.4799191833, \"195\"],\n[54.8817857167, 82.4791120667, \"168\"],\n[54.8815184167, 82.4779607667, \"156\"],\n[54.8831976333, 82.4593128167, \"21\"],\n[54.8823417833, 82.4681742167, \"82\"],\n[54.8827111, 82.4679744667, \"93\"],\n[54.8832019667, 82.4591213833, \"19\"],\n[54.8815556333, 82.4802543833, \"174A\"],\n[54.88215085, 82.4723449167, \"108\"],\n[54.8815176167, 82.4778254833, \"154\"],\n[54.8820986333, 82.4731788833, \"114\"],\n[54.8820722833, 82.47386775, \"120\"],\n[54.8821363667, 82.4725972667, \"110\"],\n[54.8818740833, 82.47394495, \"120A\"],\n[54.8820951167, 82.4734228167, \"116\"],\n[54.88208125, 82.4736554333, \"118\"],\n[54.8816796667, 82.4786736667, \"164B\"],\n[54.88313585, 82.4678512667, \"91\"],\n[54.8824046833, 82.4740707, \"153\"],\n[54.8829457667, 82.45767015, \"12A\"],\n[54.8825498667, 82.45756275, \"12\"],\n[54.8832922167, 82.4578983333, \"13\"],\n[54.8829356167, 82.4578815, \"14\"],\n[54.8832731833, 82.4580626167, \"15\"],\n[54.8833720833, 82.4564383833, \"1\"],\n[54.8833604167, 82.4567315167, \"3\"],\n[54.8828452833, 82.4659509, \"75\"],\n[54.88283615, 82.4661431333, \"77\"],\n[54.8828280833, 82.4662871833, \"79\"],\n[54.8831762333, 82.4650671667, \"63A\"],\n[54.8832807333, 82.4650862667, \"63B\"],\n[54.8828784, 82.4654325333, \"69\"],\n[54.88286845, 82.4656069833, \"71\"],\n[54.8828541167, 82.4657729833, \"73\"],\n[54.88225265, 82.4763298333, \"171\"],\n[54.88244025, 82.4731903833, \"143\"],\n[54.88277745, 82.4714596167, \"123A\"],\n[54.8825218833, 82.4714168, \"123\"],\n[54.8826166167, 82.4697419333, \"105\"],\n[54.88317465, 82.4595099667, \"23\"],\n[54.88146045, 82.47846145, \"162\"],\n[54.8818026833, 82.47869275, \"164A\"],\n[54.8825380333, 82.47125165, \"121\"],\n[54.8821686667, 82.4812678167, \"207A\"],\n[54.8825423167, 82.47107055, \"119\"],\n[54.8818212833, 82.4783825, \"160\"],\n[54.8825595667, 82.4708636, \"117\"],\n[54.8822055167, 82.4713504167, \"104\"],\n[54.8821969167, 82.4715105167, \"106\"],\n[54.88270855, 82.4681556333, \"95\"],\n[54.8818339, 82.4781130167, \"158\"],\n[54.88248225, 82.4723453, \"129\"],\n[54.8825806, 82.4706828667, \"115\"],\n[54.8824171833, 82.47368635, \"149\"],\n[54.8830100833, 82.4662410333, \"77A\"],\n[54.88294835, 82.4681855, \"95A\"],\n[54.8824262667, 82.4734592, \"147\"],\n[54.88256465, 82.4739109667, \"151A\"],\n[54.88265405, 82.4627631667, \"50A\"],\n[54.88273475, 82.4676983, \"89\"],\n[54.8826450667, 82.4629121333, \"50B\"],\n[54.8827506167, 82.4674962833, \"87\"],\n[54.8824087, 82.4738996167, \"151\"],\n[54.8752754167, 82.4687945, \"5\"],\n[54.8762403, 82.4685664667, \"17\"],\n[54.8754141333, 82.46920485, \"7\"],\n[54.87579005, 82.4687529833, \"11B\"],\n[54.8756581167, 82.4691656167, \"9\"],\n[54.8765213333, 82.4682912, \"19D\"],\n[54.8756935167, 82.46956425, \"10\"],\n[54.87642715, 82.46787445, \"19B\"],\n[54.8755152333, 82.4695951833, \"8\"],\n[54.8764289167, 82.46891995, \"20\"],\n[54.8753332833, 82.4696019833, \"6\"],\n[54.8751625833, 82.4692038167, \"3\"],\n[54.8751427, 82.4696164667, \"4\"],\n[54.8764386833, 82.46867495, \"21\"],\n[54.87496015, 82.4696499, \"2\"],\n[54.8756744167, 82.4688181667, \"11A\"],\n[54.8749777333, 82.4692451667, \"1\"],\n[54.8763775667, 82.4681980333, \"19A\"],\n[54.87626605, 82.46911145, \"16\"],\n[54.8765451333, 82.4678920167, \"19C\"],\n[54.87614825, 82.4692725667, \"14\"],\n[54.87655055, 82.4693377, \"18\"],\n[54.8760211, 82.4693800167, \"12\"],\n[54.87610675, 82.46867635, \"15\"],\n[54.8759566833, 82.4689563167, \"13\"],\n[54.8746548333, 82.4923337833, \"108\"],\n[54.8761834667, 82.4925171833, \"86\"],\n[54.8786149333, 82.4916796167, \"61\"],\n[54.8767351, 82.4913667333, \"83\"],\n[54.8802232333, 82.49233165, \"48\"],\n[54.8775048833, 82.4913709, \"75\"],\n[54.8754266, 82.4923112333, \"98\"],\n[54.8778063333, 82.4924615667, \"72\"],\n[54.8803238667, 82.49186235, \"45\"],\n[54.8723323333, 82.49117315, \"131\"],\n[54.8718419, 82.4924310167, \"138\"],\n[54.8711135, 82.4946030167, \"148\"],\n[54.8697698833, 82.4923552333, \"166\"],\n[54.8688831, 82.4922950167, \"176\"],\n[54.8789681333, 82.4925074, \"58\"],\n[54.8820738333, 82.4926333167, \"30\"],\n[54.8812172, 82.49178955, \"37\"],\n[54.88069745, 82.4925708333, \"42\"],\n[54.8787213167, 82.4903820667, \"63\"],\n[54.8789726667, 82.4909397833, \"59\"],\n[54.8796000667, 82.498281167, \"53\"],\n[54.8795261833, 82.49247645, \"54\"],\n[54.8736368167, 82.4923986833, \"124\"],\n[54.8727232333, 82.4924140333, \"126\"],\n[54.87437165, 82.4674392167, \"27\"],\n[54.8746732167, 82.4701863, \"7\"],\n[54.8744574833, 82.4691624667, \"17\"],\n[54.8743822167, 82.47024785, \"9A\"],\n[54.8749997667, 82.4700487, \"12\"],\n[54.8743498667, 82.4700893333, \"9B\"],\n[54.8752501333, 82.4707564333, \"4\"],\n[54.8746036167, 82.46989845, \"11\"],\n[54.8744127333, 82.4663752333, \"33\"],\n[54.87455375, 82.4696726333, \"13\"],\n[54.87442195, 82.4683011333, \"21\"],\n[54.87475005, 82.4704344167, \"5\"],\n[54.8747738, 82.4664531833, \"32\"],\n[54.8747376833, 82.4677991, \"24\"],\n[54.8748038833, 82.4662112833, \"34\"],\n[54.8743485, 82.4672374833, \"29\"],\n[54.87475315, 82.4683317, \"22\"],\n[54.8747034167, 82.4672897833, \"28\"],\n[54.8751725667, 82.4705402833, \"6\"],\n[54.8743703, 82.46656865, \"31\"],\n[54.8747061667, 82.4675099333, \"26\"],\n[54.8749663833, 82.4711516, \"1\"],\n[54.8750729167, 82.4702726833, \"10\"],\n[54.8747800333, 82.4687326833, \"20\"],\n[54.8747974333, 82.468992, \"18\"],\n[54.87484445, 82.4707471667, \"3\"],\n[54.8754537333, 82.47035305, \"8A\"],\n[54.8753716, 82.4710875, \"2\"],\n[54.8749196, 82.4697604667, \"14\"],\n[54.8744452, 82.4661277667, \"35\"],\n[54.8744961833, 82.46941455, \"15\"],\n[54.8747449667, 82.4666386167, \"30\"],\n[54.87482605, 82.4692223833, \"16\"],\n[54.8754105667, 82.4702048167, \"8B\"],\n[54.8743849167, 82.4676931, \"25\"],\n[54.8744337, 82.4689042667, \"19\"],\n[54.8743984167, 82.4679389167, \"23\"],\n[54.8778069667, 82.4712312167, \"25\"],\n[54.8763120333, 82.4717215833, \"44\"],\n[54.87672545, 82.4712506833, \"41\"],\n[54.8772550667, 82.471782167, \"32\"],\n[54.8668511333, 82.4718110667, \"166\"],\n[54.8767613667, 82.4717327167, \"40\"],\n[54.8733181333, 82.47092935, \"81\"],\n[54.86564525, 82.47179185, \"172\"],\n[54.866566, 82.47182225, \"170\"],\n[54.8709313833, 82.472052, \"102\"],\n[54.8773583833, 82.4709902333, \"33A\"],\n[54.8718238, 82.4719052833, \"100\"],\n[54.8636636, 82.4713474333, \"185\"],\n[54.8639432, 82.4718744833, \"180\"],\n[54.87639895, 82.4712276333, \"43\"],\n[54.86320725, 82.47180795, \"190\"],\n[54.87736335, 82.4707706667, \"33B\"],\n[54.8635744667, 82.4721996167, \"1/186\"],\n[54.8770291667, 82.4712897833, \"37\"],\n[54.8744578833, 82.4712959833, \"63\"],\n[54.87760745, 82.4717249167, \"30\"],\n[54.8748192, 82.47130365, \"59\"],\n[54.8647013333, 82.4717920833, \"174\"],\n[54.8754668167, 82.4712709333, \"55\"],\n[54.8748770833, 82.478243167, \"62\"],\n[54.863631, 82.4717906, \"186\"],\n[54.8759205833, 82.4712616667, \"51\"],\n[54.86283285, 82.4713374833, \"195\"],\n[54.8773474667, 82.4713414333, \"35\"],\n[54.87610145, 82.4712462667, \"47\"],\n[54.8736575, 82.4709245667, \"75\"],\n[54.8743432333, 82.4718551833, \"66\"],\n[54.86451155, 82.47179665, \"176\"],\n[54.8735859667, 82.4719257333, \"74\"],\n[54.8734058167, 82.47132365, \"79\"],\n[54.8742359, 82.4712991333, \"67\"],\n[54.87358325, 82.4713242167, \"77\"],\n[54.87305765, 82.4719396833, \"82\"],\n[54.8727949333, 82.4719115167, \"86\"],\n[54.8722028667, 82.4741686, \"90\"],\n[54.8675567167, 82.4711739833, \"137\"],\n[54.8725890333, 82.46970215, \"2/95\"],\n[54.8726248333, 82.4710150833, \"1/95\"],\n[54.8702623, 82.4720475333, \"116\"],\n[54.8780759667, 82.4717211333, \"24\"],\n[54.8738727167, 82.4713038, \"73\"],\n[54.8739672333, 82.4710486167, \"71\"],\n[54.8935260167, 82.4748064, \"10\"],\n[54.89273555, 82.4747373, \"16\"],\n[54.8919345833, 82.4746388833, \"24\"],\n[54.89328595, 82.4747852667, \"12\"],\n[54.8938477333, 82.47430505, \"8A\"],\n[54.8936160833, 82.47481635, \"8\"],\n[54.8920694833, 82.4757293833, \"23A\"],\n[54.89206575, 82.4752388667, \"23\"],\n[54.8923724, 82.4746924667, \"18\"],\n[54.89353315, 82.47444375, \"10A\"],\n[54.8899805167, 82.4750166667, \"41\"],\n[54.89167325, 82.4757043333, \"27A\"],\n[54.89028415, 82.47505045, \"39\"],\n[54.892463, 82.47526755, \"17\"],\n[54.8918398667, 82.4752066, \"25\"],\n[54.8908128167, 82.4750707333, \"33\"],\n[54.8904636333, 82.4750504333, \"37\"],\n[54.8906359833, 82.47507655, \"35\"],\n[54.8916253, 82.47516515, \"27\"],\n[54.8909492333, 82.47507265, \"31\"],\n[54.8905761667, 82.4744542167, \"1/30-5/30\"],\n[54.8881462333, 82.4754198167, \"57\"],\n[54.88850555, 82.47524575, \"53\"],\n[54.8894041667, 82.47498115, \"45\"],\n[54.9014205, 82.4676039667, \"9\"],\n[54.905282667, 82.4691138833, \"53\"],\n[54.90503895, 82.46905685, \"51\"],\n[54.90533595, 82.4686957333, \"55\"],\n[54.90163855, 82.46769255, \"17\"],\n[54.9033958, 82.4683840167, \"35\"],\n[54.9053689667, 82.46858075, \"57\"],\n[54.9012599667, 82.4679458667, \"12\"],\n[54.9014051333, 82.4680825, \"14\"],\n[54.9015679, 82.4680723333, \"16\"],\n[54.9031653, 82.4679986833, \"31A\"],\n[54.9007696333, 82.46734585, \"1\"],\n[54.9017356333, 82.4681344333, \"18\"],\n[54.9019312333, 82.46780625, \"19\"],\n[54.9019026, 82.4682113333, \"20\"],\n[54.9023515833, 82.4679880667, \"23\"],\n[54.9025247833, 82.4680511, \"25\"],\n[54.9019499, 82.46872425, \"26\"],\n[54.9027011167, 82.4680964167, \"27\"],\n[54.90322595, 82.4683034667, \"33\"],\n[54.9022090667, 82.46834225, \"28\"],\n[54.9028740333, 82.4681630167, \"29\"],\n[54.9009473167, 82.4678397833, \"2\"],\n[54.9030474, 82.46823325, \"31\"],\n[54.9024255333, 82.4684154833, \"32\"],\n[54.9024751, 82.4690537, \"34A\"],\n[54.9025607, 82.4684754, \"34\"],\n[54.9047760167, 82.4688679333, \"49\"],\n[54.9035690833, 82.46844705, \"37\"],\n[54.9032248, 82.4687414833, \"38\"],\n[54.9037398833, 82.4685398, \"39\"],\n[54.90425835, 82.4687235833, \"45\"],\n[54.9039185, 82.4686071, \"41\"],\n[54.9040853333, 82.4686607667, \"43\"],\n[54.9044377833, 82.46879205, \"47\"],\n[54.9027932167, 82.4685815833, \"36\"],\n[54.90099425, 82.46709335, \"3\"],\n[54.90111195, 82.4678951333, \"4\"],\n[54.9010127333, 82.4674434667, \"5\"],\n[54.9012417333, 82.4675368333, \"7\"],\n[54.9054492167, 82.4684984667, \"59\"],\n[54.9055391, 82.4685278333, \"61\"],\n[54.90550535, 82.46878055, \"63\"],\n[54.9054566667, 82.46921805, \"65\"],\n[54.90230745, 82.4676206667, \"21A\"],\n[54.9021682, 82.4679036667, \"21\"],\n[54.8808262333, 82.4773818, \"55A\"],\n[54.8830005833, 82.4767448167, \"16\"],\n[54.8828296667, 82.4767286, \"18\"],\n[54.88259875, 82.4772334333, \"31\"],\n[54.8824754, 82.47721195, \"33\"],\n[54.8831398167, 82.4779190333, \"17\"],\n[54.8825963167, 82.4777829, \"29\"],\n[54.8842646833, 82.4768462333, \"2\"],\n[54.8810851333, 82.476127, \"36\"],\n[54.8806964, 82.47760075, \"57\"],\n[54.8805952167, 82.4775984333, \"59\"],\n[54.8813687667, 82.4765958833, \"32\"],\n[54.8824115167, 82.4772049833, \"35\"],\n[54.8811797, 82.4765765833, \"34\"],\n[54.8815471667, 82.4766046333, \"30\"],\n[54.88417235, 82.4773933667, \"3\"],\n[54.88174695, 82.4772075667, \"39\"],\n[54.8809885833, 82.47654575, \"38\"],\n[54.8814635333, 82.4771838167, \"43\"],\n[54.8816058667, 82.4771958, \"41\"],\n[54.88064845, 82.4765253, \"42\"],\n[54.8808178333, 82.4765337333, \"40\"],\n[54.883982, 82.4773589667, \"5\"],\n[54.8834955667, 82.4767355667, \"10\"],\n[54.88350755, 82.4765409, \"10A\"],\n[54.8836987667, 82.47736385, \"7\"],\n[54.88321935, 82.4767625833, \"12\"],\n[54.8833260667, 82.4773372, \"13\"],\n[54.8830089, 82.4772931833, \"19A\"],\n[54.8831393167, 82.4773106833, \"19\"],\n[54.88264695, 82.47671705, \"20\"],\n[54.88292945, 82.4775952333, \"21\"],\n[54.8824614333, 82.4767002833, \"22\"],\n[54.8828817167, 82.4779039, \"23\"],\n[54.8823059167, 82.4766897833, \"24\"],\n[54.8827997667, 82.4772721833, \"25A\"],\n[54.8828034167, 82.4775536833, \"25B\"],\n[54.8827016667, 82.4777941, \"27\"],\n[54.8828062, 82.47779805, \"27A\"],\n[54.8817341833, 82.4766062333, \"28\"],\n[54.8813136167, 82.4771594167, \"45\"],\n[54.8811630667, 82.4771457, \"47\"],\n[54.8809942833, 82.4776755833, \"51\"],\n[54.8804464667, 82.4764969833, \"44\"],\n[54.8810737, 82.4776356667, \"49\"],\n[54.8809778333, 82.4774265, \"53A\"],\n[54.8810030333, 82.4771406667, \"53\"],\n[54.88079105, 82.47712645, \"55\"],\n[54.8835414333, 82.4773520667, \"9\"],\n[54.8805955667, 82.4771014667, \"61\"],\n[54.8804778167, 82.4770884667, \"63\"],\n[54.8802896833, 82.4770558, \"65\"],\n[54.8834467833, 82.4778119333, \"11\"],\n[54.8878083, 82.4623779167, \"49A\"],\n[54.8872817833, 82.45737585, \"10\"],\n[54.8877537333, 82.4595533, \"27A\"],\n[54.8884375167, 82.45748685, \"11B\"],\n[54.8878958, 82.4596416167, \"27B\"],\n[54.88824535, 82.45746395, \"11A\"],\n[54.8875099833, 82.4575973667, \"14\"],\n[54.8866716167, 82.4603215333, \"36B\"],\n[54.8871296333, 82.4604902833, \"36C\"],\n[54.8873681333, 82.4599526667, \"30\"],\n[54.8880297, 82.4601033833, \"31A\"],\n[54.8881606833, 82.4601333667, \"31B\"],\n[54.8869335833, 82.4608386833, \"40A\"],\n[54.8873096333, 82.4609038, \"40\"],\n[54.8878578167, 82.4576188333, \"13\"],\n[54.8871150667, 82.4574956333, \"12\"],\n[54.8878406333, 82.45785455, \"15\"],\n[54.8871478667, 82.4578061667, \"16A\"],\n[54.8869680833, 82.4578044667, \"16B\"],\n[54.8874965167, 82.4577967, \"16\"],\n[54.8872507333, 82.4580158333, \"18A\"],\n[54.88747815, 82.4580365167, \"18\"],\n[54.8880638833, 82.45810725, \"19A\"],\n[54.88784345, 82.4580772667, \"19\"],\n[54.8877572333, 82.45932705, \"25\"],\n[54.8879145667, 82.45669455, \"1\"],\n[54.8873702833, 82.4595467333, \"26\"],\n[54.8879238167, 82.4569262833, \"1A\"],\n[54.8874736, 82.4582577833, \"20\"],\n[54.8878260333, 82.4583038167, \"21\"],\n[54.8873656333, 82.4597425833, \"28\"],\n[54.8879435667, 82.4597720333, \"29A\"],\n[54.8881376167, 82.45977945, \"29B\"],\n[54.8883413667, 82.4597758333, \"29C\"],\n[54.8884945333, 82.45978905, \"29D\"],\n[54.8877360167, 82.45978725, \"29\"],\n[54.8871679167, 82.4598937333, \"30A\"],\n[54.8877368167, 82.45999715, \"31\"],\n[54.8873456, 82.4602082167, \"32\"],\n[54.8877073333, 82.4602192333, \"33\"],\n[54.88687805, 82.4602032667, \"34A\"],\n[54.8866636, 82.4602061833, \"34B\"],\n[54.8868802667, 82.4603641333, \"36A\"],\n[54.8877013333, 82.4604213, \"35\"],\n[54.8875414167, 82.4568279333, \"2\"],\n[54.8873298167, 82.4604643167, \"36\"],\n[54.8876929833, 82.4606236833, \"37\"],\n[54.8869503167, 82.4606911333, \"38A\"],\n[54.8873173833, 82.46064935, \"38\"],\n[54.8880788167, 82.46095015, \"39A\"],\n[54.8876923833, 82.4607943167, \"39\"],\n[54.88767155, 82.4610391833, \"41\"],\n[54.8876050833, 82.4618428, \"43\"],\n[54.8876116333, 82.4619894, \"45\"],\n[54.88820765, 82.4571291333, \"3A\"],\n[54.88840855, 82.4571648833, \"3B\"],\n[54.8875992833, 82.4621293167, \"47\"],\n[54.88757835, 82.4622876333, \"49\"],\n[54.8875702, 82.4625005667, \"51\"],\n[54.8875504, 82.46284035, \"53\"],\n[54.8875351833, 82.46302475, \"55\"],\n[54.88811905, 82.4635122, \"57E\"],\n[54.88825965, 82.46351715, \"57F\"],\n[54.8882625, 82.4633885, \"57G\"],\n[54.8882589333, 82.4632448167, \"57H\"],\n[54.8875218833, 82.4632180167, \"57\"],\n[54.8875030667, 82.4634566667, \"59\"],\n[54.8871363, 82.4643333667, \"64\"],\n[54.88744265, 82.4645542333, \"65\"],\n[54.8871286333, 82.4645791667, \"66\"],\n[54.8876065667, 82.4648085833, \"67A\"],\n[54.8874482, 82.4647992167, \"67\"],\n[54.88711895, 82.4648136, \"68\"],\n[54.8885710333, 82.4571354, \"5A\"],\n[54.8886647667, 82.4571676667, \"5B\"],\n[54.8874510667, 82.4649796333, \"69A\"],\n[54.8875224833, 82.4649906833, \"69B\"],\n[54.8878563833, 82.4571620833, \"7A\"],\n[54.8880328667, 82.4571656833, \"7B\"],\n[54.8875264167, 82.4573541, \"8\"],\n[54.88804485, 82.4574312167, \"9B\"],\n[54.8875345667, 82.4570015833, \"6\"],\n[54.8878647667, 82.45740435, \"9A\"],\n[54.8879745833, 82.4634900667, \"57D\"],\n[54.8878037333, 82.4633596833, \"57B\"],\n[54.8878387167, 82.4631928333, \"57A\"],\n[54.8878102333, 82.46349065, \"57C\"],\n[54.9019538167, 82.4671126833, \"7A\"],\n[54.903244, 82.4676256333, \"14A\"],\n[54.9020871667, 82.4668353167, \"7\"],\n[54.9027623667, 82.4671213167, \"11\"],\n[54.9025892667, 82.4670505333, \"10\"],\n[54.9024684667, 82.4672691667, \"10A\"],\n[54.90241945, 82.4669742667, \"9\"],\n[54.9029300667, 82.4671840333, \"12\"],\n[54.90311145, 82.4672579333, \"13\"],\n[54.9032782833, 82.4673314833, \"14\"],\n[54.9036218833, 82.4674643167, \"16\"],\n[54.9037919667, 82.46753785, \"17\"],\n[54.90344895, 82.4673941667, \"15\"],\n[54.9039705667, 82.4676045333, \"18\"],\n[54.9041435833, 82.467671, \"19\"],\n[54.9010125167, 82.4664210333, \"1A\"],\n[54.9007809667, 82.4663229167, \"1\"],\n[54.9043140333, 82.4677303167, \"20\"],\n[54.90448985, 82.46780755, \"21\"],\n[54.9046493333, 82.4670530667, \"23\"],\n[54.9048533833, 82.4675182833, \"24\"],\n[54.9012388167, 82.46653205, \"2\"],\n[54.9014534667, 82.46660645, \"4\"],\n[54.9017320167, 82.4669518333, \"5\"],\n[54.9018944667, 82.4667655333, \"6\"],\n[54.9022384667, 82.46689735, \"8\"],\n[54.90570045, 82.46976825, \"72/91\"],\n[54.9051381333, 82.4722857333, \"96\"],\n[54.9032204, 82.4703621333, \"53\"],\n[54.9053162167, 82.4723414, \"98\"],\n[54.9037962833, 82.4711215833, \"5/91\"],\n[54.9055880667, 82.4707876167, \"108/91\"],\n[54.9045404333, 82.4699855167, \"46/91\"],\n[54.9016813667, 82.4703439167, \"17\"],\n[54.9047542667, 82.4700433333, \"48/91\"],\n[54.9038862333, 82.4703755167, \"31/91\"],\n[54.9046661667, 82.4695472667, \"56/91\"],\n[54.9033795167, 82.4706831, \"10/91\"],\n[54.9049449167, 82.4696617167, \"54/91\"],\n[54.90342665, 82.4705010167, \"26/91\"],\n[54.9042283333, 82.4698824, \"43/91\"],\n[54.9034820167, 82.4702482, \"27/91\"],\n[54.9041029833, 82.471257, \"3/91\"],\n[54.9035045167, 82.47071685, \"11/91\"],\n[54.9034292833, 82.4709543667, \"8/91\"],\n[54.9035455167, 82.4705136333, \"25/91\"],\n[54.9044278, 82.4696974167, \"52/91\"],\n[54.9036199667, 82.4702949333, \"28/91\"],\n[54.9050604833, 82.4696742167, \"53/91\"],\n[54.9035777167, 82.4701138, \"29/91\"],\n[54.9047726833, 82.46981425, \"49/91\"],\n[54.9037153, 82.4701772333, \"30/91\"],\n[54.90366135, 82.4710693333, \"6/91\"],\n[54.9036912333, 82.4708029167, \"12/91\"],\n[54.9039544333, 82.4701398833, \"39/91\"],\n[54.90384865, 82.4708670667, \"13/91\"],\n[54.90441965, 82.4694715667, \"58/91\"],\n[54.9039537167, 82.4709042667, \"14/91\"],\n[54.9048014667, 82.46941845, \"66/91\"],\n[54.90397155, 82.4704078333, \"32/91\"],\n[54.9046743167, 82.4697731167, \"50/91\"],\n[54.9040982, 82.4709554167, \"15/91\"],\n[54.9049822333, 82.4694750833, \"67/91\"],\n[54.9042064833, 82.4709969, \"16/91\"],\n[54.9039450167, 82.4711861667, \"4/91\"],\n[54.9043704167, 82.47106545, \"17/91\"],\n[54.9045624167, 82.4693054333, \"64/91\"],\n[54.90449515, 82.4711117167, \"18/91\"],\n[54.9040047, 82.46996625, \"40/91\"],\n[54.9038797333, 82.4706635, \"24/91\"],\n[54.9035451833, 82.4710177667, \"7/91\"],\n[54.9039780833, 82.4707046333, \"23/91\"],\n[54.9045066833, 82.46972115, \"51/91\"],\n[54.9041615833, 82.4707864333, \"22/91\"],\n[54.9060640333, 82.4699358833, \"91/91\"],\n[54.9042534333, 82.47082315, \"21/91\"],\n[54.9047130333, 82.4693776833, \"65/91\"],\n[54.9044305, 82.47089635, \"20/91\"],\n[54.9043041167, 82.46989765, \"44/91\"],\n[54.9041919167, 82.4691500833, \"61/91\"],\n[54.9044746667, 82.46996645, \"45/91\"],\n[54.9042904667, 82.4691828667, \"62/91\"],\n[54.9040487167, 82.4697756833, \"41/91\"],\n[54.90415055, 82.4693699833, \"60/91\"],\n[54.90446065, 82.46926835, \"63/91\"],\n[54.9042810333, 82.46945405, \"59/91\"],\n[54.9032851, 82.4708958667, \"9/91\"],\n[54.90451895, 82.4709371333, \"19/91\"],\n[54.9045116833, 82.4694999333, \"57/91\"],\n[54.9040854167, 82.4704954667, \"33/91\"],\n[54.9043916, 82.4713621667, \"1/91\"],\n[54.9041970167, 82.4705370833, \"34/91\"],\n[54.9050893833, 82.46956665, \"68/91\"],\n[54.9043310833, 82.4706087333, \"35/91\"],\n[54.9040848, 82.4696433167, \"42/91\"],\n[54.90443305, 82.4706374667, \"36/91\"],\n[54.90476785, 82.4695885167, \"55/91\"],\n[54.9045282833, 82.4706701333, \"37/91\"],\n[54.9042286667, 82.471303, \"2/91\"],\n[54.90462665, 82.4707112667, \"38/91\"],\n[54.9046719667, 82.4700236667, \"47/91\"],\n[54.9063787833, 82.47006835, \"93/91\"],\n[54.9052918833, 82.4698329167, \"76/91\"],\n[54.9052114833, 82.4700221833, \"77/91\"],\n[54.9050883833, 82.4701973667, \"79/91\"],\n[54.9053839167, 82.4698613, \"75/91\"],\n[54.9052999333, 82.47006295, \"78/91\"],\n[54.9051933667, 82.47023875, \"80/91\"],\n[54.9052919167, 82.4702715333, \"81/91\"],\n[54.9055609, 82.4699386667, \"74/91\"],\n[54.9056495333, 82.4699711, \"73/91\"],\n[54.9054736, 82.4701402167, \"82/91\"],\n[54.9063660167, 82.4715132167, \"102/91\"],\n[54.9062675667, 82.4719148667, \"118/91\"],\n[54.9062345, 82.4720598833, \"134/91\"],\n[54.9061993167, 82.4712732833, \"104/91\"],\n[54.9061410333, 82.4715093, \"117/91\"],\n[54.90608265, 82.4717494667, \"119/91\"],\n[54.9060274833, 82.47199395, \"133/91\"],\n[54.9059191, 82.4719566333, \"132/91\"],\n[54.9059778667, 82.47169975, \"120/91\"],\n[54.90603625, 82.4714595667, \"116/91\"],\n[54.9061060667, 82.4711529667, \"105/91\"],\n[54.9053162667, 82.4716843, \"137/91\"],\n[54.9055131833, 82.478282167, \"136/91\"],\n[54.9055088, 82.471073, \"112/91\"],\n[54.9056170833, 82.4711144833, \"113/91\"],\n[54.9057647667, 82.4711699333, \"114/91\"],\n[54.9058762667, 82.4712157167, \"115/91\"],\n[54.9054861167, 82.4707589, \"109/91\"],\n[54.9055522167, 82.4701764667, \"83/91\"],\n[54.9057089833, 82.4702698167, \"84/91\"],\n[54.9058203833, 82.4703197833, \"85/91\"],\n[54.90590455, 82.4701097667, \"89/91\"],\n[54.9059963, 82.4701506667, \"88/91\"],\n[54.90573235, 82.4708471167, \"107/91\"],\n[54.9061820167, 82.4702237333, \"87/91\"],\n[54.9062864333, 82.4702866167, \"86/91\"],\n[54.9058177667, 82.47087525, \"106/91\"],\n[54.9064954833, 82.4701769667, \"94/91\"],\n[54.9065182667, 82.4703407, \"95/91\"],\n[54.90647405, 82.4705396167, \"96/91\"],\n[54.906434, 82.4707011, \"97/91\"],\n[54.9064003667, 82.47087115, \"98/91\"],\n[54.9065184833, 82.4709171667, \"100/91\"],\n[54.9053462, 82.4696260167, \"69/91\"],\n[54.9054348333, 82.46965845, \"70/91\"],\n[54.9056151167, 82.4697359333, \"71/91\"],\n[54.9065477667, 82.4707929167, \"99/91\"],\n[54.9063361667, 82.4716625167, \"103/91\"],\n[54.9064024833, 82.47136415, \"101/91\"],\n[54.9062771167, 82.4700270833, \"92/91\"],\n[54.90561825, 82.4717954167, \"135/91\"],\n[54.9052021167, 82.4714629667, \"127/91\"],\n[54.9053039667, 82.4714958833, \"128/91\"],\n[54.9055797833, 82.4715935333, \"130/91\"],\n[54.9057338, 82.4716617333, \"131/91\"],\n[54.9054388, 82.47153415, \"129/91\"],\n[54.90521165, 82.4711876167, \"126/91\"],\n[54.9053168167, 82.47122065, \"125/91\"],\n[54.9054577833, 82.4712800167, \"124/91\"],\n[54.9055496333, 82.47131675, \"123/91\"],\n[54.9057004333, 82.47138065, \"122/91\"],\n[54.9057989, 82.4714176167, \"121/91\"],\n[54.9052758833, 82.4709810667, \"110/91\"],\n[54.9053744333, 82.4710138667, \"111/91\"],\n[54.9029642833, 82.4708119167, \"49\"],\n[54.9013200667, 82.47020055, \"9\"],\n[54.9059721, 82.4699033333, \"90/91\"],\n[54.9009692833, 82.4700359167, \"1\"],\n[54.9020093333, 82.4704903167, \"25\"],\n[54.9028505, 82.4713808167, \"42\"],\n[54.9026220667, 82.4707023167, \"41\"],\n[54.9030775167, 82.47144105, \"44\"],\n[54.9032627, 82.4715188333, \"46\"],\n[54.90279945, 82.4707535, \"47\"],\n[54.9034596333, 82.4715854667, \"48\"],\n[54.9046305667, 82.4720644, \"90\"],\n[54.9048369667, 82.472151, \"92\"],\n[54.9049919, 82.4722146, \"94\"],\n[54.9036494333, 82.4716701167, \"50\"],\n[54.90358525, 82.4846141, \"12\"],\n[54.9037579, 82.4852529, \"6\"],\n[54.9038024667, 82.4850978, \"7\"],\n[54.9037217667, 82.4849037333, \"8\"],\n[54.90347035, 82.4850285667, \"2\"],\n[54.9032276333, 82.48546265, \"3\"],\n[54.9035196167, 82.4852706167, \"4\"],\n[54.9036445667, 82.4853146167, \"5\"],\n[54.893842, 82.4658828667, \"14\"],\n[54.8942232167, 82.4658869, \"10\"],\n[54.8942694, 82.4655608, \"10A\"],\n[54.8939012167, 82.46629055, \"11\"],\n[54.89414105, 82.46563135, \"12A\"],\n[54.8940382, 82.4658608667, \"12\"],\n[54.8928791667, 82.4657609, \"18\"],\n[54.8920411833, 82.4656866167, \"26\"],\n[54.8947138333, 82.46562585, \"4A\"],\n[54.89482635, 82.4656405333, \"4B\"],\n[54.8943928667, 82.4659067667, \"8\"],\n[54.89417895, 82.4666384333, \"7A\"],\n[54.8941652333, 82.4663256, \"7\"],\n[54.8930164333, 82.4657825333, \"16\"],\n[54.8945337167, 82.46636655, \"3\"],\n[54.8947049667, 82.4662976667, \"1\"],\n[54.8943467167, 82.4663510667, \"5\"],\n[54.8945939667, 82.46589925, \"6A\"],\n[54.8946026667, 82.4655432, \"6B\"],\n[54.89400605, 82.4666357, \"9A\"],\n[54.89400415, 82.4663002333, \"9\"],\n[54.8947237, 82.4659225, \"4\"],\n[54.8948905833, 82.4659464167, \"2\"],\n[54.8926863, 82.465739, \"20\"],\n[54.8923385, 82.4654623833, \"24B\"],\n[54.89249375, 82.4657308833, \"22\"],\n[54.8923111667, 82.4657147167, \"24\"],\n[54.8815449167, 82.4655157, \"12\"],\n[54.8822096833, 82.4655813667, \"2\"],\n[54.88233595, 82.4651839667, \"1\"],\n[54.8816413667, 82.4648852333, \"9B\"],\n[54.8828295, 82.4651827, \"3\"],\n[54.8816216167, 82.4650913833, \"9A\"],\n[54.8814350167, 82.4653094667, \"13\"],\n[54.8813971333, 82.4649169833, \"11B\"],\n[54.8814120833, 82.4650868167, \"11A\"],\n[54.8819977833, 82.4651571333, \"5\"],\n[54.8818037833, 82.46516125, \"7\"],\n[54.9272509333, 82.5707935167, \"17\"],\n[54.92487165, 82.5688565167, \"50\"],\n[54.9279805, 82.5715888167, \"2/4\"],\n[54.9281482167, 82.57159225, \"3/4\"],\n[54.9277371667, 82.5716141833, \"1/4\"],\n[54.9283277667, 82.5715995333, \"4/4\"],\n[54.9259907667, 82.5697310833, \"41\"],\n[54.9139028667, 82.4794934333, \"16\"],\n[54.9131072667, 82.4784122, \"5\"],\n[54.913859, 82.4793484, \"14\"],\n[54.9137596833, 82.4789706167, \"10\"],\n[54.9129783833, 82.4779572167, \"1\"],\n[54.9134818333, 82.4796230333, \"13\"],\n[54.9134313, 82.47942965, \"11\"],\n[54.9130481833, 82.4781893667, \"3\"],\n[54.9136100333, 82.4785928, \"8\"],\n[54.9137780667, 82.47816635, \"6A\"],\n[54.9134069333, 82.4779523167, \"2\"],\n[54.9134797167, 82.4781646167, \"4\"],\n[54.9135479833, 82.4783853833, \"6\"],\n[54.9074968667, 82.4759960667, \"26\"],\n[54.90790835, 82.4788683333, \"53\"],\n[54.9077523333, 82.47593355, \"26A\"],\n[54.9075665667, 82.47624025, \"30\"],\n[54.9073841167, 82.47837545, \"45\"],\n[54.90830365, 82.4786741167, \"52\"],\n[54.9087247333, 82.4801247333, \"64\"],\n[54.9075075667, 82.478882333, \"51\"],\n[54.9088166, 82.4804266333, \"66\"],\n[54.9082595167, 82.4801578667, \"65\"],\n[54.9082304, 82.47843325, \"50\"],\n[54.90781645, 82.4785779, \"49\"],\n[54.9083352333, 82.48044785, \"67\"],\n[54.9065845333, 82.4744138667, \"15\"],\n[54.9069974, 82.47423525, \"12\"],\n[54.9065571167, 82.4727805333, \"2\"],\n[54.9066387833, 82.47305845, \"4\"],\n[54.9068011, 82.4735746167, \"8\"],\n[54.90669225, 82.47329415, \"6\"],\n[54.9072826667, 82.4752864833, \"18\"],\n[54.9081420333, 82.47812825, \"44\"],\n[54.9076585, 82.47803815, \"43\"],\n[54.9079773, 82.4776514, \"42\"],\n[54.9080697, 82.4779212, \"42A\"],\n[54.90758785, 82.4777916167, \"41\"],\n[54.90774285, 82.4783192, \"47\"],\n[54.9085469333, 82.47804035, \"46\"],\n[54.907853, 82.4771642833, \"40\"],\n[54.90694245, 82.4762600833, \"27A\"],\n[54.90714115, 82.4762523167, \"27\"],\n[54.9085940333, 82.4781931, \"48\"],\n[54.90842915, 82.4807205833, \"69\"],\n[54.90889165, 82.4806537667, \"68\"],\n[54.9090825167, 82.4813461833, \"72\"],\n[54.9085069833, 82.48098455, \"71\"],\n[54.9091493333, 82.4815615167, \"74\"],\n[54.9085867333, 82.4812446833, \"73\"],\n[54.90638345, 82.4737115833, \"9\"],\n[54.9073718833, 82.4770443667, \"35\"],\n[54.9076616333, 82.4765182, \"34\"],\n[54.9070147167, 82.4757612667, \"19\"],\n[54.9080529667, 82.4794295333, \"61\"],\n[54.9081081167, 82.4796110667, \"63\"],\n[54.9067812333, 82.4766508667, \"29\"],\n[54.90727425, 82.4767382167, \"33\"],\n[54.9080598, 82.4763364, \"32\"],\n[54.9080013, 82.4761604, \"32A\"],\n[54.9072168667, 82.4765151833, \"31\"],\n[54.9069078, 82.47611375, \"21A\"],\n[54.9070925167, 82.4759961167, \"21\"],\n[54.9073595833, 82.4755532, \"20\"],\n[54.9078311, 82.47552015, \"22\"],\n[54.9066715333, 82.4762365333, \"23\"],\n[54.9074292167, 82.4757909, \"24\"],\n[54.9067200667, 82.4763614333, \"25\"],\n[54.9079507667, 82.47594195, \"28\"],\n[54.9077839333, 82.4769487333, \"38\"],\n[54.9087032167, 82.478581, \"54\"],\n[54.9075582, 82.4791360667, \"55\"],\n[54.9087507167, 82.47871815, \"56\"],\n[54.9075607333, 82.4792694833, \"57\"],\n[54.9085885667, 82.4789704, \"58A\"],\n[54.908387, 82.47897535, \"58\"],\n[54.9078259667, 82.4793328833, \"59A\"],\n[54.90801855, 82.47915195, \"59\"],\n[54.90845065, 82.4792147, \"60\"],\n[54.9086727, 82.4815190333, \"75\"],\n[54.9092022333, 82.4817325833, \"76\"],\n[54.9087436333, 82.4817835, \"77\"],\n[54.9068335333, 82.475831, \"19A\"],\n[54.9064835, 82.4740658167, \"11\"],\n[54.9068924667, 82.4738985333, \"10\"],\n[54.90772245, 82.47673845, \"36\"],\n[54.9153057833, 82.4700439333, \"8\"],\n[54.9151920167, 82.470103, \"7\"],\n[54.9154897833, 82.4704254667, \"4\"],\n[54.91544255, 82.4701449833, \"6\"],\n[54.9152406333, 82.4705098833, \"3\"],\n[54.9155660833, 82.47067085, \"2\"],\n[54.9153145667, 82.470762, \"1\"],\n[54.915152, 82.4703036833, \"5\"],\n[54.8753657, 82.4666292833, \"7\"],\n[54.8752355833, 82.4664042833, \"5\"],\n[54.8751239167, 82.4667343, \"3\"],\n[54.8749005333, 82.4667724833, \"1\"],\n[54.8759491, 82.4666146833, \"13\"],\n[54.8761423333, 82.4666642667, \"15\"],\n[54.8757443667, 82.46657535, \"11\"],\n[54.8755500833, 82.4665719333, \"9\"],\n[54.8762191, 82.4673812833, \"18\"],\n[54.8764603333, 82.4671767333, \"22\"],\n[54.87631595, 82.4667095833, \"17\"],\n[54.8765421, 82.4670481833, \"23\"],\n[54.8764974333, 82.4666557, \"19\"],\n[54.8765351667, 82.46685605, \"21\"],\n[54.8763332, 82.4671934833, \"20\"],\n[54.8761136667, 82.4670612333, \"16\"],\n[54.8759115833, 82.4670291, \"14\"],\n[54.8757069333, 82.4669862167, \"12\"],\n[54.87555015, 82.4673181667, \"10\"],\n[54.8754323167, 82.4670474333, \"8\"],\n[54.8752163333, 82.4671320667, \"6\"],\n[54.8750437, 82.4671685, \"4\"],\n[54.87486615, 82.4671727833, \"2\"],\n[54.8836992833, 82.4725036, \"23A\"],\n[54.8827955833, 82.47167325, \"34\"],\n[54.88383525, 82.47247865, \"21B\"],\n[54.8836711, 82.4721970333, \"23\"],\n[54.88384845, 82.4721985333, \"21A\"],\n[54.8832467333, 82.4721379, \"31\"],\n[54.8852774167, 82.4718275333, \"10\"],\n[54.8841115833, 82.4722314667, \"17\"],\n[54.882555, 82.4720817333, \"41\"],\n[54.8814569667, 82.4715107167, \"46\"],\n[54.8826952667, 82.4720762667, \"39\"],\n[54.8834193, 82.4725388, \"27\"],\n[54.8834190667, 82.47216485, \"29\"],\n[54.8835037667, 82.4725855, \"25\"],\n[54.88308205, 82.4721211333, \"33\"],\n[54.88081245, 82.47212895, \"67A\"],\n[54.8808169167, 82.4719355833, \"67\"],\n[54.8854703, 82.4715485833, \"8A\"],\n[54.8854802667, 82.4723117333, \"7\"],\n[54.8819775333, 82.4720601833, \"45\"],\n[54.8820338, 82.4715768333, \"38\"],\n[54.88505425, 82.4725552, \"11A\"],\n[54.8816020167, 82.4715219833, \"44\"],\n[54.8818502167, 82.4715604167, \"40\"],\n[54.8817451, 82.4715327167, \"42\"],\n[54.8817693333, 82.4720335, \"47\"],\n[54.8826490167, 82.4716679, \"36\"],\n[54.882937, 82.4720998667, \"35\"],\n[54.8828116667, 82.4720924167, \"37\"],\n[54.8851022, 82.4718166333, \"12\"],\n[54.8817387667, 82.47236985, \"49\"],\n[54.8812409667, 82.4710926333, \"50\"],\n[54.8815675333, 82.4723074, \"51A\"],\n[54.8816046833, 82.4720110833, \"51\"],\n[54.8812419, 82.4709490833, \"52\"],\n[54.8811635333, 82.4709188667, \"54\"],\n[54.8814256833, 82.47197785, \"55\"],\n[54.8811236333, 82.4712705167, \"56\"],\n[54.8811993, 82.4719696333, \"57\"],\n[54.88108405, 82.4714977167, \"58\"],\n[54.8809842667, 82.4719474833, \"59\"],\n[54.8809340167, 82.4725577, \"61\"],\n[54.8808571667, 82.47147535, \"62A\"],\n[54.8808698167, 82.4712961833, \"62B\"],\n[54.88095885, 82.4727073167, \"63\"],\n[54.8805953667, 82.471471, \"64\"],\n[54.8808394, 82.4727179833, \"65\"],\n[54.8856441667, 82.4723274, \"5\"],\n[54.8856559833, 82.47193445, \"6A\"],\n[54.8858045667, 82.4719521, \"6\"],\n[54.8854608833, 82.4718410833, \"8\"],\n[54.8852512333, 82.4722922833, \"9\"],\n[54.8812897833, 82.47150895, \"48\"],\n[54.8846497167, 82.4717921833, \"18\"],\n[54.8850509167, 82.4722740667, \"11\"],\n[54.8849657833, 82.4718045667, \"14\"],\n[54.8863145, 82.47202075, \"4\"],\n[54.8863136833, 82.4724193333, \"3\"],\n[54.8848130833, 82.4725039833, \"13A\"],\n[54.8848266333, 82.47225735, \"13\"],\n[54.8839960167, 82.4722167, \"19\"],\n[54.8848076833, 82.47180565, \"16\"],\n[54.8847455833, 82.4722526833, \"15\"],\n[54.8850477, 82.4726911167, \"11B\"],\n[54.8941738167, 82.4707689, \"84D\"],\n[54.8940840667, 82.4708939333, \"84C\"],\n[54.8941785, 82.4709219, \"84B\"],\n[54.8941324333, 82.47094385, \"84A\"],\n[54.8935136, 82.4612187667, \"11\"],\n[54.8939243167, 82.4608987333, \"10\"],\n[54.8933340667, 82.4717043167, \"100\"],\n[54.8936952, 82.4650319333, \"42\"],\n[54.8932683, 82.4655177833, \"41\"],\n[54.8936863667, 82.46521985, \"44\"],\n[54.8936738833, 82.4655087667, \"46\"],\n[54.8938362667, 82.4624257833, \"22\"],\n[54.8937817, 82.4635414833, \"30\"],\n[54.8938118, 82.4643993167, \"40A\"],\n[54.8937340833, 82.4643627, \"40\"],\n[54.8935297167, 82.4682022667, \"68\"],\n[54.8932907833, 82.4653249667, \"39\"],\n[54.8935900167, 82.4670001333, \"54\"],\n[54.89330695, 82.4650841, \"37\"],\n[54.8927154833, 82.4709052, \"65B\"],\n[54.8927901, 82.4708936667, \"65A\"],\n[54.8927898667, 82.4705552833, \"63A\"],\n[54.8930308333, 82.461289, \"13A\"],\n[54.8932869167, 82.46127415, \"13\"],\n[54.89365705, 82.4657872833, \"48\"],\n[54.8939401, 82.46390025, \"32A\"],\n[54.8936144167, 82.4665801333, \"52\"],\n[54.89383355, 82.4665993833, \"52A\"],\n[54.8932530667, 82.47349375, \"120\"],\n[54.8934369833, 82.4623886667, \"19\"],\n[54.8942868333, 82.4610974, \"12\"],\n[54.89390075, 82.46130575, \"14\"],\n[54.8934877, 82.4615844, \"15\"],\n[54.89438475, 82.4619340667, \"16A\"],\n[54.89440795, 82.46167145, \"16\"],\n[54.89348165, 82.4617730167, \"17\"],\n[54.8938709333, 82.46165795, \"18\"],\n[54.8933871167, 82.4633617, \"27\"],\n[54.8934256333, 82.46270255, \"21\"],\n[54.8934101, 82.4630095833, \"23\"],\n[54.8938231667, 82.4626998167, \"24\"],\n[54.8938185, 82.4629043667, \"26\"],\n[54.8933327, 82.4599851667, \"1\"],\n[54.8938655, 82.4619277667, \"20\"],\n[54.8933737667, 82.4636349, \"29\"],\n[54.8933599167, 82.4638405667, \"31\"],\n[54.8937605833, 82.4638030667, \"32\"],\n[54.8933501333, 82.4640728, \"33\"],\n[54.89409735, 82.4639711333, \"34\"],\n[54.89333535, 82.46433465, \"35\"],\n[54.8937382833, 82.4641705, \"36\"],\n[54.8938094833, 82.46310885, \"28\"],\n[54.8937422833, 82.4642690333, \"38\"],\n[54.8932706, 82.46028355, \"3A\"],\n[54.8934162167, 82.4602382333, \"3\"],\n[54.8935366333, 82.4605623667, \"5\"],\n[54.8935312, 82.4607884833, \"7\"],\n[54.89396845, 82.4602069333, \"8\"],\n[54.8935128167, 82.4609781167, \"9\"],\n[54.8932981167, 82.47301005, \"108\"],\n[54.8932691667, 82.4732267667, \"110\"],\n[54.8936267667, 82.47335325, \"112A\"],\n[54.8938256167, 82.4733656, \"112B\"],\n[54.8936103333, 82.4733669833, \"112\"],\n[54.8937215333, 82.4735637667, \"114\"],\n[54.89365715, 82.4738653167, \"116\"],\n[54.8935390333, 82.4735507333, \"118\"],\n[54.8934577667, 82.4693120833, \"70\"],\n[54.8929881833, 82.4703184667, \"59\"],\n[54.8929812667, 82.4706668833, \"63\"],\n[54.8929615667, 82.47086305, \"65\"],\n[54.8929371167, 82.4712434167, \"69\"],\n[54.8929520667, 82.47105645, \"67\"],\n[54.89367425, 82.46743525, \"58A\"],\n[54.8937744667, 82.4673928, \"58B\"],\n[54.8935667833, 82.46736855, \"58\"],\n[54.89367375, 82.4675524167, \"60A\"],\n[54.8937666333, 82.4676028333, \"60B\"],\n[54.8935516833, 82.46756615, \"60\"],\n[54.8935477333, 82.4677751333, \"62\"],\n[54.8935387833, 82.4679283333, \"64\"],\n[54.8935372333, 82.4680373167, \"66\"],\n[54.8934518, 82.4694155833, \"72\"],\n[54.8934506167, 82.4695295167, \"74\"],\n[54.8934785833, 82.4697087167, \"76\"],\n[54.8934174, 82.4705130167, \"82\"],\n[54.8934133, 82.4707143833, \"84\"],\n[54.89339765, 82.4708925667, \"86\"],\n[54.8937520167, 82.4710181667, \"88\"],\n[54.8933705, 82.47113315, \"90\"],\n[54.8934223167, 82.4702347833, \"78\"],\n[54.8933635, 82.4712602167, \"92\"],\n[54.8933623333, 82.4713753167, \"94\"],\n[54.89334455, 82.4715971333, \"98\"],\n[54.8933610333, 82.4714828333, \"96\"],\n[54.89307625, 82.4690541333, \"2/53\"],\n[54.8930733667, 82.46912325, \"3/53\"],\n[54.8930706333, 82.4691856, \"4/53\"],\n[54.89306775, 82.4692547333, \"5/53\"],\n[54.8930755833, 82.4687906833, \"47\"],\n[54.8930806333, 82.4689783167, \"1/53\"],\n[54.8937726, 82.46406345, \"36A\"],\n[54.8940399167, 82.4626443667, \"24A\"],\n[54.89306665, 82.4694318, \"57A\"],\n[54.8929485833, 82.4694292, \"57B\"],\n[54.893691, 82.4662858833, \"50\"],\n[54.892929, 82.4695717833, \"57C\"],\n[54.8818993667, 82.48831235, \"10\"],\n[54.8819047, 82.4884493667, \"9\"],\n[54.8818925167, 82.4887367833, \"8\"],\n[54.8817909833, 82.4886448, \"7\"],\n[54.88156225, 82.4884151333, \"5\"],\n[54.8816410667, 82.4884968833, \"6\"],\n[54.8817882667, 82.4881434333, \"12\"],\n[54.8820450667, 82.4880255, \"14\"],\n[54.8820399833, 82.4881601833, \"13\"],\n[54.8817013833, 82.48815045, \"11\"],\n[54.8814522333, 82.4882864667, \"4\"],\n[54.88135345, 82.4881963833, \"3\"],\n[54.89047955, 82.3660982833, \"48\"],\n[54.8939863833, 82.3676102167, \"84\"],\n[54.8908236333, 82.3668215167, \"57\"],\n[54.8927242667, 82.3669994667, \"72\"],\n[54.89707325, 82.3696241833, \"111\"],\n[54.8951834, 82.3681841167, \"96\"],\n[54.8891679333, 82.3661342, \"25\"],\n[54.8990757167, 82.4813831667, \"12\"],\n[54.8990598, 82.4826089667, \"27\"],\n[54.8996862, 82.48382855, \"34\"],\n[54.8998746167, 82.4868621833, \"99\"],\n[54.9001283, 82.4864203833, \"97\"],\n[54.9002882, 82.4875789833, \"111\"],\n[54.9004845333, 82.4875032167, \"113\"],\n[54.9005451667, 82.4877341667, \"115\"],\n[54.8987095167, 82.48150085, \"15\"],\n[54.8987892, 82.4817609, \"17\"],\n[54.8991357, 82.48159105, \"14\"],\n[54.89891375, 82.4808869667, \"10\"],\n[54.8985199667, 82.4808965667, \"11\"],\n[54.8985627833, 82.4811206333, \"13\"],\n[54.8992842667, 82.4821156167, \"18-20\"],\n[54.8988612333, 82.48195285, \"19\"],\n[54.8993973833, 82.4824338, \"22\"],\n[54.8989453833, 82.48216625, \"23\"],\n[54.8994684833, 82.4826182833, \"24\"],\n[54.8989983, 82.48239085, \"25\"],\n[54.8995365667, 82.4828116833, \"26\"],\n[54.8982566833, 82.4800233833, \"1\"],\n[54.8995900333, 82.48303525, \"28\"],\n[54.8991642833, 82.4829475167, \"29\"],\n[54.8996510167, 82.4832267667, \"30\"],\n[54.899284, 82.4832051333, \"31\"],\n[54.8983305, 82.4802590667, \"3\"],\n[54.8985982333, 82.4800186167, \"2\"],\n[54.8995170333, 82.4845078667, \"49\"],\n[54.8987404667, 82.4802334667, \"4\"],\n[54.89943635, 82.4849588167, \"77\"],\n[54.8983839667, 82.4804605, \"5\"],\n[54.8987906833, 82.4804517, \"6\"],\n[54.8997182, 82.4849414, \"81\"],\n[54.8984425333, 82.4806757, \"7\"],\n[54.8988546833, 82.4806650333, \"8\"],\n[54.8982073167, 82.4808983833, \"9\"],\n[54.9002304333, 82.4868039667, \"101\"],\n[54.8997452667, 82.48737465, \"103\"],\n[54.9001569667, 82.4873521333, \"105A\"],\n[54.90035675, 82.4871693, \"105\"],\n[54.89977645, 82.4853644833, \"85\"],\n[54.8998911833, 82.4857328667, \"93\"],\n[54.89830875, 82.4810073667, \"11A\"],\n[54.8991998, 82.4818039833, \"16\"],\n[54.9000736, 82.48765565, \"109\"],\n[54.8998738833, 82.4877091, \"107\"],\n[54.8584179167, 82.3917306, \"28C\"],\n[54.8604560167, 82.3943771, \"27\"],\n[54.8594062, 82.39328765, \"22\"],\n[54.8602464667, 82.3945281333, \"25\"],\n[54.8580738, 82.3913907167, \"28B\"],\n[54.8588583833, 82.3948410167, \"10\"],\n[54.8597253167, 82.3943257167, \"20\"],\n[54.8594598667, 82.3949546667, \"17\"],\n[54.85742675, 82.3934756833, \"28D\"],\n[54.85779025, 82.3909575667, \"28A\"],\n[54.8602461333, 82.39392145, \"24\"],\n[54.8615513167, 82.3930931833, \"30\"],\n[54.8615702833, 82.3936576333, \"41\"],\n[54.8648762167, 82.391556, \"85\"],\n[54.8669371833, 82.38969465, \"116\"],\n[54.8656294833, 82.39053055, \"96\"],\n[54.8627939333, 82.3928152833, \"57\"],\n[54.8642163, 82.3938465167, \"63B\"],\n[54.8633075167, 82.3925197167, \"63A\"],\n[54.8752946833, 82.47600165, \"16\"],\n[54.8752789, 82.4745710667, \"26\"],\n[54.8752698667, 82.474182667, \"30\"],\n[54.8752788833, 82.4747855667, \"24\"],\n[54.8753729833, 82.4773013667, \"4\"],\n[54.8752503333, 82.47339515, \"36\"],\n[54.8753239, 82.4768918333, \"8\"],\n[54.8752590667, 82.4736461333, \"34\"],\n[54.8756213167, 82.4747827833, \"25\"],\n[54.8752682333, 82.4738759333, \"32\"],\n[54.8752943, 82.47621685, \"14\"],\n[54.8755946667, 82.4783229167, \"2\"],\n[54.8757436, 82.47737735, \"7\"],\n[54.8758519, 82.4778569167, \"3\"],\n[54.8756174833, 82.4745228, \"27\"],\n[54.8756574833, 82.4762356, \"15\"],\n[54.8756050833, 82.4734895, \"33\"],\n[54.875302, 82.4766701833, \"10\"],\n[54.8756027333, 82.4736947333, \"31\"],\n[54.8752780667, 82.4758057, \"18\"],\n[54.8757905833, 82.477583, \"5\"],\n[54.8756395833, 82.4758414333, \"19\"],\n[54.8756402, 82.4760084333, \"17\"],\n[54.8752715833, 82.4751979, \"20\"],\n[54.8757130167, 82.4771411333, \"9\"],\n[54.8752756833, 82.47501635, \"22\"],\n[54.87527695, 82.47433525, \"28\"],\n[54.8756425833, 82.4752112667, \"21\"],\n[54.8752937833, 82.4764377, \"12\"],\n[54.87559675, 82.4732172, \"35\"],\n[54.8753504333, 82.477108, \"6\"],\n[54.8755737333, 82.4729657167, \"37\"],\n[54.8756244333, 82.4743205667, \"29\"],\n[54.8755172667, 82.4727099833, \"39\"],\n[54.8756327333, 82.4750188, \"23\"],\n[54.8754463333, 82.4724567833, \"41\"],\n[54.8753804667, 82.4721916167, \"43\"],\n[54.8753413, 82.4719123167, \"45\"],\n[54.8751775167, 82.4728065, \"40\"],\n[54.87523985, 82.4731198167, \"38\"],\n[54.9129636333, 82.47354695, \"15\"],\n[54.9129915667, 82.4741582833, \"10\"],\n[54.9130924, 82.4741147667, \"12\"],\n[54.91301345, 82.4738697833, \"14\"],\n[54.9125089, 82.47363755, \"3\"],\n[54.9126150667, 82.4743185833, \"4\"],\n[54.9126618333, 82.4735482833, \"5\"],\n[54.9125892, 82.47392305, \"6\"],\n[54.9127883167, 82.47388245, \"8\"],\n[54.9126731333, 82.473192, \"7\"],\n[54.91275485, 82.47314795, \"9\"],\n[54.9128106333, 82.4733799667, \"11\"],\n[54.9123932, 82.4739944667, \"2\"],\n[54.9123316833, 82.4737106167, \"1\"],\n[54.9838611667, 82.5750239333, \"209\"],\n[54.9690023333, 82.5700330333, \"12\"],\n[54.9711171, 82.5702027833, \"25\"],\n[54.9779899, 82.570433, \"1/122\"],\n[54.97820695, 82.57005845, \"2/122\"],\n[54.9800575, 82.5723918333, \"153\"],\n[54.9811843, 82.5731835, \"177\"],\n[54.9754233167, 82.57078555, \"95\"],\n[54.8838929167, 82.4818853167, \"12\"],\n[54.8837344667, 82.4818862, \"14\"],\n[54.8835817667, 82.4818741, \"16\"],\n[54.8834241, 82.4818550667, \"18\"],\n[54.8832506167, 82.48183555, \"20\"],\n[54.8830817667, 82.4818428833, \"22\"],\n[54.8828965167, 82.48182015, \"24\"],\n[54.8827122833, 82.4817928, \"26\"],\n[54.8814133667, 82.4817274333, \"44\"],\n[54.8813040833, 82.48171155, \"46\"],\n[54.8810746667, 82.4817141833, \"48\"],\n[54.8809023, 82.4816841, \"50\"],\n[54.8807272167, 82.4816891167, \"52\"],\n[54.8805686833, 82.4816589167, \"54\"],\n[54.8803979167, 82.4816530833, \"56\"],\n[54.8801843833, 82.48158535, \"58\"],\n[54.8825403667, 82.4813836167, \"32A\"],\n[54.88253505, 82.4817773, \"32\"],\n[54.8825069167, 82.48115065, \"34\"],\n[54.88240895, 82.4812873333, \"36\"],\n[54.8823411, 82.4817443167, \"38\"],\n[54.8822324, 82.4817659167, \"40\"],\n[54.8852853, 82.4825293667, \"1\"],\n[54.8852325667, 82.4820864167, \"2\"],\n[54.8856616, 82.4830290667, \"3\"],\n[54.8851546, 82.4819058667, \"4\"],\n[54.8853310833, 82.4831131333, \"5\"],\n[54.8851287833, 82.4816127333, \"6\"],\n[54.8827869667, 82.4815392833, \"26B\"],\n[54.88484925, 82.4820581167, \"8\"],\n[54.9024855, 82.4814230667, \"6\"],\n[54.9027508667, 82.48132635, \"2\"],\n[54.90267385, 82.4810493833, \"3\"],\n[54.902509, 82.4810477333, \"4\"],\n[54.90239855, 82.4812007, \"5\"],\n[54.8861399167, 82.4659005167, \"2A\"],\n[54.8858972, 82.4701092167, \"36\"],\n[54.8867484667, 82.4678494333, \"19\"],\n[54.8861574833, 82.46575525, \"2\"],\n[54.8864493167, 82.4662703167, \"3\"],\n[54.88622685, 82.47015215, \"39\"],\n[54.88624375, 82.4699778833, \"37\"],\n[54.8863943167, 82.4703065667, \"39A\"],\n[54.8858773667, 82.4704395333, \"38\"],\n[54.8866652833, 82.4663845667, \"3A\"],\n[54.8862623667, 82.4706270167, \"41\"],\n[54.8856218833, 82.4704532333, \"40\"],\n[54.8854065833, 82.4706356333, \"42B\"],\n[54.88625425, 82.4707564167, \"43\"],\n[54.88541165, 82.4704709667, \"42A\"],\n[54.8861368333, 82.47271145, \"55\"],\n[54.886122, 82.4661553833, \"4\"],\n[54.8863355167, 82.4685020667, \"27\"],\n[54.8865969667, 82.4687519167, \"29A\"],\n[54.8865831, 82.4689422667, \"31A\"],\n[54.8860333167, 82.46789315, \"20\"],\n[54.8858932167, 82.4702396667, \"36A\"],\n[54.88643745, 82.4660770167, \"1\"],\n[54.8857492, 82.46868685, \"30A\"],\n[54.8855154167, 82.4686515333, \"30B\"],\n[54.8856861, 82.46828205, \"24A\"],\n[54.8860060667, 82.4682543333, \"24\"],\n[54.8863518833, 82.4681365167, \"23\"],\n[54.8860244, 82.4680726833, \"22\"],\n[54.8860988667, 82.4665564833, \"10\"],\n[54.8863865333, 82.4673575, \"11\"],\n[54.8863826833, 82.4675404, \"13\"],\n[54.8863788667, 82.4677124167, \"15\"],\n[54.8860585833, 82.4674608333, \"14\"],\n[54.8856044667, 82.46749745, \"16A\"],\n[54.8857502, 82.46754885, \"16\"],\n[54.8864570833, 82.4677168333, \"17\"],\n[54.8860457333, 82.4676692, \"18\"],\n[54.8867451667, 82.4680089167, \"19A\"],\n[54.8858168333, 82.4717908, \"58\"],\n[54.8866057333, 82.4666266833, \"5A\"],\n[54.8864473333, 82.4665519333, \"5\"],\n[54.88573305, 82.4662191833, \"6\"],\n[54.8861234333, 82.4729670667, \"57\"],\n[54.8861040833, 82.4732588, \"59\"],\n[54.8857812833, 82.4727290333, \"62\"],\n[54.8860733167, 82.47367975, \"63\"],\n[54.8853214167, 82.47302445, \"64A\"],\n[54.8857647, 82.4729568833, \"64\"],\n[54.8860630667, 82.4741376333, \"65\"],\n[54.8855514167, 82.4731432833, \"66A\"],\n[54.8857605333, 82.4732639667, \"66\"],\n[54.88604615, 82.4744234333, \"67\"],\n[54.8857253333, 82.4734757667, \"68\"],\n[54.8860271667, 82.4749003, \"71\"],\n[54.8864273833, 82.4668194167, \"7\"],\n[54.8861134167, 82.4663483833, \"8\"],\n[54.88530955, 82.4734951667, \"72A\"],\n[54.8853649167, 82.4735031333, \"72\"],\n[54.8857145667, 82.47370235, \"74\"],\n[54.88570935, 82.4738793833, \"76\"],\n[54.8856962833, 82.4740871833, \"78\"],\n[54.8855425, 82.4740492667, \"80\"],\n[54.8855359667, 82.47421665, \"82\"],\n[54.8856920333, 82.4742632667, \"84\"],\n[54.88567285, 82.4743871833, \"86\"],\n[54.8856348, 82.47498665, \"88\"],\n[54.8864008667, 82.4671270833, \"9\"],\n[54.8859601833, 82.47522375, \"73\"],\n[54.8859930167, 82.4754003167, \"75\"],\n[54.88563045, 82.4752063667, \"90\"],\n[54.8856196667, 82.4754834167, \"94\"],\n[54.8855985333, 82.4757720333, \"98\"],\n[54.8852094333, 82.4756059333, \"96\"],\n[54.8856225333, 82.4706336667, \"44\"],\n[54.8863443167, 82.4711711167, \"45A\"],\n[54.8862241333, 82.47112885, \"45\"],\n[54.8858591, 82.4707636333, \"46\"],\n[54.8862151, 82.4713376833, \"47\"],\n[54.88584785, 82.4710055, \"48\"],\n[54.8863784667, 82.4716221167, \"49A\"],\n[54.88619305, 82.4716161667, \"49\"],\n[54.8854010167, 82.4710779333, \"50A\"],\n[54.8855194, 82.4710888, \"50\"],\n[54.8861586167, 82.4718484, \"51\"],\n[54.8855134333, 82.4712143833, \"52\"],\n[54.8858417833, 82.4713232833, \"54\"],\n[54.8858254, 82.4715816333, \"56\"],\n[54.8859913, 82.4685190667, \"28\"],\n[54.8863223167, 82.4686848833, \"29\"],\n[54.8859773333, 82.46879095, \"30\"],\n[54.8863225167, 82.4688814167, \"31\"],\n[54.8859628333, 82.4690224667, \"32\"],\n[54.8863278333, 82.4690195667, \"33\"],\n[54.8860351333, 82.4746824, \"69\"],\n[54.88563915, 82.4684005167, \"26\"],\n[54.8863489, 82.4683084, \"25\"],\n[54.8866069, 82.4673016, \"11A\"],\n[54.8868120167, 82.4673208833, \"11B\"],\n[54.88578115, 82.4680634667, \"22A\"],\n[54.8863727, 82.4679364, \"21\"],\n[54.8858363, 82.4659994, \"4A\"],\n[54.88658795, 82.4674919167, \"13A\"],\n[54.92234345, 82.4747052, \"199\"],\n[54.92177305, 82.4769218333, \"2\"],\n[54.9221347833, 82.47694995, \"1\"],\n[54.9222941667, 82.47512075, \"165\"],\n[54.9219244667, 82.4755311667, \"126\"],\n[54.92194885, 82.4751084333, \"164\"],\n[54.92227225, 82.4756573333, \"109\"],\n[54.9226473833, 82.47590455, \"105\"],\n[54.9217738833, 82.4766539667, \"38\"],\n[54.9226126333, 82.4765605333, \"45\"],\n[54.9221432333, 82.4762786, \"51\"],\n[54.92185925, 82.4759778667, \"80\"],\n[54.9219880167, 82.4744712833, \"230\"],\n[54.9213271, 82.4744695667, \"200\"],\n[54.9210363333, 82.4743909167, \"210\"],\n[54.9206876333, 82.4744863, \"220\"],\n[54.9212772667, 82.4748825167, \"184\"],\n[54.9213329, 82.4754072167, \"194\"],\n[54.92179965, 82.4763127667, \"50\"],\n[54.9226488667, 82.4760626667, \"101\"],\n[54.9224377167, 82.4742912, \"231\"],\n[54.9222663833, 82.4741209667, \"253\"],\n[54.9220891, 82.4742094833, \"250\"],\n[54.8763709833, 82.4737251167, \"6\"],\n[54.8762928, 82.4740830833, \"7\"],\n[54.8757872, 82.47372185, \"2\"],\n[54.8759274833, 82.4737143667, \"4\"],\n[54.8761889833, 82.4744309833, \"5B\"],\n[54.8760917667, 82.4744256833, \"5A\"],\n[54.8760035, 82.47408515, \"3\"],\n[54.8758006, 82.4741481167, \"1\"],\n[54.8945807833, 82.4731283, \"92\"],\n[54.8952838, 82.4659743667, \"9\"],\n[54.8945913667, 82.47286075, \"88\"],\n[54.8948307167, 82.4678840833, \"26\"],\n[54.8946495333, 82.4715883833, \"68\"],\n[54.8955784167, 82.4666195833, \"17\"],\n[54.8950308833, 82.4707890333, \"55\"],\n[54.8950268333, 82.4708643, \"57\"],\n[54.8950210333, 82.4709645333, \"59\"],\n[54.8950726167, 82.4692980667, \"35\"],\n[54.8948167167, 82.4681206667, \"28\"],\n[54.89480715, 82.4683576167, \"30\"],\n[54.89448235, 82.47392275, \"100\"],\n[54.8949025833, 82.4736886667, \"101\"],\n[54.8944604833, 82.4740989333, \"102\"],\n[54.8940345667, 82.4741795333, \"104\"],\n[54.8948037, 82.4748156667, \"105\"],\n[54.8944383833, 82.4744140333, \"106\"],\n[54.8949698833, 82.4659329667, \"10\"],\n[54.8949612167, 82.4663892333, \"12\"],\n[54.8949153, 82.46660965, \"14\"],\n[54.8948991667, 82.46678365, \"16\"],\n[54.8947661, 82.46694865, \"18A\"],\n[54.8944432333, 82.4669301, \"18B\"],\n[54.8948852, 82.4669605667, \"18\"],\n[54.8948780167, 82.46712785, \"20\"],\n[54.8944023, 82.4672810833, \"22B\"],\n[54.8947610167, 82.46729965, \"22A\"],\n[54.8948679667, 82.46733215, \"22\"],\n[54.8948783833, 82.46748345, \"1/24-7/24\"],\n[54.8947230167, 82.4702766667, \"42\"],\n[54.8946909667, 82.4707959333, \"54\"],\n[54.8946726833, 82.4711023333, \"60\"],\n[54.8946703833, 82.4712066833, \"62\"],\n[54.8946656, 82.4712626667, \"64\"],\n[54.8949888833, 82.4656431, \"6\"],\n[54.8949382, 82.4729810833, \"93\"],\n[54.8945739333, 82.47341895, \"94\"],\n[54.8949277, 82.4731673, \"95\"],\n[54.89438165, 82.4736724333, \"96A\"],\n[54.8945503667, 82.4736765833, \"96\"],\n[54.8949105333, 82.47340155, \"97A\"],\n[54.8942335833, 82.4737639667, \"98\"],\n[54.8946295667, 82.4718361, \"72\"],\n[54.89462675, 82.4719766167, \"74\"],\n[54.8949939167, 82.4719069333, \"77\"],\n[54.8946185167, 82.4722803667, \"82\"],\n[54.8949549, 82.4725255167, \"87\"],\n[54.8949826333, 82.4657729, \"8\"],\n[54.8952739667, 82.4662657333, \"11\"],\n[54.8954714167, 82.4664023833, \"13A\"],\n[54.8955781667, 82.46640275, \"13B\"],\n[54.8952808167, 82.4663722, \"13\"],\n[54.89527365, 82.4665192833, \"15\"],\n[54.8956551167, 82.4661953667, \"11B\"],\n[54.8953330833, 82.4650771, \"1\"],\n[54.8950785667, 82.469182167, \"33\"],\n[54.8950110333, 82.4654238667, \"2\"],\n[54.8950599167, 82.4704818, \"45\"],\n[54.8950526167, 82.4705562667, \"47\"],\n[54.8950517333, 82.4706304167, \"49\"],\n[54.8950748667, 82.4694276667, \"41\"],\n[54.8953314667, 82.4653118333, \"3\"],\n[54.8950057833, 82.46551395, \"4\"],\n[54.8950353, 82.4734756833, \"97\"],\n[54.8950013, 82.4717792, \"75\"],\n[54.8950426833, 82.4706778167, \"51\"],\n[54.89503905, 82.4707278833, \"53\"],\n[54.8950147333, 82.4710415167, \"61\"],\n[54.8950166833, 82.4711306, \"63\"],\n[54.8950141, 82.4712134833, \"65\"],\n[54.8950130833, 82.4712694167, \"67\"],\n[54.8950105, 82.4713271, \"69\"],\n[54.8950101667, 82.4713877667, \"71\"],\n[54.8950061333, 82.4714993167, \"73\"],\n[54.8953044, 82.4655703333, \"5\"],\n[54.8953043, 82.4657896167, \"7\"],\n[54.8948314667, 82.46896985, \"36\"],\n[54.8944233667, 82.4670945167, \"20B\"],\n[54.89476705, 82.4671119, \"20A\"],\n[54.8948155167, 82.46873695, \"34\"],\n[54.8785435, 82.4391193, \"108\"],\n[54.85482825, 82.43943885, \"372\"],\n[54.8843674667, 82.44077705, \"44\"],\n[54.8514708333, 82.44301855, \"414\"],\n[54.8786210833, 82.4386722333, \"107\"],\n[54.8536346167, 82.43854, \"2/377\"],\n[54.88482555, 82.43861845, \"37\"],\n[54.85393405, 82.4384665833, \"1/377\"],\n[54.87792065, 82.43870995, \"115\"],\n[54.8616766, 82.43942835, \"296\"],\n[54.8758269167, 82.439114, \"136\"],\n[54.8611102167, 82.4393358, \"302\"],\n[54.8630311167, 82.4365396167, \"279\"],\n[54.8653560833, 82.4373495833, \"253\"],\n[54.8757949833, 82.4386379333, \"137\"],\n[54.8786179833, 82.4342996333, \"2/105\"],\n[54.8874004, 82.4391212667, \"1/10-2/10\"],\n[54.8447363167, 82.43930545, \"482\"],\n[54.88403545, 82.4386151333, \"45\"],\n[54.8717442667, 82.4349390667, \"183\"],\n[54.8767875333, 82.4386578667, \"127\"],\n[54.8797060833, 82.4386293833, \"93\"],\n[54.8866638167, 82.4390628, \"18\"],\n[54.8791973, 82.4386315, \"97\"],\n[54.88585575, 82.4362985167, \"19\"],\n[54.8790987667, 82.4391399833, \"100\"],\n[54.8771662, 82.43926595, \"124\"],\n[54.8838361, 82.4391195833, \"48\"],\n[54.8857025667, 82.4423457333, \"30\"],\n[54.8854774667, 82.4423092, \"3/30\"],\n[54.8449495333, 82.43932215, \"480\"],\n[54.8540070333, 82.4394581833, \"376\"],\n[54.8831838833, 82.4385145, \"55\"],\n[54.8588749833, 82.4393561333, \"326\"],\n[54.86279375, 82.4385341667, \"281\"],\n[54.8445601333, 82.43930445, \"484\"],\n[54.84437095, 82.43930065, \"486\"],\n[54.8788133833, 82.4351573667, \"1/105\"],\n[54.8800643333, 82.4356186, \"1/93\"],\n[54.87918835, 82.4355875333, \"2/93\"],\n[54.88086735, 82.4358693833, \"83\"],\n[54.88697085, 82.4385406333, \"15\"],\n[54.8505857167, 82.4386953333, \"425\"],\n[54.8857656333, 82.4386266333, \"21\"],\n[54.8517299333, 82.43952155, \"404\"],\n[54.8859354667, 82.4391316833, \"20\"],\n[54.8643110167, 82.43852915, \"269\"],\n[54.8638944167, 82.4352222, \"271\"],\n[54.8629044167, 82.4394276667, \"280\"],\n[54.8636698333, 82.4384519167, \"273\"],\n[54.87065885, 82.4387204333, \"197\"],\n[54.870552, 82.4392104333, \"198\"],\n[54.86847865, 82.4362560333, \"215\"],\n[54.8682894833, 82.4387331667, \"221\"],\n[54.8723437333, 82.4386659167, \"179\"],\n[54.8713473833, 82.4386830333, \"191\"],\n[54.8803684, 82.4391223, \"84\"],\n[54.8801818167, 82.4386532333, \"89\"],\n[54.8795138833, 82.4391232667, \"98\"],\n[54.88233015, 82.4385688167, \"67\"],\n[54.8822730833, 82.439127, \"68\"],\n[54.8815140333, 82.4385229167, \"75\"],\n[54.88161725, 82.43921275, \"76\"],\n[54.88298115, 82.4391210167, \"60\"],\n[54.88356985, 82.44183935, \"54\"],\n[54.88688885, 82.4390723333, \"16\"],\n[54.8854630667, 82.44062525, \"1/30\"],\n[54.8857315833, 82.4406345667, \"2/30\"],\n[54.8850814333, 82.4391024667, \"32\"],\n[54.85615335, 82.4394051333, \"358\"],\n[54.8484322833, 82.4386304333, \"451\"],\n[54.849595, 82.4395278833, \"438\"],\n[54.8685579333, 82.43929385, \"222\"],\n[54.8673376667, 82.4387301333, \"231\"],\n[54.8672263, 82.4391822833, \"234\"],\n[54.8658104, 82.4384541833, \"249\"],\n[54.8650818333, 82.4384285833, \"257\"],\n[54.8572850833, 82.4388435667, \"345\"],\n[54.8695889833, 82.4385987333, \"207\"],\n[54.8444514833, 82.4388799167, \"483\"],\n[54.8828889333, 82.4356993, \"51\"],\n[54.8832340833, 82.4358504, \"1/51\"],\n[54.8573635, 82.4392901833, \"342\"],\n[54.86163445, 82.43881845, \"295\"],\n[54.8624819833, 82.438809, \"287\"],\n[54.84347995, 82.4385449833, \"495\"],\n[54.85704685, 82.4422632333, \"346\"],\n[54.8881785167, 82.4536787833, \"11\"],\n[54.8876931833, 82.4532197833, \"5\"],\n[54.887782833, 82.4536870667, \"7\"],\n[54.8883681, 82.4535562333, \"2/10\"],\n[54.88862675, 82.4537201667, \"4/10\"],\n[54.88857235, 82.4536184167, \"3/10\"],\n[54.88834935, 82.45339255, \"1/10\"],\n[54.8880737833, 82.4534382833, \"9\"],\n[54.88862905, 82.4582377167, \"8\"],\n[54.888388, 82.4577553167, \"5A\"],\n[54.8890413167, 82.4584074, \"10A\"],\n[54.8890455167, 82.45818135, \"10\"],\n[54.8893714, 82.4579083667, \"1\"],\n[54.8891550333, 82.4579009333, \"2\"],\n[54.8889156, 82.45789245, \"3\"],\n[54.8887209667, 82.4578687833, \"4\"],\n[54.8885121, 82.45785425, \"5\"],\n[54.8884355167, 82.4579579333, \"6\"],\n[54.8884670667, 82.4581608667, \"7\"],\n[54.88885115, 82.4581993167, \"9\"],\n[54.88829695, 82.4581456, \"7A\"],\n[54.89493095, 82.50293945, \"2/207\"],\n[54.8939846833, 82.4919359167, \"1/143\"],\n[54.9326599333, 82.5720857333, \"946\"],\n[54.8940428667, 82.4929087, \"2/143\"],\n[54.93985015, 82.5776648, \"1006\"],\n[54.9234984333, 82.5621109333, \"816\"],\n[54.9374057, 82.57533755, \"1004\"],\n[54.92045495, 82.5594362667, \"773\"],\n[54.9370037333, 82.5752245333, \"1002\"],\n[54.9233134, 82.5619061667, \"814\"],\n[54.9247701333, 82.5642938333, \"838\"],\n[54.9091874667, 82.5318147333, \"504\"],\n[54.90968075, 82.53436585, \"525\"],\n[54.9100798667, 82.53351915, \"518\"],\n[54.9137304333, 82.5349179, \"560\"],\n[54.9131590333, 82.53488155, \"558\"],\n[54.9072097667, 82.5257719, \"458\"],\n[54.89594205, 82.4996267667, \"178\"],\n[54.9372702, 82.57594035, \"1013\"],\n[54.89638255, 82.5065894833, \"246\"],\n[54.8968645833, 82.50876055, \"259\"],\n[54.8980340833, 82.5096747833, \"276\"],\n[54.8986749667, 82.5105449167, \"280\"],\n[54.89924075, 82.5129982667, \"295\"],\n[54.9015737, 82.515433, \"324\"],\n[54.91571275, 82.5534373, \"705\"],\n[54.9162442833, 82.5534827, \"706\"],\n[54.9148016833, 82.54767885, \"648\"],\n[54.9148501, 82.5499118333, \"673\"],\n[54.9151485667, 82.5495203167, \"660\"],\n[54.9197264, 82.5575957333, \"748\"],\n[54.9212959167, 82.5604435167, \"787\"],\n[54.9255722167, 82.5660694167, \"852\"],\n[54.9026268333, 82.5172354667, \"356\"],\n[54.8950368333, 82.5025268833, \"1/207\"],\n[54.9122779833, 82.5393717167, \"2/573\"],\n[54.9114679667, 82.5398593333, \"3/573\"],\n[54.91540075, 82.5527015167, \"699\"],\n[54.9012012167, 82.51619825, \"335\"],\n[54.9168711667, 82.5553676, \"719\"],\n[54.982395667, 82.5561893167, \"723\"],\n[54.9180392833, 82.5566833, \"739\"],\n[54.9130946167, 82.5474586167, \"637\"],\n[54.8940036333, 82.4831404833, \"29\"],\n[54.8943207667, 82.4865820833, \"69\"],\n[54.8943952833, 82.4886118, \"71\"],\n[54.8951511833, 82.4905976667, \"112\"],\n[54.90356905, 82.5202661333, \"379\"],\n[54.9042539, 82.5213877833, \"391\"],\n[54.9058724667, 82.5242790667, \"427\"],\n[54.9355250333, 82.57499645, \"987\"],\n[54.9134563333, 82.5426692667, \"603\"],\n[54.9135913667, 82.54315755, \"607\"],\n[54.91401355, 82.5428852833, \"608\"],\n[54.9106131167, 82.5359661167, \"539\"],\n[54.9111353167, 82.53571595, \"542\"],\n[54.9113920167, 82.5360293167, \"546\"],\n[54.9121793167, 82.5377621, \"568\"],\n[54.9346634, 82.5743922333, \"979\"],\n[54.9374423833, 82.5674758833, \"972\"],\n[54.9156359, 82.55118655, \"692\"],\n[54.9155415167, 82.5508029, \"690\"],\n[54.90281625, 82.51905675, \"373\"],\n[54.9027791333, 82.582252833, \"358\"],\n[54.8958690833, 82.5018481167, \"190\"],\n[54.9789857333, 82.4405075667, \"168\"],\n[54.9695422, 82.4324544167, \"23\"],\n[54.9694634, 82.4313197333, \"12\"],\n[54.9734056167, 82.4391843667, \"105\"],\n[54.9748037833, 82.4419470833, \"123\"],\n[54.9775236, 82.4415263333, \"155\"],\n[54.9782757667, 82.44079755, \"166\"],\n[54.9718126167, 82.4347789833, \"54\"],\n[54.8974829, 82.4523839667, \"11\"],\n[54.896949, 82.4538974333, \"10\"],\n[54.8973599167, 82.4533428167, \"3\"],\n[54.89717915, 82.4544804167, \"4\"],\n[54.8973309833, 82.45308765, \"5\"],\n[54.8972213833, 82.4542655167, \"6\"],\n[54.8972975167, 82.452858, \"7\"],\n[54.8971736167, 82.4540106333, \"8\"],\n[54.8972301333, 82.4525011667, \"9\"],\n[54.8962831, 82.4514132833, \"40\"],\n[54.8962904167, 82.4509267333, \"42\"],\n[54.8964889167, 82.4515006167, \"44\"],\n[54.8966648, 82.4514576667, \"46\"],\n[54.8963241333, 82.4516917333, \"38\"],\n[54.8971486, 82.4537583167, \"12\"],\n[54.8974914833, 82.4522686333, \"13\"],\n[54.8968280167, 82.4517962167, \"32\"],\n[54.8965602833, 82.4518541, \"34\"],\n[54.8963553, 82.4518366333, \"36\"],\n[54.8972173667, 82.4551419333, \"2\"],\n[54.8970665667, 82.45323925, \"14\"],\n[54.8971966, 82.4522688167, \"15\"],\n[54.8968064, 82.4532278167, \"16\"],\n[54.8967456833, 82.4531232333, \"18\"],\n[54.8974595167, 82.4539856833, \"1\"],\n[54.89702105, 82.4529966167, \"20\"],\n[54.89697325, 82.4525840667, \"22\"],\n[54.8966754833, 82.45262025, \"24\"],\n[54.8965024, 82.4525581333, \"26\"],\n[54.8967277167, 82.4524711167, \"28\"],\n[54.8969411167, 82.4523854, \"30\"],\n[54.8971252667, 82.4517190167, \"17\"],\n[54.8973954333, 82.4516434667, \"19\"],\n[54.89734885, 82.4512056667, \"27\"],\n[54.8975603333, 82.4513639167, \"23\"],\n[54.8975662667, 82.45155165, \"21\"],\n[54.89758735, 82.45118755, \"25\"],\n[54.8976514, 82.4505551833, \"25A\"],\n[54.93618265, 82.4679452833, \"99\"],\n[54.9364427, 82.47434405, \"47\"],\n[54.93602995, 82.4635648833, \"143\"],\n[54.9363754167, 82.4732709667, \"55\"],\n[54.9364611, 82.47575415, \"37\"],\n[54.9362570167, 82.4694700833, \"89\"],\n[54.9356639667, 82.4542221333, \"225\"],\n[54.9365317333, 82.4564987833, \"201\"],\n[54.9357644333, 82.45652615, \"1/201\"],\n[54.9356391667, 82.4555529667, \"209\"],\n[54.9359229, 82.4614506167, \"157\"],\n[54.9354519, 82.4510958, \"245\"],\n[54.8043647667, 82.3646767, \"9\"],\n[54.8033645333, 82.3644417333, \"14\"],\n[54.8041373, 82.3641572833, \"11\"],\n[54.9559902833, 82.4358548667, \"1/3116\"],\n[54.9541933, 82.43567675, \"3126\"],\n[54.9159823833, 82.4458315667, \"2/3627\"],\n[54.91406535, 82.4497318167, \"3668\"],\n[54.9555601667, 82.4360378833, \"2/3116\"],\n[54.9139425833, 82.4497730667, \"3666\"],\n[54.9160902, 82.4453786667, \"1/3627\"],\n[54.9619189333, 82.4331309167, \"3032\"],\n[54.9609963833, 82.4328218833, \"3039\"],\n[54.9616219333, 82.4333006833, \"3036\"],\n[54.9329983333, 82.4291615333, \"3361\"],\n[54.9152040667, 82.4487561167, \"3654\"],\n[54.9319928333, 82.430282167, \"3384\"],\n[54.91578065, 82.4478569, \"3642\"],\n[54.9157454833, 82.4465326333, \"3635\"],\n[54.9151056, 82.4479749833, \"3643\"],\n[54.91545865, 82.4473662167, \"3639\"],\n[54.9155843167, 82.4470310167, \"3637\"],\n[54.9027715667, 82.45210165, \"3794\"],\n[54.9032760833, 82.4549883, \"3784\"],\n[54.9748930833, 82.4242103667, \"2855\"],\n[54.9773033833, 82.42065365, \"2829\"],\n[54.9444458667, 82.4188207667, \"3217\"],\n[54.9012992833, 82.4500824333, \"3807\"],\n[54.9127339333, 82.4503371, \"3682\"],\n[54.90071495, 82.4536467833, \"3829\"],\n[54.9048702167, 82.45171675, \"2/3774\"],\n[54.9001265, 82.4627736833, \"3910\"],\n[54.8984810667, 82.4580702, \"2/3879\"],\n[54.8987156833, 82.45782225, \"3/3879\"],\n[54.8996284833, 82.4598028333, \"3886\"],\n[54.91662675, 82.4488524167, \"3648\"],\n[54.9105417167, 82.4505777, \"3714\"],\n[54.9047285333, 82.458219, \"1/3774\"],\n[54.98387015, 82.4128784667, \"2/2724\"],\n[54.9836752333, 82.4125610667, \"1/2724\"],\n[54.8997874, 82.4596524, \"2/3886\"],\n[54.8999206167, 82.4595150667, \"3/3886\"],\n[54.9052384833, 82.4516238333, \"3/3774\"],\n[54.9009602667, 82.4546291667, \"3846\"],\n[54.89997485, 82.4588545167, \"3890\"],\n[54.9160101833, 82.4469321333, \"3636\"],\n[54.9504464333, 82.43548145, \"3164\"],\n[54.90139465, 82.4518174, \"3808\"],\n[54.9003306333, 82.4547485333, \"3831\"],\n[54.9150642, 82.4457459, \"3631\"],\n[54.9700292833, 82.4302066, \"2954\"],\n[54.9719347833, 82.4284579333, \"2920\"],\n[54.9684611833, 82.4302354667, \"2959\"],\n[54.9638249667, 82.4310026333, \"3011\"],\n[54.9635499667, 82.4311723667, \"3013\"],\n[54.9621262833, 82.4321201167, \"3025\"],\n[54.9599553667, 82.4336584667, \"3059\"],\n[54.9593913167, 82.4346581667, \"3072\"],\n[54.9671775, 82.4315904833, \"2978\"],\n[54.9654828167, 82.4323972833, \"2996\"],\n[54.9304655333, 82.4298457167, \"3403\"],\n[54.9397400667, 82.4320840667, \"3292\"],\n[54.9397871333, 82.4311546, \"3299\"],\n[54.93902, 82.4299714, \"3301\"],\n[54.93884655, 82.4297564667, \"3311\"],\n[54.9378664, 82.42977575, \"3320\"],\n[54.9375432, 82.42891805, \"3321\"],\n[54.9370408, 82.4289005833, \"3331\"],\n[54.9364621167, 82.4289989833, \"3337\"],\n[54.9358432667, 82.4290959667, \"3339\"],\n[54.95477045, 82.4310178833, \"3103\"],\n[54.9508932667, 82.4345944, \"3163\"],\n[54.9502843833, 82.4345016333, \"3169\"],\n[54.9476339333, 82.4348761333, \"1/3200\"],\n[54.9459382167, 82.4300649167, \"3215\"],\n[54.9294075333, 82.4304862, \"3414\"],\n[54.9292768667, 82.4300710167, \"3415\"],\n[54.9481910333, 82.43494365, \"2/3200\"],\n[54.9276201333, 82.4302237167, \"3433\"],\n[54.9263022167, 82.4323864333, \"3456\"],\n[54.9577552167, 82.43514095, \"3090\"],\n[54.9559199, 82.4356498167, \"3110\"],\n[54.9556312, 82.4352157667, \"3111\"],\n[54.9541667833, 82.4350528333, \"3127\"],\n[54.924353, 82.43477375, \"3488\"],\n[54.92140285, 82.4361990333, \"3521\"],\n[54.9216205, 82.4367220333, \"3522\"],\n[54.9199150167, 82.4372039667, \"3537\"],\n[54.9191848333, 82.4377457167, \"3553\"],\n[54.91800785, 82.4398907667, \"3571\"],\n[54.982554, 82.4427753167, \"3596\"],\n[54.9167918667, 82.4434860333, \"3611\"],\n[54.9154718333, 82.4484893833, \"3650\"],\n[54.91254, 82.4489284667, \"3693\"],\n[54.9096463167, 82.4500162167, \"3715\"],\n[54.9095109, 82.45076725, \"3718\"],\n[54.90312135, 82.4513793, \"3791\"],\n[54.9025248833, 82.4514848833, \"3797\"],\n[54.9027026, 82.4521118333, \"3796\"],\n[54.9012756, 82.4523393333, \"3809\"],\n[54.9000247833, 82.4550734667, \"3847\"],\n[54.8996109167, 82.45623955, \"3853\"],\n[54.8990466, 82.4570460167, \"3861\"],\n[54.8982341833, 82.4584695333, \"1/3879\"],\n[54.9037354333, 82.4513122, \"3783\"],\n[54.9164707667, 82.4457016833, \"3626\"],\n[54.9005404, 82.4554475167, \"3838\"],\n[54.92350345, 82.4354481833, \"3498\"],\n[54.92093435, 82.4372154, \"3528\"],\n[54.9733884167, 82.4270654167, \"2900\"],\n[54.9735011833, 82.426221, \"2883\"],\n[54.9737880333, 82.4258421667, \"2881\"],\n[54.9736479167, 82.4268099667, \"2882\"],\n[54.8857180167, 82.4319128667, \"1/1699\"],\n[54.8762356, 82.4124507167, \"1498\"],\n[54.8760383833, 82.4119469333, \"1494\"],\n[54.8881260667, 82.4328696, \"2/1715\"],\n[54.8866376, 82.4333463667, \"1/1715\"],\n[54.8884282, 82.4323350167, \"1714\"],\n[54.8881726667, 82.44522875, \"1835A\"],\n[54.8828618833, 82.42668015, \"1643\"],\n[54.8875062667, 82.4321305667, \"1713\"],\n[54.8891637, 82.4487508333, \"1863\"],\n[54.8890458667, 82.4450934833, \"1835\"],\n[54.8893503667, 82.4505826167, \"1881\"],\n[54.8892833167, 82.4493800333, \"1871\"],\n[54.88967995, 82.44903065, \"1866\"],\n[54.8897650833, 82.45173775, \"1894\"],\n[54.88972655, 82.4509517833, \"1886\"],\n[54.8893972, 82.4519753167, \"1895\"],\n[54.8893728833, 82.4515209833, \"1891\"],\n[54.8893832667, 82.458283333, \"1893\"],\n[54.88975065, 82.4512729833, \"1888\"],\n[54.8897555167, 82.4524542333, \"1896\"],\n[54.8789651833, 82.4203288667, \"1567\"],\n[54.8891086, 82.4330816833, \"1716\"],\n[54.8749076, 82.4095179667, \"1466\"],\n[54.8766546833, 82.41371075, \"1510\"],\n[54.87762145, 82.4159128833, \"1532\"],\n[54.8778396333, 82.41638935, \"1534\"],\n[54.8784475833, 82.482476, \"1544\"],\n[54.8789228667, 82.4189449833, \"1560\"],\n[54.8838774833, 82.4277925667, \"1659\"],\n[54.8865829, 82.4310726667, \"2/1699\"],\n[54.8869873, 82.4315526833, \"1705\"],\n[54.8887145167, 82.4342103167, \"1735\"],\n[54.8886082667, 82.4386434, \"1786\"],\n[54.8888977833, 82.4397067833, \"1788\"],\n[54.8889447833, 82.4399386, \"1790\"],\n[54.8891184, 82.4403393, \"1800\"],\n[54.8886052167, 82.44114285, \"1811\"],\n[54.8890688833, 82.4442045667, \"1829\"],\n[54.8894286667, 82.4442416167, \"1830\"],\n[54.8894495167, 82.4447870333, \"1832\"],\n[54.8894350833, 82.4526888167, \"1903\"],\n[54.8898216167, 82.45284305, \"1902\"],\n[54.8898244333, 82.45305355, \"1906\"],\n[54.8895077667, 82.4534430333, \"1907\"],\n[54.8895153, 82.4539427833, \"1913\"],\n[54.8820731, 82.4246370667, \"1/1628\"],\n[54.8829790333, 82.42515415, \"2/1628\"],\n[54.8829182333, 82.42331235, \"3/1628\"],\n[54.8846927167, 82.4287510833, \"1669\"],\n[54.8857990667, 82.4293535333, \"1682\"],\n[54.8859693167, 82.4303029167, \"1/1689\"],\n[54.8861213333, 82.4304782, \"1689\"],\n[54.9054227833, 82.4822613, \"5\"],\n[54.90567515, 82.4819121167, \"6\"],\n[54.9058446667, 82.4825176167, \"10\"],\n[54.9057151167, 82.4832514, \"11\"],\n[54.9059177, 82.4827449333, \"12\"],\n[54.9062382833, 82.48278225, \"14\"],\n[54.9059932667, 82.4830166333, \"16\"],\n[54.90537935, 82.4821119, \"3\"],\n[54.9055974, 82.4816880167, \"4\"],\n[54.9055800167, 82.4827762667, \"7\"],\n[54.9053443333, 82.4819134167, \"1\"],\n[54.9056483167, 82.4830068333, \"9\"],\n[54.9687541667, 82.5740302667, \"1149\"],\n[54.9203192833, 82.5148173833, \"4/319\"],\n[54.9566814833, 82.5624372, \"1/978\"],\n[54.95688745, 82.5621776167, \"2/978\"],\n[54.9580920167, 82.5647472333, \"995\"],\n[54.92775475, 82.5378236667, \"2/568\"],\n[54.92609085, 82.5347061333, \"1/542\"],\n[54.9266186167, 82.5349056333, \"2/542\"],\n[54.9269626167, 82.5353566167, \"3/542\"],\n[54.9208396833, 82.5299344667, \"422\"],\n[54.9207653333, 82.5242669667, \"387\"],\n[54.9178039333, 82.49454775, \"140\"],\n[54.9456599, 82.5548334167, \"2/836\"],\n[54.9455115167, 82.5542481167, \"1/836\"],\n[54.9194724833, 82.5061424833, \"238\"],\n[54.9193864333, 82.5055969833, \"232\"],\n[54.982102167, 82.49730755, \"159\"],\n[54.9307227667, 82.53812715, \"1/618-10/618\"],\n[54.9369806, 82.5416204833, \"648A\"],\n[54.93400485, 82.5405088167, \"648\"],\n[54.9352812167, 82.5418752167, \"656\"],\n[54.9261541333, 82.5367970667, \"564\"],\n[54.9276279, 82.5381303167, \"1/568\"],\n[54.9461318333, 82.5545134167, \"842\"],\n[54.94315595, 82.5537148, \"806\"],\n[54.9464287167, 82.5549129667, \"844\"],\n[54.9713060833, 82.57780675, \"1198\"],\n[54.9403528, 82.5492173333, \"748\"],\n[54.9406445667, 82.5496667833, \"1/750\"],\n[54.9282707, 82.5363209167, \"7/568\"],\n[54.9188207333, 82.505113, \"225\"],\n[54.9388163333, 82.5467693, \"714\"],\n[54.9405476, 82.5503991667, \"749\"],\n[54.94102555, 82.55021985, \"750\"],\n[54.94425745, 82.5552436333, \"819\"],\n[54.9459448333, 82.55501645, \"838\"],\n[54.9465835833, 82.5559441, \"845\"],\n[54.9472323167, 82.5550552833, \"850\"],\n[54.9479511833, 82.5562512667, \"1/861\"],\n[54.9481898667, 82.55635715, \"2/861\"],\n[54.9500993333, 82.5559819167, \"888\"],\n[54.95089095, 82.5580154, \"899\"],\n[54.9289862833, 82.5364012833, \"6/568\"],\n[54.9653755, 82.5702818667, \"1099\"],\n[54.9299398667, 82.5377803667, \"3/610\"],\n[54.9297131333, 82.5382649, \"2/610\"],\n[54.92950415, 82.5389677333, \"1/610\"],\n[54.9285464333, 82.53936505, \"601\"],\n[54.92981565, 82.5365770833, \"568\"],\n[54.9335473333, 82.5403341667, \"646\"],\n[54.9331034167, 82.5400956, \"642\"],\n[54.9327759167, 82.538732, \"640\"],\n[54.9334526333, 82.5387036667, \"638\"],\n[54.93320675, 82.5383744833, \"636\"],\n[54.9336129167, 82.5375626, \"634\"],\n[54.93288865, 82.5381226667, \"632\"],\n[54.9327198833, 82.53720065, \"630\"],\n[54.93255565, 82.53790585, \"628\"],\n[54.93178035, 82.5394509333, \"626\"],\n[54.9186410667, 82.5002110833, \"182\"],\n[54.9172343667, 82.4951996667, \"139\"],\n[54.9180053667, 82.5002946167, \"183\"],\n[54.9174022167, 82.4964858167, \"151\"],\n[54.9234301333, 82.5355513833, \"516\"],\n[54.9434775667, 82.5532109833, \"808\"],\n[54.93984305, 82.5484721667, \"742\"],\n[54.9705266833, 82.57732895, \"182\"],\n[54.9272626167, 82.53717615, \"3/568\"],\n[54.9532905667, 82.5580751833, \"926\"],\n[54.9528798333, 82.5576940667, \"924\"],\n[54.9659760333, 82.5710443833, \"1/1111\"],\n[54.9396966667, 82.5481831, \"740\"],\n[54.9128371, 82.4832793167, \"19\"],\n[54.9140123833, 82.4838446333, \"26\"],\n[54.9172423167, 82.4912675833, \"106\"],\n[54.91736885, 82.4918037833, \"110\"],\n[54.9824985, 82.4930980167, \"120\"],\n[54.9169178833, 82.4926386, \"121\"],\n[54.9163286667, 82.4889877833, \"85\"],\n[54.9169649167, 82.4891728833, \"86\"],\n[54.9165898167, 82.4905852833, \"97\"],\n[54.9139972667, 82.4850735, \"37\"],\n[54.9158482667, 82.48707945, \"68\"],\n[54.9195504667, 82.5065384833, \"240\"],\n[54.9197355333, 82.5077362, \"256\"],\n[54.9187252667, 82.5091617167, \"263\"],\n[54.9196476833, 82.5108055333, \"277\"],\n[54.9202849333, 82.5111623667, \"300\"],\n[54.9206995667, 82.5135292833, \"1/314\"],\n[54.9207361, 82.5138259667, \"2/314\"],\n[54.9562101, 82.5616106, \"972\"],\n[54.9204318667, 82.5155629167, \"1/319\"],\n[54.9203768167, 82.5151516333, \"2/319\"],\n[54.91788475, 82.51599185, \"3/319\"],\n[54.9208983667, 82.5150343667, \"322\"],\n[54.9207446167, 82.5174052333, \"355\"],\n[54.9213706667, 82.5182903833, \"364\"],\n[54.9209673667, 82.5228385667, \"381\"],\n[54.9121427, 82.48111095, \"1\"],\n[54.9210744167, 82.526721, \"398\"],\n[54.92060065, 82.5267811333, \"421\"],\n[54.9203042167, 82.53031625, \"441\"],\n[54.9205438667, 82.5322192667, \"472\"],\n[54.95440025, 82.5603198167, \"949\"],\n[54.9549745833, 82.5610077, \"955\"],\n[54.9557622833, 82.5620862333, \"971\"],\n[54.95699575, 82.56162575, \"976\"],\n[54.96071475, 82.5671597833, \"1043\"],\n[54.95945125, 82.5654647667, \"1048\"],\n[54.9618459333, 82.56799375, \"1/1049\"],\n[54.9616152833, 82.5678077833, \"2/1049\"],\n[54.9661303667, 82.5708020833, \"2/1111\"],\n[54.9667493333, 82.57131025, \"1115\"],\n[54.96711415, 82.5715806667, \"1117\"],\n[54.9675804833, 82.5719935, \"1121\"],\n[54.9684296167, 82.5727105333, \"1133\"],\n[54.9470393333, 82.5592361, \"859\"],\n[54.91908795, 82.5034454, \"1/222\"],\n[54.9190107333, 82.5030951833, \"2/222\"],\n[54.9182063667, 82.4975724833, \"162\"],\n[54.9215276333, 82.5398657167, \"338\"],\n[54.9214903, 82.5403513167, \"347\"],\n[54.9192073833, 82.5385113667, \"60\"],\n[54.9194124167, 82.53863005, \"70\"],\n[54.9202965333, 82.5390272333, \"170\"],\n[54.9202201333, 82.5394256333, \"187\"],\n[54.9200427667, 82.5393355, \"165\"],\n[54.9196745333, 82.5387265333, \"110\"],\n[54.9196443833, 82.5391287333, \"113\"],\n[54.9200210333, 82.5388776, \"148\"],\n[54.9198508167, 82.5392385667, \"139\"],\n[54.9198443833, 82.53880195, \"130\"],\n[54.92078415, 82.5393372, \"240\"],\n[54.9203728, 82.5395211833, \"205\"],\n[54.92054995, 82.5391807, \"218\"],\n[54.9207016833, 82.53928345, \"222\"],\n[54.9204983167, 82.5396219333, \"225\"],\n[54.9206377, 82.5392380167, \"220\"],\n[54.9209028833, 82.53941765, \"1/258\"],\n[54.9206256667, 82.5397483667, \"243\"],\n[54.92098855, 82.5394799, \"2/258\"],\n[54.9211211, 82.54010905, \"303\"],\n[54.9207808, 82.5398586, \"261\"],\n[54.9209433167, 82.5399736333, \"285\"],\n[54.9210710833, 82.53953355, \"3/258\"],\n[54.9213220667, 82.54020665, \"325\"],\n[54.9213740167, 82.5397642, \"320\"],\n[54.9216746167, 82.5399703333, \"356\"],\n[54.9217735667, 82.5401128333, \"370\"],\n[54.9216458, 82.5405448833, \"373\"],\n[54.92187255, 82.54025525, \"386\"],\n[54.9219284333, 82.5408441667, \"401\"],\n[54.9103304833, 82.4721328333, \"10\"],\n[54.9102787167, 82.4719914, \"11\"],\n[54.9108774833, 82.4715148, \"1\"],\n[54.91067615, 82.4716186, \"3\"],\n[54.9107711833, 82.4719261333, \"4\"],\n[54.9105010667, 82.4716637167, \"5\"],\n[54.9106344833, 82.4720128, \"6\"],\n[54.9103480333, 82.4717653333, \"7\"],\n[54.91015655, 82.4718258167, \"9\"],\n[54.9104869167, 82.47212505, \"8\"],\n[54.8164228, 82.5139775667, \"1\"],\n[54.8062942167, 82.5133165, \"174\"],\n[54.8153860333, 82.5132536167, \"21\"],\n[54.8101489667, 82.5102431, \"70\"],\n[54.81422025, 82.5124331667, \"36\"],\n[54.8662685833, 82.38685585, \"101\"],\n[54.8696932667, 82.3909689667, \"156\"],\n[54.86591225, 82.38439815, \"82\"],\n[54.8665148, 82.3851989333, \"100\"],\n[54.8672423833, 82.385944, \"102\"],\n[54.8633081833, 82.3778155667, \"18\"],\n[54.8628883333, 82.3783555833, \"20\"],\n[54.8633668167, 82.3794526667, \"34\"],\n[54.8687968833, 82.3875604333, \"124\"],\n[54.87375745, 82.4073473, \"309\"],\n[54.871102, 82.3963777667, \"206\"],\n[54.8643377167, 82.3813198167, \"48A\"],\n[54.8647317667, 82.38235055, \"62\"],\n[54.8653946, 82.3839015333, \"72\"],\n[54.8691804167, 82.3885183, \"136\"],\n[54.8695428667, 82.3900536333, \"150\"],\n[54.8708532667, 82.3954820167, \"200\"],\n[54.8696376833, 82.3931483, \"165\"],\n[54.8708364167, 82.3980991167, \"221\"],\n[54.8769260167, 82.3983096333, \"256B\"],\n[54.8739190333, 82.4060778667, \"298\"],\n[54.8736307833, 82.4070128, \"307\"],\n[54.8743770667, 82.4077305, \"316\"],\n[54.8703100667, 82.3894640833, \"146\"],\n[54.8697010667, 82.39052375, \"154\"],\n[54.8641413167, 82.3808931667, \"48E\"],\n[54.8673080333, 82.3779883667, \"48B\"],\n[54.8673718333, 82.3785550833, \"48C\"],\n[54.8674977833, 82.3793694333, \"48D\"],\n[54.86895095, 82.3799414833, \"66B\"],\n[54.8626150667, 82.3776425167, \"14\"],\n[54.87166565, 82.3986665667, \"254A\"],\n[54.8723313833, 82.4007501, \"256A\"],\n[54.8728116833, 82.4024396333, \"276A\"],\n[54.8735445333, 82.4044031333, \"276B\"],\n[54.8788183833, 82.3998753, \"276C\"],\n[54.8700288, 82.39251035, \"170\"],\n[54.8700618833, 82.3926480833, \"172\"],\n[54.87032565, 82.3935790167, \"182\"],\n[54.87129395, 82.3971019667, \"210\"],\n[54.8684687167, 82.3787688, \"66A\"],\n[54.86917345, 82.3816180667, \"66\"],\n[54.8994036333, 82.46781995, \"2\"],\n[54.89908445, 82.46789945, \"3\"],\n[54.8992924, 82.46819555, \"4\"],\n[54.8990193667, 82.4681169167, \"5\"],\n[54.8994638333, 82.46840135, \"6\"],\n[54.8988995167, 82.4683006333, \"7\"],\n[54.8992033, 82.46852295, \"8\"],\n[54.8866583833, 82.4532039667, \"33F\"],\n[54.8864233833, 82.4521969667, \"32\"],\n[54.8866203333, 82.4534927833, \"33E\"],\n[54.8874682, 82.45179065, \"24A\"],\n[54.8826686, 82.4521089833, \"48\"],\n[54.8871881167, 82.4517683, \"26A\"],\n[54.8891620833, 82.4522299333, \"2A\"],\n[54.8870288833, 82.458263333, \"28A\"],\n[54.8847421333, 82.4521349667, \"46\"],\n[54.8866198667, 82.4517700333, \"30A\"],\n[54.8847517, 82.4530716833, \"49\"],\n[54.8864979167, 82.4517625333, \"32A\"],\n[54.8877413167, 82.4522157, \"22\"],\n[54.8875273, 82.4522017833, \"24\"],\n[54.8886485, 82.4522158667, \"10\"],\n[54.8863276167, 82.4526999167, \"39\"],\n[54.8872459167, 82.4521917333, \"26\"],\n[54.8869694333, 82.4521850167, \"28\"],\n[54.8884949833, 82.4526693667, \"11\"],\n[54.8884365167, 82.4522167833, \"12\"],\n[54.8883604667, 82.45266065, \"13\"],\n[54.88909265, 82.4527732833, \"1A\"],\n[54.8890918, 82.4526509167, \"1\"],\n[54.8892247667, 82.4522300833, \"2\"],\n[54.8889543167, 82.4526548333, \"3\"],\n[54.88878835, 82.4526679667, \"5\"],\n[54.8879826333, 82.4526516667, \"17\"],\n[54.8879732333, 82.4522717, \"18\"],\n[54.8876465167, 82.4529919333, \"21\"],\n[54.8874666333, 82.4526953333, \"23\"],\n[54.88718005, 82.45269155, \"27\"],\n[54.88667215, 82.4527091167, \"35\"],\n[54.8865333667, 82.452713, \"37\"],\n[54.8869211167, 82.4527025667, \"31\"],\n[54.8889064667, 82.45167665, \"6\"],\n[54.8887104, 82.4530365333, \"7\"],\n[54.8888331333, 82.45221635, \"8\"],\n[54.8886320167, 82.4530411167, \"9\"],\n[54.8866415, 82.4537552833, \"33D\"],\n[54.8868032, 82.4537838167, \"33C\"],\n[54.8868312167, 82.45354015, \"33B\"],\n[54.8868582, 82.4532279333, \"33A\"],\n[54.8867126, 82.4521915667, \"30\"],\n[54.89138475, 82.4647044, \"31\"],\n[54.8884147667, 82.4636648, \"60B\"],\n[54.8944636333, 82.4644644833, \"10A\"],\n[54.8944416833, 82.4645756833, \"10\"],\n[54.8941219, 82.46491495, \"11\"],\n[54.8943222167, 82.4642833333, \"12A\"],\n[54.8930367667, 82.4648168, \"15A\"],\n[54.8931255, 82.4648136167, \"15B\"],\n[54.8931035167, 82.4644127333, \"18\"],\n[54.89292315, 82.4648254167, \"19\"],\n[54.8942371, 82.4645572667, \"12\"],\n[54.89397735, 82.4649136, \"13\"],\n[54.89409845, 82.4643458667, \"14\"],\n[54.89391375, 82.4645277333, \"16\"],\n[54.8929680833, 82.4643951, \"20\"],\n[54.8927348833, 82.46480795, \"21\"],\n[54.8928157667, 82.46437875, \"22A\"],\n[54.8927337833, 82.4643644833, \"22\"],\n[54.8925561167, 82.46478985, \"23\"],\n[54.8923608833, 82.4647155, \"25A\"],\n[54.8924641833, 82.46493565, \"25\"],\n[54.8949511, 82.4649854, \"1A\"],\n[54.8922117333, 82.4647047167, \"27\"],\n[54.8915681667, 82.4646986833, \"29\"],\n[54.8913701667, 82.4642759667, \"30A-30D\"],\n[54.8913990167, 82.4642620667, \"30\"],\n[54.8913092333, 82.46425895, \"32\"],\n[54.8912003667, 82.46469755, \"33\"],\n[54.8911230333, 82.4642383333, \"34A\"],\n[54.8911486667, 82.46399235, \"34B\"],\n[54.8911019, 82.4642380167, \"34\"],\n[54.89098895, 82.4646725333, \"35\"],\n[54.89084255, 82.4642192333, \"36A\"],\n[54.8909496167, 82.46422895, \"36B\"],\n[54.8908606333, 82.4642211667, \"36\"],\n[54.8948280833, 82.46498935, \"3\"],\n[54.8908666333, 82.4646632833, \"37\"],\n[54.8907759333, 82.4646549833, \"39A\"],\n[54.8907216667, 82.4646473167, \"39B\"],\n[54.8906578833, 82.4646450333, \"39C\"],\n[54.8905375667, 82.4646237167, \"41\"],\n[54.8904761833, 82.4646328667, \"43\"],\n[54.8902941833, 82.4641657667, \"44A\"],\n[54.8902406833, 82.46415805, \"44B\"],\n[54.8903436667, 82.4641675667, \"44\"],\n[54.89028625, 82.46460345, \"45\"],\n[54.8901877167, 82.4641515667, \"46A\"],\n[54.89013315, 82.4641537667, \"46B\"],\n[54.8949605167, 82.4645740333, \"4\"],\n[54.8900607167, 82.4645841333, \"47\"],\n[54.8900176, 82.4641449833, \"48\"],\n[54.8899419667, 82.464572, \"49A\"],\n[54.88987475, 82.4645733833, \"49B\"],\n[54.8898110667, 82.4645667333, \"49C\"],\n[54.8896632167, 82.4645695333, \"49D\"],\n[54.8898541333, 82.46475255, \"49E\"],\n[54.8897567333, 82.4647629, \"49F\"],\n[54.8896634667, 82.4647669667, \"49G\"],\n[54.8898924167, 82.4641263833, \"50\"],\n[54.8897574667, 82.4641326833, \"52\"],\n[54.8889242333, 82.4640623167, \"54\"],\n[54.88865535, 82.4644431167, \"55\"],\n[54.8887946833, 82.4638054667, \"56A\"],\n[54.8946296667, 82.4649645, \"5\"],\n[54.8887812167, 82.4640600833, \"56\"],\n[54.8884208167, 82.46442915, \"57\"],\n[54.8886385667, 82.4637760833, \"58A\"],\n[54.8886053667, 82.4640482, \"58\"],\n[54.8882043667, 82.4644158333, \"59\"],\n[54.8885028333, 82.463677, \"60A\"],\n[54.88839355, 82.4640293333, \"60\"],\n[54.8879652167, 82.4644074, \"61\"],\n[54.8877446333, 82.46437685, \"63\"],\n[54.8881502667, 82.4640036667, \"64\"],\n[54.8879700167, 82.4639859333, \"66\"],\n[54.8878033167, 82.4639686667, \"68\"],\n[54.8947931167, 82.4646081167, \"6A\"],\n[54.8948649333, 82.4643251333, \"6\"],\n[54.8944518833, 82.4649523167, \"7\"],\n[54.8946088333, 82.4645449667, \"8\"],\n[54.89429465, 82.4649376, \"9\"],\n[54.8951769667, 82.4645875167, \"2\"],\n[54.88757625, 82.46390195, \"70\"],\n[54.8940272667, 82.4652238, \"11A\"],\n[54.8929316167, 82.4651907833, \"19A\"],\n[54.8910516167, 82.4651865667, \"35A\"],\n[54.8950131667, 82.4649995667, \"1\"],\n[54.8946681667, 82.4642288167, \"8A\"],\n[54.8950832, 82.4643562167, \"2A\"],\n[54.89289445, 82.4639297667, \"1/22-11/22\"],\n[54.8839810833, 82.4856866167, \"3\"],\n[54.8839609167, 82.4862087667, \"4\"],\n[54.8813706667, 82.4859932667, \"25\"],\n[54.8815762, 82.4860593167, \"23\"],\n[54.88176925, 82.48611695, \"21\"],\n[54.8819291833, 82.4861440667, \"19\"],\n[54.8812535167, 82.48626755, \"28\"],\n[54.8814419833, 82.486341, \"26\"],\n[54.8816454, 82.486407, \"24\"],\n[54.8817836833, 82.4864573167, \"22\"],\n[54.8823392667, 82.4866145167, \"20\"],\n[54.8824710167, 82.4866385333, \"18\"],\n[54.8823897, 82.4862189833, \"17\"],\n[54.8810208833, 82.4857673833, \"27\"],\n[54.8809241333, 82.4860744, \"32\"],\n[54.8810838833, 82.4862027833, \"30\"],\n[54.8807501667, 82.4855223, \"35\"],\n[54.8809029, 82.48565165, \"33\"],\n[54.88077235, 82.4859607667, \"34\"],\n[54.8805942833, 82.48538215, \"37\"],\n[54.8806738833, 82.48500715, \"39\"],\n[54.8804429167, 82.4856392833, \"36\"],\n[54.8806746667, 82.48474885, \"41\"],\n[54.8802171333, 82.4854475, \"38\"],\n[54.8800456167, 82.4853260167, \"40\"],\n[54.8805906167, 82.4847991833, \"43\"],\n[54.8803164833, 82.4846505, \"49\"],\n[54.8803990833, 82.4851850833, \"45\"],\n[54.8802597333, 82.4850626167, \"47\"],\n[54.8800347333, 82.4849136333, \"53\"],\n[54.88023585, 82.4846241, \"51\"],\n[54.87911725, 82.4844298333, \"63\"],\n[54.8793032, 82.4845327167, \"61\"],\n[54.8794998, 82.48456245, \"59\"],\n[54.8796728333, 82.48464225, \"57\"],\n[54.8798386, 82.4844502667, \"55B\"],\n[54.87985855, 82.4847564333, \"55\"],\n[54.8798501167, 82.4851561333, \"42\"],\n[54.8792051, 82.48470885, \"65\"],\n[54.8796635, 82.4850343667, \"44\"],\n[54.8834352333, 82.4858534667, \"5\"],\n[54.8832857667, 82.4859341667, \"7\"],\n[54.88359745, 82.4863355833, \"8\"],\n[54.8830905833, 82.4860275333, \"9\"],\n[54.88377265, 82.48624865, \"6\"],\n[54.8826329333, 82.4866849167, \"16\"],\n[54.8825409333, 82.4862091167, \"15\"],\n[54.8827294333, 82.4862135, \"13\"],\n[54.8834279333, 82.4864298333, \"10\"],\n[54.8832412, 82.4865308833, \"12\"],\n[54.883058, 82.4865957667, \"14\"],\n[54.8828529667, 82.4861158333, \"11\"],\n[54.8834473167, 82.3733817, \"7\"],\n[54.8821477, 82.3739511333, \"17\"],\n[54.8835727833, 82.3742963167, \"4\"],\n[54.8829996167, 82.37376495, \"11\"],\n[54.8799677333, 82.3744603833, \"49\"],\n[54.8801634167, 82.37443835, \"43\"],\n[54.8131783667, 82.38169875, \"10\"],\n[54.8129868833, 82.3819189, \"8\"],\n[54.8122474333, 82.3825065833, \"6C\"],\n[54.8130850833, 82.3823078833, \"6A\"],\n[54.8124561333, 82.38300715, \"6B\"],\n[54.81348525, 82.3804658333, \"12\"],\n[54.81168165, 82.3801314, \"16B\"],\n[54.8110145667, 82.3801371167, \"16C\"],\n[54.8106325333, 82.3808725167, \"16D\"],\n[54.8105196, 82.379982, \"16E\"],\n[54.8134586333, 82.37986425, \"16A\"],\n[54.8608434833, 82.4499011, \"43\"],\n[54.8612150667, 82.44990305, \"45\"],\n[54.8618689167, 82.4498981167, \"47\"],\n[54.86239125, 82.4505662333, \"49\"],\n[54.8626794667, 82.4498931333, \"51\"],\n[54.86272035, 82.4492676833, \"53\"],\n[54.86160045, 82.4492898833, \"55\"],\n[54.8830900667, 82.48706325, \"2\"],\n[54.8833400667, 82.4873493167, \"3\"],\n[54.88330455, 82.4870247333, \"4\"],\n[54.8835654833, 82.4872303, \"5\"],\n[54.8835200667, 82.48693185, \"6\"],\n[54.8837668167, 82.4872335833, \"7\"],\n[54.88372005, 82.48686615, \"8\"],\n[54.88385335, 82.4870479667, \"9\"],\n[54.8831409167, 82.4873846167, \"1\"],\n[54.8838673, 82.4868328833, \"10\"],\n[54.88305215, 82.4682743333, \"2\"],\n[54.8832460833, 82.4683237, \"3\"],\n[54.8833727333, 82.4683497167, \"4\"],\n[54.8833539333, 82.4684306333, \"5\"],\n[54.8832353667, 82.4684359833, \"6\"],\n[54.8356606333, 82.4259896, \"44\"],\n[54.8361144333, 82.4254149667, \"39\"],\n[54.8298011333, 82.4247086333, \"97\"],\n[54.8328783, 82.4254824333, \"73\"],\n[54.8326006333, 82.42427305, \"71\"],\n[54.831938, 82.42577585, \"85\"],\n[54.8296909667, 82.4253358667, \"98A\"],\n[54.8304079333, 82.42640705, \"98B\"],\n[54.9136688833, 82.47027315, \"11\"],\n[54.9136547333, 82.47069685, \"10\"],\n[54.9138316333, 82.4708094833, \"12\"],\n[54.9137826667, 82.4703954167, \"16\"],\n[54.91318695, 82.4705625333, \"1\"],\n[54.913282333, 82.4701367, \"3\"],\n[54.9134621167, 82.47077345, \"4\"],\n[54.9134043833, 82.47044285, \"5\"],\n[54.9136208, 82.4710819333, \"6\"],\n[54.91350565, 82.47029995, \"7\"],\n[54.9137004667, 82.4710525667, \"8\"],\n[54.9135834833, 82.4699601167, \"9\"],\n[54.8994691333, 82.46256515, \"2\"],\n[54.8995118667, 82.4628252833, \"2A\"],\n[54.8995123, 82.4630041667, \"2B\"],\n[54.8994579333, 82.4622181667, \"1\"],\n[54.8974378833, 82.4617671667, \"28\"],\n[54.8974075167, 82.4619900333, \"26\"],\n[54.89761855, 82.4608725333, \"25\"],\n[54.8977565167, 82.4606562, \"27\"],\n[54.8979072833, 82.4605283333, \"29\"],\n[54.89808565, 82.4603934333, \"31\"],\n[54.8982804333, 82.46037375, \"33\"],\n[54.89837375, 82.4602651333, \"35\"],\n[54.89802395, 82.46003665, \"50\"],\n[54.8978844167, 82.4601356167, \"48\"],\n[54.8977532, 82.4602402333, \"46\"],\n[54.8976160167, 82.4603286167, \"44\"],\n[54.89819545, 82.4599255167, \"52\"],\n[54.8974890167, 82.4604333667, \"42\"],\n[54.8973825833, 82.46056285, \"40\"],\n[54.8984307833, 82.4623306333, \"14\"],\n[54.8993176, 82.46225845, \"3\"],\n[54.8982570167, 82.4622604, \"16\"],\n[54.89807915, 82.4621847167, \"18\"],\n[54.8979096167, 82.46211465, \"20\"],\n[54.8977295167, 82.4620442, \"22\"],\n[54.8983868833, 82.4619344833, \"11\"],\n[54.8982446, 82.4618734, \"13\"],\n[54.8980852, 82.46182235, \"15\"],\n[54.8979221167, 82.4617471667, \"17\"],\n[54.8977388167, 82.4616313167, \"19\"],\n[54.8975900833, 82.4619512333, \"24\"],\n[54.8976432833, 82.4613693, \"21\"],\n[54.8976362833, 82.4611184667, \"23\"],\n[54.8973338667, 82.4610383, \"34\"],\n[54.89734735, 82.46128405, \"32\"],\n[54.8973671167, 82.4615326833, \"30\"],\n[54.8983740833, 82.4600625, \"37\"],\n[54.8973341333, 82.46074505, \"38\"],\n[54.8971390333, 82.46087135, \"36\"],\n[54.8986548667, 82.4624186833, \"12\"],\n[54.89883265, 82.462497, \"10\"],\n[54.8990063167, 82.46257255, \"8\"],\n[54.8991676833, 82.4626289833, \"6\"],\n[54.8993200333, 82.4626184667, \"4\"],\n[54.8990043833, 82.4621885667, \"7\"],\n[54.8988871333, 82.4621417, \"9\"],\n[54.8991505333, 82.4622658, \"5\"],\n[54.9839604, 82.45833975, \"21\"],\n[54.9833674167, 82.4588416833, \"15\"],\n[54.8359882667, 82.4393378167, \"84\"],\n[54.81988195, 82.4304131333, \"303\"],\n[54.8180250667, 82.4265244667, \"359\"],\n[54.8183922667, 82.42604195, \"361\"],\n[54.8176359333, 82.4250678167, \"377\"],\n[54.8345467667, 82.4387839833, \"99\"],\n[54.83385615, 82.4387189, \"107\"],\n[54.80686185, 82.4025271167, \"621E\"],\n[54.8072254833, 82.4031670833, \"621F\"],\n[54.8157959333, 82.4221578, \"401B\"],\n[54.8061875667, 82.401462, \"621A\"],\n[54.8058821833, 82.4010980167, \"621B\"],\n[54.81469335, 82.4231989, \"406\"],\n[54.8174082667, 82.4176129667, \"413\"],\n[54.8141161167, 82.4226544167, \"416\"],\n[54.8138467167, 82.4215990833, \"419\"],\n[54.8135359833, 82.4220777667, \"424\"],\n[54.81227475, 82.4238289333, \"426\"],\n[54.81351715, 82.4209686667, \"431\"],\n[54.8344727, 82.43943635, \"100\"],\n[54.8341482167, 82.4394138833, \"102\"],\n[54.8335249, 82.4387248167, \"111\"],\n[54.8332444167, 82.4386937167, \"113\"],\n[54.8258899667, 82.4354216333, \"201\"],\n[54.8207155167, 82.4310458, \"287\"],\n[54.82205395, 82.4322644, \"273\"],\n[54.82211345, 82.4333285833, \"268\"],\n[54.8116728667, 82.4194537167, \"440A\"],\n[54.8113214333, 82.4130010333, \"491A\"],\n[54.8163042833, 82.4288074167, \"348B\"],\n[54.81563165, 82.4286594, \"348A\"],\n[54.8059561833, 82.41024335, \"566\"],\n[54.8054795833, 82.3996853333, \"621D\"],\n[54.8049338667, 82.4001146333, \"621C\"],\n[54.8194743833, 82.42997115, \"315\"],\n[54.8179959833, 82.4296346167, \"328\"],\n[54.8184434333, 82.4287788333, \"327\"],\n[54.8064376833, 82.406161, \"597B\"],\n[54.8062919333, 82.4056468333, \"597C\"],\n[54.8165707167, 82.4301424, \"336B\"],\n[54.8172738, 82.4285947167, \"336A\"],\n[54.8189469333, 82.4303026167, \"312A\"],\n[54.81940555, 82.4307701833, \"312B\"],\n[54.8199143667, 82.4312459, \"300\"],\n[54.882767667, 82.4291582, \"334\"],\n[54.8152067667, 82.4162956667, \"441B\"],\n[54.8142325667, 82.4148164667, \"441D\"],\n[54.8149509, 82.4159546667, \"441C\"],\n[54.815999, 82.482927333, \"441A\"],\n[54.80413515, 82.4042530167, \"612\"],\n[54.8036285, 82.4024796333, \"627B\"],\n[54.8014316833, 82.4040596333, \"636\"],\n[54.8026355333, 82.4024570667, \"638\"],\n[54.8046866167, 82.4038756333, \"613\"],\n[54.8028006833, 82.4016926167, \"639A\"],\n[54.8015622167, 82.408231, \"652\"],\n[54.8004875333, 82.4008727667, \"670\"],\n[54.7997891, 82.40002805, \"676\"],\n[54.8083442333, 82.4139592833, \"509\"],\n[54.8074935333, 82.4139840667, \"532\"],\n[54.8072659167, 82.4124669333, \"543\"],\n[54.8081279, 82.40823995, \"567A\"],\n[54.8087099667, 82.4071535667, \"567C\"],\n[54.804962, 82.4071512, \"586\"],\n[54.8046189167, 82.4061273333, \"598\"],\n[54.8052894167, 82.4083249, \"576\"],\n[54.8060052167, 82.4083508333, \"571\"],\n[54.8053679167, 82.4062368, \"597A\"],\n[54.8051049667, 82.4051947167, \"607\"],\n[54.8089437667, 82.4076931167, \"567B\"],\n[54.8113679833, 82.4200005667, \"440B\"],\n[54.8112042667, 82.482891, \"463\"],\n[54.8114033, 82.4191389167, \"442\"],\n[54.81667955, 82.4240415167, \"387\"],\n[54.8160871, 82.4248795, \"390\"],\n[54.81503135, 82.4226562, \"401A\"],\n[54.8158879667, 82.42335465, \"393\"],\n[54.8104159333, 82.41701115, \"477\"],\n[54.84176295, 82.4387852167, \"25\"],\n[54.8394856333, 82.43871765, \"53\"],\n[54.84315575, 82.4396268667, \"4\"],\n[54.8382764833, 82.4387401333, \"65\"],\n[54.8365486833, 82.4387233, \"81\"],\n[54.83550145, 82.4387130167, \"91\"],\n[54.8063373333, 82.40984385, \"565A\"],\n[54.8068884167, 82.4101122333, \"553\"],\n[54.8073266833, 82.40938595, \"565B\"],\n[54.8022880667, 82.4015246833, \"647\"],\n[54.8032717167, 82.3994722333, \"649\"],\n[54.8125184833, 82.4206463, \"432A\"],\n[54.8131087167, 82.4214898833, \"432D\"],\n[54.81219155, 82.4220903333, \"432B\"],\n[54.8123494833, 82.4226102667, \"432C\"],\n[54.8323999167, 82.4388484167, \"113/1\"],\n[54.8137884667, 82.4184721333, \"439B\"],\n[54.8128705833, 82.4202196333, \"439A\"],\n[54.8030845, 82.4029651, \"634\"],\n[54.80229035, 82.4038689333, \"634A\"],\n[54.8016416, 82.4044987167, \"634B\"],\n[54.8040659833, 82.4028728333, \"627A\"],\n[54.8039385667, 82.4012164167, \"627C\"],\n[54.8041331833, 82.4011953333, \"627D\"],\n[54.8104539833, 82.4114936333, \"501\"],\n[54.8095276, 82.41551535, \"491C\"],\n[54.8104942333, 82.4142607333, \"491B\"],\n[54.8118822333, 82.4251615167, \"426A\"],\n[54.9146426833, 82.46333945, \"8\"],\n[54.9146966667, 82.4641698333, \"12\"],\n[54.9148385667, 82.4646229167, \"14\"],\n[54.9145846833, 82.4637018, \"10\"],\n[54.9148759167, 82.4632119667, \"6\"],\n[54.9150353667, 82.4631399, \"4\"],\n[54.8791983833, 82.48491125, \"1\"],\n[54.8794456833, 82.4852828333, \"4\"],\n[54.8795405, 82.4855742333, \"6\"],\n[54.8796772167, 82.4856965, \"8\"],\n[54.87980185, 82.4857916833, \"10\"],\n[54.8796864, 82.4861288, \"15\"],\n[54.8797264167, 82.4859489333, \"12\"],\n[54.8795614, 82.4860496167, \"13\"],\n[54.8794049667, 82.4858653167, \"11\"],\n[54.8792908167, 82.4856798667, \"9\"],\n[54.8791893, 82.4854042167, \"5\"],\n[54.879194, 82.4855697, \"7\"],\n[54.87919295, 82.4851510333, \"3\"],\n[54.9021503333, 82.4819923833, \"1\"],\n[54.9020893333, 82.4817469667, \"2\"],\n[54.90202325, 82.4814764333, \"3\"],\n[54.90189885, 82.4813368167, \"4\"],\n[54.9017681, 82.4813746667, \"5\"],\n[54.9017408667, 82.4815826667, \"6\"],\n[54.9018523, 82.4818607167, \"7\"],\n[54.90192475, 82.4821145, \"8\"],\n[54.9122682, 82.46593575, \"11\"],\n[54.9122654667, 82.4666392333, \"2\"],\n[54.9124824333, 82.4664875, \"1\"],\n[54.9126646667, 82.4661762167, \"3\"],\n[54.9121691, 82.4663371, \"4\"],\n[54.9126312167, 82.4661364333, \"5\"],\n[54.9121084167, 82.46614215, \"6\"],\n[54.91239705, 82.46620525, \"7\"],\n[54.912165, 82.4659997167, \"8\"],\n[54.91234125, 82.4659673167, \"9\"],\n[54.8640527833, 82.4896800333, \"1/239\"],\n[54.8637439833, 82.4893278333, \"2/239\"],\n[54.8399393, 82.4691242833, \"563\"],\n[54.8403040167, 82.4695932333, \"555\"],\n[54.8626741167, 82.4890199667, \"250\"],\n[54.86235545, 82.4877547333, \"263\"],\n[54.8621190833, 82.4881775833, \"260\"],\n[54.8697908333, 82.4976855333, \"2/143\"],\n[54.8696097167, 82.50222845, \"109\"],\n[54.8650994667, 82.4906942667, \"217\"],\n[54.8587062667, 82.4842270833, \"308\"],\n[54.8585393667, 82.4832368167, \"323\"],\n[54.856982, 82.4821791333, \"337\"],\n[54.8557220333, 82.4813075, \"357\"],\n[54.87269675, 82.51109805, \"9\"],\n[54.86818685, 82.4965807167, \"154\"],\n[54.8391881333, 82.4691244833, \"570\"],\n[54.8392424167, 82.4682793833, \"573\"],\n[54.8384787167, 82.4682486667, \"580\"],\n[54.8380699833, 82.4677177667, \"586\"],\n[54.83591845, 82.4652008167, \"1/620\"],\n[54.8356297, 82.4656015333, \"2/620\"],\n[54.85443655, 82.48126465, \"362\"],\n[54.8543465667, 82.4803770667, \"363\"],\n[54.8533677, 82.4796417833, \"383\"],\n[54.8400570333, 82.4693165167, \"559\"],\n[54.8701502, 82.5066921333, \"58\"],\n[54.8688167, 82.5031792667, \"94\"],\n[54.8633276833, 82.48971255, \"240\"],\n[54.84499075, 82.47397555, \"489\"],\n[54.8390078667, 82.4675286, \"579\"],\n[54.8615817667, 82.4874484667, \"272\"],\n[54.8611261, 82.48692335, \"1/276\"],\n[54.8609821, 82.48677485, \"2/276\"],\n[54.8443942167, 82.4735167, \"491\"],\n[54.84453425, 82.4741157833, \"490\"],\n[54.8728439333, 82.5114111333, \"5\"],\n[54.8479137833, 82.47588805, \"449\"],\n[54.8694130667, 82.5004653167, \"118\"],\n[54.8381128333, 82.4689194667, \"578\"],\n[54.8387493167, 82.4686557833, \"576\"],\n[54.834946, 82.4616395, \"648\"],\n[54.8355279667, 82.4648596667, \"626\"],\n[54.8352287, 82.46082495, \"670\"],\n[54.84359945, 82.4735256167, \"500\"],\n[54.8437138833, 82.4730056833, \"501\"],\n[54.8433661667, 82.4727594167, \"511\"],\n[54.8429640667, 82.4725448333, \"513\"],\n[54.8424090833, 82.4720656833, \"517\"],\n[54.8419261, 82.4716311333, \"529\"],\n[54.84138045, 82.4707106667, \"535\"],\n[54.8407243, 82.4700550167, \"551\"],\n[54.84032605, 82.4702964, \"552\"],\n[54.8397895, 82.46968935, \"562\"],\n[54.83966945, 82.4688137833, \"567\"],\n[54.8458821833, 82.4743360167, \"479\"],\n[54.8523557667, 82.4795548667, \"394\"],\n[54.8519909833, 82.4785619833, \"401\"],\n[54.85128865, 82.4790768167, \"408\"],\n[54.8505837, 82.4777973667, \"419\"],\n[54.8494416833, 82.4767902167, \"429\"],\n[54.8501747833, 82.478082, \"422\"],\n[54.8487495333, 82.477303, \"446\"],\n[54.8613924167, 82.4866768333, \"275\"],\n[54.8612592667, 82.48651665, \"277\"],\n[54.8606625, 82.4863779, \"280\"],\n[54.8602587667, 82.4860168333, \"288\"],\n[54.8662275, 82.4932509, \"192\"],\n[54.8656668, 82.4925030333, \"206\"],\n[54.8718011, 82.50936105, \"31\"],\n[54.871327, 82.50837775, \"41\"],\n[54.8481012833, 82.4755436333, \"455\"],\n[54.8662202833, 82.4971715833, \"2/164\"],\n[54.8665327833, 82.4968656167, \"1/164\"],\n[54.87262005, 82.5101317, \"11\"],\n[54.8407464167, 82.4693628, \"553\"],\n[54.8687301, 82.50368985, \"92\"],\n[54.8576066333, 82.4826215667, \"331\"],\n[54.867679, 82.4952846833, \"164\"],\n[54.8698948833, 82.4990379333, \"133\"],\n[54.8639344, 82.49046205, \"230\"],\n[54.8645916667, 82.4912248333, \"224\"],\n[54.8710460833, 82.50036065, \"125\"],\n[54.8694796667, 82.4976021667, \"1/143\"],\n[54.8733131, 82.4691004333, \"3A\"],\n[54.87406055, 82.4694125667, \"6A\"],\n[54.8735341167, 82.469327, \"5\"],\n[54.8735109667, 82.46960345, \"7\"],\n[54.87351105, 82.4698807333, \"11\"],\n[54.8735358667, 82.47009225, \"13\"],\n[54.8736709667, 82.4702864167, \"17\"],\n[54.8737941667, 82.47025885, \"16\"],\n[54.8738211333, 82.4693453167, \"4\"],\n[54.8737987667, 82.46968045, \"8\"],\n[54.8738769167, 82.4699632, \"10\"],\n[54.8739402833, 82.4701521167, \"12\"],\n[54.8732443833, 82.4692419333, \"3B\"],\n[54.8740679833, 82.4695514833, \"6B\"],\n[54.8739830167, 82.4704122667, \"14\"],\n[54.8735580667, 82.4702317, \"15\"],\n[54.87328745, 82.4697687167, \"9\"],\n[54.8738628167, 82.46909085, \"2\"],\n[54.8735833, 82.4690007, \"1\"],\n[54.9140601833, 82.4734438833, \"1\"],\n[54.91414235, 82.4726753, \"7A\"],\n[54.9148196333, 82.4729240333, \"4\"],\n[54.9145959167, 82.4727449, \"5\"],\n[54.9144294, 82.4728081667, \"6\"],\n[54.9142862333, 82.4729454, \"7\"],\n[54.9140804667, 82.4729594, \"8\"],\n[54.91442545, 82.4732771, \"2A\"],\n[54.9146292, 82.47320695, \"3\"],\n[54.9142898833, 82.4733283333, \"2\"],\n[54.8924708, 82.4694829667, \"3\"],\n[54.8921866833, 82.4690726, \"4-6\"],\n[54.8744290667, 82.4729675333, \"16\"],\n[54.8747743333, 82.4729266667, \"17\"],\n[54.8743306833, 82.4749814667, \"2\"],\n[54.8743712167, 82.4747777167, \"4\"],\n[54.8743979833, 82.4745281667, \"6\"],\n[54.8744096167, 82.47429405, \"8\"],\n[54.8744245167, 82.4740094333, \"10\"],\n[54.8744545333, 82.4736160667, \"12\"],\n[54.8742322333, 82.47382395, \"10A\"],\n[54.87422675, 82.47369315, \"12A\"],\n[54.8742394, 82.4730406667, \"16A\"],\n[54.8742450667, 82.4731634667, \"14A\"],\n[54.8744790667, 82.4732784833, \"14\"],\n[54.8747754833, 82.4731559, \"15\"],\n[54.8747613167, 82.4734085833, \"13\"],\n[54.8747389, 82.4736529667, \"11\"],\n[54.8747211167, 82.47387885, \"9\"],\n[54.8747006167, 82.4741313, \"7\"],\n[54.8746909667, 82.4743708167, \"5\"],\n[54.8746798167, 82.4746769, \"3\"],\n[54.8748711167, 82.4748117167, \"3A\"],\n[54.8748328833, 82.4749142833, \"1A\"],\n[54.874621, 82.4750391, \"1\"],\n[54.8755351667, 82.4795168667, \"6A\"],\n[54.8754681, 82.4798997667, \"6\"],\n[54.8756842833, 82.4798735833, \"8\"],\n[54.8756412167, 82.4794951833, \"8A\"],\n[54.8758023167, 82.4803141667, \"5\"],\n[54.8757598667, 82.4801058, \"7\"],\n[54.8757471833, 82.4799721833, \"9\"],\n[54.8755322, 82.4802420833, \"3\"],\n[54.8753549833, 82.47993535, \"4\"],\n[54.888292, 82.4617109667, \"4A\"],\n[54.8820907333, 82.4622059833, \"5\"],\n[54.8815066, 82.4617161667, \"4B\"],\n[54.888234333, 82.4618948333, \"6A\"],\n[54.8815026667, 82.46184895, \"6B\"],\n[54.8815932167, 82.46217415, \"10A\"],\n[54.8817450167, 82.46226225, \"10\"],\n[54.8818722667, 82.4626555167, \"11\"],\n[54.8817309, 82.4624690333, \"12\"],\n[54.8821211333, 82.4617608833, \"1\"],\n[54.8817646833, 82.4615252167, \"2A\"],\n[54.8815099, 82.4615357667, \"2B\"],\n[54.88209615, 82.4619084, \"3\"],\n[54.8820657333, 82.4624910833, \"7\"],\n[54.8817491333, 82.4620671833, \"8A\"],\n[54.8814882667, 82.4620343, \"8B\"],\n[54.8820256333, 82.4626954, \"9\"],\n[54.9011387, 82.4845455833, \"11A\"],\n[54.9004465667, 82.4842316167, \"6\"],\n[54.9006268333, 82.4836419, \"1\"],\n[54.9005414333, 82.4845609667, \"10\"],\n[54.9009292833, 82.4847187667, \"11\"],\n[54.9009982, 82.48493945, \"13\"],\n[54.900608, 82.4848214333, \"14\"],\n[54.9002908667, 82.4835936167, \"2\"],\n[54.9003859333, 82.4839906667, \"4\"],\n[54.9007548667, 82.4840674, \"5\"],\n[54.9008090833, 82.4842714333, \"7\"],\n[54.90027845, 82.4844867667, \"8\"],\n[54.90087325, 82.4844819167, \"9\"],\n[54.9010882333, 82.4852001, \"15\"],\n[54.9007465833, 82.4850981333, \"16\"],\n[54.9008384, 82.48536275, \"18\"],\n[54.9009003833, 82.4836903667, \"3A\"],\n[54.9006948, 82.48386545, \"3\"],\n[54.8352114167, 82.3932620667, \"614\"],\n[54.8358616, 82.3932373667, \"607\"],\n[54.8527932167, 82.4481416, \"66\"],\n[54.8535776833, 82.4477748333, \"59\"],\n[54.8513053333, 82.4468875167, \"88\"],\n[54.8367923167, 82.39439545, \"597\"],\n[54.8356857333, 82.39511535, \"594\"],\n[54.8338485, 82.3905351667, \"644\"],\n[54.8342344833, 82.3914293833, \"636\"],\n[54.8349352, 82.39110985, \"631\"],\n[54.8340942167, 82.3894187167, \"647\"],\n[54.8361288, 82.3943564333, \"603\"],\n[54.835456, 82.3923533167, \"621\"],\n[54.8316758833, 82.3851704333, \"690\"],\n[54.82606465, 82.3729124, \"823A\"],\n[54.8360247333, 82.40845075, \"472\"],\n[54.8367576167, 82.4058547167, \"499\"],\n[54.8307850333, 82.3833224167, \"716\"],\n[54.8297911333, 82.3838338167, \"722A\"],\n[54.82856305, 82.3853371, \"722B\"],\n[54.8366530833, 82.4158296167, \"407\"],\n[54.8343563333, 82.3899946667, \"645\"],\n[54.83378605, 82.3887814833, \"649\"],\n[54.8383438833, 82.4167502667, \"403A\"],\n[54.8269138333, 82.3707719, \"823B\"],\n[54.8262433167, 82.37126425, \"823C\"],\n[54.8278735833, 82.3745076, \"791C\"],\n[54.82803615, 82.3751116833, \"791B\"],\n[54.8284354167, 82.3743400333, \"791D\"],\n[54.8283312333, 82.3722626167, \"803H\"],\n[54.8308135833, 82.3857800333, \"700A\"],\n[54.83039575, 82.3861873667, \"700B\"],\n[54.8297918, 82.3866039833, \"700C\"],\n[54.8323622833, 82.3869592167, \"680A\"],\n[54.8317271833, 82.3872918333, \"680B\"],\n[54.8320544167, 82.3863078833, \"680C\"],\n[54.8265114833, 82.3737262, \"811A\"],\n[54.8268406667, 82.37269475, \"811B\"],\n[54.8272920833, 82.3716203, \"811C\"],\n[54.8537437333, 82.4489413667, \"62\"],\n[54.83192005, 82.3841341833, \"695\"],\n[54.8368657833, 82.4028889833, \"525\"],\n[54.83376425, 82.3968886333, \"590B\"],\n[54.8299130333, 82.3859233667, \"702C\"],\n[54.8305810833, 82.38512625, \"702B\"],\n[54.8360455333, 82.4081179333, \"474\"],\n[54.8276760833, 82.3808082167, \"756C\"],\n[54.8283299333, 82.3802092167, \"756B\"],\n[54.85043345, 82.4461019, \"100\"],\n[54.8297131833, 82.38286445, \"724A\"],\n[54.82929325, 82.383521, \"724B\"],\n[54.8369757, 82.3983033667, \"571\"],\n[54.8376989333, 82.4166211, \"403B\"],\n[54.8368311167, 82.4050104667, \"505\"],\n[54.8412127667, 82.4050228833, \"491A\"],\n[54.83852105, 82.4062947, \"491B\"],\n[54.8338348833, 82.3934827333, \"622B\"],\n[54.8330032, 82.3939467333, \"622C\"],\n[54.8282068, 82.376844, \"775A\"],\n[54.8295163167, 82.3755049667, \"775B\"],\n[54.828404, 82.37718215, \"775C\"],\n[54.8362426, 82.39711805, \"578\"],\n[54.8361603, 82.39675875, \"580\"],\n[54.8424267833, 82.4340512167, \"232\"],\n[54.84114775, 82.4311295833, \"272\"],\n[54.82872315, 82.3709866833, \"803A\"],\n[54.8285930667, 82.3703004167, \"803B\"],\n[54.8294768667, 82.3691337, \"803C\"],\n[54.8292017, 82.36888125, \"803D\"],\n[54.8285291333, 82.36580345, \"803E\"],\n[54.8298995333, 82.3673114167, \"803F\"],\n[54.8302568833, 82.36760835, \"803G\"],\n[54.8267714167, 82.3742385167, \"807\"],\n[54.83126665, 82.3844291833, \"702A\"],\n[54.83016355, 82.3818740833, \"734\"],\n[54.8296635167, 82.3807643167, \"742\"],\n[54.82974665, 82.3798092, \"747\"],\n[54.829114, 82.3799039833, \"752\"],\n[54.8288072833, 82.3779985667, \"765\"],\n[54.8278203667, 82.3760339333, \"789\"],\n[54.8274609333, 82.3753562, \"791A\"],\n[54.8320049, 82.39796425, \"592B\"],\n[54.8304380667, 82.3993220667, \"592C\"],\n[54.8323366667, 82.3982387333, \"592D\"],\n[54.8332103167, 82.39666495, \"590A\"],\n[54.8362232667, 82.4049506333, \"504\"],\n[54.83689715, 82.4034307333, \"523\"],\n[54.8362677, 82.4030851833, \"522\"],\n[54.8363718333, 82.4003976167, \"548\"],\n[54.836423, 82.3953457167, \"585\"],\n[54.83596855, 82.3959414667, \"586\"],\n[54.8392194, 82.4133888333, \"439\"],\n[54.8367003667, 82.4102236167, \"461\"],\n[54.83586315, 82.412182333, \"442\"],\n[54.8387438833, 82.4244664667, \"318\"],\n[54.8382094333, 82.42266185, \"346\"],\n[54.8366223667, 82.4173578167, \"396\"],\n[54.8405799833, 82.4294097167, \"284\"],\n[54.8409799, 82.4286117333, \"289\"],\n[54.8404157, 82.4273133667, \"291\"],\n[54.8448297, 82.4386074, \"188\"],\n[54.8445996333, 82.4385307833, \"190\"],\n[54.8445953833, 82.4381869167, \"192\"],\n[54.8462362333, 82.4406972, \"162\"],\n[54.8453950333, 82.4394750167, \"180\"],\n[54.8561178167, 82.4522334, \"11\"],\n[54.8560307, 82.4511923667, \"17\"],\n[54.8361288, 82.4061807167, \"492\"],\n[54.83609445, 82.40683275, \"490\"],\n[54.8545275667, 82.44950565, \"40\"],\n[54.8375230333, 82.4199872333, \"372\"],\n[54.8388781167, 82.4226393667, \"343\"],\n[54.83701825, 82.41844345, \"378\"],\n[54.8371192833, 82.4187303167, \"376\"],\n[54.8373785667, 82.4194973167, \"374\"],\n[54.8367387167, 82.4085570167, \"473\"],\n[54.8318677333, 82.3858444, \"688\"],\n[54.8327873167, 82.3878064833, \"674\"],\n[54.83304365, 82.3883507667, \"664\"],\n[54.8366133333, 82.4130614667, \"427\"],\n[54.8508733333, 82.44641935, \"94\"],\n[54.8433085667, 82.4359371667, \"212\"],\n[54.8376679667, 82.3994774833, \"549\"],\n[54.8388004167, 82.3998009833, \"549C\"],\n[54.8369648167, 82.40033875, \"549B\"],\n[54.8376661833, 82.3999770333, \"549A\"],\n[54.8368055667, 82.3968196667, \"575\"],\n[54.8369513667, 82.39729965, \"573\"],\n[54.836328, 82.3975344167, \"576\"],\n[54.8419685667, 82.4332863667, \"240\"],\n[54.83147865, 82.3703224333, \"781A\"],\n[54.8302962167, 82.3727004833, \"781B\"],\n[54.8300511833, 82.3734676833, \"781C\"],\n[54.9155750333, 82.4788872333, \"103\"],\n[54.9080710333, 82.4815503833, \"39C\"],\n[54.9081354167, 82.48171275, \"39B\"],\n[54.90819845, 82.4819203833, \"39A\"],\n[54.9165609667, 82.4784770333, \"115\"],\n[54.91497395, 82.4792572167, \"99\"],\n[54.9096164833, 82.4817164167, \"49\"],\n[54.9116786667, 82.48074935, \"69\"],\n[54.9140226, 82.479658, \"85\"],\n[54.9069150833, 82.4829900333, \"27A\"],\n[54.9069469833, 82.4828211667, \"27B\"],\n[54.9141799333, 82.4796010667, \"87\"],\n[54.9148269, 82.4793132333, \"95\"],\n[54.9148061667, 82.47892315, \"97\"],\n[54.9052287833, 82.4834456667, \"7A\"],\n[54.9157397167, 82.4785532167, \"107A\"],\n[54.9164115167, 82.4783404167, \"113\"],\n[54.9162113333, 82.4786140333, \"109\"],\n[54.9159243667, 82.4787397833, \"107B\"],\n[54.91564195, 82.4783057333, \"107\"],\n[54.9095836167, 82.48142755, \"49A\"],\n[54.9097563, 82.4813824667, \"51A\"],\n[54.9142505167, 82.4798245, \"89A\"],\n[54.9143203667, 82.4795241, \"89\"],\n[54.9143582167, 82.4791171833, \"91A\"],\n[54.90809605, 82.4820482833, \"37A\"],\n[54.9080426833, 82.4818123, \"37B\"],\n[54.9079928333, 82.4816048, \"37C\"],\n[54.9144982167, 82.4794426833, \"91\"],\n[54.9146732833, 82.4793797, \"93\"],\n[54.9046052333, 82.48406395, \"1\"],\n[54.90479665, 82.4839646833, \"3\"],\n[54.9049845333, 82.4838759833, \"5\"],\n[54.9061106, 82.4833581667, \"17\"],\n[54.9062431667, 82.4833112333, \"19\"],\n[54.9063920333, 82.4832255333, \"21\"],\n[54.9065708, 82.48314765, \"23\"],\n[54.9067455333, 82.4830679333, \"25\"],\n[54.90686575, 82.4825972667, \"29\"],\n[54.9053759667, 82.4837128167, \"11\"],\n[54.9055325, 82.4836456167, \"13\"],\n[54.9057146333, 82.4835634667, \"15\"],\n[54.9080300333, 82.4824985, \"35\"],\n[54.9081798333, 82.4824187833, \"37\"],\n[54.90842625, 82.4822687667, \"39\"],\n[54.90871305, 82.4821525333, \"43\"],\n[54.9071454167, 82.4828962333, \"31\"],\n[54.90945405, 82.4818068167, \"47\"],\n[54.9097787167, 82.4816407833, \"51\"],\n[54.9101221667, 82.48147745, \"55\"],\n[54.9099619333, 82.4815613833, \"53\"],\n[54.9108703, 82.48113905, \"57\"],\n[54.9111010167, 82.4810227833, \"61\"],\n[54.9113033333, 82.4806476167, \"63A\"],\n[54.9113063333, 82.4809305333, \"63\"],\n[54.9113486333, 82.48054435, \"65\"],\n[54.9115162333, 82.4808384167, \"67\"],\n[54.9118321, 82.4806828667, \"71\"],\n[54.912005, 82.4805931333, \"73\"],\n[54.9126924, 82.4801856167, \"75\"],\n[54.9128904333, 82.48013955, \"77\"],\n[54.91306105, 82.4801038667, \"79\"],\n[54.91323275, 82.4800307667, \"81\"],\n[54.90504305, 82.48350075, \"7\"],\n[54.9161411, 82.4791161, \"104\"],\n[54.9052017167, 82.4837928833, \"9\"],\n[54.9048593333, 82.4837002833, \"5A\"],\n[54.9134008167, 82.4799760333, \"83\"],\n[54.91608025, 82.4781871, \"111A\"],\n[54.9159769333, 82.4778862, \"111B\"],\n[54.91609255, 82.4778227833, \"111C\"],\n[54.9162477333, 82.4781089667, \"111D\"],\n[54.8954434833, 82.47689195, \"1\"],\n[54.7968509833, 82.4409205333, \"218\"],\n[54.7967954, 82.4415974333, \"226\"],\n[54.79061135, 82.4311808833, \"105\"],\n[54.7936930167, 82.4323678167, \"144\"],\n[54.7936793, 82.4341171833, \"169\"],\n[54.7906754167, 82.4300550333, \"101\"],\n[54.7923387667, 82.4305234833, \"114\"],\n[54.7921506667, 82.4312033333, \"119\"],\n[54.79638115, 82.44350555, \"244\"],\n[54.9026378, 82.4249371167, \"6\"],\n[54.9018287167, 82.4251090167, \"15\"],\n[54.9005140167, 82.4267575167, \"32\"],\n[54.90030005, 82.4272810167, \"36\"],\n[54.9000367833, 82.4266413167, \"1/45\"],\n[54.8999172167, 82.4269248667, \"2/45\"],\n[54.8998128167, 82.42722285, \"3/45\"],\n[54.8997664167, 82.4278138333, \"46\"],\n[54.89874045, 82.42933485, \"47\"],\n[54.90246715, 82.4251130833, \"8\"],\n[54.98415945, 82.5440391833, \"1/398\"],\n[54.9842023, 82.5446759833, \"398\"],\n[54.9673053833, 82.5493618, \"1/200\"],\n[54.9595488167, 82.5503643667, \"2/94\"],\n[54.9548066833, 82.5547442167, \"41\"],\n[54.975043, 82.5502804667, \"288\"],\n[54.9674483333, 82.54948405, \"2/200\"],\n[54.9675936167, 82.54960055, \"3/200\"],\n[54.9536896833, 82.5558200833, \"21\"],\n[54.9537523333, 82.5551846667, \"24\"],\n[54.9758721, 82.55151395, \"297\"],\n[54.9715911333, 82.5505416, \"246\"],\n[54.97615305, 82.5531409833, \"1/299\"],\n[54.9759959833, 82.553822167, \"2/299\"],\n[54.9762314333, 82.5517778833, \"3/299\"],\n[54.9789959667, 82.5511051167, \"1/317\"],\n[54.9791978667, 82.5509703167, \"2/317\"],\n[54.97016405, 82.5511682333, \"233\"],\n[54.9840100667, 82.5422511833, \"3/398\"],\n[54.9832081667, 82.5409176, \"4/398\"],\n[54.9626150333, 82.5485202333, \"1/142\"],\n[54.9620708667, 82.5493090333, \"139\"],\n[54.9646945333, 82.5484742, \"164\"],\n[54.95884865, 82.5515776333, \"91\"],\n[54.9588039667, 82.5510064, \"1/94\"],\n[54.9794108833, 82.5497014333, \"332\"],\n[54.9806783167, 82.5477771, \"352\"],\n[54.8757744167, 82.46972585, \"1\"],\n[54.8758043667, 82.4700843, \"3\"],\n[54.8758559833, 82.4703261667, \"5\"],\n[54.8759855667, 82.4703921667, \"7\"],\n[54.8761207333, 82.4703036833, \"9\"],\n[54.8763731833, 82.4703581, \"8B\"],\n[54.8763879, 82.4701746167, \"8A\"],\n[54.8760971833, 82.4699428, \"6\"],\n[54.8763947, 82.46978015, \"4\"],\n[54.8760231167, 82.4695721, \"2\"],\n[54.84887105, 82.5612401333, \"268\"],\n[54.8480716667, 82.5605471, \"1/271\"],\n[54.8481743833, 82.5599216, \"2/271\"],\n[54.8475651333, 82.5602482833, \"273\"],\n[54.8549548833, 82.5645155167, \"187\"],\n[54.8590531333, 82.56929455, \"111\"],\n[54.8579502, 82.5697828667, \"1/128\"],\n[54.8577433333, 82.5697812167, \"2/128\"],\n[54.8663423167, 82.5687757833, \"25\"],\n[54.8659378833, 82.5701593333, \"1/32\"],\n[54.8656144667, 82.5703594167, \"2/32\"],\n[54.9075306667, 82.4735409, \"8\"],\n[54.90741835, 82.4736250333, \"12\"],\n[54.9077710167, 82.4736747, \"3\"],\n[54.90756245, 82.4735306833, \"7\"],\n[54.90776065, 82.4736345167, \"4\"],\n[54.9076790833, 82.4734552333, \"6\"],\n[54.90770165, 82.4734532167, \"5\"],\n[54.90742555, 82.4736053833, \"11\"],\n[54.9074725833, 82.4739170833, \"14\"],\n[54.9074575333, 82.47388525, \"13\"],\n[54.90752205, 82.4737226167, \"10\"],\n[54.9075427667, 82.4737034667, \"9\"],\n[54.9078406167, 82.4738848333, \"1\"],\n[54.9078192667, 82.4738328667, \"2\"],\n[54.907982667, 82.4742687333, \"19\"],\n[54.9076409333, 82.4739459, \"15\"],\n[54.9077643333, 82.4742689, \"18\"],\n[54.9077539833, 82.4742287, \"17\"],\n[54.9076577333, 82.47400055, \"16\"],\n[54.9079030333, 82.4742141667, \"20\"],\n[54.9156256167, 82.4748749833, \"78\"],\n[54.9146128333, 82.4721344167, \"56A\"],\n[54.9151661833, 82.4733835167, \"66\"],\n[54.9140138, 82.4694897, \"30\"],\n[54.9140857167, 82.46969035, \"32\"],\n[54.9144033, 82.4695158, \"33\"],\n[54.91414165, 82.4698978167, \"34\"],\n[54.91444875, 82.4697295833, \"35\"],\n[54.9142653833, 82.4703260667, \"38\"],\n[54.9142211667, 82.4701128667, \"36\"],\n[54.9155440833, 82.4732913, \"65\"],\n[54.9134283, 82.4674369333, \"14\"],\n[54.9155934667, 82.4735220833, \"67\"],\n[54.9151737667, 82.4721487333, \"57\"],\n[54.9155787333, 82.4746912167, \"76\"],\n[54.9143332167, 82.4693118167, \"29\"],\n[54.9151155, 82.4718793167, \"55\"],\n[54.9134783167, 82.4676862167, \"16\"],\n[54.91350365, 82.4678403, \"18\"],\n[54.9135371667, 82.4680652, \"20\"],\n[54.9135827167, 82.4682467, \"22\"],\n[54.9136676, 82.4684140667, \"24\"],\n[54.91375, 82.4685284833, \"26\"],\n[54.9144983333, 82.4699386333, \"39\"],\n[54.9145579833, 82.4701247833, \"41\"],\n[54.9146344333, 82.4703215833, \"43\"],\n[54.9140692167, 82.4706085833, \"46\"],\n[54.91469445, 82.47051275, \"47\"],\n[54.9143359333, 82.4705744833, \"48\"],\n[54.9147432833, 82.47069995, \"49\"],\n[54.9146982, 82.4717894167, \"54\"],\n[54.9147643333, 82.47204645, \"56\"],\n[54.91485235, 82.4723157167, \"58\"],\n[54.9149395167, 82.4725939833, \"60\"],\n[54.9144000333, 82.4707812, \"50\"],\n[54.9148043167, 82.4709096, \"51\"],\n[54.9157513167, 82.4752532333, \"82\"],\n[54.9158039333, 82.47545195, \"84\"],\n[54.9156901667, 82.4750640167, \"80\"],\n[54.9158563833, 82.4756482667, \"86\"],\n[54.91508355, 82.4731087, \"64\"],\n[54.9154807667, 82.4730812167, \"63\"],\n[54.9154616667, 82.4742882833, \"72\"],\n[54.9155282, 82.47449895, \"74\"],\n[54.9790357333, 82.4624267667, \"19\"],\n[54.9791358667, 82.4611471, \"6\"],\n[54.9797030333, 82.4636025333, \"30\"],\n[54.9790060167, 82.4621910833, \"17\"],\n[54.9786417667, 82.4608476833, \"5\"],\n[54.9804888333, 82.4691719, \"83\"],\n[54.9793757333, 82.4644864667, \"37\"],\n[54.9794654667, 82.4649678833, \"39\"],\n[54.9815936, 82.4721696167, \"104\"],\n[54.9806346333, 82.46753305, \"62\"],\n[54.9801957667, 82.4694512667, \"1/83\"],\n[54.9813943, 82.4789249667, \"2/172\"],\n[54.9811831333, 82.4791219167, \"1/172\"],\n[54.9815603333, 82.4787492833, \"3/172\"],\n[54.9817079333, 82.4785843667, \"4/172\"],\n[54.98098455, 82.4692836, \"84\"],\n[54.9797661167, 82.4828635833, \"209\"],\n[54.9819302167, 82.4751814833, \"130\"],\n[54.9810331167, 82.4792768333, \"172\"],\n[54.9791101833, 82.4807109667, \"193\"],\n[54.9211995833, 82.54297615, \"118\"],\n[54.9213446, 82.5421832, \"105\"],\n[54.9211681167, 82.54216685, \"107\"],\n[54.9209082667, 82.5425332333, \"111\"],\n[54.9208103667, 82.542655, \"113\"],\n[54.92117155, 82.5424739667, \"109\"],\n[54.9206148667, 82.5429439167, \"119\"],\n[54.9207782667, 82.5431801, \"117\"],\n[54.9210005833, 82.542809, \"115\"],\n[54.9223620333, 82.5419011, \"44\"],\n[54.9221513667, 82.5414861833, \"22\"],\n[54.9220122833, 82.54171955, \"48\"],\n[54.9214541667, 82.5419499167, \"103\"],\n[54.9216856333, 82.54226385, \"110\"],\n[54.92188255, 82.54189345, \"70\"],\n[54.9216037833, 82.5417236667, \"79\"],\n[54.9217873667, 82.5420768833, \"90\"],\n[54.9207292667, 82.5435594333, \"127\"],\n[54.9215061833, 82.5424147833, \"112\"],\n[54.9214096333, 82.5425683833, \"114\"],\n[54.9212674167, 82.5427841667, \"116\"],\n[54.9211160833, 82.5431952167, \"120\"],\n[54.9210373167, 82.5434004167, \"122\"],\n[54.9209575167, 82.5435602167, \"124\"],\n[54.9206745667, 82.5433710667, \"125\"],\n[54.92082745, 82.54361115, \"128\"],\n[54.9209216, 82.5437402667, \"126\"],\n[54.9205988167, 82.5431733333, \"123\"],\n[54.9204654167, 82.54300295, \"121\"],\n[54.9059849833, 82.4685779333, \"10\"],\n[54.9063778167, 82.4688591, \"11\"],\n[54.9057737333, 82.4693218333, \"2\"],\n[54.9064842, 82.4693450167, \"7\"],\n[54.9060801333, 82.46881255, \"12\"],\n[54.9060230333, 82.46940395, \"1\"],\n[54.9060816167, 82.4691977833, \"3\"],\n[54.90581185, 82.4691003833, \"4\"],\n[54.9063729333, 82.4693653667, \"5\"],\n[54.9058748833, 82.4689197333, \"6\"],\n[54.90586325, 82.46860955, \"8\"],\n[54.9064269833, 82.4690855667, \"9\"],\n[54.8955635667, 82.4714488333, \"3\"],\n[54.89574055, 82.4716702667, \"6\"],\n[54.8760291333, 82.4752209667, \"4\"],\n[54.8761012667, 82.4756677333, \"5\"],\n[54.8761172, 82.4749063833, \"6A\"],\n[54.8762485667, 82.4748657167, \"6B\"],\n[54.8765363167, 82.4750690167, \"10\"],\n[54.87633255, 82.4751297667, \"8\"],\n[54.8767972333, 82.4754502, \"13\"],\n[54.8767630833, 82.4749863833, \"12\"],\n[54.87581215, 82.4752698833, \"2\"],\n[54.8757609167, 82.4757446833, \"1\"],\n[54.8774312833, 82.4746756833, \"25\"],\n[54.87757445, 82.4749078, \"23\"],\n[54.8773315167, 82.4749104, \"21\"],\n[54.8772196833, 82.4750822833, \"19\"],\n[54.8771222167, 82.47521495, \"17\"],\n[54.8769752, 82.4753515167, \"15\"],\n[54.8766353, 82.47550835, \"11\"],\n[54.8764627667, 82.4755687833, \"9\"],\n[54.8762885333, 82.4756105, \"7\"],\n[54.8759247333, 82.4757173667, \"3\"],\n[54.8769794333, 82.4747672167, \"14\"],\n[54.97891525, 82.4601520333, \"772\"],\n[54.9464645333, 82.4822205167, \"329\"],\n[54.9470361333, 82.4829135, \"337\"],\n[54.9713491167, 82.4612835833, \"684\"],\n[54.9615547167, 82.4636732, \"578\"],\n[54.9642195, 82.4617228, \"606\"],\n[54.9214648167, 82.4783231833, \"49\"],\n[54.9212708833, 82.47781485, \"1/49\"],\n[54.9230265, 82.478089, \"65\"],\n[54.9669955167, 82.46143295, \"653\"],\n[54.9801441, 82.4596936833, \"784\"],\n[54.91909305, 82.4782088, \"27\"],\n[54.9278700667, 82.4760814333, \"122\"],\n[54.9393246667, 82.4798381833, \"256\"],\n[54.98099395, 82.4594168167, \"788\"],\n[54.9235198, 82.4765764833, \"76\"],\n[54.9838248833, 82.4507092333, \"885\"],\n[54.9840650667, 82.4492086167, \"893\"],\n[54.9819271833, 82.4584667833, \"812\"],\n[54.97680425, 82.4605180667, \"746\"],\n[54.9772555, 82.4612509, \"751\"],\n[54.9553357833, 82.4689185833, \"484\"],\n[54.9549016, 82.4705773167, \"469\"],\n[54.9549819, 82.4681984167, \"492\"],\n[54.95610765, 82.4687586833, \"495\"],\n[54.9558325167, 82.4681527833, \"496\"],\n[54.9563786, 82.4673479667, \"506\"],\n[54.9588897333, 82.4662872333, \"549\"],\n[54.9374805167, 82.4792935833, \"232\"],\n[54.9385204667, 82.4796240833, \"250\"],\n[54.9418827167, 82.48053625, \"282\"],\n[54.9422215667, 82.4814613667, \"291\"],\n[54.9452781, 82.4815002, \"318\"],\n[54.9482466667, 82.4790639833, \"372\"],\n[54.9497215167, 82.47691875, \"396\"],\n[54.9341688833, 82.4782591167, \"196\"],\n[54.9265146833, 82.4765383667, \"109\"],\n[54.93050445, 82.4778804333, \"151\"],\n[54.9283181, 82.4771124167, \"129\"],\n[54.9251162, 82.4762160667, \"98\"],\n[54.92343355, 82.4771558167, \"73\"],\n[54.9239441667, 82.4794231667, \"75\"],\n[54.9241087667, 82.4769972833, \"83\"],\n[54.9222823667, 82.4774759333, \"61\"],\n[54.9199369167, 82.4774060333, \"34\"],\n[54.9203899333, 82.475518, \"36\"],\n[54.9203777167, 82.4773256, \"40\"],\n[54.9206612167, 82.4765307833, \"42\"],\n[54.9210448, 82.4771433833, \"44\"],\n[54.9220389167, 82.47755095, \"57\"],\n[54.91929535, 82.4775611167, \"26\"],\n[54.9216718667, 82.4775874667, \"55\"],\n[54.98317275, 82.4515617, \"874\"],\n[54.9834542667, 82.449681, \"890\"],\n[54.94112955, 82.48040145, \"278\"],\n[54.9511382833, 82.4768400333, \"401\"],\n[54.9529536833, 82.4734404167, \"447\"],\n[54.9818127667, 82.4589793667, \"794\"],\n[54.9216345833, 82.4771334167, \"50\"],\n[54.9817718333, 82.4597500333, \"789\"],\n[54.8840469167, 82.4595505333, \"3A\"],\n[54.8836735833, 82.4604158333, \"4B\"],\n[54.88403835, 82.4600429333, \"5\"],\n[54.8834882, 82.4601379, \"1A\"],\n[54.88367125, 82.4597893667, \"1\"],\n[54.8835863, 82.4604458167, \"2A\"],\n[54.8835968, 82.4601401333, \"2\"],\n[54.88386135, 82.4597867, \"3\"],\n[54.88376075, 82.4601527667, \"4\"],\n[54.8838918833, 82.4601641667, \"6\"],\n[54.8842726667, 82.4597851667, \"5A\"],\n[54.8840725833, 82.4598049333, \"3B\"],\n[54.8976647333, 82.4710761333, \"3\"],\n[54.8975512333, 82.4708644667, \"7\"],\n[54.8973241167, 82.4703941833, \"15\"],\n[54.8972415667, 82.4702575667, \"17\"],\n[54.8973903333, 82.4705850167, \"13\"],\n[54.8974731667, 82.4707213, \"9\"],\n[54.8976014, 82.4709784167, \"5\"],\n[54.8973658833, 82.4713826333, \"1\"],\n[54.88263055, 82.4789374667, \"2\"],\n[54.88295785, 82.4787557167, \"3\"],\n[54.88262705, 82.4787408333, \"4\"],\n[54.8828655833, 82.47856665, \"5\"],\n[54.8826968, 82.4785708667, \"6\"],\n[54.8829381167, 82.4790952, \"1\"],\n[54.8829405833, 82.4789477, \"1A\"],\n[54.9471062833, 82.4443811, \"285\"],\n[54.9482693333, 82.4618783667, \"129\"],\n[54.9477489, 82.4616306833, \"134\"],\n[54.94778825, 82.4623992333, \"120\"],\n[54.9476318333, 82.4527723667, \"205\"],\n[54.9487271, 82.47377555, \"22\"],\n[54.9483278667, 82.4699560333, \"64\"],\n[54.9505486833, 82.475507, \"3\"],\n[54.9471956833, 82.45408385, \"192\"],\n[54.9474878167, 82.4494432167, \"241\"],\n[54.9465419167, 82.4494655333, \"240\"],\n[54.8980432167, 82.4818800667, \"20\"],\n[54.8980799167, 82.4813788167, \"11\"],\n[54.8979071, 82.4814689833, \"11A\"],\n[54.8976527, 82.4820540667, \"10\"],\n[54.8978225833, 82.48198855, \"12\"],\n[54.8980157833, 82.4823010833, \"14\"],\n[54.8981133, 82.4825153333, \"18\"],\n[54.8972657167, 82.48179755, \"1\"],\n[54.8982001167, 82.4818174667, \"22\"],\n[54.89831945, 82.48166055, \"26\"],\n[54.8974300667, 82.4821601, \"2\"],\n[54.8976037833, 82.4823142833, \"6\"],\n[54.8975959167, 82.4816213167, \"7\"],\n[54.8977532667, 82.48153515, \"9\"],\n[54.8985379, 82.4825481, \"24\"],\n[54.8966536667, 82.4826586833, \"25A\"],\n[54.8984072, 82.48528765, \"54A\"],\n[54.8960960167, 82.4812310167, \"5\"],\n[54.8976620167, 82.4837889667, \"38\"],\n[54.8957596833, 82.4808671833, \"1\"],\n[54.896049, 82.4808353333, \"1A\"],\n[54.89630705, 82.4808317833, \"3\"],\n[54.8980094, 82.4834140167, \"34\"],\n[54.89804835, 82.4835438167, \"36\"],\n[54.8978337, 82.483244, \"30\"],\n[54.8977234667, 82.4828271167, \"26\"],\n[54.8974671333, 82.4832206833, \"28\"],\n[54.89729555, 82.4826933167, \"22\"],\n[54.8982734, 82.4859548167, \"60\"],\n[54.8993387167, 82.4873577333, \"76\"],\n[54.8971479167, 82.4808783833, \"10\"],\n[54.8959557167, 82.48164725, \"11\"],\n[54.8973392833, 82.4807942, \"12\"],\n[54.8973916333, 82.4808756, \"14\"],\n[54.8966921833, 82.4822478333, \"21\"],\n[54.89642605, 82.4824713833, \"23\"],\n[54.8967609167, 82.4825135833, \"25\"],\n[54.8971820833, 82.4809704667, \"16\"],\n[54.89693775, 82.4814169833, \"18A\"],\n[54.8968612333, 82.4812093333, \"18\"],\n[54.8968348, 82.4827666333, \"27\"],\n[54.8969158833, 82.4829914167, \"29\"],\n[54.8969838333, 82.4832029333, \"31\"],\n[54.89760075, 82.4835397, \"32\"],\n[54.8970568167, 82.48351615, \"33\"],\n[54.8967365, 82.4807273, \"2\"],\n[54.8979339167, 82.4848533, \"44\"],\n[54.8967854, 82.4809565833, \"4\"],\n[54.8958402333, 82.481278, \"7\"],\n[54.8964383667, 82.4812642667, \"9\"],\n[54.8980381167, 82.4851460667, \"48\"],\n[54.8985301167, 82.4851492, \"52\"],\n[54.8981529, 82.4855380167, \"54\"],\n[54.8986448333, 82.4855899833, \"56\"],\n[54.8985807833, 82.4870328333, \"66\"],\n[54.8986987667, 82.4873079333, \"68\"],\n[54.8987788167, 82.4875430667, \"74\"],\n[54.89890085, 82.4879704667, \"80\"],\n[54.8966231333, 82.4820502667, \"17A\"],\n[54.8964502667, 82.4821239667, \"17B\"],\n[54.896275, 82.48221365, \"17\"],\n[54.8964864333, 82.4816180167, \"15\"],\n[54.89829765, 82.4849233667, \"48A\"],\n[54.8983503, 82.4862882, \"62\"],\n[54.8963564333, 82.4817611, \"15A\"],\n[54.8961816167, 82.4819250833, \"15B\"],\n[54.8838324667, 82.4758307667, \"1\"],\n[54.8836433833, 82.4758399333, \"2\"],\n[54.8833977167, 82.47575535, \"3\"],\n[54.8833314667, 82.4755896167, \"4\"],\n[54.8834651, 82.4752073, \"5A\"],\n[54.8833988833, 82.4754131, \"5\"],\n[54.8836138833, 82.4754014333, \"6\"],\n[54.88376315, 82.4754688833, \"7\"],\n[54.8453489, 82.4520246, \"12\"],\n[54.8453374333, 82.44998695, \"30\"],\n[54.8456579, 82.4496963667, \"33\"],\n[54.84527125, 82.4440318, \"40\"],\n[54.8447595167, 82.4494073667, \"38\"],\n[54.8453093333, 82.4489722667, \"40\"],\n[54.8453195333, 82.4515149667, \"16\"],\n[54.8833522167, 82.4662158833, \"2/13\"],\n[54.8838213, 82.46524815, \"10A\"],\n[54.88380855, 82.46613485, \"7A\"],\n[54.8832769, 82.4662041167, \"1/13\"],\n[54.88379275, 82.4654513833, \"10\"],\n[54.88377815, 82.4658082667, \"11\"],\n[54.88342395, 82.4662276833, \"3/13\"],\n[54.883518, 82.4662264667, \"4/13\"],\n[54.8836896667, 82.4656703833, \"14\"],\n[54.8834471333, 82.4658730667, \"15\"],\n[54.88344295, 82.46574735, \"16\"],\n[54.8843819333, 82.4658316167, \"1\"],\n[54.8844031667, 82.4655400167, \"2\"],\n[54.8841441667, 82.4660546, \"3A\"],\n[54.8841592333, 82.46611295, \"3B\"],\n[54.8842008167, 82.4658206, \"3\"],\n[54.8841960167, 82.4655438833, \"4\"],\n[54.8840714, 82.4658066333, \"5\"],\n[54.8840438, 82.4655440333, \"6\"],\n[54.8839425167, 82.46582275, \"7\"],\n[54.8839567167, 82.4654131167, \"8\"],\n[54.8837516, 82.4660999833, \"9\"],\n[54.883711, 82.4655393167, \"12\"],\n[54.9413734667, 82.4995142833, \"306\"],\n[54.9264553167, 82.4927426, \"101\"],\n[54.9263942667, 82.495421, \"93\"],\n[54.9367796667, 82.49396525, \"218\"],\n[54.9306420333, 82.4927391167, \"147\"],\n[54.9314740333, 82.4922045333, \"156\"],\n[54.9346698333, 82.4939321167, \"195\"],\n[54.9210469167, 82.49473535, \"45\"],\n[54.9244517667, 82.4930819833, \"76\"],\n[54.92482195, 82.4937379833, \"85\"],\n[54.9278428667, 82.49133405, \"116\"],\n[54.928097, 82.4920060333, \"117\"],\n[54.9259406, 82.4921851333, \"98\"],\n[54.9432639333, 82.5024320833, \"321\"],\n[54.9478774167, 82.50590725, \"360\"],\n[54.9006717, 82.3709368333, \"24\"],\n[54.90793765, 82.3650150333, \"121\"],\n[54.9056018833, 82.3671315333, \"89\"],\n[54.9073516833, 82.3655189333, \"119\"],\n[54.8986494833, 82.4611173667, \"1\"],\n[54.8984617833, 82.4610480667, \"3\"],\n[54.8983073667, 82.4609003333, \"5\"],\n[54.8985554833, 82.4614893833, \"2\"],\n[54.8983680333, 82.4614087, \"4\"],\n[54.8981331333, 82.4608315333, \"7\"],\n[54.8982140167, 82.4613434833, \"6\"],\n[54.8979873167, 82.4611021667, \"10\"],\n[54.8980203833, 82.4609355833, \"9\"],\n[54.89806, 82.4612782333, \"8\"],\n[54.9028616833, 82.4335225667, \"29\"],\n[54.9031164833, 82.4331062, \"27\"],\n[54.908270667, 82.4336130833, \"43\"],\n[54.9018962667, 82.4342030167, \"42\"],\n[54.9035645333, 82.4334544, \"21\"],\n[54.8997075167, 82.4313605167, \"63\"],\n[54.9028940667, 82.4339966333, \"28\"],\n[54.90126025, 82.43430315, \"54\"],\n[54.9009420667, 82.4335351333, \"57\"],\n[54.8997543667, 82.4328163667, \"67\"],\n[54.9042664833, 82.4334384833, \"9\"],\n[54.9004958, 82.4365008, \"56\"],\n[54.8999357667, 82.4364970167, \"58\"],\n[54.9193787167, 82.4035627667, \"29\"],\n[54.9187184, 82.40134295, \"50\"],\n[54.91970595, 82.4043742667, \"21\"],\n[54.93012645, 82.3979479333, \"179\"],\n[54.9287776167, 82.3984838, \"167\"],\n[54.9244404833, 82.40003235, \"125\"],\n[54.9182969, 82.4015440667, \"46\"],\n[54.9198358, 82.4009195, \"62\"],\n[54.9214928833, 82.4003147333, \"82\"],\n[54.9276005833, 82.3979560333, \"156\"],\n[54.9090980833, 82.47152255, \"112B\"],\n[54.9100087667, 82.47027605, \"121A\"],\n[54.90817245, 82.47139345, \"103\"],\n[54.90884805, 82.4719748, \"108A\"],\n[54.9089414167, 82.4722395833, \"108B\"],\n[54.9084711833, 82.47177935, \"104\"],\n[54.90863345, 82.47171425, \"106\"],\n[54.9083213167, 82.47131235, \"105\"],\n[54.9090004, 82.472447, \"108C\"],\n[54.9028464833, 82.4753390167, \"26B\"],\n[54.9078277833, 82.4723944833, \"4/96\"],\n[54.90357775, 82.4740898333, \"36\"],\n[54.90385065, 82.473554, \"35A\"],\n[54.9035803667, 82.47369605, \"35\"],\n[54.90815455, 82.4719365833, \"100\"],\n[54.91190955, 82.4702316833, \"138\"],\n[54.90756, 82.4722275333, \"7/96\"],\n[54.9089549167, 82.47103335, \"111\"],\n[54.9044076167, 82.4737216, \"42\"],\n[54.9011103, 82.4747561, \"13\"],\n[54.9113504333, 82.46916605, \"135B\"],\n[54.90916025, 82.4717170833, \"112A\"],\n[54.9104814167, 82.4713397667, \"124B\"],\n[54.9113419667, 82.4696552833, \"133A\"],\n[54.9116247167, 82.4707302833, \"134A\"],\n[54.9118128833, 82.4706304, \"134B\"],\n[54.9117777333, 82.46919275, \"139A\"],\n[54.91172915, 82.4689741333, \"139B\"],\n[54.9091821167, 82.47238525, \"110C\"],\n[54.9112748167, 82.46989875, \"131A\"],\n[54.9112112333, 82.46968315, \"131B\"],\n[54.9018407333, 82.474509, \"17\"],\n[54.9021059167, 82.4747859167, \"18\"],\n[54.9022214333, 82.4747533667, \"20\"],\n[54.9021081667, 82.4743658667, \"21\"],\n[54.9024045833, 82.4746604333, \"22\"],\n[54.90227905, 82.4742904, \"23\"],\n[54.9025434333, 82.4745909167, \"24\"],\n[54.9033884667, 82.4737883, \"33\"],\n[54.9029568833, 82.4739659833, \"31\"],\n[54.90244755, 82.4742011333, \"25\"],\n[54.9026128, 82.4741282667, \"27\"],\n[54.9027832333, 82.4740469833, \"29\"],\n[54.9027372833, 82.4744949833, \"30\"],\n[54.9028963667, 82.4744151167, \"32\"],\n[54.9039784167, 82.4735005167, \"39\"],\n[54.9041466, 82.47341055, \"41\"],\n[54.9043180167, 82.4733317667, \"43\"],\n[54.9044306, 82.4732717, \"45\"],\n[54.9002813333, 82.4746537333, \"3A\"],\n[54.9003363333, 82.4746345833, \"3B\"],\n[54.9003208833, 82.4742427, \"3C\"],\n[54.9004106, 82.47457215, \"3D\"],\n[54.9008182333, 82.4749564333, \"7\"],\n[54.9008622667, 82.4745689333, \"9A\"],\n[54.9087553333, 82.47168745, \"108\"],\n[54.9087847167, 82.47111335, \"109\"],\n[54.9090482, 82.4718688667, \"110A\"],\n[54.9089821833, 82.47162705, \"110\"],\n[54.9097564, 82.47064845, \"117\"],\n[54.90991065, 82.4711398333, \"118\"],\n[54.9098192, 82.4703204, \"119A\"],\n[54.9100781833, 82.4710667, \"120\"],\n[54.9102616, 82.4713288833, \"120A\"],\n[54.91019675, 82.4704249667, \"121\"],\n[54.9102786333, 82.47095955, \"122\"],\n[54.91061325, 82.47114525, \"124A\"],\n[54.9104595333, 82.4709259167, \"124\"],\n[54.9103273167, 82.4703685833, \"125\"],\n[54.9009658333, 82.47489005, \"9\"],\n[54.9106314167, 82.47081795, \"126\"],\n[54.9105098833, 82.4702934833, \"127\"],\n[54.9115283, 82.47038715, \"132\"],\n[54.9114078, 82.4698388833, \"133\"],\n[54.9117353833, 82.4702887167, \"136\"],\n[54.91165515, 82.4697282333, \"137\"],\n[54.91209905, 82.4701214833, \"140\"],\n[54.91192095, 82.46961505, \"141\"],\n[54.91209585, 82.4695346667, \"143\"],\n[54.91223925, 82.4694837833, \"145\"],\n[54.9129544, 82.46972655, \"148\"],\n[54.9127850833, 82.46918905, \"149\"],\n[54.9131046167, 82.4696231333, \"150\"],\n[54.9129241667, 82.4691591333, \"151\"],\n[54.9133420333, 82.4695050167, \"152\"],\n[54.9134355667, 82.4694691333, \"154\"],\n[54.9136254167, 82.4688124833, \"155\"],\n[54.9135736667, 82.4693978333, \"156\"],\n[54.9137485167, 82.4693549667, \"158\"],\n[54.9144754, 82.46902505, \"164\"],\n[54.9147488833, 82.4695174667, \"166\"],\n[54.9147467167, 82.4689613833, \"168\"],\n[54.9053532, 82.4735344167, \"44A\"],\n[54.9052717667, 82.4733045167, \"44\"],\n[54.90506265, 82.4729767833, \"49\"],\n[54.9052035667, 82.4729156167, \"51\"],\n[54.9053496, 82.4728617833, \"53\"],\n[54.9054862667, 82.47279975, \"55\"],\n[54.9071557, 82.47249445, \"88\"],\n[54.9011584833, 82.47587265, \"10\"],\n[54.9012260167, 82.4757750333, \"12\"],\n[54.9011779333, 82.47526505, \"14\"],\n[54.9024628, 82.4750374833, \"22A\"],\n[54.9024647, 82.4751844167, \"22B\"],\n[54.9004774333, 82.4751149333, \"1\"],\n[54.9028335, 82.4750389333, \"28\"],\n[54.9004664333, 82.4755579667, \"2\"],\n[54.9005692, 82.4755242167, \"4\"],\n[54.9006539333, 82.4750368333, \"5\"],\n[54.9010841833, 82.4755968, \"8A\"],\n[54.9008984167, 82.4753584833, \"8\"],\n[54.9091240667, 82.4721442833, \"110B\"],\n[54.9097632833, 82.47034635, \"117A\"],\n[54.9082253333, 82.4719109833, \"102\"],\n[54.9114097833, 82.4693441333, \"135A\"],\n[54.9112057333, 82.4692141667, \"135C\"],\n[54.91167365, 82.4687884833, \"139D\"],\n[54.9112668833, 82.4694056333, \"135\"],\n[54.9111444667, 82.4690280333, \"135D\"],\n[54.9115951667, 82.4692708167, \"139\"],\n[54.9115359, 82.4690900833, \"139C\"],\n[54.9106014, 82.4702607333, \"129\"],\n[54.9076115833, 82.4723767833, \"98\"],\n[54.9075872333, 82.4722996, \"8/96\"],\n[54.9076397833, 82.4724662167, \"10/96\"],\n[54.9076588167, 82.4725362667, \"11/96\"],\n[54.9076818333, 82.47261165, \"12/96\"],\n[54.90787275, 82.4725516833, \"6/96\"],\n[54.9078548167, 82.4724749, \"5/96\"],\n[54.9078033833, 82.47231415, \"3/96\"],\n[54.9077763833, 82.4722320833, \"2/96\"],\n[54.9077493833, 82.4721500167, \"1/96\"],\n[54.9027466667, 82.4750991167, \"26A\"],\n[54.9013304167, 82.4746607667, \"13A\"],\n[54.9012675, 82.4744082333, \"13B\"],\n[54.9010857333, 82.4744788167, \"13C\"],\n[54.91033795, 82.47011845, \"125A\"],\n[54.90225545, 82.4739976167, \"23A\"],\n[54.9099696333, 82.4705395667, \"119\"],\n[54.9152684167, 82.4687266333, \"176\"],\n[54.8767274167, 82.4498122333, \"31\"],\n[54.8753801, 82.4141292833, \"347\"],\n[54.8749301667, 82.4229940833, \"269\"],\n[54.8780543667, 82.4318462667, \"2/193\"],\n[54.87844965, 82.4315496667, \"4/193\"],\n[54.877916, 82.4313673167, \"3/193\"],\n[54.8772684667, 82.4313525833, \"1/193\"],\n[54.8745261, 82.41460525, \"336\"],\n[54.8730149167, 82.4139278833, \"348\"],\n[54.8749023333, 82.4133807833, \"357\"],\n[54.8748893, 82.4158492, \"331\"],\n[54.87500415, 82.4305876333, \"199\"],\n[54.8762052667, 82.4298853667, \"209\"],\n[54.876837, 82.4272319333, \"231\"],\n[54.8750526167, 82.4337470333, \"173\"],\n[54.8750786167, 82.4326617667, \"185\"],\n[54.8765961833, 82.4422767333, \"1/101\"],\n[54.8765928833, 82.44146825, \"2/101\"],\n[54.8766094667, 82.4450663167, \"1/75\"],\n[54.8751227667, 82.4479436, \"47\"],\n[54.8785082667, 82.4463698333, \"59\"],\n[54.8749291833, 82.42188625, \"275\"],\n[54.8750447, 82.4367026, \"145\"],\n[54.8746106333, 82.4284329, \"218\"],\n[54.8745961333, 82.4294403, \"210\"],\n[54.8729241167, 82.4301093, \"204\"],\n[54.8730751833, 82.4315361667, \"192\"],\n[54.8764695333, 82.4360706167, \"2/151\"],\n[54.8750668667, 82.4352073833, \"161\"],\n[54.8745754667, 82.4496806333, \"32\"],\n[54.87504855, 82.4370912, \"141\"],\n[54.8745623, 82.4221763333, \"276\"],\n[54.8745616667, 82.4217338333, \"278\"],\n[54.8749560667, 82.4206555833, \"291\"],\n[54.87457185, 82.42039215, \"292\"],\n[54.8749318, 82.4195155667, \"297\"],\n[54.8749193167, 82.4189609333, \"301\"],\n[54.8745523667, 82.4178998833, \"314\"],\n[54.87555895, 82.4169412167, \"317\"],\n[54.8727607, 82.4172541833, \"320\"],\n[54.87489075, 82.41689625, \"325\"],\n[54.8762137833, 82.4211919167, \"283\"],\n[54.8773094667, 82.4190741833, \"295\"],\n[54.8766782167, 82.4177899333, \"307\"],\n[54.87495795, 82.4292900167, \"211\"],\n[54.87496815, 82.4277122333, \"229\"],\n[54.87496315, 82.4270601833, \"235\"],\n[54.87495715, 82.4262284667, \"243\"],\n[54.87466625, 82.4340618833, \"166\"],\n[54.8731281333, 82.43353715, \"176\"],\n[54.8746368667, 82.43285965, \"180\"],\n[54.8746353667, 82.4320823333, \"188\"],\n[54.8746651833, 82.43837135, \"134\"],\n[54.8746581, 82.4361343333, \"152\"],\n[54.8766056667, 82.4444213667, \"2/75\"],\n[54.8750381333, 82.4425046833, \"95\"],\n[54.8758251333, 82.4478232833, \"49\"],\n[54.8751582, 82.4469793167, \"51\"],\n[54.8771227333, 82.4464864167, \"57\"],\n[54.8750768, 82.445912, \"61\"],\n[54.8750693833, 82.4452335333, \"71\"],\n[54.8765724333, 82.4321372667, \"191\"],\n[54.876819, 82.4318101833, \"1/191\"],\n[54.8750694, 82.4518701667, \"15\"],\n[54.8750833, 82.4512497167, \"21\"],\n[54.87511365, 82.449825667, \"37\"],\n[54.8744741833, 82.4113393, \"372\"],\n[54.87448925, 82.4111035167, \"374\"],\n[54.8749085333, 82.4183780667, \"309\"],\n[54.8748987, 82.4119560833, \"371\"],\n[54.8754877, 82.4485419667, \"43\"],\n[54.87489105, 82.4142969333, \"1/347\"],\n[54.87509285, 82.4505922, \"23\"],\n[54.8746456667, 82.4350032667, \"162\"],\n[54.8817882333, 82.46555605, \"1\"],\n[54.8817762333, 82.4657047, \"2\"],\n[54.88177495, 82.4658300167, \"3\"],\n[54.8818317167, 82.4659088333, \"4\"],\n[54.8818769833, 82.4658514167, \"5\"],\n[54.881892, 82.4657157833, \"6\"],\n[54.8819030667, 82.4655528667, \"7\"],\n[54.8249572667, 82.3822644167, \"62C\"],\n[54.8241013167, 82.3830562833, \"62B\"],\n[54.8235533667, 82.3836837833, \"62A\"],\n[54.8232282333, 82.38113915, \"42\"],\n[54.8216185167, 82.3801976167, \"24\"],\n[54.8233693667, 82.3818881167, \"50\"],\n[54.8238237167, 82.38163785, \"48\"],\n[54.8223544167, 82.3807860167, \"34\"],\n[54.8221907167, 82.38064385, \"32\"],\n[54.798240833, 82.4757575167, \"369\"],\n[54.7917070167, 82.4768378667, \"371\"],\n[54.7976220833, 82.4791485667, \"310\"],\n[54.8026816667, 82.4738649167, \"241\"],\n[54.8063079833, 82.4719216833, \"198\"],\n[54.8127222, 82.46321975, \"88\"],\n[54.79851905, 82.4782582, \"298\"],\n[54.7982161667, 82.4784413833, \"300\"],\n[54.7979628667, 82.4785954333, \"304\"],\n[54.7989472167, 82.4770213333, \"289\"],\n[54.8124759, 82.46149895, \"66\"],\n[54.80813105, 82.4692921667, \"133\"],\n[54.80903515, 82.4695616333, \"164\"],\n[54.81169535, 82.4617913167, \"77\"],\n[54.7931904667, 82.4771456167, \"359\"],\n[54.90154435, 82.4820577833, \"17A\"],\n[54.9023211333, 82.4866221333, \"50\"],\n[54.9029791167, 82.4860176833, \"43\"],\n[54.9018640167, 82.4839159667, \"29\"],\n[54.9017065667, 82.4845584, \"32\"],\n[54.9013472667, 82.4832850333, \"20\"],\n[54.9022597667, 82.4852180667, \"37\"],\n[54.90235635, 82.4855437333, \"39\"],\n[54.9020226167, 82.48626825, \"48A\"],\n[54.90219835, 82.4862075833, \"48\"],\n[54.9028144833, 82.4859300667, \"41A\"],\n[54.9019145833, 82.4857036333, \"38\"],\n[54.9012494167, 82.4836438333, \"22A\"],\n[54.90117625, 82.4832889167, \"20A\"],\n[54.9013004333, 82.4831083, \"18A\"],\n[54.9018345667, 82.48310725, \"23A\"],\n[54.9014717833, 82.4845211, \"30A\"],\n[54.9011141833, 82.4813179833, \"11\"],\n[54.9012595833, 82.4829706167, \"18\"],\n[54.9012063333, 82.4815285167, \"13\"],\n[54.90106015, 82.48224675, \"14\"],\n[54.9014018333, 82.4835019, \"22\"],\n[54.90164195, 82.4831019333, \"23\"],\n[54.9014562667, 82.4837066, \"24\"],\n[54.9017002833, 82.48331585, \"25\"],\n[54.9013501333, 82.4820586167, \"17\"],\n[54.9017979167, 82.48370115, \"27A\"],\n[54.9017437333, 82.4834995, \"27\"],\n[54.9015959833, 82.4841416, \"28\"],\n[54.9016565333, 82.4843582167, \"30\"],\n[54.9019526833, 82.4841925, \"31\"],\n[54.90202855, 82.4844477667, \"33\"],\n[54.9008982667, 82.4817133, \"8\"],\n[54.9024487833, 82.4858792167, \"41\"],\n[54.9020930667, 82.4858615167, \"42\"],\n[54.9025991167, 82.4863993167, \"49\"],\n[54.9021011667, 82.4846921667, \"35\"],\n[54.9014189333, 82.4823503167, \"19\"],\n[54.90126485, 82.4817892167, \"15\"],\n[54.9015360333, 82.4839226833, \"26\"],\n[54.83531625, 82.4933037333, \"196\"],\n[54.8352276167, 82.4927147833, \"195\"],\n[54.8360773, 82.4912368, \"187\"],\n[54.8346867167, 82.49328105, \"201\"],\n[54.82529725, 82.5052682333, \"361\"],\n[54.8370500167, 82.4896684, \"163\"],\n[54.8396963333, 82.4849568, \"1/133\"],\n[54.8292152667, 82.4972928333, \"281\"],\n[54.8293017833, 82.4982716333, \"300\"],\n[54.8282765333, 82.4989055, \"307\"],\n[54.8274501333, 82.5007519833, \"333\"],\n[54.8273441167, 82.5024751333, \"2/336\"],\n[54.8261453167, 82.5047067667, \"360\"],\n[54.8301054, 82.4958695333, \"275\"],\n[54.8271283667, 82.5028555, \"1/336\"],\n[54.8369560667, 82.4905711833, \"172\"],\n[54.81904615, 82.5025335167, \"7/369\"],\n[54.8218408167, 82.50377335, \"4/369\"],\n[54.8209456333, 82.5022760833, \"6/369\"],\n[54.8208349667, 82.5044007, \"5/369\"],\n[54.8238658, 82.50523275, \"2/369\"],\n[54.8190694, 82.5003232333, \"8/369\"],\n[54.8120237667, 82.5010552833, \"10/369\"],\n[54.8118820833, 82.50392555, \"11/369\"],\n[54.8356394, 82.4927849, \"192\"],\n[54.8452920167, 82.4770441167, \"6\"],\n[54.8332265167, 82.4939223333, \"232\"],\n[54.8297708, 82.4960635, \"253\"],\n[54.8393579167, 82.4857046667, \"2/133\"],\n[54.83878395, 82.48766725, \"142\"],\n[54.8379286333, 82.4890502, \"152\"],\n[54.8364941, 82.4914751, \"186\"],\n[54.8248432833, 82.5066992833, \"369\"],\n[54.82553745, 82.5068898833, \"380\"],\n[54.83202985, 82.4941239333, \"240\"],\n[54.82194035, 82.5057576833, \"3/369\"],\n[54.8227608167, 82.5063209333, \"1/369\"],\n[54.8141088167, 82.5037792333, \"9/369\"],\n[54.8382942833, 82.48852635, \"148\"],\n[54.8603913833, 82.4492696, \"57\"],\n[54.8592938167, 82.42099095, \"308C\"],\n[54.85984295, 82.42067725, \"308B\"],\n[54.8598229167, 82.4210151667, \"308A\"],\n[54.8598344333, 82.3976947833, \"508\"],\n[54.8603243333, 82.4140272833, \"369\"],\n[54.8603184, 82.4123881167, \"385\"],\n[54.86106375, 82.4477743833, \"67\"],\n[54.861365, 82.4476857667, \"73\"],\n[54.8613431833, 82.4479565167, \"69\"],\n[54.86191185, 82.44788405, \"71\"],\n[54.8603987333, 82.4502737667, \"53\"],\n[54.86045645, 82.4319935167, \"209\"],\n[54.8603551333, 82.4258720333, \"263\"],\n[54.8599289833, 82.4315900833, \"210\"],\n[54.8604198833, 82.4334522667, \"195\"],\n[54.8627496167, 82.42078385, \"309B\"],\n[54.8609723167, 82.4515878667, \"37\"],\n[54.8603717833, 82.4514413333, \"39\"],\n[54.8609809, 82.4517044667, \"35\"],\n[54.86096795, 82.45250335, \"27\"],\n[54.8604741333, 82.4530975833, \"17\"],\n[54.8603852667, 82.451807, \"33\"],\n[54.8572038, 82.42770555, \"246\"],\n[54.8604631667, 82.4363373667, \"171\"],\n[54.8591713833, 82.4484903833, \"62\"],\n[54.8604119667, 82.4340429333, \"191\"],\n[54.8603663667, 82.4354625167, \"179\"],\n[54.8603935, 82.4373993667, \"161\"],\n[54.8600009, 82.44318935, \"108\"],\n[54.8599224167, 82.4265426167, \"256\"],\n[54.8612047333, 82.4464131333, \"81B\"],\n[54.8599028667, 82.4231039167, \"288\"],\n[54.8602706, 82.4220058333, \"295\"],\n[54.8602638667, 82.4191497333, \"323\"],\n[54.8609657667, 82.4187969, \"327\"],\n[54.8602931, 82.4179491333, \"329\"],\n[54.8598848667, 82.4176532167, \"338\"],\n[54.8632475167, 82.4173751333, \"339\"],\n[54.8599251667, 82.4255647333, \"1/264\"],\n[54.8599279667, 82.4253799333, \"2/264\"],\n[54.86045495, 82.4383567333, \"157\"],\n[54.8604267333, 82.4421660333, \"113\"],\n[54.8617114333, 82.4414719167, \"125\"],\n[54.8603943167, 82.43982245, \"143\"],\n[54.8604978, 82.4449393667, \"89\"],\n[54.8603957167, 82.4488193667, \"59\"],\n[54.8599959167, 82.4481568167, \"64\"],\n[54.8603463333, 82.4481201667, \"65\"],\n[54.8603207833, 82.44708855, \"75\"],\n[54.8617075, 82.4464497667, \"85\"],\n[54.8603354667, 82.4458761167, \"87\"],\n[54.8603924833, 82.4529279333, \"21\"],\n[54.8603805, 82.4522459167, \"31\"],\n[54.8603894333, 82.4465241, \"81\"],\n[54.8624513667, 82.4464558667, \"2/85\"],\n[54.8603426, 82.42038605, \"309A\"],\n[54.8597382167, 82.4030150833, \"468\"],\n[54.8600008333, 82.4468853333, \"78\"],\n[54.8600151833, 82.4476529333, \"70\"],\n[54.8619444167, 82.4473194667, \"77\"],\n[54.8604090333, 82.4206673167, \"309\"],\n[54.8599482667, 82.4450833833, \"90\"],\n[54.8599667333, 82.4439503167, \"102\"],\n[54.8599639167, 82.4443829333, \"98\"],\n[54.8604016667, 82.4435244167, \"107\"],\n[54.8602872667, 82.4157777167, \"357C\"],\n[54.8619551667, 82.4154903667, \"357B\"],\n[54.8602759333, 82.41535695, \"357\"],\n[54.8599460833, 82.4464074167, \"82\"],\n[54.8585100167, 82.4461918667, \"84\"],\n[54.8604238667, 82.4437588667, \"105\"],\n[54.86030515, 82.4229068167, \"289\"],\n[54.9165466667, 82.5400699667, \"47\"],\n[54.9163835, 82.5395208667, \"52\"],\n[54.9162024833, 82.5415235333, \"4/35\"],\n[54.9138618, 82.5389959167, \"20\"],\n[54.9147363, 82.5367299167, \"4\"],\n[54.9171924833, 82.5398619667, \"53\"],\n[54.9156216333, 82.5400467167, \"1/35\"],\n[54.9156090167, 82.5406467667, \"2/35\"],\n[54.9155483, 82.54130355, \"3/35\"],\n[54.9161911333, 82.5412111333, \"5/35\"],\n[54.9177019333, 82.5406090667, \"57\"],\n[54.9172073167, 82.5390771667, \"56\"],\n[54.8413934333, 82.3669168333, \"185\"],\n[54.8417850333, 82.3689200833, \"199\"],\n[54.8428339667, 82.3706989, \"216\"],\n[54.8416074, 82.36479145, \"164\"],\n[54.8409904167, 82.3645986833, \"157\"],\n[54.84092815, 82.3644066167, \"161\"],\n[54.8749487833, 82.4757354167, \"4\"],\n[54.8748824667, 82.4752927333, \"3\"],\n[54.8746354, 82.475246, \"5\"],\n[54.8742075167, 82.4755986333, \"10\"],\n[54.8743622667, 82.4759894667, \"8A\"],\n[54.8744567667, 82.4756695333, \"8\"],\n[54.8748683833, 82.4760352167, \"4A\"],\n[54.8742254333, 82.47601205, \"10A\"],\n[54.8747158167, 82.4760297167, \"6A\"],\n[54.8746737833, 82.4757186333, \"6\"],\n[54.9465236167, 82.3809737667, \"672\"],\n[54.9005455, 82.4730509333, \"22\"],\n[54.9003672167, 82.4684980833, \"17\"],\n[54.9003614667, 82.4682696667, \"13\"],\n[54.9009926333, 82.4714326, \"18B\"],\n[54.9004931, 82.4733237333, \"24\"],\n[54.90023555, 82.4663222333, \"3\"],\n[54.9003731333, 82.4738848333, \"30\"],\n[54.90041915, 82.4736641333, \"28A\"],\n[54.9008516833, 82.47143275, \"18A\"],\n[54.9009989333, 82.4716885333, \"18C\"],\n[54.9011166833, 82.4715942833, \"18D\"],\n[54.9013468667, 82.4716314833, \"18E\"],\n[54.9013142333, 82.4713999333, \"18F\"],\n[54.9007320667, 82.4678888833, \"12\"],\n[54.9007490333, 82.4682728833, \"14\"],\n[54.9002906, 82.4672436333, \"11\"],\n[54.9005921667, 82.4728228833, \"20\"],\n[54.9012265333, 82.4713549, \"18G\"],\n[54.8998487333, 82.4663062167, \"1\"],\n[54.9004667833, 82.4734721, \"26\"],\n[54.9007287833, 82.4668388, \"4\"],\n[54.9002529667, 82.4665572, \"5\"],\n[54.9002680333, 82.4668009667, \"7\"],\n[54.9002738833, 82.4670198667, \"9\"],\n[54.90052665, 82.4737441167, \"28B\"],\n[54.9202440833, 82.4647199333, \"59\"],\n[54.9186491, 82.4631960333, \"74\"],\n[54.9197376, 82.46404755, \"63\"],\n[54.9209585333, 82.4715133667, \"31\"],\n[54.92198325, 82.4719067667, \"32\"],\n[54.9200168333, 82.4637374167, \"64\"],\n[54.9199907667, 82.4714465333, \"9\"],\n[54.91941015, 82.4649217833, \"65\"],\n[54.9196411667, 82.4633694333, \"66\"],\n[54.91916365, 82.4639929833, \"67A\"],\n[54.9194144667, 82.4637018833, \"67\"],\n[54.9193556833, 82.4631293833, \"70\"],\n[54.9191286667, 82.4630976, \"72\"],\n[54.9189485833, 82.4635427667, \"69\"],\n[54.9201641167, 82.4662894167, \"55\"],\n[54.9211940333, 82.4656174833, \"56A\"],\n[54.920671, 82.4657966667, \"56\"],\n[54.92006415, 82.4658042, \"57A\"],\n[54.9213706, 82.4727426833, \"23\"],\n[54.9214441667, 82.4732278667, \"24\"],\n[54.9202821667, 82.4732763833, \"18\"],\n[54.9204884667, 82.4729263, \"19\"],\n[54.9211967, 82.47098555, \"33\"],\n[54.92094835, 82.4706909167, \"35\"],\n[54.9219078167, 82.47147535, \"34\"],\n[54.9197843667, 82.46309625, \"68\"],\n[54.9210935333, 82.46484215, \"60A\"],\n[54.9212236167, 82.4704147167, \"40\"],\n[54.9197908, 82.4659149333, \"55A\"],\n[54.92033405, 82.4655102, \"57\"],\n[54.9211895167, 82.46547285, \"58A\"],\n[54.9207404, 82.46524515, \"58\"],\n[54.91857275, 82.4635986167, \"71\"],\n[54.9182674667, 82.46367495, \"73\"],\n[54.9195246333, 82.4715611, \"11\"],\n[54.9216761833, 82.4729861167, \"26\"],\n[54.92162375, 82.4721619667, \"27\"],\n[54.9218544, 82.4726169833, \"28\"],\n[54.9215389333, 82.4715153167, \"29\"],\n[54.9219467167, 82.4722808333, \"30\"],\n[54.9193754, 82.4726740833, \"12\"],\n[54.9195867667, 82.4721921667, \"13\"],\n[54.9196743333, 82.4735581167, \"14A\"],\n[54.91978385, 82.4729767167, \"14\"],\n[54.9200549833, 82.4726106667, \"15\"],\n[54.9197512333, 82.4737709, \"16\"],\n[54.9204467, 82.4722458667, \"17\"],\n[54.9199559, 82.4736553667, \"18A\"],\n[54.9193368833, 82.4700432833, \"1\"],\n[54.9218013667, 82.4711677833, \"36\"],\n[54.9204076, 82.4708148667, \"37\"],\n[54.928217833, 82.4702188667, \"38A\"],\n[54.9215826, 82.4708205333, \"38\"],\n[54.9207000333, 82.4703961167, \"39\"],\n[54.9205687167, 82.4700339833, \"41\"],\n[54.9208976, 82.46987095, \"42\"],\n[54.92033355, 82.4687946, \"45\"],\n[54.91982325, 82.4679912667, \"47A\"],\n[54.9209613833, 82.4677278167, \"48A\"],\n[54.92131875, 82.4676346167, \"48B\"],\n[54.9205986, 82.4680208, \"48\"],\n[54.9196399667, 82.4679596667, \"49B\"],\n[54.9202544833, 82.4681937167, \"47\"],\n[54.9198937833, 82.4678851833, \"49A\"],\n[54.9205374667, 82.46738275, \"50\"],\n[54.9213241, 82.4675107, \"50B\"],\n[54.9201188667, 82.4669429, \"51\"],\n[54.92103205, 82.4665559333, \"52A\"],\n[54.9205449167, 82.4668373833, \"52\"],\n[54.9198923833, 82.46667, \"53\"],\n[54.9210808167, 82.4664227833, \"54A\"],\n[54.920561, 82.4662841333, \"54\"],\n[54.91946705, 82.4707291667, \"5\"],\n[54.9193920833, 82.47035955, \"3\"],\n[54.9195288167, 82.4710633833, \"7\"],\n[54.92069515, 82.4648828167, \"60\"],\n[54.9209773667, 82.4675400333, \"50A\"],\n[54.9201842667, 82.46752845, \"49\"],\n[54.9200461167, 82.4643875333, \"61\"],\n[54.9205402833, 82.4644506333, \"62\"],\n[54.9196651333, 82.4646621833, \"63A\"],\n[54.9211008833, 82.4733943, \"22\"],\n[54.9207025167, 82.4734697333, \"20\"],\n[54.9209406667, 82.47297795, \"21\"],\n[54.9211156333, 82.4720907167, \"25\"],\n[54.9221545333, 82.4731278833, \"26A\"],\n[54.8946718167, 82.4691448667, \"53\"],\n[54.8945620667, 82.46918055, \"55\"],\n[54.8942623667, 82.4697152833, \"52\"],\n[54.894203, 82.4688735167, \"65\"],\n[54.89425415, 82.4689361333, \"63\"],\n[54.89414905, 82.4688349167, \"67\"],\n[54.8939181333, 82.4694227167, \"64\"],\n[54.8938391333, 82.4693460667, \"66\"],\n[54.8907021167, 82.4667148333, \"93\"],\n[54.8906039, 82.4666683167, \"95\"],\n[54.8902027167, 82.4664942833, \"103\"],\n[54.8905652, 82.4673196167, \"92\"],\n[54.8898694, 82.4663493333, \"107\"],\n[54.8897077333, 82.4662881167, \"113\"],\n[54.8897784833, 82.4663228, \"111\"],\n[54.8956830333, 82.4710189333, \"32\"],\n[54.8955352667, 82.4709092833, \"36\"],\n[54.8954734333, 82.4708266833, \"38\"],\n[54.8960418333, 82.47138995, \"28\"],\n[54.8820345667, 82.46329545, \"3/201\"],\n[54.8822174333, 82.46335335, \"1/201\"],\n[54.8821085167, 82.4633248, \"2/201\"],\n[54.8823766667, 82.4634171667, \"197\"],\n[54.8841371, 82.46403415, \"82A\"],\n[54.8841525333, 82.4636656, \"82B\"],\n[54.8864762667, 82.4645354333, \"151\"],\n[54.8863782833, 82.4644388833, \"153\"],\n[54.8862153, 82.4648985833, \"155\"],\n[54.8860901, 82.4648409833, \"157\"],\n[54.8880628167, 82.4656834833, \"133\"],\n[54.8878619333, 82.4655976667, \"135\"],\n[54.8906979667, 82.4673655, \"90\"],\n[54.8907991, 82.4667608667, \"91\"],\n[54.8961849167, 82.4707743833, \"25\"],\n[54.8836823667, 82.4638652167, \"181\"],\n[54.8836385667, 82.4632253833, \"183\"],\n[54.8838402, 82.4639201167, \"179\"],\n[54.8982437333, 82.4734017333, \"1\"],\n[54.8849776167, 82.46438955, \"171\"],\n[54.8843719833, 82.4641355167, \"173\"],\n[54.8839963167, 82.4632512833, \"177\"],\n[54.88393085, 82.4634884, \"179B\"],\n[54.8837384333, 82.4634720333, \"181A\"],\n[54.8834786833, 82.4638174667, \"185\"],\n[54.8834804667, 82.46322915, \"187\"],\n[54.8833056667, 82.4637555833, \"189\"],\n[54.88310485, 82.4633649667, \"191A\"],\n[54.8831340833, 82.4636871, \"191\"],\n[54.8830253167, 82.4636718333, \"193\"],\n[54.8819504, 82.4632695667, \"203\"],\n[54.88170725, 82.4631031, \"205\"],\n[54.88149825, 82.4630156833, \"207\"],\n[54.8813178333, 82.4626260667, \"209A\"],\n[54.8813002167, 82.4629425167, \"209\"],\n[54.8810862833, 82.4628550167, \"211\"],\n[54.8884475, 82.46494685, \"125A\"],\n[54.88836565, 82.4649932, \"127A\"],\n[54.88680255, 82.4645032, \"145\"],\n[54.8866910333, 82.4647031667, \"147A\"],\n[54.8863981167, 82.4649715167, \"149\"],\n[54.8859491, 82.4647828333, \"159\"],\n[54.8857348333, 82.4647021333, \"161\"],\n[54.8856289833, 82.4642462833, \"163\"],\n[54.8854787333, 82.4646066833, \"165\"],\n[54.8853169667, 82.4645344833, \"167\"],\n[54.8851657167, 82.4644626667, \"169\"],\n[54.89008265, 82.4664379167, \"105\"],\n[54.8888476167, 82.4659953167, \"117\"],\n[54.88862475, 82.4659086167, \"121\"],\n[54.8884613833, 82.4658299, \"123\"],\n[54.8884445167, 82.4652906, \"125\"],\n[54.8883496833, 82.46527395, \"127\"],\n[54.8882554833, 82.46575415, \"129\"],\n[54.8881798833, 82.4652017833, \"131\"],\n[54.8876298667, 82.4655107667, \"137\"],\n[54.8874722667, 82.4654312667, \"139\"],\n[54.8870441833, 82.4652550333, \"141\"],\n[54.8868197, 82.46516795, \"143\"],\n[54.8865865, 82.46503135, \"147\"],\n[54.8944378167, 82.4698605333, \"48\"],\n[54.8943299667, 82.4697972167, \"50\"],\n[54.8946586167, 82.46927655, \"51\"],\n[54.8942089833, 82.4696627, \"54\"],\n[54.89410215, 82.46963495, \"56\"],\n[54.8944861833, 82.4691251333, \"57\"],\n[54.89410185, 82.4695671167, \"58\"],\n[54.89440395, 82.4690316833, \"59\"],\n[54.8940363833, 82.4695254833, \"60\"],\n[54.8943071333, 82.4689793333, \"61\"],\n[54.8939694333, 82.4694826, \"62\"],\n[54.8937483667, 82.4692441333, \"68\"],\n[54.8940153, 82.4687127667, \"69\"],\n[54.8936944333, 82.4691774333, \"70\"],\n[54.8939444833, 82.4686454167, \"71\"],\n[54.8914311167, 82.4676565833, \"78\"],\n[54.8914605833, 82.4668025833, \"81\"],\n[54.8911125833, 82.467531, \"82\"],\n[54.8913374667, 82.46691925, \"83\"],\n[54.8909541667, 82.4674899167, \"84\"],\n[54.8912424167, 82.4668760167, \"85\"],\n[54.89086865, 82.4674540833, \"86\"],\n[54.8911290333, 82.46682535, \"87\"],\n[54.8908065333, 82.4674188167, \"88\"],\n[54.8909961333, 82.4667623333, \"89\"],\n[54.89043345, 82.4672657667, \"98\"],\n[54.8976105333, 82.47313585, \"10\"],\n[54.8975240667, 82.47213955, \"17\"],\n[54.8964341, 82.4719897, \"18\"],\n[54.8965768167, 82.4718193667, \"20\"],\n[54.8964536167, 82.47098525, \"21\"],\n[54.8965168, 82.4717821667, \"22\"],\n[54.8963066833, 82.4708868167, \"23\"],\n[54.8964117, 82.4716877833, \"24\"],\n[54.8973729833, 82.4718744167, \"19\"],\n[54.8961056167, 82.4707024167, \"27\"],\n[54.89606105, 82.4706588333, \"29\"],\n[54.8957499, 82.4710900333, \"30\"],\n[54.8960081167, 82.4706084667, \"31\"],\n[54.89595535, 82.4705515167, \"33\"],\n[54.8962650667, 82.4715582333, \"26\"],\n[54.8977395833, 82.4736163833, \"2A\"],\n[54.8976182167, 82.4734736333, \"2\"],\n[54.8950879167, 82.4697355, \"49\"],\n[54.8953451167, 82.47080125, \"40\"],\n[54.8952480833, 82.4706864833, \"42\"],\n[54.8953311333, 82.4699905167, \"43\"],\n[54.8951690167, 82.4705682833, \"44\"],\n[54.8952598667, 82.4699087, \"45\"],\n[54.8951447333, 82.4705209333, \"46\"],\n[54.8951409333, 82.4698058667, \"47\"],\n[54.8954689333, 82.4701014167, \"41A\"],\n[54.8958601667, 82.4704608833, \"35\"],\n[54.8957632833, 82.4703618, \"37\"],\n[54.89565655, 82.4702728333, \"39\"],\n[54.8955528, 82.4701858833, \"41\"],\n[54.8976127167, 82.4736873167, \"4A\"],\n[54.8974748, 82.4735857667, \"4\"],\n[54.8973855833, 82.4735356667, \"6\"],\n[54.8974473167, 82.4733615667, \"8\"],\n[54.8896038, 82.4662530833, \"115\"],\n[54.8938700833, 82.46857325, \"73\"],\n[54.8913213333, 82.4676180667, \"80\"],\n[54.89351535, 82.4690702167, \"76\"],\n[54.8936501, 82.4683802833, \"77\"],\n[54.8937599333, 82.4684853667, \"75\"],\n[54.8935794833, 82.4691255, \"72\"],\n[54.88384375, 82.4636547333, \"179A\"],\n[54.8877088, 82.4661684833, \"104\"],\n[54.8853223833, 82.4655525667, \"128B\"],\n[54.88438085, 82.4648718667, \"136C\"],\n[54.8841924667, 82.46482515, \"138\"],\n[54.8840040333, 82.4647229667, \"140\"],\n[54.8838259833, 82.4646471667, \"142\"],\n[54.8836846833, 82.4645814167, \"144\"],\n[54.8833978167, 82.4647726167, \"146A\"],\n[54.88347465, 82.46450515, \"146\"],\n[54.8832495667, 82.4646684333, \"148B\"],\n[54.8833107333, 82.4644183167, \"148A\"],\n[54.8830987333, 82.4643600833, \"150\"],\n[54.88243095, 82.4641342, \"152\"],\n[54.8822347333, 82.4643721667, \"154A\"],\n[54.88231865, 82.4640810833, \"154\"],\n[54.8820192, 82.4644994833, \"156\"],\n[54.8820541833, 82.46428995, \"158A\"],\n[54.8821268, 82.4640207, \"158\"],\n[54.88190465, 82.4639371333, \"160\"],\n[54.8817260167, 82.4638787833, \"162\"],\n[54.8814407667, 82.4640942167, \"164A\"],\n[54.8815740333, 82.46375875, \"164\"],\n[54.8814061667, 82.4637101333, \"166\"],\n[54.8812219167, 82.4636397667, \"168\"],\n[54.8810714, 82.4635707167, \"170\"],\n[54.8849612333, 82.4651687333, \"134\"],\n[54.8867657833, 82.46587165, \"116\"],\n[54.8873525667, 82.4663687, \"108A\"],\n[54.8875141333, 82.46643145, \"108B\"],\n[54.88740205, 82.4660429667, \"108\"],\n[54.8872605, 82.46600665, \"110\"],\n[54.8870516667, 82.4659278333, \"114\"],\n[54.8859261833, 82.4657479333, \"122A\"],\n[54.8859050667, 82.4659105167, \"122B\"],\n[54.8859588, 82.4655614, \"122\"],\n[54.88575615, 82.4657199833, \"124A\"],\n[54.8857864167, 82.4655019333, \"124\"],\n[54.8855956333, 82.46541875, \"126\"],\n[54.8854599, 82.4652737833, \"128\"],\n[54.8852678333, 82.46529905, \"130\"],\n[54.8850946667, 82.4652269667, \"132\"],\n[54.8878558833, 82.4662192833, \"100\"],\n[54.88434005, 82.4648704833, \"136B\"],\n[54.88430585, 82.4648585667, \"136A\"],\n[54.9102085667, 82.47267125, \"50B\"],\n[54.9116658, 82.4774299167, \"86A\"],\n[54.91171815, 82.4771741167, \"82A\"],\n[54.90942125, 82.47189105, \"37\"],\n[54.91030625, 82.47526205, \"63B\"],\n[54.9104127167, 82.4752166, \"63A\"],\n[54.9095648833, 82.47290545, \"49A\"],\n[54.9093032333, 82.4714794833, \"35A\"],\n[54.90934235, 82.47164185, \"35B\"],\n[54.9093857333, 82.4728978167, \"47B\"],\n[54.9095356333, 82.4723232833, \"43\"],\n[54.9094703333, 82.4721117667, \"39\"],\n[54.9096594333, 82.4715342167, \"40\"],\n[54.9080098833, 82.4672010667, \"5\"],\n[54.9083293833, 82.4682696833, \"13\"],\n[54.9089423167, 82.4690827667, \"20\"],\n[54.9089409167, 82.4702961167, \"29\"],\n[54.9081540667, 82.46658445, \"2\"],\n[54.9097415167, 82.478228833, \"42\"],\n[54.9101694333, 82.4746051167, \"57\"],\n[54.9080884, 82.4674672833, \"7\"],\n[54.91215875, 82.4797119167, \"102\"],\n[54.9118344667, 82.4799542, \"103\"],\n[54.9106944, 82.4744461, \"62A\"],\n[54.9113962667, 82.4772112333, \"82\"],\n[54.90982995, 82.4733563, \"51A\"],\n[54.9115914833, 82.4801362333, \"107A\"],\n[54.9092558833, 82.4696357, \"26B\"],\n[54.91002055, 82.4726635167, \"50A\"],\n[54.90847515, 82.46755925, \"10\"],\n[54.9082532667, 82.4680019333, \"11\"],\n[54.9088822833, 82.4688571833, \"18\"],\n[54.9086208167, 82.4692152333, \"19\"],\n[54.9085374333, 82.4677686333, \"12\"],\n[54.9086063833, 82.4679739333, \"14\"],\n[54.9086596833, 82.4681819, \"16\"],\n[54.9086889667, 82.4694297167, \"21\"],\n[54.9089948667, 82.4692835833, \"22\"],\n[54.9087513667, 82.4696475333, \"23\"],\n[54.9090557667, 82.4694965167, \"24\"],\n[54.9088116333, 82.4698680667, \"25\"],\n[54.9091091, 82.46969345, \"26\"],\n[54.907833, 82.4666559167, \"1\"],\n[54.9091789833, 82.4699557667, \"28\"],\n[54.9096087, 82.4713450667, \"38\"],\n[54.9092433833, 82.4701392333, \"30\"],\n[54.9090019833, 82.47051235, \"31\"],\n[54.9093068333, 82.4703555833, \"32\"],\n[54.9090940833, 82.4707707667, \"33\"],\n[54.90938145, 82.4705582833, \"34\"],\n[54.9094346667, 82.4707651333, \"36\"],\n[54.9088761167, 82.47007805, \"27\"],\n[54.9098069333, 82.4719604833, \"44\"],\n[54.9098796833, 82.4721707667, \"46\"],\n[54.909607, 82.4725725667, \"45\"],\n[54.90920615, 82.4729688333, \"47A\"],\n[54.9093402667, 82.4728171, \"47\"],\n[54.9099493833, 82.4724105167, \"48\"],\n[54.9096936333, 82.47284265, \"49\"],\n[54.9079234833, 82.4669311833, \"3\"],\n[54.9082463667, 82.4668155333, \"4\"],\n[54.9097714167, 82.4731308333, \"51\"],\n[54.9100506833, 82.4729631167, \"52\"],\n[54.9101362833, 82.473234, \"54\"],\n[54.9105130333, 82.4743347667, \"60\"],\n[54.91028125, 82.4747888167, \"59\"],\n[54.9105830167, 82.4745966167, \"62\"],\n[54.9106531, 82.4748493333, \"64\"],\n[54.90835855, 82.4671917333, \"8\"],\n[54.9081653833, 82.4677261, \"9\"],\n[54.9120752833, 82.4794866167, \"100\"],\n[54.9117925167, 82.47970425, \"101\"],\n[54.91190545, 82.4801769333, \"105\"],\n[54.9122550333, 82.4799224833, \"106\"],\n[54.9116940333, 82.48024145, \"107\"],\n[54.9124476, 82.4801052833, \"108\"],\n[54.9117246833, 82.4803671833, \"109\"],\n[54.9103405167, 82.4750005667, \"61\"],\n[54.9104726833, 82.4754203667, \"65\"],\n[54.9107200333, 82.47506155, \"66\"],\n[54.91053305, 82.4756331, \"67\"],\n[54.9111229833, 82.476363, \"74\"],\n[54.9114657833, 82.4764926, \"76A\"],\n[54.911183, 82.4765541167, \"76\"],\n[54.91150505, 82.47660575, \"78A\"],\n[54.9112499833, 82.4767965667, \"78\"],\n[54.9115982333, 82.4769201167, \"80A\"],\n[54.911382167, 82.4769843333, \"80\"],\n[54.91152935, 82.4777795, \"88\"],\n[54.9117877, 82.4784990667, \"92\"],\n[54.9118644667, 82.4787878833, \"94\"],\n[54.9121825833, 82.4787955833, \"96A\"],\n[54.9119467333, 82.47904265, \"96\"],\n[54.9119913167, 82.4792895833, \"98\"],\n[54.9117365667, 82.47948695, \"99\"],\n[54.9107912667, 82.4752822833, \"68\"],\n[54.9108477833, 82.4754937167, \"70\"],\n[54.9118233, 82.4773533, \"86B\"],\n[54.9119954167, 82.47727035, \"86C\"],\n[54.9115303833, 82.4774913167, \"86\"],\n[54.9082149, 82.4684349833, \"13A\"],\n[54.8870698333, 82.4663411167, \"1-13\"],\n[54.8871554667, 82.4663601, \"2-12\"],\n[54.9016082667, 82.4806621, \"30\"],\n[54.9010984667, 82.4803028833, \"22\"],\n[54.9012443833, 82.4808339333, \"24\"],\n[54.9013056667, 82.4802206, \"26\"],\n[54.90149895, 82.4805675833, \"28\"],\n[54.9015629833, 82.4800562667, \"32\"],\n[54.90147835, 82.4797437167, \"45\"],\n[54.8996289167, 82.4806158667, \"2A\"],\n[54.89956085, 82.4797871333, \"11\"],\n[54.9009366167, 82.4793407667, \"37\"],\n[54.9010581667, 82.4795131167, \"39\"],\n[54.8992862833, 82.4802488833, \"5\"],\n[54.90020145, 82.4797472, \"10\"],\n[54.9003469333, 82.47964355, \"12\"],\n[54.89972725, 82.47967295, \"13\"],\n[54.9006396, 82.4794276, \"14\"],\n[54.8998769167, 82.47947625, \"15\"],\n[54.9007610667, 82.4795863833, \"16\"],\n[54.9008528833, 82.47974655, \"18\"],\n[54.9009693167, 82.4799194, \"20\"],\n[54.90002065, 82.47947515, \"17\"],\n[54.9001685333, 82.4793572, \"19\"],\n[54.8993512667, 82.4806693, \"1\"],\n[54.9003158833, 82.479241, \"21\"],\n[54.9004667167, 82.4791244167, \"23\"],\n[54.9006037, 82.4790302167, \"25\"],\n[54.90070445, 82.4786061667, \"27\"],\n[54.9007410667, 82.4788370167, \"29\"],\n[54.9008196333, 82.4791513333, \"31\"],\n[54.901124, 82.4788828667, \"33\"],\n[54.90119195, 82.4790490333, \"35\"],\n[54.9013381833, 82.4794026, \"41\"],\n[54.8997734, 82.4805030333, \"2\"],\n[54.8992978333, 82.4804472333, \"3\"],\n[54.9012097667, 82.4797523667, \"43\"],\n[54.8996789, 82.48033335, \"4\"],\n[54.8998323667, 82.4800290167, \"6\"],\n[54.8993387167, 82.4800615833, \"7\"],\n[54.9000414667, 82.4798654, \"8\"],\n[54.8994266333, 82.47991435, \"9\"],\n[54.8172086167, 82.36975015, \"17\"],\n[54.8189982167, 82.3714596333, \"28C\"],\n[54.8174889333, 82.3716284333, \"35\"],\n[54.8180339667, 82.3717238667, \"36\"],\n[54.8172767, 82.3702897333, \"25\"],\n[54.8183033167, 82.3704190333, \"28A\"],\n[54.8177806167, 82.3709889833, \"30\"],\n[54.8184724667, 82.3714858167, \"34\"],\n[54.8172573833, 82.3723560333, \"37\"],\n[54.882974333, 82.3697317, \"18\"],\n[54.8189201833, 82.3708153, \"28B\"],\n[54.8170975, 82.3688759833, \"7\"],\n[54.8174008333, 82.3711639167, \"31\"],\n[54.8177271333, 82.3719905167, \"39\"],\n[54.9105104667, 82.4696305667, \"29\"],\n[54.9105738333, 82.4698784833, \"33\"],\n[54.9119496333, 82.4744651, \"75\"],\n[54.9124263667, 82.4747625167, \"76\"],\n[54.9120037833, 82.47464375, \"77A\"],\n[54.9103653167, 82.4676619667, \"20\"],\n[54.9108393333, 82.4707173, \"41\"],\n[54.91176765, 82.4719875333, \"58A\"],\n[54.9116183, 82.4720772, \"58\"],\n[54.9128712, 82.4761248167, \"86\"],\n[54.9124839333, 82.47629265, \"85\"],\n[54.9104650167, 82.4694600667, \"27\"],\n[54.9109299, 82.4697178333, \"40\"],\n[54.9109971667, 82.4699570333, \"42\"],\n[54.9097695, 82.4672281333, \"11\"],\n[54.9100539667, 82.4665771, \"10\"],\n[54.91041835, 82.4666636, \"12A\"],\n[54.9101176333, 82.4667979833, \"12\"],\n[54.90983315, 82.4674340333, \"13\"],\n[54.9104875, 82.4669176667, \"14A\"],\n[54.9101736833, 82.4670051, \"14\"],\n[54.9098833833, 82.46762845, \"15\"],\n[54.9102367667, 82.4672218833, \"16\"],\n[54.9099549667, 82.46780795, \"17\"],\n[54.9105899, 82.46737165, \"18A\"],\n[54.9102941833, 82.4674259333, \"18\"],\n[54.91020335, 82.4685710333, \"21\"],\n[54.9102757167, 82.4688396333, \"23\"],\n[54.9105438167, 82.46821955, \"22\"],\n[54.9105772667, 82.4685320333, \"26\"],\n[54.9104076167, 82.4692623833, \"25\"],\n[54.9094199667, 82.4660506333, \"1\"],\n[54.9106404167, 82.4687469667, \"28\"],\n[54.9107060667, 82.4689637167, \"30\"],\n[54.9103114167, 82.4698414333, \"31\"],\n[54.9110137167, 82.4690528333, \"34A\"],\n[54.9107613667, 82.4691689333, \"34\"],\n[54.91081495, 82.4693474, \"36A\"],\n[54.9110468333, 82.46924275, \"36B\"],\n[54.9108736, 82.4695344167, \"38A\"],\n[54.9111242, 82.46941945, \"38B\"],\n[54.9098216167, 82.4658393167, \"2\"],\n[54.91088605, 82.4708887833, \"43\"],\n[54.9112278167, 82.4705661167, \"44\"],\n[54.9109336667, 82.47106555, \"45\"],\n[54.91129165, 82.4707536333, \"46\"],\n[54.9109882333, 82.4712586667, \"47\"],\n[54.9113449167, 82.47095045, \"48\"],\n[54.9110579667, 82.4714307833, \"49\"],\n[54.9094612667, 82.4662574167, \"3\"],\n[54.9114052833, 82.4711525333, \"50\"],\n[54.9114515333, 82.4713499667, \"52\"],\n[54.9111246333, 82.47187335, \"51\"],\n[54.9117082, 82.4723085667, \"60\"],\n[54.918221667, 82.4724906333, \"62\"],\n[54.91170015, 82.47359465, \"63\"],\n[54.9182395, 82.4737979833, \"65\"],\n[54.9120630333, 82.4735410667, \"66A\"],\n[54.9122263, 82.47353625, \"66B\"],\n[54.9118108167, 82.4740034667, \"67\"],\n[54.9113339, 82.4743958833, \"69\"],\n[54.90952435, 82.4664596667, \"5\"],\n[54.90970875, 82.4670344667, \"9\"],\n[54.91152875, 82.4743488, \"71\"],\n[54.9123023, 82.47433295, \"72\"],\n[54.9118344167, 82.4742989833, \"73A\"],\n[54.9118896667, 82.4742717333, \"73\"],\n[54.9123685833, 82.4745438, \"74\"],\n[54.91204505, 82.4747885167, \"77B\"],\n[54.9124726167, 82.4749395667, \"78\"],\n[54.9120965167, 82.47493145, \"79\"],\n[54.9099235167, 82.46615755, \"6\"],\n[54.9099866, 82.4663651333, \"8\"],\n[54.9126461, 82.4754722667, \"80\"],\n[54.9123464833, 82.4758373333, \"81\"],\n[54.9124222167, 82.4761109333, \"83\"],\n[54.9129424833, 82.47629755, \"88A\"],\n[54.91334525, 82.4762585833, \"90A\"],\n[54.9134976667, 82.4761915, \"90B\"],\n[54.9133118333, 82.47629305, \"90\"],\n[54.9127142, 82.4769782833, \"87\"],\n[54.9127630833, 82.4771701667, \"89\"],\n[54.9131761, 82.47644985, \"92A\"],\n[54.9131949667, 82.47653455, \"92B\"],\n[54.9130077167, 82.4766852167, \"94\"],\n[54.9131084667, 82.4770053833, \"96\"],\n[54.9133594333, 82.4770784833, \"98\"],\n[54.91309155, 82.4760073833, \"86B\"],\n[54.9127336333, 82.4757125833, \"82\"],\n[54.9128152667, 82.4759342833, \"84\"],\n[54.9129075333, 82.4763391333, \"88\"],\n[54.8906112, 82.4636290667, \"8\"],\n[54.8906010667, 82.4641357833, \"1A\"],\n[54.8905902667, 82.4639329, \"4\"],\n[54.8905940833, 82.4640698, \"2\"],\n[54.8906316167, 82.4632836667, \"13\"],\n[54.8907058, 82.4633735833, \"17\"],\n[54.8905923, 82.4640024833, \"3\"],\n[54.8907071833, 82.4634437667, \"18\"],\n[54.8906947667, 82.4635948667, \"20\"],\n[54.8906874333, 82.4636836833, \"21\"],\n[54.890681, 82.4637655167, \"22\"],\n[54.8906765333, 82.4638413833, \"23\"],\n[54.8906641, 82.4639166833, \"24\"],\n[54.8906549, 82.4639912667, \"25\"],\n[54.8906532333, 82.4640676833, \"26\"],\n[54.8906518667, 82.46414095, \"27\"],\n[54.8906011167, 82.4638605167, \"5\"],\n[54.8906079667, 82.4637939167, \"6\"],\n[54.8906326167, 82.4634340333, \"11\"],\n[54.8906169667, 82.4635610833, \"9\"],\n[54.8906290333, 82.46349725, \"10\"],\n[54.8906352333, 82.4633559333, \"12\"],\n[54.8906300833, 82.4632139167, \"14\"],\n[54.8906897167, 82.4632274, \"15\"],\n[54.8905997667, 82.46420885, \"1\"],\n[54.8906515667, 82.4642292333, \"28\"],\n[54.8905993833, 82.4637104667, \"7\"],\n[54.8905424667, 82.4641317333, \"1B\"],\n[54.8906997833, 82.4632963667, \"16\"],\n[54.89069985, 82.4635183333, \"19\"],\n[54.82488245, 82.3937114333, \"107\"],\n[54.82511735, 82.3936415, \"105\"],\n[54.8241600833, 82.3938937, \"115\"],\n[54.8257229, 82.3934403167, \"95\"],\n[54.8311935833, 82.39119285, \"34\"],\n[54.8312837167, 82.3938057, \"44\"],\n[54.8302991667, 82.3911272833, \"39\"],\n[54.8298778833, 82.38838305, \"33\"],\n[54.8260734, 82.3947714167, \"94C\"],\n[54.8263358833, 82.3938421667, \"94A\"],\n[54.8279937667, 82.394307, \"72C\"],\n[54.8246244833, 82.3942836667, \"110\"],\n[54.82928665, 82.3931185833, \"58\"],\n[54.8239608833, 82.3939572, \"117\"],\n[54.8307863167, 82.3929875333, \"46B\"],\n[54.83183475, 82.3898969167, \"19\"],\n[54.82823865, 82.3933544333, \"72A\"],\n[54.82829215, 82.3941929833, \"72B\"],\n[54.8278144167, 82.3934866833, \"72D\"],\n[54.8263441833, 82.3946904167, \"94B\"],\n[54.8258577167, 82.3939724833, \"94D\"],\n[54.8252182667, 82.3953295167, \"108\"],\n[54.8301352667, 82.3922486833, \"46A\"],\n[54.8325430167, 82.3898667667, \"14\"],\n[54.8327221167, 82.3897138833, \"12\"],\n[54.91482215, 82.4749911167, \"3\"],\n[54.9154439833, 82.4755851833, \"12\"],\n[54.9151334833, 82.4758027, \"13\"],\n[54.9152983167, 82.4757077333, \"14\"],\n[54.9150524833, 82.4746568833, \"2\"],\n[54.9147571833, 82.4747972, \"1\"],\n[54.9151202833, 82.4748550667, \"4\"],\n[54.9149427, 82.4758335, \"11\"],\n[54.91488335, 82.4751902167, \"5\"],\n[54.9149361833, 82.4753859667, \"7\"],\n[54.9149649167, 82.475589, \"9\"],\n[54.9153104333, 82.4754419667, \"10\"],\n[54.9151775667, 82.4750489, \"6\"],\n[54.91523395, 82.4752497167, \"8\"],\n[54.8190687333, 82.3738382833, \"23\"],\n[54.8189306833, 82.3733703333, \"25\"],\n[54.8190215667, 82.37468215, \"15\"],\n[54.8191251667, 82.3740887167, \"21\"],\n[54.81873305, 82.3726976833, \"27A-27C\"],\n[54.8806986667, 82.4693562667, \"63\"],\n[54.8809032, 82.46938395, \"61\"],\n[54.88419255, 82.4697289167, \"25\"],\n[54.8840685833, 82.4692688833, \"26A\"],\n[54.8849148667, 82.4692615167, \"24\"],\n[54.8847644833, 82.4697682667, \"23\"],\n[54.8813066833, 82.4696684167, \"55A\"],\n[54.8841734833, 82.4692622667, \"26\"],\n[54.8840862833, 82.46972585, \"27\"],\n[54.883927, 82.46906515, \"28A\"],\n[54.8838748833, 82.4692541667, \"28\"],\n[54.8838499, 82.4696946333, \"29\"],\n[54.88359805, 82.4692251167, \"30\"],\n[54.8837043833, 82.4696835, \"31\"],\n[54.8834259333, 82.4692035833, \"32\"],\n[54.88355905, 82.4696786667, \"33\"],\n[54.8832160667, 82.4691627833, \"34\"],\n[54.8834721833, 82.4701433, \"35\"],\n[54.8829353667, 82.4691514, \"36\"],\n[54.8833598667, 82.4701280667, \"37\"],\n[54.8821233833, 82.4690720167, \"44\"],\n[54.8818720333, 82.4690515667, \"46\"],\n[54.8816436667, 82.4690230167, \"48\"],\n[54.8815636667, 82.4686263, \"50\"],\n[54.8818555333, 82.4695200333, \"51\"],\n[54.8812979333, 82.4689347, \"52A\"],\n[54.8814706833, 82.46880395, \"52\"],\n[54.8816095333, 82.46944925, \"53\"],\n[54.8816625, 82.4696671833, \"53A\"],\n[54.8811724833, 82.46894365, \"54\"],\n[54.8833521, 82.46965845, \"39\"],\n[54.882727, 82.4691108167, \"40\"],\n[54.88320755, 82.4696409167, \"41\"],\n[54.8830678333, 82.4696227833, \"43\"],\n[54.8828830167, 82.4695893333, \"45\"],\n[54.8827233167, 82.4695686167, \"47\"],\n[54.88095035, 82.4689156, \"56\"],\n[54.8811470667, 82.4694376833, \"57\"],\n[54.8807286167, 82.4689006167, \"58\"],\n[54.8809772667, 82.4695997, \"59\"],\n[54.8855099667, 82.4700903333, \"11A\"],\n[54.8863533667, 82.4694588667, \"10\"],\n[54.8855251167, 82.46980435, \"11\"],\n[54.8858918167, 82.4693764333, \"12\"],\n[54.88541135, 82.46981195, \"13\"],\n[54.8857694833, 82.4693831333, \"14\"],\n[54.8853156333, 82.4697983, \"15\"],\n[54.88556005, 82.4693647167, \"16\"],\n[54.8851626, 82.4697849833, \"17\"],\n[54.8853764833, 82.4693362333, \"18\"],\n[54.8850294167, 82.4700537333, \"19A\"],\n[54.8850045667, 82.4697427167, \"19\"],\n[54.88522955, 82.4692991667, \"20\"],\n[54.8869080667, 82.4699470333, \"1\"],\n[54.8866734833, 82.4699262833, \"3\"],\n[54.8868586667, 82.46949025, \"4\"],\n[54.8866564167, 82.4694635, \"6\"],\n[54.8864874833, 82.4690444333, \"8A\"],\n[54.8864948, 82.4694661333, \"8\"],\n[54.8857426, 82.4698434167, \"9\"],\n[54.8813893667, 82.46946355, \"55\"],\n[54.8757085833, 82.4720279333, \"14\"],\n[54.8760134667, 82.4732799333, \"4\"],\n[54.8762548333, 82.4722784667, \"9\"],\n[54.87627795, 82.47290345, \"5\"],\n[54.8759331333, 82.4720918833, \"16\"],\n[54.8759628833, 82.47273515, \"8\"],\n[54.8762970167, 82.4732576833, \"3\"],\n[54.8762245833, 82.47260565, \"7\"],\n[54.8760141333, 82.4735054833, \"2\"],\n[54.87599385, 82.4730087667, \"6\"],\n[54.8759230167, 82.4724739333, \"10\"],\n[54.8762960167, 82.4734868833, \"1\"],\n[54.8760504333, 82.4719608, \"18\"],\n[54.8759146, 82.4722788167, \"12\"],\n[54.8741210833, 82.4688841833, \"4\"],\n[54.874194, 82.4684628667, \"3\"],\n[54.8738320667, 82.467738, \"7C\"],\n[54.8739506833, 82.4677262667, \"7B\"],\n[54.8738354667, 82.4680554, \"7D\"],\n[54.8739794167, 82.4680445667, \"7A\"],\n[54.8738342833, 82.46848195, \"9\"],\n[54.8740206, 82.4684673, \"5\"],\n[54.8739604167, 82.4688864, \"6\"],\n[54.8735957167, 82.4683405333, \"11\"],\n[54.8734235667, 82.4681024, \"13\"],\n[54.87339585, 82.4678321167, \"15\"],\n[54.8733727667, 82.46763935, \"17\"],\n[54.8728499833, 82.46814045, \"18B\"],\n[54.8728848, 82.468283, \"18A\"],\n[54.8730660667, 82.4686787667, \"12B\"],\n[54.8734160167, 82.4687180167, \"10\"],\n[54.87312285, 82.4687848, \"12A\"],\n[54.8730669833, 82.4679829333, \"20\"],\n[54.8731389833, 82.4682574833, \"16\"],\n[54.8732649167, 82.4684832833, \"14\"],\n[54.8732605833, 82.4675842167, \"19\"],\n[54.8729366833, 82.4674852167, \"24\"],\n[54.8730152333, 82.4677481333, \"22\"],\n[54.87312065, 82.4675707, \"21\"],\n[54.7940869167, 82.4650218, \"53\"],\n[54.7987550833, 82.46275265, \"10\"],\n[54.7930822167, 82.4661922833, \"60\"],\n[54.9811612, 82.51623075, \"170\"],\n[54.980836, 82.5157299167, \"171\"],\n[54.9807136667, 82.5162809333, \"172\"],\n[54.8615888667, 82.47847875, \"25\"],\n[54.8612666833, 82.4791558, \"31\"],\n[54.86047605, 82.48172545, \"60\"],\n[54.8620611333, 82.4774431167, \"13\"],\n[54.8607505167, 82.4799311167, \"41\"],\n[54.8611511833, 82.4794658167, \"35\"],\n[54.86108515, 82.4796282, \"37\"],\n[54.8604406, 82.48091835, \"55\"],\n[54.8595911333, 82.483664, \"72\"],\n[54.8582950167, 82.4794636833, \"1/55\"],\n[54.8599109167, 82.4805425167, \"49\"],\n[54.86081285, 82.4790711333, \"33\"],\n[54.9125544667, 82.4795344, \"6A\"],\n[54.9129032667, 82.479114, \"8\"],\n[54.9131012, 82.4790179333, \"10\"],\n[54.9132466667, 82.4789829167, \"11\"],\n[54.9130141, 82.4787519333, \"1\"],\n[54.9128543833, 82.4788087167, \"2\"],\n[54.9126783167, 82.47889955, \"3\"],\n[54.9125031333, 82.47905685, \"4\"],\n[54.91254025, 82.4792764833, \"5\"],\n[54.9127399333, 82.4793322333, \"7\"],\n[54.9130969667, 82.47952775, \"9\"],\n[54.9126911167, 82.4796185, \"6\"],\n[54.8188045667, 82.445279, \"356B\"],\n[54.8182903167, 82.4447447333, \"356A\"],\n[54.8086473833, 82.4195512167, \"27\"],\n[54.8137567, 82.4426504333, \"299\"],\n[54.8131862167, 82.4434878167, \"297\"],\n[54.8157127333, 82.43953285, \"300A\"],\n[54.8094742167, 82.4189907, \"19\"],\n[54.80933355, 82.4191978667, \"23\"],\n[54.8084224833, 82.4207951, \"41\"],\n[54.8095742167, 82.43605105, \"226\"],\n[54.81325255, 82.4410722, \"291\"],\n[54.8149016667, 82.44148445, \"310\"],\n[54.8155769667, 82.44213865, \"316\"],\n[54.8161747167, 82.4426252167, \"326A\"],\n[54.81712155, 82.4417707667, \"326B\"],\n[54.8169698833, 82.4434206167, \"332\"],\n[54.81770375, 82.4442239833, \"346\"],\n[54.81930575, 82.4457899333, \"370\"],\n[54.82310865, 82.4495740167, \"422\"],\n[54.8103162667, 82.4344773833, \"224B\"],\n[54.8100267333, 82.4348309167, \"224A\"],\n[54.8072155167, 82.4256129167, \"88B\"],\n[54.8070962167, 82.42278495, \"59\"],\n[54.8044940333, 82.4270097, \"105\"],\n[54.8046275667, 82.4276069, \"110\"],\n[54.8047349, 82.43229485, \"165\"],\n[54.8073398, 82.4232142167, \"68\"],\n[54.8064126167, 82.4330381167, \"188\"],\n[54.8063987833, 82.4339707667, \"209\"],\n[54.8103206333, 82.4378506833, \"241\"],\n[54.8117777667, 82.4393874, \"269\"],\n[54.8074375833, 82.43233545, \"192\"],\n[54.8099668167, 82.4365891667, \"236\"],\n[54.8038524, 82.4307279167, \"156\"],\n[54.808759, 82.4183171167, \"17\"],\n[54.805885, 82.4246946333, \"81\"],\n[54.8072272, 82.4225943333, \"57\"],\n[54.8056120333, 82.4262290333, \"98\"],\n[54.80400575, 82.4287991167, \"122\"],\n[54.8162936333, 82.43817215, \"300B\"],\n[54.80809795, 82.4212756, \"49\"],\n[54.8102496667, 82.4184802, \"8\"],\n[54.8057899167, 82.43198855, \"174\"],\n[54.8060113, 82.4256459333, \"88A\"],\n[54.8183982, 82.4416558, \"336\"],\n[54.8108804, 82.4393530667, \"257\"],\n[54.81106865, 82.4386178, \"255\"],\n[54.816436, 82.4370654, \"298\"],\n[54.8152743833, 82.4390058833, \"298A\"],\n[54.8136452667, 82.44031535, \"288\"],\n[54.8123581, 82.44091935, \"285\"],\n[54.81283995, 82.4401099833, \"283\"],\n[54.8198763333, 82.4462982, \"382\"],\n[54.8164479167, 82.4439082, \"331\"],\n[54.80775795, 82.4225746667, \"62\"],\n[54.8039981833, 82.43163845, \"161\"],\n[54.81343775, 82.4401047167, \"286\"],\n[54.92047495, 82.46336425, \"9\"],\n[54.9203008333, 82.4618285667, \"10\"],\n[54.9198670667, 82.4617700333, \"6\"],\n[54.9207259667, 82.4627925167, \"18\"],\n[54.9204614, 82.4619784833, \"12\"],\n[54.9205793667, 82.4621705667, \"14\"],\n[54.9207471167, 82.463665, \"22\"],\n[54.9208443, 82.4640230833, \"24\"],\n[54.9207801667, 82.4632019667, \"20\"],\n[54.919291, 82.4622796167, \"1\"],\n[54.92066135, 82.4624384833, \"16\"],\n[54.9203523333, 82.4637463, \"11\"],\n[54.9192657167, 82.4618642833, \"2\"],\n[54.9197237333, 82.4622129, \"3\"],\n[54.91957955, 82.4618272333, \"4\"],\n[54.9201776333, 82.4622242, \"5\"],\n[54.9203935, 82.4628145667, \"7\"],\n[54.9201192, 82.46174985, \"8\"],\n[54.9031613333, 82.4779369333, \"8\"],\n[54.90302285, 82.47799245, \"9\"],\n[54.9033285333, 82.4778655833, \"7\"],\n[54.90346695, 82.4777957167, \"6B\"],\n[54.9031769667, 82.4783186167, \"1\"],\n[54.9034699667, 82.47848295, \"2A\"],\n[54.90334345, 82.4782583833, \"2\"],\n[54.9035249833, 82.4781788667, \"3\"],\n[54.9037982667, 82.4780497167, \"4A\"],\n[54.9037089833, 82.4781017333, \"4\"],\n[54.9035266667, 82.4777643667, \"6A\"],\n[54.9036756833, 82.4778188333, \"5\"],\n[54.9129985333, 82.4689246333, \"3\"],\n[54.9132911, 82.4686436333, \"4\"],\n[54.9127876667, 82.4680122167, \"13\"],\n[54.9126336667, 82.46802445, \"13A\"],\n[54.91304995, 82.4678746833, \"10\"],\n[54.91280555, 82.4681958333, \"11\"],\n[54.9127504833, 82.4677229167, \"15\"],\n[54.9133710167, 82.4688942167, \"2\"],\n[54.9129377, 82.4687422333, \"5\"],\n[54.9128397333, 82.4683664833, \"9\"],\n[54.9125584, 82.4677322333, \"15A\"],\n[54.9132129833, 82.4683870333, \"6\"],\n[54.9128774667, 82.4685356, \"7\"],\n[54.9131322833, 82.4681105167, \"8\"],\n[54.9164839667, 82.4695277167, \"2/205\"],\n[54.9167949333, 82.4782119333, \"287\"],\n[54.9086755, 82.4537326833, \"37\"],\n[54.91527815, 82.4546945333, \"2/88\"],\n[54.9142658167, 82.4551371, \"1/88\"],\n[54.9145371, 82.4555229667, \"88\"],\n[54.9167784167, 82.4698118167, \"209\"],\n[54.91671315, 82.4695459, \"207\"],\n[54.916654, 82.4692565, \"203\"],\n[54.9168566667, 82.4764833167, \"269\"],\n[54.9170098667, 82.4835371333, \"332\"],\n[54.9109654167, 82.455206, \"60\"],\n[54.9170810333, 82.4814135167, \"310\"],\n[54.9168965667, 82.4758632667, \"263\"],\n[54.9154102833, 82.46304445, \"149\"],\n[54.9154961, 82.4634764667, \"153\"],\n[54.9152487667, 82.4638892333, \"157\"],\n[54.9156422333, 82.4641169833, \"159\"],\n[54.9158050167, 82.4648025333, \"165\"],\n[54.91375215, 82.4584178167, \"106\"],\n[54.9147696833, 82.4594047833, \"114\"],\n[54.91474835, 82.46019985, \"121\"],\n[54.9158845167, 82.4586385833, \"112\"],\n[54.9150857, 82.459884, \"120\"],\n[54.9126885833, 82.4573289333, \"82\"],\n[54.91648165, 82.4694261333, \"1/205\"],\n[54.9168508333, 82.4701398833, \"211\"],\n[54.9169940167, 82.4708593833, \"219\"],\n[54.9170359, 82.4710790167, \"221\"],\n[54.91708375, 82.4713339, \"223\"],\n[54.9170401, 82.4721885167, \"231\"],\n[54.9170336667, 82.4724657667, \"233\"],\n[54.9169188667, 82.4749939667, \"249\"],\n[54.9168660833, 82.4760673333, \"265\"],\n[54.91686435, 82.4768689833, \"271\"],\n[54.9166818667, 82.4769821, \"273\"],\n[54.9168443333, 82.4772235167, \"275\"],\n[54.9166369667, 82.4773580167, \"277\"],\n[54.9165761667, 82.4777388, \"279\"],\n[54.9168418833, 82.47757295, \"281\"],\n[54.9168319167, 82.47791855, \"283\"],\n[54.9165834833, 82.47804975, \"285\"],\n[54.91697015, 82.4853758167, \"344\"],\n[54.9180125667, 82.4811616, \"316\"],\n[54.9169954833, 82.48221265, \"318\"],\n[54.9157653333, 82.4543129833, \"3/88\"],\n[54.9154571667, 82.4552445, \"4/88\"],\n[54.8827312167, 82.4872892833, \"5\"],\n[54.8831903667, 82.4877676167, \"8\"],\n[54.8828024333, 82.4875113, \"7\"],\n[54.8831045, 82.4875104167, \"6\"],\n[54.8828241, 82.4877701, \"9\"],\n[54.88302025, 82.4867592333, \"2\"],\n[54.8827238667, 82.4870656, \"3\"],\n[54.8832792333, 82.48802495, \"10\"],\n[54.88271135, 82.4868632, \"1\"],\n[54.8830189167, 82.4869722, \"4\"],\n[54.8828316667, 82.4879782167, \"11\"],\n[54.8831031667, 82.4879840167, \"12\"],\n[54.8829747, 82.4879948833, \"13\"],\n[54.88274605, 82.48484915, \"21\"],\n[54.8834571667, 82.4855031833, \"4\"],\n[54.8834955333, 82.4856944167, \"2\"],\n[54.8838132333, 82.4854477333, \"3\"],\n[54.8835369833, 82.4848281833, \"11\"],\n[54.88336725, 82.48485965, \"13\"],\n[54.8831959833, 82.48485645, \"15\"],\n[54.8828621167, 82.48476675, \"19\"],\n[54.8838400833, 82.4849657333, \"7\"],\n[54.8837638167, 82.4848016167, \"9\"],\n[54.8829594167, 82.4854216, \"10\"],\n[54.8827830667, 82.4855451, \"12\"],\n[54.88274165, 82.4853534, \"14\"],\n[54.8827611667, 82.4850917, \"16\"],\n[54.8830644, 82.48501895, \"17\"],\n[54.8838288, 82.4856380833, \"1\"],\n[54.8838275, 82.4852247167, \"5\"],\n[54.883443, 82.4852514667, \"6\"],\n[54.8831229667, 82.4853610833, \"8\"],\n[54.8145997, 82.4058182333, \"13\"],\n[54.8147182333, 82.4078123, \"28\"],\n[54.81457405, 82.4067919, \"23\"],\n[54.8140701667, 82.4071422833, \"27\"],\n[54.8142806667, 82.4076163167, \"29\"],\n[54.8149311167, 82.4068842833, \"22\"],\n[54.8150038333, 82.4059631, \"16\"],\n[54.7951609167, 82.3942458333, \"200\"],\n[54.7911471333, 82.3929187167, \"159B\"],\n[54.7905987667, 82.3938164667, \"159C\"],\n[54.7912155833, 82.3932714167, \"159A\"],\n[54.79397065, 82.3941075167, \"190\"],\n[54.7944302667, 82.3943967333, \"196\"],\n[54.7902842667, 82.3925200667, \"151\"],\n[54.79289115, 82.3931896, \"174\"],\n[54.7936966833, 82.3937764, \"188\"],\n[54.7941318167, 82.3948274667, \"191\"],\n[54.7978721333, 82.3984214333, \"249\"],\n[54.7981105667, 82.39574825, \"232A\"],\n[54.7938025333, 82.3924897, \"178\"],\n[54.7985639333, 82.3952936333, \"232B\"],\n[54.7918765, 82.3926438167, \"162\"],\n[54.7908330333, 82.39227155, \"154\"],\n[54.7962404, 82.3968673, \"225\"],\n[54.7923051, 82.3933906333, \"171A\"],\n[54.7927951833, 82.3942652333, \"171B\"],\n[54.7901405833, 82.3919332833, \"146\"],\n[54.7965292833, 82.396445, \"226\"],\n[54.7989539333, 82.3987508667, \"258\"],\n[54.7975085, 82.3942399167, \"218A\"],\n[54.7982403667, 82.3938506167, \"218B\"],\n[54.7947115833, 82.3953049, \"203\"],\n[54.7925679167, 82.3935303833, \"171C\"],\n[54.7951510667, 82.3951699667, \"206\"],\n[54.7942058167, 82.39426, \"192\"],\n[54.8151522, 82.3671718, \"2\"],\n[54.8124476333, 82.3641774667, \"38C\"],\n[54.8142324833, 82.3640258333, \"36\"],\n[54.8147477833, 82.3658554333, \"18\"],\n[54.8149241, 82.3663270333, \"14\"],\n[54.8127630333, 82.3645959667, \"38D\"],\n[54.8802473333, 82.4761364833, \"161\"],\n[54.8803540333, 82.4775673167, \"169A\"],\n[54.8808955167, 82.4678431, \"87A\"],\n[54.8812967167, 82.45925645, \"22A\"],\n[54.8801625833, 82.4788012833, \"181\"],\n[54.8801798667, 82.4784953, \"179\"],\n[54.8805060333, 82.4783115333, \"82\"],\n[54.8802037167, 82.4779421333, \"171\"],\n[54.8802002, 82.4782253667, \"173\"],\n[54.88066575, 82.4696257, \"105\"],\n[54.88142225, 82.4685359, \"99D\"],\n[54.880149, 82.4790061333, \"183\"],\n[54.8807033, 82.4684905333, \"99A\"],\n[54.8811922, 82.4685214167, \"99C\"],\n[54.8809802667, 82.4685055, \"99B\"],\n[54.88134225, 82.4657706, \"69\"],\n[54.8807472167, 82.46754285, \"83\"],\n[54.8802148333, 82.4776531667, \"169\"],\n[54.8802820833, 82.4763336, \"163\"],\n[54.8802558333, 82.4772608667, \"165\"],\n[54.8806246667, 82.4705465167, \"113\"],\n[54.88113685, 82.4643511667, \"53A\"],\n[54.88095905, 82.4643489, \"53\"],\n[54.88154715, 82.4657577833, \"67\"],\n[54.8809616167, 82.4639502667, \"49\"],\n[54.8802025833, 82.48084275, \"191A\"],\n[54.8806056333, 82.47098625, \"117\"],\n[54.88044865, 82.47329545, \"127\"],\n[54.8804726333, 82.47306075, \"125\"],\n[54.8806984167, 82.4686680667, \"101\"],\n[54.8805955167, 82.4711419833, \"117A\"],\n[54.8806145167, 82.4707781333, \"115\"],\n[54.88164575, 82.45804455, \"16B\"],\n[54.88036875, 82.4755842, \"153\"],\n[54.8806508333, 82.4700866667, \"109\"],\n[54.8815960333, 82.4577537, \"14\"],\n[54.88151485, 82.4579781667, \"16A\"],\n[54.8813847833, 82.4644447333, \"55\"],\n[54.8813670167, 82.4645692667, \"57\"],\n[54.8809571333, 82.4641156833, \"51\"],\n[54.8816293, 82.45738225, \"10\"],\n[54.8818759333, 82.4575147, \"12A\"],\n[54.8820464833, 82.4575854833, \"12B\"],\n[54.8820319167, 82.4576747167, \"12C\"],\n[54.8818586167, 82.4576652167, \"12D\"],\n[54.8810945667, 82.46145875, \"36\"],\n[54.8810898, 82.46167115, \"38\"],\n[54.8810809667, 82.461937, \"40\"],\n[54.8810701667, 82.4621895167, \"42\"],\n[54.8812240833, 82.45898385, \"20\"],\n[54.88121955, 82.45918975, \"22\"],\n[54.8811737667, 82.45983295, \"24\"],\n[54.88115855, 82.46004515, \"26\"],\n[54.8811441, 82.46023075, \"28\"],\n[54.8814057333, 82.4604056667, \"30\"],\n[54.8811296167, 82.4604632667, \"32\"],\n[54.88144325, 82.4580904667, \"18\"],\n[54.88168545, 82.4564695667, \"2\"],\n[54.8809346833, 82.4645998167, \"59\"],\n[54.8809249833, 82.4648314, \"61\"],\n[54.8810648667, 82.4624290833, \"44\"],\n[54.8816609833, 82.4570327667, \"8\"],\n[54.8804975333, 82.4721639167, \"119\"],\n[54.8804971667, 82.4724005167, \"121\"],\n[54.8806352, 82.4729319167, \"123A\"],\n[54.8804951667, 82.4726299167, \"123\"],\n[54.8806614, 82.4698499833, \"107\"],\n[54.8806724167, 82.4731077667, \"125A\"],\n[54.8808698667, 82.47335925, \"129\"],\n[54.8808554167, 82.4735094333, \"131\"],\n[54.8804224667, 82.4735332333, \"133\"],\n[54.8804913, 82.47469655, \"137B\"],\n[54.8803901, 82.4747040167, \"137\"],\n[54.8803887333, 82.47486625, \"139\"],\n[54.8807482167, 82.46714865, \"77A\"],\n[54.8807597833, 82.4669996167, \"77\"],\n[54.8807607667, 82.4673298667, \"79\"],\n[54.88104675, 82.46741105, \"81\"],\n[54.8812452833, 82.4676640333, \"85\"],\n[54.8809039167, 82.4650308333, \"63\"],\n[54.88112735, 82.4652241167, \"65A\"],\n[54.8808660833, 82.4654164833, \"65\"],\n[54.8811361, 82.4657563, \"71\"],\n[54.8808503, 82.4658921167, \"73\"],\n[54.8808297667, 82.4661495833, \"75\"],\n[54.8807330167, 82.4677691667, \"87\"],\n[54.8811556833, 82.46787915, \"89\"],\n[54.88071555, 82.4680383167, \"91A\"],\n[54.8807704167, 82.46804005, \"91B\"],\n[54.88083325, 82.4680391667, \"91C\"],\n[54.8809986, 82.4680511, \"91\"],\n[54.8807155167, 82.46826605, \"93\"],\n[54.8809702167, 82.4682232667, \"95\"],\n[54.8807815333, 82.4750173333, \"143\"],\n[54.8803783667, 82.4751021, \"145\"],\n[54.88035755, 82.4753576667, \"147\"],\n[54.8807471667, 82.47541785, \"149\"],\n[54.8807513667, 82.4755767167, \"151\"],\n[54.8803393, 82.4758476333, \"159\"],\n[54.8802462333, 82.4774083333, \"167\"],\n[54.8800620667, 82.4804408, \"189\"],\n[54.8800557667, 82.48072595, \"191\"],\n[54.88004135, 82.481018, \"193\"],\n[54.8807389667, 82.47578795, \"155\"],\n[54.88007905, 82.4799234833, \"185\"],\n[54.88086485, 82.4703347667, \"111A\"],\n[54.8806350333, 82.4703154167, \"111\"],\n[54.8800789, 82.4801471833, \"187\"],\n[54.8800045833, 82.4815507667, \"197\"],\n[54.8800214333, 82.4812237167, \"195\"],\n[54.8939151167, 82.4701667, \"27\"],\n[54.8936762, 82.4701298, \"31\"],\n[54.8924783167, 82.4700222667, \"47\"],\n[54.8918865167, 82.469973, \"51\"],\n[54.89367495, 82.4697996667, \"24\"],\n[54.8943151667, 82.4702028667, \"7\"],\n[54.8941286667, 82.4702044, \"23\"],\n[54.8942378667, 82.4698431, \"2\"],\n[54.8945567833, 82.47024855, \"1/1-3/1\"],\n[54.8935522667, 82.4697719, \"28\"],\n[54.8939433, 82.4703330667, \"25\"],\n[54.8937860667, 82.4701428667, \"29\"],\n[54.8935538167, 82.4701164833, \"41\"],\n[54.8941460167, 82.46983875, \"14\"],\n[54.8938438167, 82.46980825, \"18\"],\n[54.8937419667, 82.4698073167, \"22\"],\n[54.8944316, 82.4702330333, \"3\"],\n[54.8943035167, 82.4704350167, \"9\"],\n[54.8926233833, 82.4700377333, \"43\"],\n[54.8922256167, 82.47000115, \"49\"],\n[54.8917971667, 82.46961, \"54\"],\n[54.8926854, 82.469645, \"40\"],\n[54.8921227167, 82.4696225333, \"48\"],\n[54.8939403167, 82.4698126, \"16\"],\n[54.8909714667, 82.4681493667, \"33\"],\n[54.89113605, 82.4681601333, \"31\"],\n[54.8912736333, 82.4686223167, \"26\"],\n[54.892202, 82.4686328333, \"16\"],\n[54.8921055833, 82.46861625, \"18\"],\n[54.8912406833, 82.4681574833, \"27\"],\n[54.89073535, 82.4685119833, \"32\"],\n[54.89037515, 82.4686127333, \"36\"],\n[54.8907882833, 82.4681261167, \"37-39\"],\n[54.8905470833, 82.46806415, \"41\"],\n[54.8928384833, 82.4687398333, \"4\"],\n[54.8927622667, 82.46885875, \"8\"],\n[54.8926823333, 82.4687259, \"10\"],\n[54.89258095, 82.4687121167, \"12\"],\n[54.89248485, 82.4687019167, \"14\"],\n[54.9064365333, 82.4541838333, \"29\"],\n[54.9065554833, 82.4549096667, \"1/35\"],\n[54.9060750333, 82.4550532833, \"3/35\"],\n[54.9058351667, 82.4555274667, \"5/35\"],\n[54.9055143333, 82.4559182333, \"7/35\"],\n[54.9065810667, 82.4558807167, \"36\"],\n[54.9065682333, 82.4553069, \"37\"],\n[54.9064074667, 82.4522252167, \"9\"],\n[54.9059521, 82.45592445, \"2/35\"],\n[54.9108997167, 82.4805822667, \"3\"],\n[54.9109122833, 82.47947205, \"6A\"],\n[54.9109177167, 82.47936065, \"8\"],\n[54.911182, 82.4797094, \"10\"],\n[54.9113005167, 82.4794321333, \"12\"],\n[54.9111916333, 82.4793347333, \"12A\"],\n[54.9112471833, 82.4797754667, \"14\"],\n[54.9112473667, 82.4800788167, \"11\"],\n[54.9113031333, 82.479914, \"13\"],\n[54.91063835, 82.4803100333, \"1\"],\n[54.9104951, 82.4800418667, \"2\"],\n[54.9107454333, 82.4798887833, \"4\"],\n[54.9108743667, 82.4802328833, \"5\"],\n[54.9109565333, 82.4797847, \"6\"],\n[54.9110407167, 82.4801576333, \"7\"],\n[54.9112238167, 82.4804073167, \"9\"],\n[54.921572, 82.4690554667, \"8\"],\n[54.9210102667, 82.4691739667, \"1\"],\n[54.9209054, 82.4687952333, \"2\"],\n[54.92139265, 82.4695081333, \"3\"],\n[54.9212156833, 82.4688233667, \"4\"],\n[54.92161785, 82.4693603333, \"5\"],\n[54.9215667, 82.4686771667, \"6\"],\n[54.8971280667, 82.3833620167, \"104\"],\n[54.8928069667, 82.3849023833, \"58\"],\n[54.8960316833, 82.3834830167, \"1/84\"],\n[54.8904228167, 82.38549425, \"28\"],\n[54.8953458333, 82.3837370167, \"84\"],\n[54.82145425, 82.3649986833, \"7\"],\n[54.81972895, 82.3640394833, \"24\"],\n[54.8211835333, 82.3645971667, \"11\"],\n[54.8207776167, 82.3647366833, \"14\"],\n[54.8209467167, 82.3640718167, \"15\"],\n[54.8203904333, 82.3652387, \"12\"],\n[54.9137399667, 82.3922778167, \"2/73\"],\n[54.91124595, 82.39246205, \"46\"],\n[54.9139008833, 82.3922517333, \"3/73\"],\n[54.91350815, 82.39233345, \"1/73\"],\n[54.9176178167, 82.4598785667, \"19\"],\n[54.9184013833, 82.4603797833, \"14\"],\n[54.9186543333, 82.4622474833, \"6\"],\n[54.9173606667, 82.46006885, \"19B\"],\n[54.9174988, 82.4603532, \"19C\"],\n[54.9177378167, 82.4601680667, \"19D\"],\n[54.91904695, 82.4627864167, \"1\"],\n[54.9187282, 82.46300145, \"2\"],\n[54.91901275, 82.46243355, \"3\"],\n[54.9186912, 82.46265345, \"4\"],\n[54.91856195, 82.4613744167, \"10\"],\n[54.91851535, 82.4609194, \"12\"],\n[54.9189516833, 82.4617426667, \"5\"],\n[54.9188849, 82.4613117333, \"7\"],\n[54.9186173667, 82.4618227833, \"8\"],\n[54.9188575667, 82.4608533167, \"9\"],\n[54.9173323833, 82.4597201333, \"19A\"],\n[54.9178891, 82.4598711167, \"17\"],\n[54.9180202833, 82.46025785, \"16\"],\n[54.9016754833, 82.4689591, \"10\"],\n[54.9008128667, 82.4686879833, \"2\"],\n[54.9009759333, 82.46843985, \"1\"],\n[54.9014464, 82.4685093167, \"5\"],\n[54.90130095, 82.4688850167, \"6\"],\n[54.9016211667, 82.4685312667, \"7\"],\n[54.9014644167, 82.4690226833, \"8\"],\n[54.9014864167, 82.4687479667, \"9\"],\n[54.9010720333, 82.4687982333, \"4\"],\n[54.9011746, 82.4685293333, \"3\"],\n[54.9013743333, 82.4862629167, \"3\"],\n[54.9017248, 82.48698725, \"6\"],\n[54.9012848, 82.4859531833, \"2\"],\n[54.9016014833, 82.4860586167, \"10\"],\n[54.9014527667, 82.4865486167, \"4\"],\n[54.90159855, 82.48677855, \"5\"],\n[54.90183005, 82.4869517667, \"7\"],\n[54.9017713833, 82.4866214167, \"8\"],\n[54.9016935, 82.4863532333, \"9\"],\n[54.90753, 82.46902475, \"11\"],\n[54.9095893167, 82.4677886667, \"39B\"],\n[54.9109792833, 82.4682655, \"46A\"],\n[54.91108275, 82.4685749667, \"46B\"],\n[54.91115625, 82.4686338833, \"48C\"],\n[54.9110050167, 82.46807085, \"48A\"],\n[54.91095895, 82.46781955, \"48\"],\n[54.9108204, 82.4678798667, \"46\"],\n[54.9110788833, 82.4683501, \"48B\"],\n[54.9113655167, 82.4678862333, \"52B\"],\n[54.9108344833, 82.4674433667, \"45\"],\n[54.9080208833, 82.4692374833, \"22\"],\n[54.9083263167, 82.4686353333, \"27\"],\n[54.90844025, 82.4697672333, \"26\"],\n[54.90818025, 82.4691643, \"22A\"],\n[54.91258895, 82.4673144833, \"64\"],\n[54.9123684167, 82.4671105167, \"62\"],\n[54.9127896, 82.4663434833, \"67\"],\n[54.91150695, 82.46757075, \"54\"],\n[54.9098419667, 82.4683599167, \"40\"],\n[54.91097155, 82.4673723, \"47\"],\n[54.9078617667, 82.4693023667, \"20\"],\n[54.9089053833, 82.4683338, \"29\"],\n[54.9099875333, 82.46828695, \"42\"],\n[54.9113045167, 82.4682282833, \"50A\"],\n[54.9107373, 82.4665437833, \"47C\"],\n[54.9108713, 82.4665006167, \"49B\"],\n[54.9129575833, 82.4665350833, \"69\"],\n[54.9108057333, 82.4667861, \"47B\"],\n[54.9108904167, 82.4670609667, \"47A\"],\n[54.9110041, 82.4668838667, \"49A\"],\n[54.9111488833, 82.4673072667, \"49\"],\n[54.9127369333, 82.46653495, \"65\"],\n[54.91122205, 82.46770665, \"52\"],\n[54.9113599, 82.467657, \"52A\"],\n[54.9075002667, 82.4694598, \"12\"],\n[54.9076741, 82.46939185, \"14\"],\n[54.9078864833, 82.4699014333, \"16\"],\n[54.9079676667, 82.46986515, \"18\"],\n[54.90833225, 82.4695654167, \"24\"],\n[54.9084313667, 82.4690023, \"28\"],\n[54.9096631167, 82.46843925, \"38\"],\n[54.9096189, 82.4680248667, \"39\"],\n[54.911315, 82.4684015667, \"50\"],\n[54.9073078333, 82.4691221167, \"9\"],\n[54.9093386167, 82.4686052333, \"34\"],\n[54.9091743667, 82.4682295833, \"35\"],\n[54.90945425, 82.4681136333, \"37\"],\n[54.90950645, 82.4685246333, \"36\"],\n[54.9091745333, 82.4686900667, \"32\"],\n[54.9127273333, 82.4669306667, \"66\"],\n[54.913043, 82.4669127667, \"68\"],\n[54.9113586333, 82.4672288167, \"51\"],\n[54.9113531667, 82.4670099667, \"51A\"],\n[54.9127951, 82.46667535, \"71\"],\n[54.884095, 82.4568770667, \"69A\"],\n[54.8838324333, 82.4568632333, \"73A\"],\n[54.8866347667, 82.4565719833, \"43\"],\n[54.8906992, 82.4569129667, \"5\"],\n[54.8905596667, 82.4568912833, \"7\"],\n[54.8892758333, 82.456777, \"13A\"],\n[54.8901881167, 82.45687625, \"1/11-11/11\"],\n[54.89070845, 82.4565194333, \"1/4-3/4\"],\n[54.8902009333, 82.4563996667, \"1/6-32/6\"],\n[54.8880562333, 82.4552566667, \"26A\"],\n[54.8844905833, 82.4563941, \"65\"],\n[54.8840861833, 82.45635875, \"69\"],\n[54.8863777, 82.45685, \"45A\"],\n[54.8909978167, 82.4569555833, \"3\"],\n[54.8863633167, 82.4571221667, \"45B\"],\n[54.8864835667, 82.4565624833, \"45\"],\n[54.8881257667, 82.4569633333, \"25A\"],\n[54.8905126667, 82.4574578833, \"5A\"],\n[54.8907166167, 82.4575558333, \"5B\"],\n[54.8866317167, 82.4572218, \"41A\"],\n[54.8873822167, 82.4566324, \"33\"],\n[54.8872964167, 82.4566407167, \"35\"],\n[54.8866143833, 82.4569883667, \"41\"],\n[54.8837334333, 82.45685885, \"75A\"],\n[54.8860936, 82.4570698167, \"49\"],\n[54.8855037167, 82.4564867333, \"57\"],\n[54.8847617833, 82.4564164833, \"59\"],\n[54.8844513167, 82.4566735333, \"65A\"],\n[54.88419435, 82.45689485, \"67A\"],\n[54.8842829333, 82.4563860333, \"67\"],\n[54.88391675, 82.4563527, \"73\"],\n[54.8837116667, 82.4563469333, \"75\"],\n[54.889394, 82.4567865833, \"13\"],\n[54.8890782333, 82.4567699333, \"15\"],\n[54.8888433833, 82.4567615833, \"17\"],\n[54.8886293333, 82.45674825, \"19\"],\n[54.8884455333, 82.4567414833, \"21\"],\n[54.8882809333, 82.45673085, \"23\"],\n[54.8881163667, 82.456655, \"25\"],\n[54.8880094667, 82.4562455667, \"26\"],\n[54.89142225, 82.4569765, \"1\"],\n[54.8914418, 82.4565121, \"2\"],\n[54.8870694, 82.4566186333, \"37\"],\n[54.8868689667, 82.45709495, \"39A\"],\n[54.8868342167, 82.4565953333, \"39\"],\n[54.8863517167, 82.4573732167, \"45C\"],\n[54.8861983667, 82.4570712667, \"47A\"],\n[54.8862286, 82.4568411833, \"47B\"],\n[54.8880125833, 82.4547576833, \"26B\"],\n[54.8860945833, 82.4565352167, \"49A\"],\n[54.8904199167, 82.4568860167, \"1/9-12/9\"],\n[54.8857833, 82.4565171833, \"53\"],\n[54.8856455167, 82.45651885, \"55\"],\n[54.8817373833, 82.4556858833, \"72\"],\n[54.88593655, 82.45653005, \"51\"],\n[54.8862765833, 82.4565127, \"47\"],\n[54.8775379833, 82.4825127167, \"28A\"],\n[54.87727315, 82.482376, \"28\"],\n[54.87729155, 82.4821068667, \"26\"],\n[54.8769019667, 82.4786293, \"4C\"],\n[54.8767004333, 82.4787606, \"4B\"],\n[54.8772910833, 82.4818029333, \"24\"],\n[54.8771890667, 82.48153255, \"22\"],\n[54.87708045, 82.4812278, \"20\"],\n[54.8775351, 82.4826397667, \"30A\"],\n[54.8772534167, 82.4827040167, \"30\"],\n[54.877579, 82.4818970667, \"24A\"],\n[54.876712, 82.4812017667, \"21\"],\n[54.8773884333, 82.4832404167, \"36\"],\n[54.8769804167, 82.4824093, \"27\"],\n[54.8766636667, 82.482704, \"31B\"],\n[54.8769937167, 82.4830107167, \"31\"],\n[54.8767516667, 82.479482, \"8A\"],\n[54.8769705667, 82.4818533667, \"23\"],\n[54.8766017167, 82.48246365, \"29A\"],\n[54.8764641833, 82.4825834, \"29B\"],\n[54.8769964667, 82.4820980833, \"25\"],\n[54.8769606333, 82.4826863833, \"29\"],\n[54.87679475, 82.4828674667, \"31A\"],\n[54.8770826, 82.4832520333, \"33\"],\n[54.8772377, 82.48334835, \"35\"],\n[54.8775367167, 82.48363695, \"36A\"],\n[54.8775890833, 82.4831116, \"34\"],\n[54.8773408667, 82.4829609, \"32\"],\n[54.8762828667, 82.4801149667, \"11\"],\n[54.87597055, 82.4792251167, \"3\"],\n[54.8760466167, 82.4794375833, \"5\"],\n[54.8761314, 82.4796617, \"7\"],\n[54.8764699833, 82.48058085, \"15\"],\n[54.8765455167, 82.4808159833, \"17\"],\n[54.8767292667, 82.48028335, \"14\"],\n[54.8765539833, 82.4798159833, \"10\"],\n[54.87646245, 82.4795675, \"8\"],\n[54.8763712167, 82.4793057167, \"6\"],\n[54.8776228167, 82.481266, \"20B\"],\n[54.8775729667, 82.482055, \"26A\"],\n[54.8776195833, 82.4814085333, \"22B\"],\n[54.8765414, 82.4790666667, \"6A\"],\n[54.8773585333, 82.48356815, \"38A\"],\n[54.8762120667, 82.4798686667, \"9\"],\n[54.8766452667, 82.4800751167, \"12\"],\n[54.8763675, 82.48034475, \"13\"],\n[54.8766347833, 82.4810402667, \"19\"],\n[54.8774052167, 82.4812147167, \"20A\"],\n[54.8774057667, 82.4814070167, \"22A\"],\n[54.8762723167, 82.479009, \"4\"],\n[54.8761971167, 82.4787850833, \"2\"],\n[54.8767849, 82.4796004667, \"10A\"],\n[54.87648555, 82.47892075, \"4A\"],\n[54.8767848, 82.4788595833, \"6B\"],\n[54.8997092333, 82.4818082, \"7\"],\n[54.8999472667, 82.4825543, \"15\"],\n[54.8999358167, 82.4815958167, \"4\"],\n[54.9000434833, 82.4825363833, \"17\"],\n[54.9002215333, 82.4828014167, \"16\"],\n[54.90002095, 82.4818578, \"6\"],\n[54.9000853167, 82.48210025, \"8\"],\n[54.8997820833, 82.4820087333, \"9\"],\n[54.8998240167, 82.4822147833, \"11\"],\n[54.8998576333, 82.48247455, \"13\"],\n[54.8996422833, 82.4815878833, \"5\"],\n[54.9002942833, 82.482764, \"14\"],\n[54.9001676167, 82.4824792667, \"12\"],\n[54.89953345, 82.4811912333, \"1\"],\n[54.8997866833, 82.4810307833, \"2\"],\n[54.8995802333, 82.4813792333, \"3\"],\n[54.9001401333, 82.4822942333, \"10\"],\n[54.8914648833, 82.4772108167, \"7\"],\n[54.8919011833, 82.47723515, \"1\"],\n[54.89187105, 82.4768182, \"2\"],\n[54.8913584, 82.4765354167, \"3/6\"],\n[54.8897734833, 82.47664395, \"22\"],\n[54.8913508, 82.47668445, \"1/6\"],\n[54.8915273667, 82.4762602, \"12/6\"],\n[54.8916285, 82.4772315333, \"5\"],\n[54.8913796, 82.4761122167, \"7/6\"],\n[54.8915023833, 82.4767099333, \"8/6\"],\n[54.89152, 82.4763519333, \"11/6\"],\n[54.8915372, 82.4760592333, \"14/6\"],\n[54.89153065, 82.4761616667, \"13/6\"],\n[54.8915142333, 82.4764663667, \"10/6\"],\n[54.8913717333, 82.4763199333, \"5/6\"],\n[54.8905254833, 82.4766904, \"14\"],\n[54.8903609333, 82.4766834833, \"16\"],\n[54.88999105, 82.4766566833, \"20\"],\n[54.8898741167, 82.4770700667, \"21\"],\n[54.88946535, 82.4766037667, \"24\"],\n[54.8890790333, 82.4764705833, \"28\"],\n[54.88883405, 82.4767525667, \"29\"],\n[54.8886383, 82.47663365, \"31\"],\n[54.8913739667, 82.47622135, \"6/6\"],\n[54.8913652833, 82.47641835, \"4/6\"],\n[54.8901779667, 82.4766671167, \"18\"],\n[54.8843281, 82.4794198167, \"104\"],\n[54.88535045, 82.4866782167, \"184\"],\n[54.8854485333, 82.4864475167, \"182\"],\n[54.8867971833, 82.4705084167, \"34\"],\n[54.8873998833, 82.4682775833, \"20\"],\n[54.8873415667, 82.46844545, \"22\"],\n[54.884267, 82.4871188333, \"189\"],\n[54.8843410333, 82.4813043, \"114A\"],\n[54.8836708667, 82.47833265, \"90A\"],\n[54.88402285, 82.4784176667, \"2/92\"],\n[54.8841246, 82.4784325, \"1/92\"],\n[54.8874953667, 82.4680249333, \"18\"],\n[54.8882076333, 82.4665346667, \"2\"],\n[54.8847749, 82.4777212667, \"89\"],\n[54.8847129167, 82.4883360167, \"198\"],\n[54.8852412667, 82.4950174167, \"258\"],\n[54.8851558333, 82.4809135167, \"111A\"],\n[54.88425915, 82.490565, \"219\"],\n[54.8843227167, 82.4792336667, \"102\"],\n[54.8853703333, 82.47613215, \"70\"],\n[54.8841992667, 82.4963818333, \"267\"],\n[54.8839456333, 82.47862415, \"96\"],\n[54.8849404833, 82.4785609167, \"91B\"],\n[54.8834439167, 82.5003043667, \"309\"],\n[54.8859648333, 82.4880242333, \"2/194\"],\n[54.88679165, 82.4708238833, \"36\"],\n[54.8846928333, 82.4966356667, \"270\"],\n[54.8843265, 82.4790500333, \"100\"],\n[54.8847626167, 82.48078795, \"109\"],\n[54.88474565, 82.4788347167, \"93\"],\n[54.8843263, 82.4786463833, \"94\"],\n[54.8847555167, 82.4792519167, \"95\"],\n[54.8847507833, 82.4802669333, \"103\"],\n[54.8877261667, 82.4675846667, \"1/14-8/14\"],\n[54.884759, 82.4805435333, \"105\"],\n[54.8843192, 82.4802557667, \"108\"],\n[54.8847632167, 82.4813335333, \"113\"],\n[54.8880664667, 82.4668566667, \"4\"],\n[54.8843192833, 82.4781745833, \"88\"],\n[54.8842179667, 82.4927192667, \"239\"],\n[54.8842136333, 82.4948947333, \"257\"],\n[54.8841869, 82.4971351, \"275\"],\n[54.8842592167, 82.487337, \"191\"],\n[54.8842746, 82.4896256667, \"213\"],\n[54.8842726, 82.4898100833, \"1/213\"],\n[54.8846939167, 82.49589215, \"264\"],\n[54.8847557667, 82.480013, \"101\"],\n[54.8847654333, 82.488289833, \"117\"],\n[54.8843088167, 82.4819155, \"120\"],\n[54.88495845, 82.4760208167, \"74A\"],\n[54.8858546833, 82.48954395, \"1/214\"],\n[54.8847226333, 82.49078585, \"222\"],\n[54.8853824333, 82.4904875333, \"220\"],\n[54.8851609, 82.4769312833, \"75\"],\n[54.8832135333, 82.4966401667, \"273\"],\n[54.8871125333, 82.4687638667, \"24A\"],\n[54.8836533833, 82.49965535, \"303\"],\n[54.8847623833, 82.4784197, \"91\"],\n[54.8853003167, 82.4812587, \"113B\"],\n[54.8839543333, 82.4780861333, \"86\"],\n[54.8846811667, 82.49516135, \"260\"],\n[54.8856284667, 82.4877555167, \"1/194\"],\n[54.88470535, 82.4899576833, \"1/218\"],\n[54.8858448, 82.4898961, \"2/218\"],\n[54.8857487667, 82.4882389667, \"3/194\"],\n[54.8858920833, 82.4886561833, \"4/194\"],\n[54.8854131167, 82.4885925, \"202\"],\n[54.8852231333, 82.48536035, \"174\"],\n[54.88721395, 82.4674219167, \"12A\"],\n[54.8850944, 82.4812663333, \"113A\"],\n[54.8858759667, 82.4852820333, \"172\"],\n[54.8843297167, 82.4777121167, \"80\"],\n[54.8867259833, 82.4716590667, \"42\"],\n[54.8841291333, 82.4812217833, \"114\"],\n[54.8878423667, 82.46733415, \"10\"],\n[54.8873731, 82.46722755, \"12\"],\n[54.8873645167, 82.4677444, \"16A\"],\n[54.8873792, 82.4676194833, \"16B\"],\n[54.8871674667, 82.4675664, \"16C\"],\n[54.8871631333, 82.4677062, \"16D\"],\n[54.88761885, 82.4678307833, \"16\"],\n[54.8872513, 82.4677940833, \"18A\"],\n[54.8868627833, 82.4703096167, \"32\"],\n[54.8866729333, 82.4725751667, \"46\"],\n[54.8866649333, 82.4727545667, \"48\"],\n[54.8866508833, 82.4729862833, \"50\"],\n[54.8866308167, 82.4733044333, \"52\"],\n[54.8866201167, 82.4735912, \"54\"],\n[54.8866046, 82.4738994833, \"56\"],\n[54.8867646333, 82.4710940833, \"38\"],\n[54.8867434167, 82.4713738, \"40\"],\n[54.8865795333, 82.471651, \"42A\"],\n[54.8867192167, 82.4718726833, \"44\"],\n[54.8879124167, 82.4671744, \"8\"],\n[54.8847677333, 82.48104275, \"111\"],\n[54.8842908, 82.4810946667, \"112\"],\n[54.8847655167, 82.48152025, \"115\"],\n[54.8842992333, 82.4815339, \"116\"],\n[54.8843125167, 82.488239167, \"118\"],\n[54.8847685333, 82.4795402167, \"97\"],\n[54.8847615667, 82.4797710333, \"99\"],\n[54.8849925167, 82.48009295, \"101A\"],\n[54.8850730167, 82.4803513167, \"103A\"],\n[54.8850517667, 82.4806989167, \"107\"],\n[54.8842659667, 82.4776982667, \"80A\"],\n[54.8843255167, 82.4779083833, \"82\"],\n[54.88372445, 82.4779537667, \"84A\"],\n[54.88391925, 82.4779436333, \"84\"],\n[54.8839372667, 82.4783140167, \"90\"],\n[54.8849343833, 82.47834135, \"91A\"],\n[54.8843215, 82.47842775, \"92\"],\n[54.88379995, 82.4786243333, \"96A\"],\n[54.8843308167, 82.47886585, \"98\"],\n[54.8846524333, 82.4766493167, \"76\"],\n[54.8845290833, 82.4764747667, \"78A\"],\n[54.8845141833, 82.47672525, \"78\"],\n[54.8847249, 82.4874558833, \"192\"],\n[54.88422795, 82.4880656333, \"197\"],\n[54.8842586167, 82.4888764, \"205\"],\n[54.8847152, 82.4891847, \"206\"],\n[54.8847452333, 82.48597775, \"180\"],\n[54.8842725667, 82.4862342167, \"181\"],\n[54.8842734167, 82.4864492, \"183\"],\n[54.88427415, 82.4866713, \"185\"],\n[54.8847306167, 82.48657095, \"186\"],\n[54.88426915, 82.48689685, \"187\"],\n[54.8842773667, 82.4856398, \"179\"],\n[54.8852212833, 82.4924678, \"236\"],\n[54.8854883167, 82.4880036333, \"194\"],\n[54.8854214333, 82.48956085, \"212\"],\n[54.8853153667, 82.4872245, \"190\"],\n[54.8841928667, 82.4931503833, \"241\"],\n[54.8844711667, 82.4984144, \"290\"],\n[54.8842522667, 82.4992926333, \"296\"],\n[54.88368415, 82.4993789667, \"299\"],\n[54.8852287833, 82.49615515, \"268\"],\n[54.8859148667, 82.4897217, \"214\"],\n[54.8872887667, 82.4686820167, \"24\"],\n[54.8862459167, 82.47553185, \"66\"],\n[54.884721, 82.48537045, \"176\"],\n[54.88427605, 82.4851847833, \"82\"],\n[54.8842737833, 82.4854139833, \"177\"],\n[54.88469795, 82.4945610167, \"252\"],\n[54.8853844667, 82.47677695, \"73\"],\n[54.8850111333, 82.4763984, \"74\"],\n[54.8847382167, 82.4869962333, \"188\"],\n[54.8872426333, 82.4689359833, \"26\"],\n[54.8847101833, 82.4880854667, \"196\"],\n[54.8850733, 82.4902483167, \"218\"],\n[54.8865769333, 82.4741854167, \"58\"],\n[54.8865507, 82.4747159333, \"62\"],\n[54.88798625, 82.46700445, \"6\"],\n[54.8865659, 82.4744709833, \"60\"],\n[54.8865476667, 82.4748834667, \"64\"],\n[54.8871864333, 82.4691891, \"28\"],\n[54.8871582, 82.4693788167, \"30\"],\n[54.8869467833, 82.4687736667, \"26A\"],\n[54.8856446167, 82.4771148167, \"71\"],\n[54.8851925333, 82.4762547833, \"72\"],\n[54.8869292167, 82.4689437, \"26B\"],\n[54.88426605, 82.48474735, \"171\"],\n[54.884281, 82.4849628667, \"173\"],\n[54.8847245167, 82.4848834667, \"170\"],\n[54.8680607667, 82.4844529, \"318\"],\n[54.86322315, 82.477174, \"229\"],\n[54.86023885, 82.47171045, \"177\"],\n[54.86190065, 82.4739293333, \"200\"],\n[54.8673314333, 82.4835841, \"306\"],\n[54.8671325167, 82.4839981167, \"307\"],\n[54.8657566333, 82.4825140333, \"287\"],\n[54.85661605, 82.4580103167, \"35\"],\n[54.8584986667, 82.4693192667, \"151\"],\n[54.86640715, 82.4833253333, \"293\"],\n[54.8662972, 82.48401185, \"301\"],\n[54.8615068, 82.4740312667, \"197\"],\n[54.86248105, 82.4746844667, \"208\"],\n[54.8654257333, 82.4789157833, \"256\"],\n[54.86815405, 82.4856843833, \"327\"],\n[54.8559617833, 82.4538523, \"5\"],\n[54.8560217167, 82.4541485167, \"7\"],\n[54.8545882, 82.4628883167, \"73\"],\n[54.8623530667, 82.4756642667, \"211\"],\n[54.8571193833, 82.46393905, \"91\"],\n[54.8612014833, 82.47249975, \"184\"],\n[54.8409288167, 82.37611985, \"48\"],\n[54.8396866, 82.3762834833, \"52\"],\n[54.840238, 82.3744657333, \"75\"],\n[54.84304635, 82.3783802167, \"24\"],\n[54.8407690333, 82.3753619333, \"59\"],\n[54.8447812333, 82.3774333333, \"5\"],\n[54.83956405, 82.3732069667, \"82\"],\n[54.84004855, 82.3731001333, \"83\"],\n[54.8401183167, 82.3739726667, \"77B\"],\n[54.8406453, 82.3751587333, \"63\"],\n[54.8435605667, 82.3793269333, \"20\"],\n[54.848291667, 82.3760676667, \"49\"],\n[54.8413693, 82.3763867167, \"46\"],\n[54.8399756833, 82.3748775, \"74\"],\n[54.8421274167, 82.3758927833, \"47\"],\n[54.8433708, 82.37858675, \"22\"],\n[54.8410302333, 82.3737431833, \"77A\"],\n[54.7912387167, 82.4809981333, \"33\"],\n[54.7921037167, 82.48244855, \"34\"],\n[54.7931116833, 82.4894669167, \"108\"],\n[54.7922422833, 82.4888664333, \"109\"],\n[54.8904655, 82.4340570833, \"16\"],\n[54.8912684167, 82.4347386333, \"38\"],\n[54.8918202833, 82.4356853333, \"41\"],\n[54.9076504833, 82.4808292167, \"2\"],\n[54.9077122167, 82.4810869667, \"3\"],\n[54.9078427, 82.4811889667, \"4\"],\n[54.9079905333, 82.4810739167, \"5\"],\n[54.9079955, 82.4808534333, \"6\"],\n[54.9078875833, 82.48062165, \"7\"],\n[54.8624973167, 82.3995043333, \"1302\"],\n[54.86458815, 82.3984334333, \"1302B\"],\n[54.8495279667, 82.3855142, \"1105\"],\n[54.8409388, 82.3715485333, \"965\"],\n[54.8497607833, 82.3787181667, \"1048D\"],\n[54.8474886167, 82.3815213, \"1071\"],\n[54.8692470333, 82.4060449833, \"1399\"],\n[54.86903025, 82.4050720333, \"1410\"],\n[54.8720073, 82.4080915167, \"1435\"],\n[54.8472647, 82.3801392333, \"1050\"],\n[54.8484202, 82.37745075, \"1048B\"],\n[54.8501358167, 82.37656745, \"1048C\"],\n[54.8464420667, 82.3786923167, \"1048A\"],\n[54.8636343667, 82.3989099167, \"1302A\"],\n[54.86024445, 82.39640055, \"1262B\"],\n[54.8455550167, 82.3768668, \"1032\"],\n[54.8498453667, 82.3860935167, \"1113\"],\n[54.8508258833, 82.3877938167, \"1129\"],\n[54.8538246333, 82.3925789833, \"1193\"],\n[54.8560212667, 82.3943255167, \"1209\"],\n[54.8600963167, 82.39687755, \"1262A\"],\n[54.8619671667, 82.398902, \"1292\"],\n[54.8647795167, 82.4015556333, \"1328A\"],\n[54.8641711, 82.40119575, \"1328B\"],\n[54.8653665667, 82.4021896833, \"1328\"],\n[54.8664159, 82.4057836, \"1343\"],\n[54.8487010667, 82.3828026833, \"1084B\"],\n[54.8487082, 82.3838392667, \"1095\"],\n[54.84854995, 82.3826141833, \"1084A\"],\n[54.8614933, 82.3962749667, \"1262C\"],\n[54.8941389333, 82.4685426667, \"1A\"],\n[54.8940808333, 82.46863395, \"1C\"],\n[54.8941101167, 82.46858455, \"1B\"],\n[54.8828690833, 82.4756987833, \"2\"],\n[54.8829161167, 82.4758464333, \"3\"],\n[54.8828703333, 82.47600365, \"4\"],\n[54.8826165, 82.4759774167, \"5\"],\n[54.8827374, 82.4756385167, \"1\"],\n[54.8987844, 82.5778468, \"196\"],\n[54.894548, 82.5752196167, \"249\"],\n[54.8985254833, 82.5770166167, \"3/207\"],\n[54.8979621333, 82.5725676167, \"1/207\"],\n[54.9028557167, 82.5775770667, \"1/159\"],\n[54.8968063833, 82.5714292167, \"2/209\"],\n[54.8982935667, 82.5770144167, \"4/207\"],\n[54.9069320167, 82.5687670833, \"57\"],\n[54.89817425, 82.5708251167, \"2/207\"],\n[54.90506995, 82.5738151167, \"103\"],\n[54.9103484333, 82.57042275, \"15\"],\n[54.8938830167, 82.57586675, \"1/253\"],\n[54.8936416667, 82.5760817333, \"2/253\"],\n[54.90255875, 82.5776407833, \"2/159\"],\n[54.9004225167, 82.57797105, \"178\"],\n[54.8969604, 82.5723327, \"1/209\"],\n[54.8767003833, 82.4818637833, \"31\"],\n[54.8757476333, 82.4817359, \"21A\"],\n[54.87485205, 82.4797409167, \"8\"],\n[54.87404295, 82.47989395, \"5B\"],\n[54.8752598667, 82.4811949, \"15A\"],\n[54.8760220833, 82.4807411167, \"18A\"],\n[54.8743084667, 82.4802727, \"7A\"],\n[54.8738682667, 82.4797568167, \"3C\"],\n[54.8742434333, 82.47987315, \"5A\"],\n[54.8759584333, 82.4806079667, \"16A\"],\n[54.87510295, 82.48015575, \"12\"],\n[54.8748438833, 82.48075465, \"11A\"],\n[54.8763291167, 82.4819017667, \"27\"],\n[54.8763574333, 82.4822859833, \"29A\"],\n[54.8751449333, 82.48070945, \"13\"],\n[54.8761885667, 82.4822191333, \"27A\"],\n[54.8746679833, 82.4804258667, \"9A\"],\n[54.87496675, 82.4808899333, \"13A\"],\n[54.8757570833, 82.4808296833, \"16\"],\n[54.8758986833, 82.4809562833, \"18\"],\n[54.87612285, 82.4811980333, \"20\"],\n[54.87624255, 82.4813098333, \"22\"],\n[54.8748282667, 82.47948305, \"4\"],\n[54.875127, 82.47954055, \"6\"],\n[54.8765282333, 82.4819416667, \"29\"],\n[54.87591735, 82.48192895, \"23\"],\n[54.8759485667, 82.4815328667, \"21\"],\n[54.87574945, 82.4813294167, \"19\"],\n[54.8742483167, 82.4796583833, \"3A\"],\n[54.8745132, 82.4795744833, \"3\"],\n[54.8744832833, 82.4792603167, \"1\"],\n[54.8745364667, 82.4798557, \"5\"],\n[54.8746295, 82.4801628, \"7\"],\n[54.8747969, 82.480295, \"9\"],\n[54.8745014333, 82.48041985, \"9B\"],\n[54.8740439, 82.4796883833, \"3B\"],\n[54.8764163833, 82.48148435, \"24\"],\n[54.8753753333, 82.4813299167, \"17A\"],\n[54.8749682667, 82.4800068, \"10\"],\n[54.8761475667, 82.481741, \"25\"],\n[54.8755644, 82.4811591833, \"17\"],\n[54.8753512333, 82.4809225, \"15\"],\n[54.87494615, 82.4804919833, \"11\"],\n[54.87563925, 82.4816151667, \"19A\"],\n[54.8755416, 82.4806192667, \"14\"],\n[54.9307413833, 82.4305783833, \"8\"],\n[54.9316973167, 82.4500289833, \"174\"],\n[54.9312246333, 82.4509272167, \"183\"],\n[54.9317041167, 82.4519870667, \"192\"],\n[54.9309645833, 82.4455487, \"131\"],\n[54.9313707333, 82.4417409833, \"106\"],\n[54.93144905, 82.4439987167, \"124\"],\n[54.9312471833, 82.44044115, \"90\"],\n[54.9310525167, 82.4572123333, \"249\"],\n[54.9304025833, 82.4600948, \"271\"],\n[54.9313988167, 82.4667548167, \"330\"],\n[54.9317416, 82.4711342333, \"370\"],\n[54.9311057, 82.4496502333, \"171\"],\n[54.9307743333, 82.46711525, \"333\"],\n[54.8983426, 82.4726432167, \"6\"],\n[54.8982667833, 82.4723224167, \"10\"],\n[54.8981903, 82.4719677667, \"14\"],\n[54.8981034667, 82.478259, \"16\"],\n[54.8979483667, 82.47163995, \"18\"],\n[54.8978498167, 82.4718887667, \"9\"],\n[54.89804025, 82.4727496, \"1\"],\n[54.8978692667, 82.4717117333, \"11\"],\n[54.8982294833, 82.4721665, \"12\"],\n[54.8983239333, 82.4724718833, \"8\"],\n[54.89833275, 82.4728329, \"4\"],\n[54.89817045, 82.4730263833, \"2\"],\n[54.8979749667, 82.4721439333, \"7\"],\n[54.8978645167, 82.4723602833, \"5\"],\n[54.8980527833, 82.4724426, \"3\"],\n[54.9118492167, 82.4777301333, \"75\"],\n[54.9071599667, 82.48024025, \"27A\"],\n[54.9070499833, 82.4802823167, \"27\"],\n[54.9133935, 82.477312, \"101\"],\n[54.9109577667, 82.4792493167, \"58A\"],\n[54.907982667, 82.4798474167, \"35\"],\n[54.9057049167, 82.48129845, \"18\"],\n[54.9045409833, 82.4821761, \"8A\"],\n[54.9132981167, 82.47734815, \"99\"],\n[54.9151731167, 82.4762851667, \"115A\"],\n[54.9159149667, 82.4765031667, \"128A\"],\n[54.9160620833, 82.4770954, \"126\"],\n[54.91362925, 82.4775332333, \"96\"],\n[54.9161206833, 82.47737745, \"124\"],\n[54.9138744167, 82.4774362833, \"98\"],\n[54.9159982167, 82.4768568, \"126A\"],\n[54.9045271167, 82.4818595, \"8\"],\n[54.9088441167, 82.4798303833, \"40\"],\n[54.9080257833, 82.4798009667, \"37\"],\n[54.9118080833, 82.4780394667, \"73\"],\n[54.9120441667, 82.4783650167, \"80\"],\n[54.9142880667, 82.4768798167, \"107B\"],\n[54.9159508833, 82.4774919167, \"122A\"],\n[54.9050646333, 82.4819231333, \"14A\"],\n[54.9066002, 82.4808875, \"28A\"],\n[54.90519225, 82.4815441667, \"16\"],\n[54.91452115, 82.477165, \"106\"],\n[54.90746095, 82.4804961333, \"32\"],\n[54.91248555, 82.47814135, \"86\"],\n[54.9158230167, 82.4760962167, \"123\"],\n[54.9159919, 82.47604385, \"125\"],\n[54.91623445, 82.4763621, \"130\"],\n[54.90872535, 82.4791772, \"41A\"],\n[54.9044587, 82.4821471167, \"6A\"],\n[54.9075026667, 82.4797328167, \"33A\"],\n[54.9109141167, 82.4788989667, \"58\"],\n[54.9048600833, 82.4817091833, \"12\"],\n[54.9156691333, 82.4761731833, \"121\"],\n[54.9159156667, 82.4772401333, \"120\"],\n[54.9158559667, 82.4770386667, \"118\"],\n[54.9153897167, 82.4763100667, \"117\"],\n[54.9155261333, 82.4762367333, \"119\"],\n[54.9143680667, 82.4772159833, \"104\"],\n[54.9091816833, 82.4799197, \"44A\"],\n[54.9063697833, 82.4811747, \"26B\"],\n[54.9055854667, 82.4813526667, \"18B\"],\n[54.9140346667, 82.4774023333, \"100\"],\n[54.9160233167, 82.4772866833, \"122B\"],\n[54.9046896833, 82.4817846667, \"10\"],\n[54.9078630333, 82.4802907167, \"34\"],\n[54.9074586667, 82.4800447667, \"31\"],\n[54.90766965, 82.4799655333, \"33\"],\n[54.9121775667, 82.4782823667, \"82\"],\n[54.91233785, 82.4782158167, \"84\"],\n[54.9135061167, 82.47759595, \"92\"],\n[54.9141940333, 82.4769194, \"107A\"],\n[54.9047462167, 82.4820914167, \"10A\"],\n[54.9071456333, 82.4806193333, \"30\"],\n[54.9126591, 82.4780602, \"88\"],\n[54.9043394833, 82.4819642167, \"6\"],\n[54.9136969, 82.47784185, \"96A\"],\n[54.9162752167, 82.4761951167, \"132\"],\n[54.9120850833, 82.4778879333, \"77\"],\n[54.9072933667, 82.48012235, \"29\"],\n[54.9058775167, 82.4812227667, \"20\"],\n[54.9060436, 82.48114975, \"22\"],\n[54.90620285, 82.4810768167, \"24\"],\n[54.9063685833, 82.4809921833, \"26\"],\n[54.9065447667, 82.4809131167, \"28\"],\n[54.91495335, 82.47652165, \"111\"],\n[54.9087348, 82.4794214667, \"41\"],\n[54.9089801333, 82.47978555, \"42\"],\n[54.9089057333, 82.4793457667, \"43\"],\n[54.9095931667, 82.4790578, \"51\"],\n[54.9123723167, 82.4777452667, \"81\"],\n[54.9126095167, 82.47765015, \"91\"],\n[54.91277265, 82.4775717667, \"93\"],\n[54.91509955, 82.4768812333, \"110\"],\n[54.9152698333, 82.476794, \"112\"],\n[54.9154395, 82.4767326333, \"114\"],\n[54.91572125, 82.4765971833, \"116\"],\n[54.9102388667, 82.47919135, \"50\"],\n[54.9048902, 82.4819941833, \"12A\"],\n[54.9091995333, 82.47891055, \"47A\"],\n[54.9150900667, 82.4764547333, \"113\"],\n[54.91524275, 82.4763963833, \"115\"],\n[54.9094314833, 82.4791159333, \"49\"],\n[54.9096957667, 82.4794569, \"48A\"],\n[54.9091736667, 82.4796928333, \"44\"],\n[54.9104137167, 82.4791214333, \"52\"],\n[54.9095526333, 82.47951535, \"48\"],\n[54.9092440667, 82.4791909833, \"47\"],\n[54.905025, 82.4816333, \"14\"],\n[54.91218695, 82.4778348667, \"77A\"],\n[54.9105796, 82.4790363667, \"54\"],\n[54.9142164167, 82.4773281, \"102\"],\n[54.9093673833, 82.4796006833, \"46\"],\n[54.9107540667, 82.4789564333, \"56\"],\n[54.9090764333, 82.4792701333, \"45\"],\n[54.9122119833, 82.4774975, \"79\"],\n[54.9051519, 82.4770494, \"5/37B\"],\n[54.9072341833, 82.4812645, \"74\"],\n[54.90539015, 82.47753615, \"21/37B\"],\n[54.9064404833, 82.4786360667, \"52\"],\n[54.9053830667, 82.4751337333, \"28\"],\n[54.9053326, 82.4740749833, \"20A\"],\n[54.9055134833, 82.4740488, \"20C\"],\n[54.90547225, 82.4739782, \"20B\"],\n[54.9053470167, 82.4742053667, \"20D\"],\n[54.9069486333, 82.4814998167, \"73\"],\n[54.9051562667, 82.4778512167, \"17/37B\"],\n[54.9052251333, 82.4746236833, \"24\"],\n[54.9053746, 82.4777257833, \"19/37B\"],\n[54.9071479667, 82.4809996833, \"72\"],\n[54.9050343167, 82.47739, \"24/37B\"],\n[54.9049808, 82.4775142667, \"25/37B\"],\n[54.9051211333, 82.4773504667, \"23/37B\"],\n[54.9068252833, 82.4810905167, \"69\"],\n[54.9047089333, 82.4739594, \"19\"],\n[54.9040900833, 82.4718856167, \"1\"],\n[54.9048747833, 82.4744885333, \"23\"],\n[54.90479065, 82.4742263667, \"21\"],\n[54.905018, 82.47392355, \"16\"],\n[54.9063578667, 82.4783819333, \"50\"],\n[54.9049504167, 82.4747584333, \"25\"],\n[54.9050288833, 82.47502195, \"27\"],\n[54.9072899333, 82.48271985, \"85\"],\n[54.9054541333, 82.4776966667, \"20/37B\"],\n[54.90488845, 82.4772389833, \"27/37B\"],\n[54.9047877333, 82.4775819667, \"13/37B\"],\n[54.9049796, 82.4771942833, \"28/37B\"],\n[54.9073132333, 82.4815289167, \"76\"],\n[54.9050827, 82.47699535, \"6/37B\"],\n[54.9061134667, 82.4770216167, \"40A\"],\n[54.90611365, 82.4768269667, \"38B\"],\n[54.9076197, 82.4825873167, \"84\"],\n[54.9070038333, 82.4817050667, \"75\"],\n[54.9047039333, 82.47730165, \"11/37B\"],\n[54.9075484833, 82.4823327833, \"82\"],\n[54.9054264167, 82.4753033833, \"30\"],\n[54.9069885833, 82.47905425, \"58\"],\n[54.906228, 82.477926, \"48\"],\n[54.9058200667, 82.4765282833, \"32\"],\n[54.9046413667, 82.4737464333, \"17\"],\n[54.9050075333, 82.4778885167, \"16/37B\"],\n[54.90499485, 82.4768944167, \"7/37B\"],\n[54.9046556167, 82.4771346, \"10/37B\"],\n[54.90527195, 82.47690975, \"1/37B\"],\n[54.9052758833, 82.4771711833, \"3/37B\"],\n[54.9052169, 82.4771015167, \"4/37B\"],\n[54.90529785, 82.4770102333, \"2/37B\"],\n[54.9058489333, 82.47780495, \"45\"],\n[54.9048925167, 82.4769351667, \"8/37B\"],\n[54.9043826, 82.4728787667, \"15\"],\n[54.9049060333, 82.47352905, \"12\"],\n[54.9056042667, 82.47696875, \"37\"],\n[54.9049538167, 82.47372635, \"14\"],\n[54.9048069667, 82.4730782, \"10\"],\n[54.90405505, 82.4727157833, \"11\"],\n[54.9043442, 82.4726702333, \"13\"],\n[54.9039020833, 82.4723256667, \"5\"],\n[54.9046807667, 82.4726619167, \"6\"],\n[54.9047340667, 82.47286755, \"8\"],\n[54.9050737, 82.4741203667, \"18\"],\n[54.90621865, 82.47643995, \"34\"],\n[54.9055253667, 82.4767246667, \"35\"],\n[54.9062645167, 82.4765613333, \"36\"],\n[54.9059193, 82.4768274667, \"38\"],\n[54.90570735, 82.4773252333, \"39\"],\n[54.9059801833, 82.4770579, \"40\"],\n[54.9062604167, 82.4772333833, \"42B\"],\n[54.9057853667, 82.4775903, \"43\"],\n[54.9061028167, 82.4774772667, \"44\"],\n[54.90589465, 82.47796755, \"47\"],\n[54.9068853333, 82.48130165, \"71\"],\n[54.9071345833, 82.4821319833, \"79\"],\n[54.9074696333, 82.4820778, \"80A\"],\n[54.90765195, 82.4820632833, \"80B\"],\n[54.9071948, 82.4823366167, \"81\"],\n[54.90725725, 82.4825442, \"83\"],\n[54.9042386667, 82.4723893667, \"7\"],\n[54.9049427667, 82.47739025, \"26/37B\"],\n[54.9048325667, 82.4777169, \"14/37B\"],\n[54.9048868, 82.4778717167, \"15/37B\"],\n[54.9052664833, 82.4777734333, \"18/37B\"],\n[54.9053551, 82.4774051333, \"22/37B\"],\n[54.90398685, 82.4726027167, \"9\"],\n[54.9047089333, 82.4770192, \"9/37B\"],\n[54.9061652333, 82.4777069667, \"46\"],\n[54.9067892667, 82.4808744667, \"67\"],\n[54.9068334667, 82.47996825, \"66\"],\n[54.9067120833, 82.4795692, \"60\"],\n[54.9041594, 82.4721355, \"3\"],\n[54.9046192333, 82.4724616667, \"4\"],\n[54.9050749, 82.47524375, \"29\"],\n[54.9068698, 82.4786657833, \"54\"],\n[54.9057202, 82.4762706, \"32B\"],\n[54.9051451333, 82.4743827, \"22\"],\n[54.90625565, 82.4769934167, \"40B\"],\n[54.90604295, 82.4772728667, \"42A\"],\n[54.9047528, 82.4774456167, \"12/37B\"],\n[54.9073914, 82.4817937167, \"78\"],\n[54.9070766667, 82.4819295333, \"77\"],\n[54.8755341, 82.4678237, \"7\"],\n[54.87529185, 82.467879, \"5\"],\n[54.8751691333, 82.4682586333, \"6\"],\n[54.8759656, 82.4679058667, \"13\"],\n[54.87506995, 82.4678763667, \"3\"],\n[54.8749979833, 82.46825515, \"4\"],\n[54.8748353667, 82.4678732833, \"1\"],\n[54.8755232, 82.4682126833, \"10\"],\n[54.87481615, 82.4682566167, \"2\"],\n[54.8759362, 82.4677101333, \"11\"],\n[54.8756999, 82.4681576833, \"12\"],\n[54.87587545, 82.4680599833, \"14\"],\n[54.8753491, 82.4682464333, \"8\"],\n[54.8757606333, 82.46762115, \"9\"],\n[54.8187813333, 82.5099677833, \"62\"],\n[54.81924235, 82.5087604667, \"49\"],\n[54.8177396167, 82.5119011167, \"86\"],\n[54.8178875667, 82.51156545, \"84\"],\n[54.8174387167, 82.51263255, \"90\"],\n[54.83408825, 82.55531685, \"1/1101\"],\n[54.882450333, 82.51885165, \"150\"],\n[54.8077506333, 82.541635, \"400\"],\n[54.8136809, 82.5290861, \"265\"],\n[54.8110874, 82.53251965, \"304\"],\n[54.8095875, 82.5753655167, \"2/729\"],\n[54.83343, 82.5554701333, \"1101\"],\n[54.8173373833, 82.5201625167, \"160\"],\n[54.80918625, 82.5753678333, \"1/729\"],\n[54.8101949167, 82.5340213667, \"320\"],\n[54.8114688333, 82.5313781167, \"299\"],\n[54.8110666833, 82.5317111833, \"301\"],\n[54.8174875833, 82.5162427833, \"126\"],\n[54.8121336833, 82.5303464167, \"289\"],\n[54.8180013167, 82.5178742, \"2/138\"],\n[54.81761695, 82.51742335, \"1/138\"],\n[54.8074874667, 82.5440482, \"430\"],\n[54.80752155, 82.5425832333, \"416\"],\n[54.8366309333, 82.5496806333, \"1173\"],\n[54.8169579833, 82.5214218667, \"179\"],\n[54.8298305, 82.5634204, \"1007\"],\n[54.8149217167, 82.5283630333, \"247\"],\n[54.8217308333, 82.5663090333, \"910\"],\n[54.81460935, 82.5745359167, \"797\"],\n[54.8234203333, 82.5658778, \"924\"],\n[54.8319167167, 82.5559498, \"1086\"],\n[54.8306048167, 82.5616193833, \"1023\"],\n[54.8828865, 82.57007665, \"851\"],\n[54.8329407, 82.55562365, \"1099\"],\n[54.81693675, 82.5123568167, \"95\"],\n[54.8182193, 82.5131360833, \"88\"],\n[54.8130308833, 82.5297032667, \"273\"],\n[54.8095776, 82.55597085, \"544\"],\n[54.8072376833, 82.5452215833, \"443\"],\n[54.81966705, 82.5090003167, \"48\"],\n[54.8169615333, 82.5198118833, \"159\"],\n[54.8169314, 82.51421915, \"112\"],\n[54.8080136167, 82.5463236, \"452\"],\n[54.807907, 82.5458772167, \"448\"],\n[54.80796455, 82.5461119167, \"450\"],\n[54.8168847833, 82.5220721833, \"181\"],\n[54.8354269, 82.5522720333, \"1145\"],\n[54.83545425, 82.5543820167, \"1129\"],\n[54.8082469167, 82.5385727167, \"376\"],\n[54.8076848, 82.5419475167, \"408\"],\n[54.8162252667, 82.5265092167, \"225\"],\n[54.8166361333, 82.52144, \"1/179\"],\n[54.8070565833, 82.5441373667, \"429\"],\n[54.8075943333, 82.5444878167, \"432\"],\n[54.8221778667, 82.5667572, \"911\"],\n[54.8179158667, 82.5105938667, \"73\"],\n[54.807556, 82.5460459333, \"447\"],\n[54.8080632333, 82.5465634, \"454\"],\n[54.8070305833, 82.54991865, \"483\"],\n[54.80831265, 82.5514465667, \"526\"],\n[54.80744605, 82.5634000833, \"603\"],\n[54.8164026833, 82.5278071167, \"234\"],\n[54.80656415, 82.5705962833, \"665\"],\n[54.81898205, 82.5685284167, \"862\"],\n[54.8236973167, 82.56648815, \"927\"],\n[54.8256295833, 82.5653636167, \"965\"],\n[54.8142507167, 82.57521965, \"789\"],\n[54.8094723167, 82.5346592, \"349\"],\n[54.8098434333, 82.5333155167, \"319\"],\n[54.8292230167, 82.5635525167, \"1005\"],\n[54.8173514167, 82.5221399167, \"180\"],\n[54.83840865, 82.5469221167, \"1213\"],\n[54.8379536333, 82.5475567833, \"1201\"],\n[54.81720545, 82.5149902333, \"116\"],\n[54.8085928833, 82.5380488, \"370\"],\n[54.80779995, 82.5386938833, \"379\"],\n[54.8204958333, 82.50876015, \"34\"],\n[54.82623815, 82.56358455, \"970\"],\n[54.81448725, 82.5734910333, \"804\"],\n[54.8222833167, 82.5659173667, \"912\"],\n[54.8170449333, 82.5277756167, \"1/232\"],\n[54.8176035333, 82.5269654167, \"2/232\"],\n[54.8323760333, 82.5575159333, \"1078\"],\n[54.83021075, 82.5612354667, \"1024\"],\n[54.9305489, 82.5017878333, \"90\"],\n[54.93116365, 82.5055481833, \"122\"],\n[54.9319767167, 82.5109385, \"168\"],\n[54.93029815, 82.4998441167, \"72\"],\n[54.9291897167, 82.4957679, \"35\"],\n[54.92986625, 82.4972463167, \"50\"],\n[54.9290868833, 82.4948005167, \"25\"],\n[54.9296040667, 82.4987881667, \"63\"],\n[54.9309512167, 82.5043885167, \"110\"],\n[54.9296868833, 82.4958722667, \"38\"],\n[54.9295072167, 82.4977275833, \"51\"],\n[54.9303624833, 82.5006042333, \"74\"],\n[54.9319759, 82.5106025, \"166\"],\n[54.9306431833, 82.5024661, \"96\"],\n[54.9299079167, 82.4976426667, \"52\"],\n[54.9312659333, 82.5064569833, \"132\"],\n[54.93082875, 82.50372585, \"106\"],\n[54.9320732833, 82.5108069, \"167\"],\n[54.8443465167, 82.36530835, \"32\"],\n[54.8448259333, 82.3650265167, \"36\"],\n[54.8425576167, 82.3664466333, \"8\"],\n[54.8925954833, 82.45710755, \"3\"],\n[54.8930169167, 82.45739025, \"13\"],\n[54.89310595, 82.4574966167, \"17\"],\n[54.8931706667, 82.4571386, \"19\"],\n[54.8930694833, 82.45792925, \"15\"],\n[54.892484, 82.4570883333, \"1\"],\n[54.8926542167, 82.4574440667, \"5\"],\n[54.89269795, 82.4575341667, \"7\"],\n[54.8926711333, 82.4579661, \"9\"],\n[54.8929884833, 82.4571287, \"11\"],\n[54.883121, 82.4810597, \"11\"],\n[54.8827995833, 82.4808762167, \"15\"],\n[54.8827993, 82.4810446833, \"15A\"],\n[54.88305445, 82.4806939167, \"14\"],\n[54.8832812833, 82.4806736333, \"12\"],\n[54.8829723, 82.4809516, \"13\"],\n[54.8836668, 82.4806524333, \"8\"],\n[54.88350115, 82.4806812167, \"10\"],\n[54.8838327667, 82.4806120333, \"6\"],\n[54.8836368, 82.4810848667, \"5\"],\n[54.8840162333, 82.4806070667, \"4\"],\n[54.8841447, 82.4806001167, \"2\"],\n[54.8837898, 82.4810769333, \"3\"],\n[54.8834789167, 82.4810792167, \"7\"],\n[54.8832999833, 82.4810661333, \"9\"],\n[54.8839425333, 82.4810822667, \"1\"],\n[54.8741644333, 82.466663, \"1\"],\n[54.8741701833, 82.4671011667, \"2\"],\n[54.8734758833, 82.4661548667, \"11B\"],\n[54.8730602167, 82.4660412333, \"17B\"],\n[54.8732532833, 82.4669407833, \"12\"],\n[54.8736860667, 82.4670495333, \"8\"],\n[54.8738914, 82.4662481167, \"5B\"],\n[54.8740275667, 82.46708325, \"4\"],\n[54.8728965, 82.4668399167, \"16\"],\n[54.87401705, 82.4666682333, \"3\"],\n[54.8740028333, 82.4662564, \"5A\"],\n[54.8734885167, 82.467, \"10\"],\n[54.8738630833, 82.4670664333, \"6\"],\n[54.8737826, 82.4666489667, \"7\"],\n[54.8735874, 82.46617485, \"11A\"],\n[54.8736024167, 82.4666129, \"9\"],\n[54.8730790167, 82.4668945167, \"14\"],\n[54.8729272167, 82.4664146833, \"19\"],\n[54.8733468333, 82.4665393167, \"13\"],\n[54.8731517, 82.4664815167, \"15\"],\n[54.8731441167, 82.4660683, \"17A\"],\n[54.8825944667, 82.4798169833, \"2\"],\n[54.8826055167, 82.4805495667, \"10\"],\n[54.8825809333, 82.4800131333, \"4\"],\n[54.8825441333, 82.4804278333, \"8\"],\n[54.8828469, 82.4800110667, \"3\"],\n[54.882842, 82.4802305333, \"5\"],\n[54.8825584833, 82.4801972667, \"6\"],\n[54.8828376, 82.4804269167, \"7\"],\n[54.88275275, 82.4805278667, \"9\"],\n[54.8828507833, 82.4798377667, \"1\"],\n[54.8747543667, 82.3655736, \"277\"],\n[54.8779646667, 82.3771985, \"389\"],\n[54.8791017167, 82.3701385167, \"1/326\"],\n[54.8809893667, 82.38422785, \"458\"],\n[54.8801277667, 82.3840239333, \"459\"],\n[54.8814240333, 82.3849688833, \"468\"],\n[54.8806415333, 82.38358955, \"452\"],\n[54.8785101, 82.3802812167, \"409\"],\n[54.8796759167, 82.3830951167, \"445\"],\n[54.8803115167, 82.3830208833, \"446\"],\n[54.8778165333, 82.3759684833, \"373\"],\n[54.88137445, 82.3862355333, \"473\"],\n[54.8782752833, 82.3789725, \"397\"],\n[54.8808287667, 82.3851571, \"469\"],\n[54.87896095, 82.3695827167, \"326\"],\n[54.8765604833, 82.3662541167, \"288\"],\n[54.8818931667, 82.38581595, \"474\"],\n[54.8775986, 82.3747133333, \"2/359\"],\n[54.8769582833, 82.3713375, \"331\"],\n[54.8843103667, 82.3914426833, \"531\"],\n[54.87595675, 82.3649699833, \"271\"],\n[54.8781325, 82.3739238833, \"356\"],\n[54.8763472667, 82.36476045, \"270\"],\n[54.87676475, 82.3676648667, \"298\"],\n[54.8769505833, 82.36918955, \"310\"],\n[54.8766704667, 82.36975, \"313\"],\n[54.8777166, 82.3720850333, \"334\"],\n[54.8773668333, 82.3733521333, \"349\"],\n[54.8772966667, 82.3744940833, \"1/359\"],\n[54.87831085, 82.3791264167, \"399\"],\n[54.8778886833, 82.37662545, \"377\"],\n[54.8784267667, 82.3770323833, \"388\"],\n[54.8790059333, 82.3798270667, \"408\"],\n[54.91994325, 82.4698456167, \"5\"],\n[54.9200047, 82.4693797833, \"6\"],\n[54.9195710333, 82.4694752833, \"2\"],\n[54.9203742667, 82.4697562833, \"7\"],\n[54.9196343, 82.4699295667, \"3\"],\n[54.9198162, 82.4690209, \"4\"],\n[54.8824037833, 82.4600990333, \"5\"],\n[54.88208185, 82.4598317167, \"9\"],\n[54.8826121667, 82.4600836333, \"3\"],\n[54.8826033333, 82.45961605, \"2\"],\n[54.8822431167, 82.4600865, \"7\"],\n[54.8821465833, 82.4595746, \"8\"],\n[54.8823125667, 82.45958745, \"6\"],\n[54.8824702667, 82.4595934167, \"4\"],\n[54.9092579167, 82.46735845, \"6A\"],\n[54.9089322167, 82.4674924, \"10\"],\n[54.90894585, 82.4672735167, \"12\"],\n[54.9089078333, 82.46711725, \"11\"],\n[54.9089631667, 82.4669939667, \"9\"],\n[54.90904455, 82.4673255, \"8\"],\n[54.9094559, 82.4668010167, \"1\"],\n[54.9093255, 82.4673469667, \"4A\"],\n[54.9093457833, 82.46717355, \"4\"],\n[54.9095302167, 82.4670570667, \"2\"],\n[54.9090935, 82.4664936667, \"3\"],\n[54.90917125, 82.4672602333, \"6\"],\n[54.90908325, 82.4669295667, \"7\"],\n[54.9092908333, 82.4668895333, \"5\"],\n[54.8593663833, 82.4539760167, \"251\"],\n[54.8754824, 82.4604578167, \"63\"],\n[54.8750289833, 82.4602931333, \"67\"],\n[54.7985084167, 82.4478579333, \"941\"],\n[54.842417, 82.4531796833, \"443\"],\n[54.8085080333, 82.45099665, \"810\"],\n[54.79048555, 82.44243815, \"1063\"],\n[54.8492731667, 82.4532494833, \"355\"],\n[54.8094198833, 82.4503523667, \"819\"],\n[54.8728692167, 82.4594153667, \"91\"],\n[54.8522977333, 82.4539347833, \"344\"],\n[54.8484041333, 82.45409895, \"372\"],\n[54.8479726833, 82.45304965, \"387\"],\n[54.7948086, 82.4476616833, \"994\"],\n[54.7914089, 82.4452872333, \"1027\"],\n[54.8080105, 82.4498779333, \"835\"],\n[54.8722349333, 82.459282167, \"99\"],\n[54.8091485667, 82.45085495, \"821\"],\n[54.8594542833, 82.4549678833, \"5/246\"],\n[54.8230668667, 82.4541309833, \"660\"],\n[54.8316753333, 82.4539613167, \"562\"],\n[54.8387429833, 82.4531928, \"475\"],\n[54.8545740667, 82.4540875333, \"294\"],\n[54.7900112167, 82.4442665, \"1045\"],\n[54.8172833167, 82.4539773167, \"724\"],\n[54.83503155, 82.453934, \"542\"],\n[54.8607128667, 82.4548002, \"2/241\"],\n[54.8380142833, 82.45391425, \"490\"],\n[54.8275037167, 82.4529093833, \"589\"],\n[54.8596196, 82.4542151, \"249\"],\n[54.8595530167, 82.45479165, \"3/246\"],\n[54.85959605, 82.45471705, \"2/246\"],\n[54.8592503167, 82.4544837333, \"252\"],\n[54.8713457667, 82.4587725833, \"111\"],\n[54.8595053, 82.4548791833, \"4/246\"],\n[54.79668195, 82.4482608333, \"958\"],\n[54.8227231, 82.4540730167, \"670\"],\n[54.8750904833, 82.4593735333, \"71\"],\n[54.8190378833, 82.4540990167, \"702\"],\n[54.86957775, 82.4580359, \"129\"],\n[54.8662393833, 82.4567130667, \"169\"],\n[54.8687158167, 82.4577150333, \"141\"],\n[54.86791495, 82.4573792167, \"151\"],\n[54.8089932167, 82.4507184167, \"823\"],\n[54.8666422833, 82.4569389667, \"167\"],\n[54.8738722833, 82.4598649833, \"81\"],\n[54.8169442833, 82.4534629333, \"727\"],\n[54.8185275, 82.4534621333, \"709\"],\n[54.8059395833, 82.44899615, \"859\"],\n[54.8327434833, 82.4540100333, \"550\"],\n[54.8604312833, 82.4546856333, \"1/241\"],\n[54.8610548833, 82.4549434167, \"3/241\"],\n[54.8596720667, 82.4547582, \"244\"],\n[54.8603010167, 82.4551234333, \"238\"],\n[54.874473, 82.4600767667, \"75\"],\n[54.8192958833, 82.4546863, \"698\"],\n[54.80070935, 82.4483520333, \"917\"],\n[54.8595345, 82.4546793167, \"250\"],\n[54.8395576167, 82.4538942167, \"470\"],\n[54.8600606333, 82.4551961167, \"242\"],\n[54.8587876, 82.45357305, \"261\"],\n[54.8202505167, 82.454168, \"692\"],\n[54.83062305, 82.4541314, \"574\"],\n[54.85965015, 82.4546251667, \"1/246\"],\n[54.87094345, 82.4585491667, \"115\"],\n[54.82367025, 82.4541148167, \"654\"],\n[54.8761585333, 82.4607254667, \"55\"],\n[54.8650849833, 82.4562546333, \"183\"],\n[54.8104551333, 82.45176685, \"803\"],\n[54.8601735167, 82.4545659833, \"247\"],\n[54.8072936667, 82.4501624667, \"842\"],\n[54.81121545, 82.4523795667, \"795\"],\n[54.8082023667, 82.4500136333, \"833\"],\n[54.8088097833, 82.4505667167, \"825\"],\n[54.8073512333, 82.4494723833, \"841\"],\n[54.8180043167, 82.45347675, \"713\"],\n[54.8034810667, 82.44930745, \"884A\"],\n[54.8133904167, 82.4533446667, \"767\"],\n[54.7906012833, 82.4456008, \"1032\"],\n[54.8036063333, 82.44934055, \"884\"],\n[54.8086218, 82.4503990167, \"827\"],\n[54.7990523833, 82.4480464, \"931\"],\n[54.8435690667, 82.40554535, \"296A\"],\n[54.84511005, 82.4057523167, \"282\"],\n[54.8456481333, 82.4283544, \"93\"],\n[54.8452106, 82.4213902167, \"154\"],\n[54.8456685667, 82.4217703833, \"151\"],\n[54.8450910333, 82.4066185167, \"296B\"],\n[54.84556515, 82.3859519, \"471\"],\n[54.8456769, 82.4356176167, \"29\"],\n[54.8452146333, 82.4326596167, \"54\"],\n[54.8456379667, 82.4318747833, \"59\"],\n[54.8451947667, 82.4291500167, \"82\"],\n[54.8456449667, 82.42712405, \"103\"],\n[54.8452215333, 82.4202044833, \"166\"],\n[54.84562355, 82.4192034833, \"173\"],\n[54.84520295, 82.4171995667, \"190\"],\n[54.8451047667, 82.4159582, \"204\"],\n[54.84557985, 82.4160677, \"201\"],\n[54.8451894667, 82.4139933167, \"218\"],\n[54.8455275833, 82.4075856833, \"277\"],\n[54.8455757667, 82.40668145, \"281\"],\n[54.8451309667, 82.4038956667, \"308\"],\n[54.8455923333, 82.40336095, \"313\"],\n[54.8451457333, 82.4006193, \"332\"],\n[54.8456046667, 82.3996052667, \"345\"],\n[54.8450766, 82.3979973833, \"362A\"],\n[54.8450326167, 82.3961487833, \"376\"],\n[54.84556585, 82.3949421167, \"389\"],\n[54.84503405, 82.3928639333, \"406\"],\n[54.8450819, 82.3938952833, \"398\"],\n[54.8449702833, 82.39000315, \"430\"],\n[54.8455388, 82.3929698833, \"403\"],\n[54.8455067667, 82.389923, \"431\"],\n[54.8449729167, 82.38231105, \"498\"],\n[54.8449880833, 82.38162075, \"502\"],\n[54.8432495, 82.3824779667, \"496\"],\n[54.8441658167, 82.4248163667, \"122\"],\n[54.84258355, 82.3809411333, \"512\"],\n[54.8451205833, 82.41321575, \"228\"],\n[54.8454313833, 82.3813477333, \"509\"],\n[54.8449337333, 82.3830211333, \"494\"],\n[54.8456650333, 82.4344218333, \"1/41\"],\n[54.8450306667, 82.3974560667, \"362C\"],\n[54.8463207667, 82.4343822167, \"2/42\"],\n[54.8450416833, 82.3967473667, \"372\"],\n[54.8455358167, 82.4085091, \"267\"],\n[54.8451470333, 82.4076077167, \"276\"],\n[54.84420195, 82.39791495, \"362B\"],\n[54.8452185667, 82.4259005667, \"114\"],\n[54.8456212833, 82.4347298667, \"39\"],\n[54.8452003167, 82.40904765, \"262\"],\n[54.8451996667, 82.4122621833, \"234\"],\n[54.84515415, 82.4098542167, \"256\"],\n[54.8455715833, 82.4139006833, \"223\"],\n[54.8455915333, 82.4136348333, \"225\"],\n[54.8455279667, 82.3870696, \"463\"],\n[54.8457080167, 82.4225169667, \"145\"],\n[54.8450449333, 82.3784177833, \"536\"],\n[54.8441582, 82.3843482, \"480\"],\n[54.8441567667, 82.38280735, \"494A\"],\n[54.8450534333, 82.3804865833, \"516\"],\n[54.845458, 82.3819993833, \"503\"],\n[54.8416720667, 82.4161419167, \"202\"],\n[54.84561615, 82.4169546167, \"193\"],\n[54.8456090833, 82.4248031, \"127\"],\n[54.8452347167, 82.4210866, \"156\"],\n[54.8452366333, 82.4236209667, \"136\"],\n[54.8420864167, 82.3808174, \"514\"],\n[54.9352309167, 82.4932222, \"138\"],\n[54.9344554333, 82.48793725, \"92\"],\n[54.93352515, 82.48479765, \"59\"],\n[54.9333442833, 82.4806992167, \"30\"],\n[54.9333265, 82.4832372833, \"43\"],\n[54.9338463667, 82.4867482, \"81\"],\n[54.9349315333, 82.4913314333, \"109\"],\n[54.9335968833, 82.4853604, \"63\"],\n[54.9316883, 82.48456045, \"53\"],\n[54.9338528333, 82.4839506, \"52\"],\n[54.8310454167, 82.5756857833, \"775\"],\n[54.8312273667, 82.5775630667, \"757\"],\n[54.8293654833, 82.5685721667, \"851\"],\n[54.8285495833, 82.56486995, \"881\"],\n[54.8309590333, 82.5733609, \"801\"],\n[54.8305305333, 82.5736851833, \"790\"],\n[54.8295682333, 82.56931885, \"841\"],\n[54.83130275, 82.5782757167, \"753\"],\n[54.8283176167, 82.5655312333, \"879\"],\n[54.8540068167, 82.37670555, \"34\"],\n[54.85430545, 82.3768498167, \"32\"],\n[54.8549918167, 82.3798488333, \"5\"],\n[54.85449605, 82.37689005, \"33\"],\n[54.8547125333, 82.3802214167, \"4\"],\n[54.8545867833, 82.3781517833, \"28\"],\n[54.8547440667, 82.37743325, \"31\"],\n[54.85420255, 82.3773112333, \"30\"],\n[54.8879053333, 82.5233262333, \"1/18\"],\n[54.8881771333, 82.5232950167, \"2/18\"],\n[54.8834455333, 82.45836535, \"92\"],\n[54.8863947167, 82.4586610667, \"58B\"],\n[54.8866006667, 82.45961975, \"55A\"],\n[54.8867239167, 82.4592584167, \"55\"],\n[54.88667, 82.4586812, \"56\"],\n[54.8817044333, 82.4588333167, \"113\"],\n[54.8815483333, 82.4587898667, \"115\"],\n[54.8814229167, 82.4587740833, \"117\"],\n[54.8913856667, 82.4590918167, \"18\"],\n[54.8915707667, 82.4591145167, \"16\"],\n[54.8868740833, 82.4599066167, \"53C\"],\n[54.88889255, 82.4599269833, \"37B\"],\n[54.89262475, 82.4600617167, \"7A\"],\n[54.8889847167, 82.4594067667, \"37A\"],\n[54.8925890833, 82.4585589, \"10B\"],\n[54.8824604, 82.4588691333, \"105\"],\n[54.8836036333, 82.4583701, \"90\"],\n[54.8908670667, 82.4585197333, \"24A\"],\n[54.8826975167, 82.4583391, \"98\"],\n[54.8835235167, 82.4590010333, \"95\"],\n[54.8838230333, 82.4583829333, \"88\"],\n[54.8845143667, 82.4579167, \"80A\"],\n[54.8828394333, 82.4583557667, \"96\"],\n[54.88251835, 82.4583208667, \"100\"],\n[54.8926768167, 82.4583797667, \"10C\"],\n[54.88716595, 82.4586927333, \"50\"],\n[54.8883195667, 82.4593362333, \"43\"],\n[54.8864967833, 82.4592373833, \"59\"],\n[54.8871386833, 82.4592945833, \"51\"],\n[54.8836205667, 82.4589701333, \"91\"],\n[54.8870057667, 82.4587382167, \"52\"],\n[54.8823566667, 82.4583266833, \"102\"],\n[54.8867508, 82.45831015, \"2/54\"],\n[54.88680585, 82.4583326167, \"54B\"],\n[54.8869064, 82.4592745833, \"53\"],\n[54.8836770667, 82.45788765, \"90A\"],\n[54.88377685, 82.45896945, \"91A\"],\n[54.8844059167, 82.4593669667, \"83A\"],\n[54.8843895833, 82.4590283, \"83\"],\n[54.88413765, 82.4580580833, \"84A\"],\n[54.8909576167, 82.4590556833, \"22\"],\n[54.8932342, 82.4592408833, \"4\"],\n[54.8929272167, 82.45863745, \"8B\"],\n[54.8929735167, 82.4583677333, \"8C\"],\n[54.8859658167, 82.4592039, \"71\"],\n[54.8881317333, 82.4593295333, \"45\"],\n[54.88894835, 82.45890335, \"36\"],\n[54.88873325, 82.4588844167, \"38\"],\n[54.8885017167, 82.45935385, \"41A\"],\n[54.8888022667, 82.4593873, \"39\"],\n[54.88814385, 82.4586047333, \"44A\"],\n[54.8854610167, 82.4585890667, \"66\"],\n[54.89301925, 82.4597807333, \"3\"],\n[54.8888152167, 82.4597877833, \"37C\"],\n[54.88442445, 82.4579215333, \"82A\"],\n[54.8841846833, 82.4584516, \"84\"],\n[54.8858883833, 82.4596244167, \"71A\"],\n[54.8911121167, 82.4596169167, \"21\"],\n[54.8882564333, 82.4588584167, \"42\"],\n[54.8839837, 82.4584101, \"86\"],\n[54.8862705, 82.4595605667, \"63\"],\n[54.8878208, 82.4588156833, \"46\"],\n[54.8891674833, 82.4594178, \"35\"],\n[54.8884817, 82.4588827667, \"40\"],\n[54.8845497667, 82.4584736333, \"80\"],\n[54.8908341667, 82.45958975, \"23\"],\n[54.8926482, 82.4588475667, \"10A\"],\n[54.8846152, 82.4590487333, \"81\"],\n[54.8868875833, 82.4597079333, \"53B\"],\n[54.8867661667, 82.4580206, \"1/54\"],\n[54.8923631167, 82.4601005833, \"11A\"],\n[54.8880116333, 82.4588415167, \"44\"],\n[54.88179955, 82.4582856667, \"108\"],\n[54.8819699667, 82.4588568833, \"109\"],\n[54.8906476667, 82.4590157667, \"28\"],\n[54.8846581333, 82.4584694833, \"78\"],\n[54.8843345167, 82.4584402833, \"82\"],\n[54.8841375167, 82.4590033, \"85\"],\n[54.88394965, 82.4578898667, \"86A\"],\n[54.88396905, 82.45758895, \"86B\"],\n[54.8837848667, 82.4578930833, \"88A\"],\n[54.8839426667, 82.4589834333, \"89\"],\n[54.8923547333, 82.4596697667, \"11\"],\n[54.8916483333, 82.45965705, \"13\"],\n[54.89177585, 82.4591300667, \"14\"],\n[54.8914522167, 82.459646, \"15\"],\n[54.8912940833, 82.4596277667, \"17\"],\n[54.8923723833, 82.4592214, \"12\"],\n[54.8907689667, 82.4590306667, \"24\"],\n[54.8904437833, 82.4595327, \"25A\"],\n[54.8906071167, 82.4595718167, \"25\"],\n[54.8902158167, 82.4595238167, \"27\"],\n[54.8911627, 82.4590753167, \"20\"],\n[54.8886534333, 82.4593824833, \"41\"],\n[54.8930344167, 82.4600257833, \"3A-3F\"],\n[54.8865167167, 82.4586738833, \"58\"],\n[54.8863451667, 82.4592180667, \"61\"],\n[54.88626165, 82.45980935, \"65\"],\n[54.8862540167, 82.4586216, \"60\"],\n[54.8858030167, 82.4586246, \"62\"],\n[54.8856375333, 82.4586118667, \"64\"],\n[54.89284255, 82.4600622333, \"5A\"],\n[54.8928040667, 82.4597492333, \"5\"],\n[54.8861293, 82.4592111833, \"69\"],\n[54.8858680333, 82.4598526167, \"71B\"],\n[54.885777, 82.4599270167, \"71C\"],\n[54.8857422667, 82.4597478167, \"71D\"],\n[54.88574365, 82.45918075, \"73\"],\n[54.8855746833, 82.4591693833, \"75\"],\n[54.8930622167, 82.4592157833, \"6\"],\n[54.8925581, 82.4603171, \"7B\"],\n[54.8926518167, 82.46025555, \"7C\"],\n[54.8929233, 82.4588164167, \"8A\"],\n[54.8928556667, 82.4592156833, \"8\"],\n[54.8924033, 82.4602587333, \"9\"],\n[54.8826857833, 82.4589041167, \"103\"],\n[54.8868134333, 82.4586863667, \"54\"],\n[54.8821768333, 82.4588641833, \"107\"],\n[54.8925898333, 82.4596910333, \"7\"],\n[54.8862095667, 82.46007345, \"67\"],\n[54.8893183667, 82.4594386167, \"33\"],\n[54.88182795, 82.4588519167, \"111\"],\n[54.8853995, 82.4591325167, \"77\"],\n[54.8819874833, 82.4582899, \"106\"],\n[54.8868931667, 82.4594645667, \"53A\"],\n[54.89067275, 82.4587377333, \"28A\"],\n[54.88729905, 82.45870125, \"48\"],\n[54.8872955667, 82.4593124, \"49\"],\n[54.8926355167, 82.4591491667, \"10\"],\n[54.8821580833, 82.45830775, \"104\"],\n[54.8581124833, 82.3783852167, \"535\"],\n[54.8652348667, 82.3746078, \"454\"],\n[54.8528962667, 82.3764204333, \"591C\"],\n[54.8658603333, 82.3777156333, \"466B\"],\n[54.8561505333, 82.3796002833, \"563\"],\n[54.8574877833, 82.3782657333, \"557\"],\n[54.8648613667, 82.3759225833, \"466A\"],\n[54.8680267, 82.3758790667, \"422\"],\n[54.8679018667, 82.3731075, \"420\"],\n[54.85081775, 82.3829343167, \"643\"],\n[54.8671912, 82.36468055, \"352\"],\n[54.86727615, 82.36543555, \"360\"],\n[54.8501304, 82.3806456, \"637\"],\n[54.8673357333, 82.3661331333, \"366A\"],\n[54.8673979333, 82.3667809, \"366B\"],\n[54.8526604333, 82.3775103333, \"591B\"],\n[54.8590671, 82.3777331, \"525\"],\n[54.8604441333, 82.37691195, \"511A\"],\n[54.8674681167, 82.3678874333, \"374\"],\n[54.8677148833, 82.3698444833, \"402\"],\n[54.8666863, 82.3663322333, \"365\"],\n[54.8675554, 82.3754905167, \"424A\"],\n[54.8676465167, 82.37623815, \"424\"],\n[54.86661535, 82.37609495, \"442\"],\n[54.8598401833, 82.3771549167, \"511B\"],\n[54.8661314333, 82.3647742667, \"353\"],\n[54.8666274333, 82.3736697167, \"434\"],\n[54.8662379333, 82.3738677667, \"438\"],\n[54.8520614, 82.3823100833, \"613\"],\n[54.8521965167, 82.3812996167, \"607\"],\n[54.85242245, 82.3821009333, \"605\"],\n[54.8520654833, 82.3761835667, \"591A\"],\n[54.8547938667, 82.3751005167, \"591D\"],\n[54.8600232, 82.3780412167, \"516\"],\n[54.8504624833, 82.3807091333, \"635B\"],\n[54.86694425, 82.3698350167, \"387\"],\n[54.8512808, 82.3826955167, \"635A\"],\n[54.8626598333, 82.3763083833, \"480\"],\n[54.8631832667, 82.3759811, \"478\"],\n[54.8597738, 82.3758612333, \"511\"],\n[54.8669354833, 82.3734885833, \"432\"],\n[54.8660254333, 82.3741769333, \"440\"],\n[54.8677621333, 82.3708737667, \"418\"],\n[54.86470325, 82.3749985333, \"456\"],\n[54.8496086167, 82.3843649167, \"660\"],\n[54.8533389167, 82.3814388333, \"599\"],\n[54.8513108, 82.3833057167, \"636\"],\n[54.8582031333, 82.3789229667, \"536\"],\n[54.8049091167, 82.4582433833, \"111\"],\n[54.79217, 82.4610993667, \"235\"],\n[54.7912009, 82.46131515, \"243\"],\n[54.8073855167, 82.4519374833, \"17\"],\n[54.7901330667, 82.4618390333, \"259\"],\n[54.7979543, 82.46169615, \"186\"],\n[54.7953406667, 82.4605087333, \"199\"],\n[54.8075016167, 82.4517328833, \"15\"],\n[54.7944439333, 82.4604859167, \"221\"],\n[54.8960575333, 82.47501025, \"14\"],\n[54.8979342, 82.4745448, \"31A\"],\n[54.8968049167, 82.47448785, \"24A\"],\n[54.8974204333, 82.475026, \"25\"],\n[54.8977612, 82.47473925, \"29\"],\n[54.89678435, 82.4748293, \"20\"],\n[54.89589205, 82.4749720833, \"12\"],\n[54.8966669, 82.4743795667, \"22\"],\n[54.8958911333, 82.4761947, \"5\"],\n[54.8971542833, 82.4752421167, \"21\"],\n[54.8960713, 82.4760678, \"7\"],\n[54.8971206833, 82.47398845, \"30\"],\n[54.8959413333, 82.4751180667, \"10A\"],\n[54.89774365, 82.4741330667, \"40\"],\n[54.8964759167, 82.4757599833, \"13\"],\n[54.8956967, 82.4756972333, \"6\"],\n[54.8969728167, 82.4746339333, \"24\"],\n[54.8975985667, 82.4742274833, \"38\"],\n[54.8964206167, 82.4764929, \"9\"],\n[54.89591475, 82.4748164, \"14A\"],\n[54.8963322333, 82.4747763333, \"18A\"],\n[54.8962043333, 82.4746025333, \"18B\"],\n[54.8969914833, 82.47434705, \"26A\"],\n[54.8975744667, 82.4748792167, \"27\"],\n[54.8979075667, 82.4740015333, \"42\"],\n[54.89599185, 82.4754597167, \"10\"],\n[54.89628205, 82.4758701, \"11\"],\n[54.8966986167, 82.4755950667, \"15\"],\n[54.8954172667, 82.4758408833, \"2\"],\n[54.8955642833, 82.47581195, \"4\"],\n[54.8957927167, 82.4756119833, \"8\"],\n[54.8974439333, 82.4743467667, \"36\"],\n[54.8954518167, 82.4753103, \"6A\"],\n[54.89718045, 82.4745253167, \"26\"],\n[54.89567315, 82.4763134667, \"1\"],\n[54.8957657667, 82.4763043333, \"3\"],\n[54.8965164667, 82.4750518, \"18\"],\n[54.89807905, 82.47440185, \"31\"],\n[54.8968958, 82.4754382833, \"17\"],\n[54.89631735, 82.4752079667, \"16\"],\n[54.8972125833, 82.4741699833, \"34\"],\n[54.8970015667, 82.47401225, \"28\"],\n[54.9133573833, 82.4717484667, \"287\"],\n[54.9048133167, 82.47635, \"104\"],\n[54.9049925, 82.4762745167, \"106\"],\n[54.90467735, 82.4753654167, \"107\"],\n[54.90048465, 82.4783948167, \"58\"],\n[54.8992426833, 82.4793293167, \"42\"],\n[54.9046434667, 82.4764180667, \"102\"],\n[54.91292555, 82.47197745, \"285\"],\n[54.9061096167, 82.4751589833, \"127\"],\n[54.9059487333, 82.4760527167, \"120B\"],\n[54.9058349, 82.4758649667, \"120A\"],\n[54.9046025333, 82.47507605, \"107A\"],\n[54.9043145167, 82.4765927167, \"98\"],\n[54.9026473833, 82.4773607333, \"80\"],\n[54.8985112833, 82.4791536, \"37\"],\n[54.90029415, 82.4779031333, \"57\"],\n[54.9157889333, 82.4706511667, \"307\"],\n[54.9161504167, 82.4698894, \"317\"],\n[54.9162483333, 82.47040295, \"315\"],\n[54.9119694833, 82.4724158167, \"273\"],\n[54.9127305, 82.4727451167, \"280A\"],\n[54.910892, 82.4729321833, \"257\"],\n[54.91104955, 82.4723925167, \"261\"],\n[54.91155295, 82.4731748833, \"260\"],\n[54.9104050667, 82.4728724167, \"249\"],\n[54.91055955, 82.4730871, \"251\"],\n[54.9074686167, 82.4751091833, \"188\"],\n[54.9079151, 82.4751543167, \"192A\"],\n[54.9060373, 82.4757691167, \"136\"],\n[54.90429105, 82.4760343833, \"97\"],\n[54.9123212333, 82.4728413167, \"276\"],\n[54.91122575, 82.4733142333, \"240\"],\n[54.9028192, 82.4767472833, \"83\"],\n[54.8979333667, 82.4794421167, \"31\"],\n[54.8977516, 82.4801524833, \"28\"],\n[54.89934065, 82.4785610667, \"47\"],\n[54.9103580667, 82.4731422667, \"247\"],\n[54.9106933167, 82.4735704667, \"238\"],\n[54.90118205, 82.4774954833, \"65\"],\n[54.9051274833, 82.4765782667, \"106A\"],\n[54.9001666333, 82.4786251833, \"54\"],\n[54.8996917833, 82.4776611333, \"53A\"],\n[54.9157449833, 82.4701549667, \"311\"],\n[54.8998454833, 82.47809685, \"53\"],\n[54.8999531167, 82.4780619, \"55\"],\n[54.9123259333, 82.4731539833, \"274\"],\n[54.91203635, 82.4729645833, \"262\"],\n[54.9025673667, 82.4766802, \"79A\"],\n[54.8995076667, 82.4784470167, \"49\"],\n[54.9160592167, 82.4710586333, \"316\"],\n[54.9045513333, 82.4752828833, \"105\"],\n[54.901886, 82.4778055167, \"74B\"],\n[54.9007665833, 82.4782302, \"60\"],\n[54.9027685, 82.4767654333, \"81\"],\n[54.9042667667, 82.47545395, \"99\"],\n[54.90210725, 82.4776131, \"76\"],\n[54.914356, 82.4712761333, \"299\"],\n[54.9037502167, 82.4768480333, \"94\"],\n[54.8975508667, 82.48021795, \"22\"],\n[54.9126604333, 82.4720775, \"281\"],\n[54.90140745, 82.4783687833, \"66\"],\n[54.9008916333, 82.4774276833, \"63\"],\n[54.91678785, 82.47071965, \"322\"],\n[54.9088462667, 82.4738790833, \"227\"],\n[54.9123182167, 82.4722337, \"277\"],\n[54.90000635, 82.47873665, \"52\"],\n[54.9015533, 82.47851885, \"70\"],\n[54.9015025333, 82.4779211333, \"72\"],\n[54.9159910833, 82.4705165167, \"313\"],\n[54.9138507667, 82.4715170333, \"293\"],\n[54.9090778667, 82.4737512667, \"229\"],\n[54.9128195833, 82.4726191, \"282\"],\n[54.9131350667, 82.4724749667, \"286\"],\n[54.913967, 82.4720198833, \"294\"],\n[54.9129905, 82.4725340833, \"284\"],\n[54.90123535, 82.4772228667, \"67\"],\n[54.9143479, 82.4719130833, \"298\"],\n[54.9126444833, 82.4726878, \"280\"],\n[54.9165660167, 82.4702721167, \"323\"],\n[54.8989755, 82.4782464167, \"45\"],\n[54.9093448667, 82.47364355, \"233\"],\n[54.91447635, 82.4712330833, \"301\"],\n[54.9095208333, 82.4735786833, \"235\"],\n[54.9096743333, 82.4741524, \"232\"],\n[54.89939865, 82.47921515, \"44\"],\n[54.9151960833, 82.4709698167, \"305\"],\n[54.9097280833, 82.4745849333, \"228\"],\n[54.9013794667, 82.47741285, \"69\"],\n[54.9162268667, 82.47098265, \"318\"],\n[54.8990613333, 82.4787713333, \"43\"],\n[54.89780295, 82.4806196167, \"26\"],\n[54.91541455, 82.4713506833, \"306\"],\n[54.9097875333, 82.4748558667, \"228A\"],\n[54.9081311333, 82.4748058, \"196A\"],\n[54.9150421333, 82.4709822167, \"303\"],\n[54.9053254667, 82.47610225, \"114\"],\n[54.9065445333, 82.4749703667, \"173\"],\n[54.9098205333, 82.4741548833, \"234\"],\n[54.9081538667, 82.4750639167, \"196\"],\n[54.9096973, 82.4748021167, \"226A\"],\n[54.9093885667, 82.4742162667, \"224A\"],\n[54.9091188, 82.4743508333, \"222A\"],\n[54.90953665, 82.4733968, \"235A\"],\n[54.90795735, 82.4748888667, \"194\"],\n[54.9014723, 82.47869265, \"68\"],\n[54.9095686833, 82.4733282167, \"237A\"],\n[54.9090926833, 82.47436235, \"222\"],\n[54.9012697667, 82.4780105833, \"64\"],\n[54.9165941667, 82.4699768667, \"325\"],\n[54.8983101833, 82.4790199333, \"35A\"],\n[54.8989313833, 82.4795513167, \"38\"],\n[54.9020688, 82.4782522167, \"74\"],\n[54.91629055, 82.4698086667, \"321\"],\n[54.90362685, 82.4769062, \"92\"],\n[54.8978983167, 82.480096, \"30\"],\n[54.9095879, 82.4744869833, \"226\"],\n[54.8988477333, 82.4788966333, \"41\"],\n[54.9144792667, 82.47185395, \"300\"],\n[54.90345575, 82.4769852667, \"90\"],\n[54.90295525, 82.4772238333, \"84\"],\n[54.9155634, 82.47150915, \"308A\"],\n[54.9077980667, 82.4749606833, \"192B\"],\n[54.9024718333, 82.47689145, \"79\"],\n[54.9010265333, 82.4781286667, \"62\"],\n[54.9051546167, 82.4761810167, \"108\"],\n[54.9027743667, 82.4772973, \"82\"],\n[54.9113692333, 82.4732625, \"242\"],\n[54.906182, 82.4761095667, \"140\"],\n[54.9126536833, 82.4718492, \"283\"],\n[54.89984655, 82.47884775, \"50\"],\n[54.8996625, 82.4783593833, \"51\"],\n[54.9096838, 82.4734820333, \"237\"],\n[54.9163971333, 82.4703382333, \"319\"],\n[54.9019659333, 82.47801565, \"74C\"],\n[54.9017677, 82.4778972667, \"74A\"],\n[54.9082934833, 82.4747193, \"198\"],\n[54.9124935167, 82.4721662833, \"279\"],\n[54.9112822667, 82.4727057, \"263\"],\n[54.9088314833, 82.4744561333, \"220\"],\n[54.9140193667, 82.4723065, \"294A\"],\n[54.9151048833, 82.4715047667, \"302\"],\n[54.9155721667, 82.4712705333, \"308\"],\n[54.91564375, 82.4698925833, \"309\"],\n[54.9157315333, 82.4712060333, \"310\"],\n[54.9158956833, 82.4711298667, \"312\"],\n[54.9044821667, 82.4765082167, \"100\"],\n[54.9045073333, 82.4759204333, \"101\"],\n[54.9046759167, 82.4758561667, \"103\"],\n[54.8983034667, 82.4792230333, \"35\"],\n[54.8987899833, 82.4796567167, \"36\"],\n[54.89867985, 82.4790447, \"39\"],\n[54.8990768667, 82.47943105, \"40\"],\n[54.8981085333, 82.4793068333, \"33\"],\n[54.89915065, 82.4781128333, \"45A\"],\n[54.8995490167, 82.4791011167, \"46\"],\n[54.8997315333, 82.47899365, \"48\"],\n[54.900319, 82.4785061, \"56\"],\n[54.9056642333, 82.4759370167, \"118\"],\n[54.9063413, 82.4756213333, \"150\"],\n[54.8988354833, 82.47962055, \"36A\"],\n[54.9029526, 82.4760132333, \"87\"],\n[54.90312265, 82.4771544, \"86\"],\n[54.9034438667, 82.4764194333, \"91\"],\n[54.91418395, 82.4719746167, \"296\"],\n[54.9140091667, 82.4714322, \"295\"],\n[54.9141795833, 82.4713487, \"297\"],\n[54.9138469333, 82.4720815833, \"292\"],\n[54.91351575, 82.4716747833, \"289\"],\n[54.9136813667, 82.4716021833, \"291\"],\n[54.9139259667, 82.4722800333, \"292A\"],\n[54.9136332, 82.4722156, \"290\"],\n[54.9093265, 82.4742351667, \"224\"],\n[54.8977406167, 82.4806423167, \"24\"],\n[54.9048411167, 82.4757695667, \"109\"],\n[54.9032051, 82.4765243833, \"89\"],\n[54.91528, 82.4714141667, \"304\"],\n[54.9032850667, 82.4770679, \"88\"],\n[54.9158238167, 82.4703065333, \"313A\"],\n[54.9064744333, 82.4758051, \"150A\"],\n[54.9046115, 82.4767234667, \"100A\"],\n[54.9076618833, 82.4744580667, \"197\"],\n[54.9076246167, 82.4750397167, \"190\"],\n[54.9026504333, 82.4768196167, \"79B\"],\n[54.9051801167, 82.4756040167, \"115\"],\n[54.89852955, 82.47974005, \"34\"],\n[54.9075004, 82.47452445, \"187\"],\n[54.90501535, 82.4756865333, \"111\"],\n[54.9068534667, 82.4753966333, \"180\"],\n[54.9029671, 82.4766338333, \"85\"],\n[54.9065173667, 82.4755659333, \"158\"],\n[54.9066938833, 82.4754834833, \"166\"],\n[54.9061558333, 82.4757093333, \"142\"],\n[54.90567525, 82.4753235167, \"119\"],\n[54.9124889333, 82.4727737833, \"278\"]\n];"
  },
  {
    "path": "config.main.json",
    "content": "{\n    \"host\": null,\n    \"port\": 3000,\n\n    \"defaultSkin\": \"dark\",\n    \"defaultLang\": \"ru\",\n\n    \"trafficLayerMinZoom\": 10,\n    \"trafficLayerUpdateInterval\": 300000,\n    \"ppLink2gis\": \"{gislink}/directions/tab/{rsType}/points/|{point}?m={center}%2F{zoom}&routeLink=true\",\n    \"openLink2gis\": \"{gislink}/?m={center}%2F{zoom}&openLink=true\",\n    \"ppnotLink\": \"http://2gis.{domain}/{projectCode}/center/{center}/zoom/{zoom}/routeTab/rsType/{rsType}/to/{point}╎{name}\",\n    \"photosLink\": \"http://2gis.{domain}/photos/{id}\",\n\n    \"poiLayerMinZoom\": 0,\n\n    \"detectRetina\": false,\n\n    \"webApiKey\": \"ruregt3044\",\n    \"webApiVersion\": \"2.0\",\n    \"catalogVersion\": \"3.0\",\n\n    \"regionListFields\": \"items.bounds,items.zoom_level,items.time_zone,items.code,items.flags,items.country_code,items.domain,items.default_pos\",\n    \"firmInfoFields\": \"items.reviews,items.links,items.external_content\",\n    \"geoAdditionalFields\": \"items.geometry.selection,items.links,items.adm_div,items.address,items.floors,items.description\",\n    \"geoclickerCatalogApiKey\": \"ruregt3044\",\n    \"projectLeaveMaxZoom\": 16,\n    \"flampUrl\": \"http://flamp.ru/r/\",\n    \"flampGoogleAnalytics\": \"utm_source=api2gis&utm_medium=api&utm_campaign=geoclicker\",\n\n    \"protocol\": \"http:\",\n    \"secureProtocol\": \"https:\",\n\n    \"baseUrl\": \"//maps.api.2gis.ru/2.0\",\n    \"key\": \"c5e4d7ec-f9d0-470f-b7f0-278f622f20e2\",\n\n    \"keyServer\": \"https://keys.api.2gis.com/public/v1/keys/\",\n    \"keyServices\": \"/services/tiles-raster-api\",\n\n    \"tileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&ts=online_sd&key={key}\",\n    \"retinaTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&ts=online_hd&key={key}\",\n    \"previewTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&size=64&ts=online_sd&key={key}\",\n    \"previewRetinaTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&size=64&ts=online_hd&key={key}\",\n\n    \"arabicTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&ts=online_sd_ar&key={key}\",\n    \"arabicRetinaTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&ts=online_hd_ar&key={key}\",\n    \"arabicPreviewTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&size=64&ts=online_sd_ar&key={key}\",\n    \"arabicPreviewRetinaTileServer\": \"//tile{s}-sdk.maps.2gis.com/v2/tiles?x={x}&y={y}&z={z}&v=1&size=64&ts=online_hd_ar&key={key}\",\n\n    \"trafficTileServer\": \"//traffic{s}.maps.2gis.com/{projectCode}/traffic/{z}/{x}/{y}/speed/{period}/{timestampString}\",\n    \"retinaTrafficTileServer\": \"//traffic{s}.maps.2gis.com/{projectCode}/traffic/{z}/{x}/{y}/speed/{period}/retina/{timestampString}\",\n    \"trafficMetaServer\": \"//meta{s}.maps.2gis.com/{projectCode}/meta/{z}/{x}/{y}/graph_speed/{period}/{timestampString}\",\n    \"retinaTrafficMetaServer\": \"//meta{s}.maps.2gis.com/{projectCode}/meta/{z}/{x}/{y}/graph_speed/{period}/retina/{timestampString}\",\n    \"trafficTimestampServer\": \"//traffic{s}.maps.2gis.com/{projectCode}/meta/speed/time/\",\n    \"trafficScoreServer\": \"//traffic{s}.maps.2gis.com/{projectCode}/meta/score/0/\",\n\n    \"poiMetaServer\": \"//tile{s}.maps.2gis.com/poi?x={x}&y={y}&z={z}&v=1&ts=online_sd\",\n    \"retinaPoiMetaServer\": \"//tile{s}.maps.2gis.com/poi?x={x}&y={y}&z={z}&v=1&ts=online_hd\",\n\n    \"arabicPoiMetaServer\": \"//tile{s}.maps.2gis.com/poi?x={x}&y={y}&z={z}&v=1&ts=online_sd_ar\",\n    \"arabicRetinaPoiMetaServer\": \"//tile{s}.maps.2gis.com/poi?x={x}&y={y}&z={z}&v=1&ts=online_hd_ar\",\n\n    \"webApiServer\": \"//catalog.api.2gis.ru\",\n\n    \"loadProjectListTimeout\": 5000\n}\n"
  },
  {
    "path": "functional-tests/.gitignore",
    "content": "## Project ###\nnosetests.xml\nnosetests-*.xml\nrun_my.sh\n.noseids\n\n### Python ###\n*.py[cod]\n\n### Virtualenv ###\n.env/\n\n### Tox ###\n.tox/\n\n### IDE ###\n.idea/"
  },
  {
    "path": "functional-tests/README.md",
    "content": "### Подготовка и запуск\n\n1. Устанавливаем python\n2. Устанавливаем virtualenv\n   \n```\n$ pip install -U virtualenv\n```\n    \n3. Готовим локальный environment\n    \n```\n$ ./prepare.sh\n```\n\nЕсли используется PyCharm удобно добавить локальный env.\nFile -> Settings -> Project -> Шестеренка -> Добавить локальный env -> выбрать ./.env/bin/python2.7\n\n4. Устанавливаем [selenium-launchers](https://github.com/bayandin/selenium-launchers):\n\n```bash\n# скачать zip-архив и распаковать куда-нибудь на свою машину\ncd selenium-launchers/\n./start_linux.sh (./start_mac.sh | ./start_win.sh) # запустит selenuim-сервер на порту 4455\n```\n\n5. Тесты используют шаблоны страниц. Для их генерации нужно выполнить:\n\n```\n$ ./template_render.sh\n```\n\n6. Если не поднят, поднять сервер MapsAPI\n\n7. Запустить тесты\n\n```\n$ ./run.sh\n```\n\nЧтобы запускать только конкретные тесты, необходимо скопировать файл run.sh в run_my.sh и добавить файл,\nкласс и метод теста, например:\n\n```bash\n#!/usr/bin/env bash\nsource .env/bin/activate\nPYTHONPATH=$(pwd) .env/bin/lode_runner -v tests/firm_callout_test.py:FirmCallout.firm_photo_test --with-xunit\nexit 0;\n```\n\n### Содержимое проекта\n\n* В пакете classes хранятся компоненты (сomponents), исключения (exceptions), утилиты (util)\n* В пакете config хранится конфиг для contesto\n* В пакете tests хранятся тесты и пакеты тестов\n\n\n#### Исключения\nБывает необходимо поднять и обработать исключение.\nВсе типы исключений для карты, взаимодействия с WebApi и т.д. описываются в classes.exceptioins.exceptions.\nНаследуются от базового типа исключений contesto, а затем от базового типа исключения API карт.\n\n\n#### Утилиты\nВ данном пакете описываются утилиты и базовые классы тестов для API карт.\nНа данный момент там содержится базовый класс для тестов MapsAPIBaseTest унаследованный от\nUnittestContestoTestCase, с переопределенным методом setUp.\n\n\n#### Компоненты\nВ данном пакете описываются компоненты страницы, страница и базовой компонент.\nБазовый компонент наследуется от класса BaseComponent contesto. В нем определяются черты (свойства и методы)\nсвойственные всем компонентам проекта.\n\n### Code style\n* Так как используется паттерн pageObject, в тестах не должно быть обращения к драйверу, за исключением пользовательских элементов (кнопки, ползунки и все что не входит в API карт)\n* Для проверки кода перед коммитом рекомендуется создать или добавить в pre-commit git hook содержимое pep8-hook.sh. Для работы хука должен иметься pep8. \n* Имена файлов с тестами `<название>_test.py`\n* Имена классов оформляются в `CapitalizedWords`\n* Имена тестовых методов `<объект тестирования>_<что тестируется>_test(self, *args, **kwargs)`\n* Допускается использование нескольких assert`ов в тесте если они связаны с тестируемым функционалом\n* Использовать только assert`ы contesto\n"
  },
  {
    "path": "functional-tests/classes/WAPI/__init__.py",
    "content": ""
  },
  {
    "path": "functional-tests/classes/WAPI/dataWorker.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.WAPI.request import *\nimport itertools\n# TODO: Сделать хэлпер для выпиливания html entities из ответа API\n\n\nclass GeoData(object):\n    def __init__(self, cords, zoom):\n        request = GeoSearch()\n        self.response = request.get(cords, zoom)\n\n    def get_value_by_key(self, key_name, key_value, key_return):\n        \"\"\"\n        :param key_name: Key name, that want use (example: 'subtype')\n        :param key_value: Value that element with key_name should be equal (example: 'city')\n        :param key_return: Key name that should be returned (example: 'name')\n        :return: string or list (depends on field)\n        \"\"\"\n        for elem in self.response['items']:\n            if elem.get(key_name) == key_value:\n                return elem.get(key_return)\n\n    @property\n    def city_name(self):\n        return self.get_value_by_key('subtype', 'city', 'name')\n\n    @property\n    def district_name(self):\n        return self.get_value_by_key('subtype', 'district', 'name')\n\n    @property\n    def place_address(self):\n        adm_divs = self.get_value_by_key('subtype', 'district', 'adm_div')\n        adm_divs.reverse()\n        dist_addr = adm_divs.pop(0)['name']\n        for div in adm_divs:\n            dist_addr = \"%s, %s\" % (dist_addr, div['name'])\n        return dist_addr.replace(u'\\xa0', ' ')\n\n    @property\n    def build_name(self):\n        address_name = self.get_value_by_key('subtype', None, 'address_name')\n        building_name = self.get_value_by_key('subtype', None, 'building_name')\n        if building_name is None:\n            return address_name\n        else:\n            return building_name\n\n    @property\n    def street_name(self):\n        return self.get_value_by_key('type', 'street', 'name').replace(u'\\xa0', ' ')\n\n    @property\n    def street_address(self):\n        return self.get_value_by_key('type', 'street', 'adm_div')[0]['name'].replace(u'\\xa0', ' ')\n\n    @property\n    def attraction_name(self):\n        subtype_name = self.get_value_by_key('type', 'attraction', 'subtype_name')\n        name = self.get_value_by_key('type', 'attraction', 'name')\n        if not name:\n            return subtype_name\n        else:\n            return name\n\n    @property\n    def attraction_description(self):\n        return self.get_value_by_key('type', 'attraction', 'description')\n\n\nclass FirmData(object):\n    def __init__(self, firm_id):\n        request = FirmInfo()\n        self.response = request.get(firm_id)\n\n    @property\n    def firm_name(self):\n        return self.response['items'][0]['name']\n\n    @property\n    def review_count(self):\n        return self.response['items'][0]['reviews']['review_count']\n\n    @property\n    def rating(self):\n        return self.response['items'][0]['reviews']['rating']\n\n    @property\n    def address_name(self):\n        return self.response['items'][0]['address_name'].replace(u'\\xa0', ' ')\n\n    @property\n    def address_comment(self):\n        return self.response['items'][0]['address_comment'].replace(u'\\xa0', ' ')\n\n    def _contacts_by_type(self, contact_type):\n        contacts = list()\n        contact_groups = self.response['items'][0]['contact_groups']\n        for group in contact_groups:\n            for item in group['contacts']:\n                if item['type'] == contact_type:\n                    contacts.append(item)\n        return contacts\n\n    def get_phones(self):\n        return self._contacts_by_type('phone')\n\n    def get_websites(self):\n        return self._contacts_by_type('website')\n\n    def get_emails(self):\n        return self._contacts_by_type('email')\n\n    def get_rubrics_primary(self):\n        primary = list()\n        rubrics = self.response['items'][0]['rubrics']\n        for rubric in rubrics:\n            if rubric['kind'] == 'primary':\n                primary.append(rubric)\n        return primary\n\n    def get_rubrics_additional(self):\n        additional = list()\n        rubrics = self.response['items'][0]['rubrics']\n        for rubric in rubrics:\n            if rubric['kind'] == 'additional':\n                additional.append(rubric)\n        return additional\n\n    def photo_count(self):\n        try:\n            externals = self.response['items'][0]['external_content']\n            for item in externals:\n                if item['subtype'] == 'common':\n                    return item['count']\n        except KeyError:\n            return 0\n\n\nclass GalleryData(object):\n    def __init__(self, gallery_id):\n        request = GalleryInfo()\n        self.response = request.get(gallery_id)\n\n    @property\n    def gallery_name(self):\n        return self.response['items'][0]['name']\n"
  },
  {
    "path": "functional-tests/classes/WAPI/request.py",
    "content": "# -*- coding: utf-8 -*-\nimport urllib2\nimport urllib\nimport json\nfrom config import config\nfrom classes.exceptions.exceptions import WebAPIException\n\n\nclass BaseReq(object):\n\n    def __init__(self):\n        self.api_url = '%s/%s' % (config.wapi['url'], config.wapi['version'])\n        self.base_params = {\n            'key': config.wapi['key']\n        }\n\n    def request(self, url, params):\n        \"\"\"\n        :type url: str or unicode\n        :type params: dict\n        :rtype: dict\n        \"\"\"\n        data = urllib.urlencode(params)\n        req = urllib2.Request('%s?%s' % (url, data))  # GET-method\n        response = urllib2.urlopen(req).read()\n        try:\n            result = json.loads(response)\n        except ValueError:\n            raise WebAPIException('Response not in json')\n        else:\n            if not result['meta']['code'] == 200 and not result['meta']['code'] == 404:\n                raise WebAPIException('Response code is %s, API response:\\n%s' % (result['meta']['code'], result))\n            return result['result']\n\n\nclass GeoSearch(BaseReq):\n    def __init__(self):\n        super(GeoSearch, self).__init__()\n\n    def get(self, coord, zoom):\n        \"\"\"\n        :param coord: diсt of lat and lng\n        :param zoom:  int or str\n        :return: dict\n        \"\"\"\n        method = '/geo/search'\n        params = {\n            'key': self.base_params['key'],\n            'point': '%s,%s' % (coord['lng'], coord['lat']),\n            'zoom_level': str(zoom),\n            'fields': 'items.geometry.selection,items.links,items.adm_div,items.address,items.floors,items.description',\n            'type': 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,'\n                    'street,building,adm_div.place,poi,attraction'\n        }\n        url = self.api_url + method\n        return self.request(url, params)\n\n\nclass FirmList(BaseReq):\n    def __init__(self):\n        super(FirmList, self).__init__()\n\n    def get(self, build_id, page=1):\n        \"\"\"\n        :param build_id: int or str\n        :param page:  int or str\n        :return: dict\n        \"\"\"\n        method = '/catalog/branch/list'\n        params = {\n            'key': self.base_params['key'],\n            'building_id': str(build_id),\n            'page': str(page)\n        }\n        url = \"%s%s\" % (self.api_url, method)\n        return self.request(url, params)\n\n\nclass FirmInfo(BaseReq):\n    def __init__(self):\n        super(FirmInfo, self).__init__()\n\n    def get(self, firm_id):\n        \"\"\"\n        :param firm_id: int or str\n        :return: dict\n        \"\"\"\n        method = '/catalog/branch/get'\n        params = {\n            'key': self.base_params['key'],\n            'id': str(firm_id),\n            'type': 'filial',\n            'fields': 'items.reviews,items.links,items.external_content'\n        }\n        url = \"%s%s\" % (self.api_url, method)\n        return self.request(url, params)\n\n\nclass GalleryInfo(BaseReq):\n    def __init__(self):\n        super(GalleryInfo, self).__init__()\n\n    def get(self, id):\n        \"\"\"\n        :param id: int or str\n        :return: dict\n        \"\"\"\n        method = '/geo/get'\n        params = {\n            'key': self.base_params['key'],\n            'id': str(id),\n            'type': 'filial',\n            'fields': 'items.geometry.selection,items.links,items.adm_div,items.address,items.floors,items.description'\n        }\n        url = \"%s%s\" % (self.api_url, method)\n        return self.request(url, params)\n"
  },
  {
    "path": "functional-tests/classes/__init__.py",
    "content": ""
  },
  {
    "path": "functional-tests/classes/components/__init__.py",
    "content": ""
  },
  {
    "path": "functional-tests/classes/components/balloon.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.components.component import Component\nfrom config import config\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.support.ui import WebDriverWait\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom time import time\nfrom contesto.exceptions import ElementNotFound\nfrom time import sleep\nfrom classes.util.decorators import catches_not_found\n\n\nclass Balloon(Component):\n    selectors = {\n        'self': '.leaflet-popup',\n        'content': '.dg-popup__container',\n        'scroll': '.dg-scroller__bar'\n    }\n\n    def wait_present(self):\n        WebDriverWait(self.driver, config.timeout['normal']).until(\n            EC.visibility_of(self.driver.find_element(By.CSS_SELECTOR, self.selectors['self']))\n        )\n\n    def wait_close(self, timeout=0.5, polling=0.1):\n        start = time()\n        end = start + timeout\n        present = True\n        step = start + polling\n        while time() < end and present:\n            if time() > step:\n                step += polling\n                try:\n                    self.driver.find_element_by_css_selector(['self'])\n                except ElementNotFound:\n                    present = False\n            else:\n                sleep(polling)\n\n    def count(self):\n        return len(self.driver.find_elements_by_css_selector(self.selectors['self']))\n\n    def get_content(self):\n        return self.driver.find_element_by_css_selector(self.selectors['content'])\n\n    @property\n    def width(self):\n        return self.driver.find_element_by_css_selector(self.selectors['self']).value_of_css_property('width')\n\n    @property\n    def height(self):\n        return self.driver.find_element_by_css_selector(self.selectors['self']).value_of_css_property('height')\n\n    @property\n    @catches_not_found()\n    def scroll(self):\n        return self.driver.find_element_by_css_selector(self.selectors['scroll'])\n\n\nclass BalloonCrossed(Balloon):\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button'\n    }\n\n    def close(self):\n        self.element.find_element_by_css_selector(self.selectors['X']).click()\n"
  },
  {
    "path": "functional-tests/classes/components/callout.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.util.unescape import unescape_text\nfrom classes.util.decorators import catches_not_found\nfrom classes.components.balloon import BalloonCrossed\n\n\nclass Callout(BalloonCrossed):\n    pass\n\n\nclass UnknownPlace(Callout):\n    \"\"\"\n    Unknown place callout\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button'\n    }\n\n    @property\n    def header(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['header']).text.strip()\n\n\nclass Place(Callout):\n    \"\"\"\n    Base place callout (example: city callout)\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'purpose': '.dg-map-geoclicker__purpose'\n    }\n\n    @property\n    def header(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['header']).text.strip()\n\n    @property\n    def purpose(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['purpose']).text.strip()\n\n\nclass AddressPlace(Place):\n    \"\"\"\n    Addressed place callout (example: district)\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'purpose': '.dg-map-geoclicker__purpose',\n        'drilldown': '.dg-map-geoclicker__drilldown'\n    }\n\n    @property\n    def drilldown(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return unescape_text(self.element.find_element_by_css_selector(self.selectors['drilldown']).text.strip())\n\n\nclass Attraction(Callout):\n    \"\"\"\n    Attraction callout without text (example: sandboxes, toilets, attractions)\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'purpose': '.dg-map-geoclicker__purpose'\n    }\n\n    @property\n    def header(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['header']).text.strip()\n\n    @property\n    def purpose(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['purpose']).text.strip()\n\n\nclass AttractionWrapped(Attraction):\n    \"\"\"\n    Attraction callout with text (example: monuments etc.)\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'purpose': '.dg-map-geoclicker__purpose',\n        'wrapper': '.dg-map-geoclicker__show-more-sights-link',\n        'text': '.dg-map-geoclicker__sight-description'\n    }\n\n    @property\n    def text(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['text']).text.strip()\n\n    @catches_not_found(False)\n    def wrapper(self):\n        return self.element.find_element_by_css_selector(self.selectors['wrapper'])\n\n    def unwrap(self):\n        self.element.find_element_by_css_selector(self.selectors['wrapper']).click()\n\n\nclass Build(Callout):\n    \"\"\"\n    Base build callout\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'firm': '.dg-popup__link',\n        'firm_list': '.dg-popup__button_name_all'\n    }\n    # TODO добавить конструктор route-ссылок\n\n    @property\n    def header(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['header']).text.strip()\n\n    def open_firm_by_index(self, index):\n        self.driver.find_elements_by_css_selector(self.selectors['firm'])[index].click()\n\n    @catches_not_found()\n    def open_firm_list(self):\n        self.driver.find_element_by_css_selector(self.selectors['firm_list']).click()\n\n    @catches_not_found()\n    def open_firm_by_id(self, firm_id):\n        self.driver.find_element_by_id(str(firm_id)).click()\n\n\nclass FirmList(Callout):\n    \"\"\"\n    Firm list callout\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'list': '.dg-building-callout__list'\n    }\n\n    def list_present(self):\n        return self.driver.find_element_by_css_selector(self.selectors['list']).is_displayed()\n\n\nclass Firm(Callout):\n    \"\"\"\n    Firm and common poi callout\n    \"\"\"\n    selectors = {\n        'self': '.leaflet-popup',\n        'header': '.dg-popup__header-title',\n        'X': '.leaflet-popup-close-button',\n        'photo': '.dg-popup__link_type_photos',\n        'reviews': '.dg-popup__link_type_flamp_reviews',\n        'stars': '.dg-popup__rating-stars',\n        'back': '.dg-popup__button_name_firm-card-back',\n        'route': '.dg-popup__button_name_goto',\n        'address': '.dg-firm-card__address',\n        'phones': '.dg-firm-card__phone-num',\n        'websites': '.dg-firm-card__site',\n        'email': '.dg-firm-card__email > a',\n        'primary': '.dg-firm-card__rubrics-list_type_primary > .dg-firm-card__rubrics-list-item',\n        'additional': '.dg-firm-card__rubrics-list_type_additional > .dg-firm-card__rubrics-list-item'\n    }\n\n    @property\n    def callout(self):\n        return self.driver.find_element_by_css_selector(self.selectors['self'])\n\n    @property\n    def header(self):\n        \"\"\"\n        :return: str\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['header']).text.strip()\n\n    @property\n    @catches_not_found()\n    def photo(self):\n        \"\"\"\n        :return: web_element\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['photo'])\n\n    @property\n    @catches_not_found()\n    def reviews(self):\n        \"\"\"\n        :return: web_element\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['reviews'])\n\n    @property\n    @catches_not_found()\n    def stars(self):\n        \"\"\"\n        :return: web_element\n        \"\"\"\n        return self.element.find_element_by_css_selector(self.selectors['stars'])\n\n    @catches_not_found()\n    def back(self):\n        return self.element.find_element_by_css_selector(self.selectors['back']).click()\n\n    @property\n    def route_link(self):\n        return self.element.find_element_by_css_selector(self.selectors['route'])\n\n    @property\n    def address(self):\n        return self.driver.find_element_by_css_selector(self.selectors['address'])\n\n    def phones(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['phones'])\n\n    def websites(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['websites'])\n\n    @property\n    def email(self):\n        return self.driver.find_element_by_css_selector(self.selectors['email'])\n\n    @property\n    def primary_rubrics(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['primary'])\n\n    @property\n    def additional_rubrics(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['additional'])\n"
  },
  {
    "path": "functional-tests/classes/components/component.py",
    "content": "from contesto.basis.component import BaseComponent\nfrom selenium.webdriver.common.action_chains import ActionChains\n\n\nclass Component(BaseComponent):\n    def __init__(self, test, element):\n        \"\"\"\n        :type test: InfoPortalDriver\n        :type element: InfoPortalWebElement\n        \"\"\"\n        super(Component, self).__init__(test, element)\n        self.test = self.driver\n\n    def hover(self):\n        ActionChains(self.driver).move_to_element(self.element).perform()\n\n    @property\n    def is_visible(self):\n        return self.element.is_displayed()\n"
  },
  {
    "path": "functional-tests/classes/components/map.py",
    "content": "# -*- coding: utf-8 -*-\nfrom selenium.webdriver import ActionChains\nfrom selenium.webdriver.common.keys import Keys\nfrom component import Component\nfrom classes.util.scripts import GetScripts\nfrom classes.util.scripts import SetScripts\nfrom time import time\nimport math\nfrom time import sleep\n\n\nclass Map(Component):\n    selectors = {\n        'self': '#map',\n        'info': '#info'\n    }\n\n    def zoom_selection(self):\n        center = self.driver.execute_script(GetScripts.getContainerCenter)\n        actions = ActionChains(self.driver)\n        actions.move_to_element_with_offset(self.element, int(center['x']), int(center['y']))\n        actions.key_down(Keys.SHIFT)\n        actions.click_and_hold()\n        actions.move_by_offset(300, 300)\n        actions.release()\n        actions.perform()\n\n    def center_click(self):\n        center = self.driver.execute_script(GetScripts.getContainerCenter)\n        actions = ActionChains(self.driver)\n        actions.move_to_element_with_offset(self.element, int(center['x']), int(center['y']))\n        actions.click().perform()\n\n    def center_dbclick(self):\n        center = self.driver.execute_script(GetScripts.getContainerCenter)\n        actions = ActionChains(self.driver)\n        actions.move_to_element_with_offset(self.element, int(center['x']), int(center['y']))\n        actions.double_click().perform()\n\n    def set_zoom(self, level):\n        self.driver.execute_script(SetScripts.set_zoom(level))\n\n    def wait_init(self, timeout=3, polling=0.5):\n        \"\"\"\n        :param timeout: timeout to rise exception\n        :param polling: how often check map init\n        :return: None\n        \"\"\"\n        request_num = math.ceil(timeout / polling)\n        tries = 0\n        tries_out = False\n        map_inited = False\n        start = time()\n        while not tries_out and not map_inited:\n            if time() > (start + tries * polling):\n                map_inited = self.driver.execute_script('return !!map.getZoom')\n                tries_out = tries >= request_num\n                tries += 1\n\n    def drag(self, x_offset, y_offset):\n        center = self.driver.execute_script(GetScripts.getContainerCenter)\n        actions = ActionChains(self.driver)\n        actions.move_to_element_with_offset(self.element, int(center['x']), int(center['y']))\n        actions.click_and_hold()\n        actions.move_by_offset(x_offset, y_offset)\n        actions.release().perform()\n\n    def info_elem(self):\n        return self.driver.find_element_by_css_selector(self.selectors['info'])\n"
  },
  {
    "path": "functional-tests/classes/components/mapsapi_sources.py",
    "content": "from component import Component\nfrom classes.util.decorators import catches_not_found\n\n\nclass Source(Component):\n    selectors = {\n        'loader': '[src*=\"loader\"]',\n        'app_js': 'script[src*=\"/js/?\"]'\n    }\n\n    @property\n    @catches_not_found(False)\n    def loader_present(self):\n        return bool(self.driver.find_element_by_css_selector(self.selectors['loader']))\n\n    @property\n    @catches_not_found(False)\n    def app_js_present(self):\n        return bool(self.driver.find_element_by_css_selector(self.selectors['app_js']))\n"
  },
  {
    "path": "functional-tests/classes/components/marker.py",
    "content": "from classes.components.component import Component\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.support.ui import WebDriverWait\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom selenium.webdriver.common.action_chains import ActionChains\nfrom config import config\n\n\nclass Marker(Component):\n    selectors = {\n        'self': 'div.leaflet-pane.leaflet-marker-pane > div.dg-customization__marker',\n        'label': 'div.dg-label > div.dg-label__content'\n    }\n\n    def click(self, index=0):\n        self.driver.find_elements_by_css_selector(self.selectors['self'])[index].click()\n\n    def wait_present(self):\n        WebDriverWait(self.driver, config.timeout['normal']).until(\n            EC.visibility_of(self.driver.find_element(By.CSS_SELECTOR, self.selectors['self']))\n        )\n\n    def drag_marker(self, x_offset, y_offset, index=0):\n        actions = ActionChains(self.driver)\n        marker = self.driver.find_elements_by_css_selector(self.selectors['self'])[index]\n        actions.drag_and_drop_by_offset(marker, x_offset, y_offset).perform()\n\n    def get_lat(self, name='marker'):\n        return self.driver.execute_script('return %s._latlng.lat.toFixed(3)' % name)\n\n    def get_lng(self, name='marker'):\n        return self.driver.execute_script('return %s._latlng.lng.toFixed(3)' % name)\n\n    def get_labels(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['label'])\n\n    def get_markers(self):\n        return self.driver.find_elements_by_css_selector(self.selectors['self'])\n\n    def hover_marker(self, index=0):\n        actions = ActionChains(self.driver)\n        actions.move_to_element(self.get_markers()[index]).perform()\n\n    def count(self):\n        return len(self.driver.find_elements_by_css_selector(self.selectors['self']))\n"
  },
  {
    "path": "functional-tests/classes/components/page.py",
    "content": "from contesto.basis.page import BasePage\nfrom time import sleep\n\n\nclass Page(BasePage):\n    def __init__(self, test):\n        \"\"\"\n        :type test: Mapsapi driver\n        \"\"\"\n        self.test = test\n        super(Page, self).__init__(test)\n\n    def refresh(self):\n        super(Page, self).refresh()\n        self.__init__(self.test)\n\n    def forward(self):\n        super(Page, self).forward()\n        self.__init__(self.test)\n\n    def back(self):\n        super(Page, self).back()\n        self.__init__(self.test)\n\n    @property\n    def new_window_url(self):\n        win_count = len(self.test.window_handles)\n        self.test.switch_to_window(self.test.window_handles[win_count - 1])\n        return self.test.current_url\n\n    def click(self):\n        \"\"\"\n        Left-clicks the current cursor position\n        \"\"\"\n        from selenium.webdriver.common.action_chains import ActionChains\n        act = ActionChains(self.test)\n        act.click().perform()\n\n    @property\n    def map(self):\n        \"\"\"\n        :return: MapContainer\n        \"\"\"\n        from classes.components.map import Map\n        return Map(self.test, self.test.find_element_by_css_selector(Map.selectors['self']))\n\n    @property\n    def zoom_control_in(self):\n        \"\"\"\n        :rtype: ZoomControlIn\n        \"\"\"\n        from classes.components.zoom_control import ZoomControlIn\n        return ZoomControlIn(self.test, self.test.find_element_by_css_selector(ZoomControlIn.selectors['self']))\n\n    @property\n    def zoom_control_out(self):\n        \"\"\"\n        :rtype: ZoomControlOut\n        \"\"\"\n        from classes.components.zoom_control import ZoomControlOut\n        return ZoomControlOut(self.test, self.test.find_element_by_css_selector(ZoomControlOut.selectors['self']))\n\n    @property\n    def balloon(self):\n        \"\"\"\n        :return: Callout\n        \"\"\"\n        from classes.components.balloon import Balloon\n        return Balloon(self.test, self.test.find_element_by_css_selector(Balloon.selectors['self']))\n\n    @property\n    def balloon_crossed(self):\n        \"\"\"\n        :return: CalloutCrossed\n        \"\"\"\n        from classes.components.callout import BalloonCrossed\n        return BalloonCrossed(self.test, self.test.find_element_by_css_selector(BalloonCrossed.selectors['self']))\n\n    @property\n    def unkown_place(self):\n        \"\"\"\n        :return: UnknownPlace\n        \"\"\"\n        from classes.components.callout import UnknownPlace\n        return UnknownPlace(self.test, self.test.find_element_by_css_selector(UnknownPlace.selectors['self']))\n\n    @property\n    def place_callout(self):\n        \"\"\"\n        :return: PlaceCallout\n        \"\"\"\n        from classes.components.callout import Place\n        return Place(self.test, self.test.find_element_by_css_selector(Place.selectors['self']))\n\n    @property\n    def addresed_place_callout(self):\n        \"\"\"\n        :return: AddressPlaceCallout\n        \"\"\"\n        from classes.components.callout import AddressPlace\n        return AddressPlace(self.test, self.test.find_element_by_css_selector(AddressPlace.selectors['self']))\n\n    @property\n    def build_callout(self):\n        \"\"\"\n        :return: BuildCallout\n        \"\"\"\n        from classes.components.callout import Build\n        return Build(self.test, self.test.find_element_by_css_selector(Build.selectors['self']))\n\n    @property\n    def attraction_callout(self):\n        \"\"\"\n        :return: AttractionCallout\n        \"\"\"\n        from classes.components.callout import Attraction\n        return Attraction(self.test, self.test.find_element_by_css_selector(Attraction.selectors['self']))\n\n    @property\n    def attraction_callout_wrapped(self):\n        \"\"\"\n        :return: AttractionCallout\n        \"\"\"\n        from classes.components.callout import AttractionWrapped\n        return AttractionWrapped(self.test, self.test.find_element_by_css_selector(AttractionWrapped.selectors['self']))\n\n    @property\n    def firm_callout(self):\n        \"\"\"\n        :return: FirmCallout\n        \"\"\"\n        from classes.components.callout import Firm\n        return Firm(self.test, self.test.find_element_by_css_selector(Firm.selectors['self']))\n\n    @property\n    def marker(self):\n        \"\"\"\n        :return: Marker\n        \"\"\"\n        from classes.components.marker import Marker\n        return Marker(self.test, self.test.find_element_by_css_selector(Marker.selectors['self']))\n\n    def console(self, script, timeout=0):\n        result = self.test.execute_script(script)\n        sleep(timeout)\n        return result\n\n    @property\n    def firm_list(self):\n        \"\"\"\n        :return: FirmList callout\n        \"\"\"\n        from classes.components.callout import FirmList\n        return FirmList(self.test, self.test.find_element_by_css_selector(FirmList.selectors['self']))\n\n    @property\n    def sources(self):\n        \"\"\"\n        :return: Source\n        \"\"\"\n        from classes.components.mapsapi_sources import Source\n        return Source(self.test, self.test.find_element_by_css_selector(Source.selectors['loader']))\n"
  },
  {
    "path": "functional-tests/classes/components/zoom_control.py",
    "content": "# -*- coding: utf-8 -*-\nfrom component import Component\n\n\nclass ZoomControlIn(Component):\n    selectors = {\n        'self': '.dg-zoom__in > div'\n    }\n\n    def zoom_in_click(self):\n        self.element.click()\n\n\nclass ZoomControlOut(Component):\n    selectors = {\n        'self': '.dg-zoom__out > div'\n    }\n\n    def zoom_out_click(self):\n        self.element.click()\n"
  },
  {
    "path": "functional-tests/classes/exceptions/__init__.py",
    "content": "\n"
  },
  {
    "path": "functional-tests/classes/exceptions/exceptions.py",
    "content": "from contesto.exceptions import BaseError\n\n\nclass MapsApiException(BaseError):\n    pass\n\n\nclass ElementNotFoundException(MapsApiException):\n    pass\n\n\nclass UnknownElementException(MapsApiException):\n    pass\n\n\nclass WebAPIException(MapsApiException):\n    pass\n\n\nclass CommonException(MapsApiException):\n    pass\n\n\nclass NoPageIsSelected(MapsApiException):\n    pass\n\n\nclass NotTransportTypeError(MapsApiException):\n    pass\n\n\nclass NotGeoTypeError(MapsApiException):\n    pass\n\n\nclass NotFirmTypeError(MapsApiException):\n    pass\n"
  },
  {
    "path": "functional-tests/classes/mapsapi_base_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.components.page import Page\nfrom contesto.basis.test_case import UnittestContestoTestCase\nfrom config import config\n\n\n# TODO: Переопределить логгер из contesto, чтоб не падать при пустых логах\nclass MapsAPIBaseTest(UnittestContestoTestCase):\n    def setUp(self):\n        super(MapsAPIBaseTest, self).setUp()\n        self.page = Page(self.driver)\n        if self.driver.browser != 'opera' or self.driver.browser != 'phantomjs':\n            self.driver.maximize_window()\n        self.driver.set_script_timeout(config.timeout[\"normal\"])\n        self._webAPI = None\n        self._baseWAPI = None\n\n    def tearDown(self):\n        # log.info(\"JS Errors: %s\" % self.driver.js_errors)\n        super(MapsAPIBaseTest, self).tearDown()\n"
  },
  {
    "path": "functional-tests/classes/util/__init__.py",
    "content": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "functional-tests/classes/util/decorators.py",
    "content": "# -*- coding: utf-8 -*-\nfrom contesto import config\nfrom contesto.exceptions import ElementNotFound\nfrom selenium.webdriver.support.wait import WebDriverWait\nimport functools\n\n\ndef catches_not_found(if_not_found=None):\n    def wrapper(f):\n        @functools.wraps(f)\n        def decorated(self, *args, **kwargs):\n            try:\n                return f(self, *args, **kwargs)\n            except ElementNotFound:\n                return if_not_found\n        return decorated\n    return wrapper\n\n\ndef waits_for(selectors, appear=False):\n    def wrap(f):\n        def decorate(self, *args, **kwargs):\n            f(self, *args, **kwargs)\n            for selector in selectors:\n                try:\n                    driver = self.test if 'test' in self.__class__.__dict__ else self.driver\n                    wait = WebDriverWait(driver, float(config.timeout['normal']))\n                    if appear:\n                        wait.until(lambda dr: dr.find_element_by_css_selector(selector).is_displayed())\n                    else:\n                        wait.until_not(lambda dr: dr.find_element_by_css_selector(selector).is_displayed())\n                except ElementNotFound:\n                    continue\n        return decorate\n    return wrap\n\n\ndef try_x_times(x, exceptions_to_catch, exception_to_raise, fn):\n    \"\"\"\n    :param x: int\n    :param exceptions_to_catch: tuple of Exception\n    :param exception_to_raise: tuple of Exception\n    :param fn: function\n    \"\"\"\n    @functools.wraps(fn)  # keeps name and docstring of old function\n    def new_fn(*args, **kwargs):\n        for i in xrange(x):\n            try:\n                return fn(*args, **kwargs)\n            except exceptions_to_catch:\n                pass\n        raise exception_to_raise\n    return new_fn"
  },
  {
    "path": "functional-tests/classes/util/geo_types_map.py",
    "content": "# -*- coding: utf-8 -*-\n\n\"\"\"\nВзято из models/geo.js\n\"\"\"\n\ngeo_type = {\n    'street': u'Улица',\n    'house': u'Дом',\n    'district': u'Район',\n    'division': u'Округ',\n    'city': u'Город',\n    'settlement': u'Населенный пункт',\n    'station': u'Остановка',\n    'station_platform': u'Остановочная платформа',\n    'living_area': u'Микрорайон',\n    'place': u'Место',\n    'sight': u'Достопримечательность',\n    'crossroad': u'Перекресток',\n    'metro': u'Станция метро',\n}"
  },
  {
    "path": "functional-tests/classes/util/link_generator.py",
    "content": "def photo_link(firm_id):\n    return \"http://2gis.ru/photos/%s\" % firm_id\n\n\ndef reviews_link(firm_id):\n    return \"http://flamp.ru/r/%s?utm_source=api2gis&utm_medium=api&utm_campaign=geoclicker\" % firm_id\n"
  },
  {
    "path": "functional-tests/classes/util/misc.py",
    "content": "# -*- coding: utf-8 -*-\nimport urllib\n\n\ndef extend(extension, base):\n    \"\"\"\n    :param base: dict of dicts\n    :param extension: dict\n    :return: dict\n    Extend each base dict from key of extension\n    \"\"\"\n    for part in base:\n        for default_prop in extension:\n            if default_prop not in base[part]:\n                base[part][default_prop] = extension[default_prop]\n    return base\n\n\ndef comment_equals(comment, wapi_comment):\n    \"\"\"\n    :type comment: str or unicode\n    :type wapi_comment: str or unicode\n    :rtype: bool\n    \"\"\"\n    return comment == '— '.decode('utf-8') + wapi_comment\n\n\ndef unicode_print(s):\n    \"\"\"\n    Prints unicode strings\n    :type s: unicode\n    \"\"\"\n    s = to_unicode(s)\n    print u'%s' % s,\n\n\ndef to_unicode(s):\n    \"\"\"\n    Converts string to unicode if necessary\n    :type s: str or unicode\n    :rtype: unicode\n    \"\"\"\n    try:\n        s = str(s)\n        return s.decode('utf-8')\n    except UnicodeEncodeError:\n        return s\n\n\ndef rprint(item):\n    \"\"\"\n    Prints list or dict recursively.\n    :type item: list, dict\n    \"\"\"\n    if isinstance(item, list):\n        print '[',\n        for i in item:\n            rprint(i)\n            print ', ',\n        print ']',\n    elif isinstance(item, dict):\n        print '{',\n        for key, val in item.iteritems():\n            unicode_print(key)\n            print ': ',\n            rprint(val)\n            print ', ',\n        print '}',\n    else:\n        unicode_print(item)\n\n\nclass AttrDict(dict):\n    \"\"\"\n    Wraps a dict object or literal to access values like object properties:\n    my_dict = AttrDict( {'a': 1} )\n    assert my_dict.a == 1\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        super(AttrDict, self).__init__(*args, **kwargs)\n        self.__dict__ = self\n\n\ndef to_str(s):\n    \"\"\"\n    Converts unicode to string if necessary\n    :type s: str or unicode\n    :rtype: str\n    \"\"\"\n    try:\n        return s.encode('utf-8')\n    except UnicodeDecodeError:\n        return s\n\n\ndef to_int(s):\n    \"\"\"\n    Return first number from string\n    :param s: strin or unicode\n    :return: int\n    \"\"\"\n    out = ''\n    started = False\n    for x in s:\n        if x.isdigit():\n            out += x\n            started = True\n        if started and not x.isdigit():\n            return int(out)\n    return int(out)\n\n\ndef address_and_comment(address, comment):\n    return u\"%s— %s\" % (address, comment)\n\n\ndef phone_and_comment(phone, comment):\n    return u\"%s—  %s\" % (phone, comment)\n\n\ndef check_route(link, check_part):\n    \"\"\"\n    :param link: string with route link\n    :param check_part: list of fixture base parts of route link\n    :return: bool\n    Remove protocol and unquote url\n    Split route link by '/', split last part by '╎', split coordinates part by ','\n    Save each parts in 'parts' list with original order.\n    Round coordinates and check equal part in parts and check_part, save result in 'check' list\n    Return all True of check list.\n    \"\"\"\n    # unquote\n    link = urllib.unquote(to_str(link[7:]))\n    # make parts list\n    parts = link.split('/')\n    coords = parts[len(parts) - 1].split('╎')[0]\n    address = parts[len(parts) - 1].split('╎')[1]\n    parts.remove(parts[len(parts) - 1])\n    parts.append(coords)\n    parts.append(address)\n    center = parts[3].split(',')\n    baloon = parts[len(parts) - 2].split(',')\n    parts[3] = center[0]\n    parts.insert(4, center[1])\n    parts[len(parts) - 2] = baloon[0]\n    parts.insert(len(parts) - 1, baloon[1])\n    # check equals\n    i = 0\n    check = list()\n    while i < len(parts):\n        if isinstance(check_part[i], float):\n            check_part[i] = round(check_part[i], 2)\n            parts[i] = round(float(parts[i]), 2)\n        check.append(check_part[i] == parts[i])\n        i += 1\n    return all(item for item in check)\n\n\ndef coord_equals(expected, got, precision):\n    \"\"\"\n    :param expected: Expected coordinate value\n    :param got: Got coordinate value\n    :param precision: Precision for round latitude and longitude\n    :return: bool\n    Check part by part coordinate equals with precision\n    \"\"\"\n    checks = list()\n    checks.append(round(expected['lat'], precision) == round(got['lat'], precision))\n    checks.append(round(expected['lng'], precision) == round(got['lng'], precision))\n    print(round(expected['lat'], precision))\n    print(round(got['lat'], precision))\n    print(round(expected['lng'], precision))\n    print(round(got['lng'], precision))\n    return all(check for check in checks)\n\n\ndef coord_string_to_dict(coord_str):\n    \"\"\"\n    :param coord_str: string like 'lat, lng'\n    :return: dict from coord_string content lat and lng respectively\n    \"\"\"\n    parts = coord_str.split(', ')\n    return {'lat': float(parts[0]), 'lng': float(parts[1])}\n"
  },
  {
    "path": "functional-tests/classes/util/scripts.py",
    "content": "class GetScripts:\n    getZoom = 'return map.getZoom();'\n    getCenter = 'return map.getCenter();'\n    getContainerCenter = 'return map.latLngToContainerPoint(map.getCenter());'\n\n\nclass SetScripts:\n\n    @staticmethod\n    def set_zoom(level=10):\n        return 'map.setZoom(%s, {animate: false});' % str(level)\n\n    @staticmethod\n    def pan_to(lat, lng):\n        return 'map.panTo([%s, %s], {animate: false});' % (str(lat), str(lng))\n\n    @staticmethod\n    def set_lang(lang):\n        return 'map.setLang(\"%s\");' % str(lang)\n\n    @staticmethod\n    def open_marker(name='marker'):\n        return '%s.openPopup();' % name\n\n    @staticmethod\n    def dg_then(cb=''):\n        return 'DG.then(%s);' % cb\n"
  },
  {
    "path": "functional-tests/classes/util/transport_types_map.py",
    "content": "# -*- coding: utf-8 -*-\n\nroute_type = {\n    'bus': u'Автобус',\n    'trolleybus': u'Троллейбус',\n    'tram': u'Трамвай',\n    'shuttle_bus': u'Маршрутное такси',\n    'metro': u'Метро',\n    'suburban_train': u'Электропоезд',\n    'funicular_railway': u'Фуникулер',\n    'monorail': u'Монорельс',\n    'river_transport': u'Речной транспорт',\n    'cable_car': u'Канатная дорога',\n    'light_rail': u'Скоростной трамвай',\n    'premetro': u'Метротрам',\n    'light_metro': u'Лёгкое метро',\n}\n"
  },
  {
    "path": "functional-tests/classes/util/unescape.py",
    "content": "# -*- coding: utf-8 -*-\n\n\ndef unescape_text(text):\n    \"\"\"\n    АПИ передает в выдаче эскейп-символы. Метод преобразовывает их в нормальный вид\n    см tests/search/firms_minicard/\n    \"\"\"\n    import HTMLParser\n    return HTMLParser.HTMLParser().unescape(text)\n"
  },
  {
    "path": "functional-tests/config/__init__.py",
    "content": "import os\n\nimport contesto\nfrom contesto import config as cfg\n\ncontesto.config.add_config_file(os.path.abspath(os.path.dirname(__file__)) + \"/config.ini\")\ncontesto.config.add_config_file(os.path.abspath(os.path.dirname(__file__)) + \"/config.my.ini\")\n\nconfig = cfg\n"
  },
  {
    "path": "functional-tests/config/config.ini",
    "content": "[AUT]\nlocal: http://127.0.0.1:3000/pages\n\n\n[Selenium]\nhost: localhost\nport: 4455\nbrowser: chrome\n\n[Timeout]\nnormal: 5\n\n[Session]\nshared: 0\n\n[WAPI]\nurl: http://catalog.api.2gis.ru\nkey: ruregt3044\nversion: 2.0\n"
  },
  {
    "path": "functional-tests/config/config.my.ini",
    "content": ";[AUT]\n;local: http://maps.test.webmaps.ostack.test/2.0/pages\n;\n;\n;[Selenium]\n;host: vmmaster.auto.ostack.test\n;port: 9000\n;platform: ubuntu-14.04-x64\n;browser: chrome\n;user: webmaps\n;token: d2cf4ace-b964-4d39-9df7-5b676d35a6b7\n;\n;[Timeout]\n;normal: 10\n;loading: 10\n;\n;[Session]\n;shared: 0\n;\n;[WAPI]\n;url: http://catalog.api.2gis.ru\n;key: ruregt3044\n;version: 2.0\n"
  },
  {
    "path": "functional-tests/pep8",
    "content": "[pep8]\nignore=E501"
  },
  {
    "path": "functional-tests/pep8-hook.sh",
    "content": "#!/bin/sh\n\npy_files=$(git diff `git merge-base master HEAD`..HEAD --name-only | grep \".py$\")\nif [ \"$py_files\" = \"\" ]; then\n    exit 0\nfi\n\npass=true\n\necho \"\\nValidating python source files:\\n\"\n\nfor file in ${py_files}; do\n    result=$(pep8 --format=pylint --config=functional-tests/pep8 ${file})\n    if [ \"$result\" != \"\" ]; then\n        echo \"\\t\\033[31mpep8 Failed: ${file}\\033[0m\"\n        echo \"$result\"\n        pass=false\n    else\n        echo \"\\t\\033[32mpep8 Passed: ${file}\\033[0m\"\n    fi\ndone\n\necho \"\\nPython validation complete\\n\"\n\nif ! $pass; then\n    echo \"\\033[41mCOMMIT FAILED:\\033[0m Your commit contains files that should pass pep8 but do not. Please fix the pep8 errors and try again.\\n\"\n    exit 1\nelse\n    echo \"\\033[42mCOMMIT SUCCEEDED\\033[0m\\n\"\nfi\n"
  },
  {
    "path": "functional-tests/prepare.sh",
    "content": "#!/usr/bin/env bash\nvirtualenv --python=python .env\nsource .env/bin/activate\npip install -U git+https://github.com/2gis/contesto.git@53ff11259171a8fca74cbc04bf83bbdec668424d\npip install -U git+https://github.com/2gis/lode_runner.git@7cbd608328058b4c622fcd8795a8804ef121cae7\npip install -U selenium\npip install -U pep8\npip install -U jinja2\n"
  },
  {
    "path": "functional-tests/run.sh",
    "content": "#!/usr/bin/env bash\nsource .env/bin/activate\nPYTHONPATH=$(pwd) .env/bin/lode_runner -v tests/ --with-xunit\nexit 0;\n"
  },
  {
    "path": "functional-tests/template_render.sh",
    "content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\nfrom jinja2 import Template\nfrom templates.content import pages\nimport codecs\nimport os\n\nif not os.path.exists('../dist/pages'):\n    os.mkdir('../dist/pages')\n\nbase = open('templates/base.html', 'r')\ntemplate = Template(base.read())\nbase.close()\n\nparts = pages()\n\nfor page in parts:\n    out = codecs.open(\"../dist/pages/%s.html\" % parts[page]['title'], 'w', 'utf-8')\n    out.write(template.render(parts[page]))\n    out.close()\n"
  },
  {
    "path": "functional-tests/templates/__init__.py",
    "content": ""
  },
  {
    "path": "functional-tests/templates/base.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <meta charset=\"utf-8\" />\n        <title>{{title}}</title>\n        <script src=\"{{loaderPath}}/loader.js{{getParams}}\" {{dgLoader}}></script>\n        <style>\n            {{headStyle}}\n        </style>\n    </head>\n    <body>\n        <span id=\"info\">{{info}}</span>\n        <div id=\"map\" style=\"{{style}}\"></div>\n        <script>\n            {{mapInit}}\n        </script>\n        {{controls}}\n    </body>\n</html>"
  },
  {
    "path": "functional-tests/templates/content.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.util.misc import extend\n\n\ndef pages():\n    parts = dict(\n        base={\n            'title': u'base',\n            'mapInit':\n            u\"\"\"\n            DG.then(function() {\n                map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13,\n                geoclicker: true,\n                worldCopyJump: true,\n                zoomAnimation: false\n            });\n\n                DG.control.location({position: 'bottomright'}).addTo(map);\n                DG.control.scale().addTo(map);\n                DG.control.ruler({position: 'bottomleft'}).addTo(map);\n                DG.control.traffic().addTo(map);\n            });\"\"\"\n        },\n        demo={\n            'title': u'demo',\n            'mapInit':\n            u\"\"\"\n            var  options,\n             balloonHTML;\n\n            DG.then(function () {\n                map = DG.map('map', {\n                    center: [54.980156831455, 82.897440725094],\n                    zoom: 13,\n                    geoclicker: true,\n                    worldCopyJump: true,\n                    zoomControl: false,\n                    fullscreenControl: false,\n                    zoomAnimation: false\n                });\n\n                // change control position on touch devices\n                if (DG.Browser.touch) {\n                    options = { position: 'bottomright' };\n                }\n\n                DG.control.zoom(options).addTo(map);\n                DG.control.traffic(options).addTo(map);\n                DG.control.location(options).addTo(map);\n                DG.control.ruler(options).addTo(map);\n                if (DG.screenfull.isAvailable()) {\n                    DG.control.fullscreen(options).addTo(map);\n                }\n                balloonHTML = '<a href=\"http://www.2gis.ru/\" target=\"_blank\">\\\\n\\\\\n                <img src=\"/2.0/img/2gis-logo.png\" alt=\"2GIS\" title=\"2GIS\" width=\"146\" height=\"70\" style=\"border: none\"></a>\\\\n\\\\\n                <p>Компания «ДубльГИС»</p>Тел.: (383) 363-05-55<br />Адрес: г. Новосибирск, Карла Маркса площадь, 7<br />\\\\n\\\\\n                (МФК «Сан Сити»), 13 этаж';\n\n                marker = DG.marker([54.980156831455, 82.897440725094]).addTo(map).bindPopup(balloonHTML).openPopup();\n            });\n            \"\"\",\n            'headStyle':\n            u\"\"\"\n            html,body { height: 100%; margin: 0; padding: 0; }\n            .leaflet-touch .leaflet-bottom .dg-attribution { margin-top: 70px; }\n            .leaflet-touch .leaflet-bottom .dg-zoom {margin: 40px 10px 40px 0; }\n            \"\"\"\n        },\n        draggableMarker={\n            'title': u'draggableMarker',\n            'mapInit':\n            u\"\"\"\n            DG.then(function () {\n                map = DG.map('map', {\n                    center: [54.981, 82.891],\n                    zoom: 15,\n                    zoomAnimation: false\n                });\n\n                marker = DG.marker([54.981, 82.891], {\n                    draggable: true\n                }).addTo(map);\n            });\n            \"\"\"\n        },\n        groupBalloon={\n            'title': u'groupBalloon',\n            'mapInit':\n            u\"\"\"\n            DG.then(function() {\n                var map,\n                    popups = DG.featureGroup(),\n                    coordinates = [];\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 13,\n                    zoomAnimation: false\n                });\n                for (var i = 0; i < 10; i++) {\n                    coordinates[0] = 54.98 - Math.random();\n                    coordinates[1] = 82.89 + Math.random();\n                    DG.popup()\n                        .setLatLng(coordinates)\n                        .setContent('Я балун №' + i)\n                        .addTo(popups);\n                }\n\n                popups.addTo(map);\n                map.fitBounds(popups.getBounds());\n            });\n            \"\"\"\n        },\n        groupMarkerEvent={\n            'title': u'groupMarkerEvent',\n            'mapInit':\n            u\"\"\"\n             DG.then(function() {\n\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 10,\n                    zoomAnimation: false\n                });\n\n                marker1 = DG.marker([54.96, 82.889]).addTo(map);\n                marker2 = DG.marker([54.98, 82.893]).addTo(map);\n                marker3 = DG.marker([54.847182907052186, 83.06230008602144]).addTo(map);\n\n                group = DG.featureGroup([marker1, marker2, marker3]);\n                group.addTo(map);\n                group.on('click', function(e) {\n                    map.setView([e.latlng.lat, e.latlng.lng],{animate: false});\n                });\n            });\n            \"\"\"\n        },\n        markerLabels={\n            'title': u'markerLabels',\n            'mapInit':\n            u\"\"\"\n             DG.then(function() {\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 15,\n                    zoomAnimation: false\n                });\n\n                DG.marker([54.98, 82.89])\n                    .addTo(map)\n                    .bindLabel(\"static\", {\n                        static: true\n                    });\n\n                DG.marker([54.98, 82.88])\n                    .addTo(map)\n                    .bindLabel('default');\n            });\n            \"\"\"\n\n        },\n        openBalloons={\n            'title': u'openBalloons',\n            'mapInit':\n            u\"\"\"\n                DG.then(function() {\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13,\n                        zoomAnimation: false\n                    });\n\n                    DG.popup([54.98, 82.89])\n                        .setLatLng([54.98, 82.89])\n                        .setContent('default')\n                        .openOn(map);\n\n                    myPopUp = DG.popup()\n                        .setLatLng([54.98, 82.89])\n                        .setContent('request');\n                });\n                function openPopUp() {myPopUp.openOn(map)};\n            \"\"\",\n            'controls':\n            u\"\"\"\n            <input id=\"showPopup\" type=\"button\" value=\"Открыть балун\" onclick=\"openPopUp()\"/>\n            \"\"\"\n        },\n        sprawlingBalloon={\n            'title': u'sprawlingBalloon',\n            'mapInit':\n            u\"\"\"\n            DG.then(function () {\n                        latLng = DG.latLng([54.98, 82.89]);\n\n                    map = DG.map('map', {\n                        center: latLng,\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false,\n                        zoomAnimation: false\n                    });\n\n                    document.getElementById('sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            sprawling: true\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я балун!')\n                        .openOn(map);\n                    };\n\n                    document.getElementById('no-sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я балун!')\n                        .openOn(map);\n                    };\n\n                    document.getElementById('minWidth').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            minWidth: 320\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я балун!')\n                        .openOn(map);\n                    };\n                });\n                function resize(pixels){\n                    document.getElementById('map').style.width = pixels + \"px\";\n                    map.invalidateSize(false);\n                }\n            \"\"\",\n            'controls':\n            u\"\"\"\n            <div>\n                <input style=\"width: 300px;\" type=\"button\" id=\"sprawling\" value=\"Sprawling\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"no-sprawling\" value=\"No sprawling\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"minWidth\" value=\"Minimal width 320px\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"small\" value=\"Small map\" onclick=\"resize(200)\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"mid\" value=\"Medium map\" onclick=\"resize(300)\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"large\" value=\"Large map\" onclick=\"resize(500)\">\n            </div>\n            \"\"\",\n            'style': u\"\"\"width: 300px; height: 150px;\"\"\"\n        },\n        scrollBarBaloon={\n            'title': u'scrollBarBalloon',\n            'mapInit':\n            u\"\"\"\n            DG.then(function () {\n                        latLng = DG.latLng([54.98, 82.89]);\n\n                    map = DG.map('map', {\n                        center: latLng,\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false,\n                        zoomAnimation: false\n                    });\n\n                    document.getElementById('scrollBar').onclick = function () {\n                        DG.popup({\n                            maxHeight: 300,\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ducimus ipsam itaque velit aut error ipsa sunt neque, ut molestiae. Omnis officia architecto similique, enim et voluptates sunt doloremque error repudiandae, iure est a quisquam, nulla voluptatibus quis nostrum voluptas vel ipsa consequatur ipsum velit. Nam laudantium, nemo iste enim ut soluta et explicabo amet nulla impedit sequi animi consectetur alias repellendus, laboriosam dolor dolorum tenetur quod modi sunt sapiente recusandae, pariatur! Delectus nihil provident hic perferendis veniam atque id, ad ipsum error laudantium, quo praesentium qui! Odit saepe distinctio aperiam autem dolor beatae nam, nostrum voluptate, reprehenderit tenetur quidem aspernatur!')\n                        .openOn(map);\n                    };\n\n                    document.getElementById('noMaxHeight').onclick = function () {\n                        DG.popup()\n                        .setLatLng(latLng)\n                        .setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Facere, perspiciatis corrupti? Minima beatae sed delectus obcaecati, officia eos! Sint, excepturi facere iusto, sapiente facilis repellat. Eum facere, illo necessitatibus voluptatibus, illum quas. Cumque nisi incidunt, facere laboriosam asperiores nihil fugiat dolor dolorum sequi soluta consectetur non nulla vel praesentium omnis.')\n                        .openOn(map);\n                    };\n\n                    document.getElementById('noScrollBar').onclick = function () {\n                        DG.popup({\n                            maxHeight: 300\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas numquam distinctio impedit, quod totam eveniet dolorum qui? Corporis praesentium ipsum officiis impedit quas, inventore laboriosam ipsam nobis soluta maxime delectus quasi voluptatem, tenetur obcaecati laudantium error. Velit expedita, reprehenderit natus nihil cupiditate doloribus quis? In obcaecati cupiditate vero laudantium maiores.')\n                        .openOn(map);\n                    };\n                });\n            \"\"\",\n            'controls':\n            u\"\"\"\n            <div>\n                <input style=\"width: 300px;\" type=\"button\" id=\"scrollBar\" ><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"noMaxHeight\"><br />\n                <input style=\"width: 300px;\" type=\"button\" id=\"noScrollBar\"><br />\n            </div>\n            \"\"\",\n            'style': u\"\"\"width: 300px; height: 500px;\"\"\"\n        },\n        boundsNsk={\n            'title': u'boundsNsk',\n            'mapInit':\n            u\"\"\"\n            DG.then(function() {\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 10,\n                    maxBounds: [\n                        [54.8220, 82.4304],\n                        [55.1372, 83.3505]\n                    ],\n                    minZoom: 10,\n                    maxZoom: 15,\n                    zoomAnimation: false\n                });\n            });\n            \"\"\",\n            'style': 'width: 670px; height: 400px;'\n        },\n        clickEvent={\n            'title': u'clickEvent',\n            'mapInit':\n            u\"\"\"\n            DG.then(function() {\n                    var clickedElement = document.getElementById('info'),\n                    coords = [\n                        [54.99, 82.88],\n                        [54.985, 82.94],\n                        [54.984, 82.925],\n                        [54.981, 82.928]\n                    ];\n\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 13,\n                    zoomAnimation: false\n                });\n\n                map.on('click', function(e) {\n                    clickedElement.innerHTML = 'map ' + e.latlng.lat + ', ' + e.latlng.lng;\n                });\n\n                DG.marker([54.98, 82.89])\n                    .on('click', function() {\n                        clickedElement.innerHTML = 'marker';\n                    })\n                    .addTo(map);\n\n                DG.polygon(coords)\n                    .on('click', function() {\n                        clickedElement.innerHTML = 'polygon';\n                    })\n                    .addTo(map);\n            });\n            \"\"\",\n            'style': u\"width: 100%; height: 400px;\"\n        },\n        lazyLoad={\n            'title': u'lazyLoad',\n            'getParams': u'?lazy=true'\n        },\n        notLazyLoad={\n            'title': u'notLazyLoad',\n            'getParams': u'?lazy=false'\n        }\n    )\n    defaults = dict(\n        style='width: 1000px; height: 600px;',\n        loaderPath='..',\n        dgLoader='data-id=\"dgLoader\"'\n    )\n    return extend(defaults, parts)\n"
  },
  {
    "path": "functional-tests/tests/__init__.py",
    "content": "# -*- coding: utf-8 -*-\nimport os\n\nimport contesto\nfrom contesto import config as cfg\n\ncontesto.config.add_config_file(os.path.abspath(os.path.dirname(__file__)) + \"/config.ini\")\ncontesto.config.add_config_file(os.path.abspath(os.path.dirname(__file__)) + \"/config.my.ini\")\n\nconfig = cfg\n"
  },
  {
    "path": "functional-tests/tests/balloon_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\n\n\nclass Balloons(MapsAPIBaseTest):\n    \"\"\"\n    Тесты балунов\n    \"\"\"\n    @dataprovider([\n        config.aut['local'] + u'/demo.html'\n    ])\n    def balloon_to_marker_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка появления маркера при закрытии балуна\n        1.Кликаем в контрол закрытия балуна\n        2.Проверяем видимость маркера\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.balloon_crossed.wait_present()\n        self.page.balloon_crossed.close()\n        self.assertTrue(self.page.marker.is_visible)\n\n    @dataprovider([\n        config.aut['local'] + u'/openBalloons.html'\n    ])\n    def balloon_default_open_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка програмного открытия балуна.\n        1.Проверяем что открыт балун по умолчанию\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        balloon_text = self.page.balloon.get_content().text\n        self.assertEqual('default', balloon_text)\n\n    @dataprovider([\n        config.aut['local'] + u'/openBalloons.html'\n    ])\n    def balloon_program_open_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка програмного открытия балуна.\n        1.Проверяем что открыт балун по умолчанию\n        2.Кликаем по кнопке \"Открыть балун\"\n        3.Проверяем что открыт один новый балун\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.find_element_by_css_selector('#showPopup').click()\n        self.page.balloon.wait_close()\n        self.page.balloon.wait_present()\n        balloon = self.page.balloon.get_content()\n        self.assertEqual(1, self.page.balloon.count())\n        self.assertEqual('request', balloon.text)\n\n    @dataprovider([\n        config.aut['local'] + u'/groupBalloon.html'\n    ])\n    def balloon_group_open_test(self, url):\n        \"\"\"\n        :param url:\n        Проверка открытия группы балунов\n        1.Проверяем количество открытых балунов на карте\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.balloon.wait_present()\n        self.assertEqual(10, self.page.balloon.count())\n\n    @dataprovider([\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'large', '350px'),\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'mid', '290px'),\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'small', '190px'),\n    ])\n    def balloon_sprawling_test(self, url, size, width):\n        \"\"\"\n        :param url: Адрес страницы\n        :param size: Размер карты(large - 500px, mid - 300px, small - 200px)\n        :param width: Ширина балуна\n        Проверка размера балуна с параметром sprawling на карте\n        1.Выставляем размер карты\n        2.Кликаем в создать балун\n        3.Проверяем ширину\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.find_element_by_css_selector(\"input#%s\" % size).click()\n        self.driver.find_element_by_css_selector('input#sprawling').click()\n        balloon_width = self.page.balloon.width\n        self.assertEqual(balloon_width, width)\n\n    @dataprovider([\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'small', 'large', '350px'),\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'small', 'mid', '290px'),\n        (config.aut['local'] + u'/sprawlingBalloon.html', 'large', 'small', '190px'),\n    ])\n    def balloon_sprawling_resize_test(self, url, start, end, width):\n        \"\"\"\n        :param url: Адрес страницы\n        :param start: С какого размера переключаемся (размеры в описаны balloon_sprawling_test)\n        :param end: На какой переключаемся\n        :param width: Какой размер должен принять балун\n        Проверка размера балуна с параметром sprawling на большой карте\n        1.Выставляем ширину карты\n        2.Создаем балун\n        3.Меняем ширину карты\n        4.Приверяем ширину балуна\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.find_element_by_css_selector(\"input#%s\" % start).click()\n        self.driver.find_element_by_css_selector('input#sprawling').click()\n        self.driver.find_element_by_css_selector(\"input#%s\" % end).click()\n        balloon_width = self.page.balloon.width\n        self.assertEqual(balloon_width, width)\n\n    @dataprovider([\n        (config.aut['local'] + u'/scrollBarBalloon.html', 'scrollBar', True),\n        (config.aut['local'] + u'/scrollBarBalloon.html', 'noMaxHeight', False),\n        (config.aut['local'] + u'/scrollBarBalloon.html', 'noScrollBar', False),\n    ])\n    def balloon_scroll_bar_test(self, url, type_, scroll_bar):\n        \"\"\"\n        Проверка скроллбара\n        :param url: Адрес страницы\n        :param type_: Какой балун\n        :param scroll_bar: Есть ли скролбар\n        1.Кликаем в создать балун\n        2.Проверяем наличие скролбара\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.find_element_by_css_selector(\"input#%s\" % type_).click()\n\n        self.assertEqual(bool(self.page.balloon.scroll), scroll_bar)\n\n    @dataprovider([\n        (config.aut['local'] + u'/scrollBarBalloon.html', 'scrollBar', 300),\n        (config.aut['local'] + u'/scrollBarBalloon.html', 'noScrollBar', 240),\n    ])\n    def balloon_max_height_test(self, url, type_, height):\n        \"\"\"\n        Проверка скроллбара\n        :param url: Адрес страницы\n        :param type_: Какой балун\n        :param height: Высота\n        1.Кликаем в создать балун\n        2.Проверяем высоту балуна\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.find_element_by_css_selector(\"input#%s\" % type_).click()\n\n        balloon_height = self.page.balloon.height\n        self.assertEqual(balloon_height, \"%dpx\" % height)\n"
  },
  {
    "path": "functional-tests/tests/bounds_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util import scripts\n\n\nclass Bounds(MapsAPIBaseTest):\n    \"\"\"\n    Тесты на ограничение зума и границ\n    \"\"\"\n    @dataprovider([\n        config.aut['local'] + u'/boundsNsk.html'\n    ])\n    def bound_min_zoom_script_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка ограничения минимального зума\n        1.Выставляем зум меньше ограничения\n        2.Проверяем что зум равен ограничению\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.set_zoom(9))\n        zoom = self.page.console(scripts.GetScripts.getZoom)\n        self.assertEqual(10, zoom)\n\n    @dataprovider([\n        config.aut['local'] + u'/boundsNsk.html'\n    ])\n    def bound_max_zoom_script_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка ограничения максимального зума\n        1.Выставляем зум больше ограничения\n        2.Проверяем что зум равен ограничению\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.set_zoom(16))\n        zoom = self.page.console(scripts.GetScripts.getZoom)\n        self.assertEqual(15, zoom)\n\n    @dataprovider([\n        config.aut['local'] + u'/boundsNsk.html'\n    ])\n    def bound_max_zoom_control_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка ограничения максимального зума\n        1.Выставляем зум равный ограничению\n        2.Кликаем в контрол zoom in\n        3.Проверяем что зум равен ограничению\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.set_zoom(15))\n        self.page.zoom_control_in.zoom_in_click()\n        zoom = self.page.console(scripts.GetScripts.getZoom)\n        self.assertEqual(15, zoom)\n\n    @dataprovider([\n        config.aut['local'] + u'/boundsNsk.html'\n    ])\n    def bound_min_zoom_control_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка ограничения минимального зума\n        1.Выставляем зум равный ограничения\n        2.Кликаем\n        3.Проверяем что зум равен ограничению\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.set_zoom(10))\n        self.page.zoom_control_out.zoom_out_click()\n        zoom = self.page.console(scripts.GetScripts.getZoom)\n        self.assertEqual(10, zoom)\n"
  },
  {
    "path": "functional-tests/tests/event_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util.scripts import SetScripts\nfrom classes.util import misc\n\n\nclass EventHandlers(MapsAPIBaseTest):\n    @dataprovider([\n        (config.aut['local'] + u'/clickEvent.html')\n    ])\n    def click_marker_test(self, url):\n        \"\"\"\n        Проверка события click для маркера\n        :param url: Адрес страницы\n        1.Открываем страницу\n        2.Кликаем в маркер\n        3.Проверяем содержимое info\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.marker.click()\n        info = self.page.map.info_elem()\n        self.assertEqual(info.text, 'marker')\n\n    @dataprovider([\n        (config.aut['local'] + u'/clickEvent.html', {'lat': 54.99, 'lng': 82.73})\n    ])\n    def click_map_test(self, url, point):\n        \"\"\"\n        Проверка события click для карты\n        :param url: Адрес страницы\n        :param point: Координаты на карте\n        1.Открываем страницу\n        2.Кликаем в координаты\n        3.Проверяем содержимое info\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        info = self.page.map.info_elem()\n        self.page.console(SetScripts.set_zoom(17))\n        self.page.console(SetScripts.pan_to(point['lat'], point['lng']))\n        self.page.map.center_click()\n        self.assertEqual(info.text.split(' ')[0], 'map')\n        coords = misc.coord_string_to_dict(info.text[4:])\n        self.assertTrue(misc.coord_equals(point, coords, 2))\n\n    @dataprovider([\n        (config.aut['local'] + u'/clickEvent.html', {'lat': 54.985, 'lng': 82.911})\n    ])\n    def click_polygon_test(self, url, point):\n        \"\"\"\n        Проверка события click для карты\n        :param url: Адрес страницы\n        :param point: Координаты на карте внутри полигона\n        1.Открываем страницу\n        2.Кликаем в координаты\n        3.Проверяем содержимое info\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        info = self.page.map.info_elem()\n        self.page.console(SetScripts.set_zoom(17))\n        self.page.console(SetScripts.pan_to(point['lat'], point['lng']))\n        self.page.map.center_click()\n        self.assertEqual(info.text, 'polygon')\n"
  },
  {
    "path": "functional-tests/tests/firm_callout_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util import scripts\nfrom classes.WAPI.dataWorker import FirmData\nimport classes.util.misc as misc\nimport classes.util.link_generator as links\n\n\nclass FirmCallout(MapsAPIBaseTest):\n    \"\"\"\n    Тесты на сallout фирмы\n    \"\"\"\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265770417218\n    )\n    ])\n    def firm_name_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка заголовка фирмы\n        1.Открываем калаут фирмы\n        2.Проверяем заголовок\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.pan_to(lat, lng))\n        self.page.console(scripts.SetScripts.set_zoom(17))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        self.page.build_callout.open_firm_list()\n        self.page.build_callout.open_firm_by_id(firm_id)\n        callout_text = self.page.firm_callout.header\n        f = FirmData(firm_id)\n        self.assertEqual(f.firm_name, callout_text)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254\n    )\n    ])\n    def firm_back_list_test(self, url, lat, lng):\n        \"\"\"\n        Проверка кнопки назад (в здании с мн. организаций)\n        1.Открываем калаут фирмы\n        2.Нажимаем назад\n        3.Проверяем наличие списка организаций\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.pan_to(lat, lng))\n        self.page.console(scripts.SetScripts.set_zoom(17))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        self.page.build_callout.open_firm_list()\n        self.page.build_callout.open_firm_by_index(1)\n        self.page.firm_callout.back()\n        self.assertTrue(self.page.firm_list.list_present())\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.987722587459736,\n        82.88787066936494\n    )\n    ])\n    def firm_back_build_test(self, url, lat, lng):\n        \"\"\"\n        Проверка кнопки назад (к зданию)\n        1.Открываем калаут фирмы\n        2.Нажимаем назад\n        3.Проверяем наличие колаута здания\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.pan_to(lat, lng))\n        self.page.console(scripts.SetScripts.set_zoom(17))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        self.page.build_callout.open_firm_by_index(1)\n        self.page.firm_callout.back()\n        self.assertTrue(self.page.build_callout.is_visible)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.987722587459736,\n        82.88787066936494,\n        17,\n        ['2gis.ru', 'novosibirsk', 'center', 82.89, 54.99, 'zoom', '17',\n         'routeTab', 'rsType', 'bus', 'to', 82.89, 54.99, 'Новосибирск, Ватутина, 16']\n    ), (\n        config.aut['local'] + u'/base.html',\n        -33.44449709158904,\n        -70.6516680121422,\n        18,\n        ['2gis.cl', 'santiago', 'center', -70.65, -33.44, 'zoom', '18',\n         'routeTab', 'rsType', 'bus', 'to', -70.65, -33.44, 'Santiago, Avenida Libertador Bernardo O\\'Higgins, 1112']\n    )\n    ])\n    def firm_route_to(self, url, lat, lng, zoom, parts):\n        \"\"\"\n        Проверка ссылки на проехать до\n        1.Открываем калаут фирмы\n        2.Проверяем атирибут ссылки \"Проехать сюда\"\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.pan_to(lat, lng))\n        self.page.console(scripts.SetScripts.set_zoom(zoom))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        self.page.build_callout.open_firm_by_index(1)\n        route = self.page.firm_callout.route_link\n        self.assertTrue(misc.check_route(route.get_attribute('href'), parts))\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265770417218\n    )\n    ])\n    def firm_photo_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия фото у фирмы\n        1.Открыть фирму с фото\n        2.Проверить наличие ссылки\n        3.Проверить url ссылки\n        4.Проверить количество фото\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        photo = self.page.firm_callout.photo\n        self.assertTrue(photo.is_displayed())\n        f = FirmData(firm_id)\n        num = misc.to_int(photo.text)\n        self.assertEqual(f.photo_count(), num)\n        link = links.photo_link(firm_id)\n        self.assertEqual(link, photo.get_attribute('href'))\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    )\n    ])\n    def firm_rating_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия рейтинга у фирмы\n        1.Открыть фирму с рейтингом\n        2.Проверить наличие рейтинга\n        3.Проверить url ссылки\n        4.Проверить количество отзывов\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        stars = self.page.firm_callout.stars\n        reviews = self.page.firm_callout.reviews\n        f = FirmData(firm_id)\n        self.assertTrue(stars.is_displayed())\n        self.assertEqual(reviews.get_attribute('href'), links.reviews_link(firm_id))\n        reviews_count = misc.to_int(reviews.text)\n        self.assertEqual(reviews_count, f.review_count)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.97883,\n        82.872775,\n        141265769707278\n    )\n    ])\n    def firm_address_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия адреса\n        1.Открыть фирму\n        2.Проверить наличие адреса\n        3.Проверить адрес\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        self.assertTrue(self.page.firm_callout.address.is_displayed())\n        self.assertEqual(self.page.firm_callout.address.text, f.address_name)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    )\n    ])\n    def firm_address_comment_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия комментария к адресу\n        1.Открыть фирму с комментарием\n        2.Праверить наличие комментария\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        self.assertTrue(self.page.firm_callout.address.is_displayed())\n        full_adress = misc.address_and_comment(f.address_name, f.address_comment)\n        self.assertEqual(self.page.firm_callout.address.text, full_adress)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    ), (\n        config.aut['local'] + u'/base.html',\n        54.9810307939813,\n        82.87442207336427,\n        141265769728580\n    )\n    ])\n    def firm_telephone_count_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия и количества телефонов\n        1.Открывем фирму\n        2.Получаем количество телефонов (из API)\n        3.Проверяем количество телефонов\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        phones_wapi = f.get_phones()\n        phones_num = len(phones_wapi)\n        phones_callout = self.page.firm_callout.phones()\n        self.assertEqual(phones_num, len(phones_callout))\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    )\n    ])\n    def firm_telephone_comment_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия комментария к телефону\n        1.Открываем фирму\n        2.Проверяем наличия комментария к телефону\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        phones_wapi = f.get_phones()\n        phones_callout = self.page.firm_callout.phones()\n        phone_and_comment = misc.phone_and_comment(phones_wapi[0]['text'], phones_wapi[0]['comment'])\n        self.assertEqual(phones_callout[0].text, phone_and_comment)\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265770417218\n    ), (\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265770847007\n    )\n    ])\n    def firm_website_count_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия ссылки на вебсайт\n        1.Открываем фирму\n        2.Проверяем наличие ссылки на вебсайт\n        3.Проверяем количество ссылок\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        websites_wapi = f.get_websites()\n        websites_callout = self.page.firm_callout.websites()\n        self.assertEqual(len(websites_callout), len(websites_wapi))\n        self.assertEqual(websites_callout[0].text, websites_wapi[0]['text'])\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771881838\n    )])\n    def firm_email_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия email\n        1.Открываем фирму\n        2.Проверяем наличие email\n        3.Проверяем ссыль на мейл\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        email = self.page.firm_callout.email\n        self.assertEqual(email.text, f.get_emails()[0]['text'])\n        self.assertEqual(email.get_attribute('href'), \"mailto:%s\" % f.get_emails()[0]['value'])\n\n    # для простого, списка и таблицы\n    def firm_schedule(self):\n        \"\"\"\n        Проверка наличия расписания\n        1.Открываем фирму\n        2.Проверяем наличие расписания\n        3.Проверяем наличие подсказки\n        \"\"\"\n        pass\n\n    def firm_schedule_wrapper_list(self):\n        \"\"\"\n        Проверка расписания-списка\n        1.Открываем фирму\n        2.Проверяем расписание на сегодня (для всех языков)\n        3.Кликаем в врапер\n        4.Проверяем наличие списка\n        5.Отсутсвие посдсказки на сегодня\n        \"\"\"\n        pass\n\n    def firm_schedule_wrapper_table(self):\n        \"\"\"\n        Проверка расписания-таблицы\n        1.Открываем фирму\n        2.Проверяем расписание на сегодня (для всех языков)\n        3.Кликаем в врапер\n        4.Проверяем наличие таблицы\n        5.Отсутсвие посдсказки на сегодня\n        \"\"\"\n        pass\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    )\n    ])\n    def firm_rubrics_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка рубрик\n        1.Открываем фирму\n        2.Проверяем количество рубрик\n        3.Проверяем порядок(первая, последняя, в сеередине с учетом primary)\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        f = FirmData(firm_id)\n        primary = self.page.firm_callout.primary_rubrics\n        self.assertEqual(primary[0].text, f.get_rubrics_primary()[0]['name'])\n        primary_last = len(f.get_rubrics_primary()) - 1\n        self.assertEqual(primary[primary_last].text, f.get_rubrics_primary()[primary_last]['name'])\n        additional = self.page.firm_callout.additional_rubrics\n        self.assertEqual(additional[0].text, f.get_rubrics_additional()[0]['name'])\n        additional_last = len(f.get_rubrics_additional()) - 1\n        self.assertEqual(additional[additional_last].text,\n                         f.get_rubrics_additional()[additional_last]['name'])\n\n    @dataprovider([(\n        config.aut['local'] + u'/base.html',\n        54.980678320392336,\n        82.89860486984254,\n        141265771060872\n    )\n    ])\n    def firm_scroll_bar_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        Проверка наличия скролл-бара\n        1.Открываем фирму со скроллбаром\n        2.Проверяем его наличия\n        \"\"\"\n        self._open_firm(url, lat, lng, firm_id)\n        self.assertTrue(self.page.firm_callout.scroll.is_displayed())\n\n    def _open_firm(self, url, lat, lng, firm_id):\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(scripts.SetScripts.pan_to(lat, lng))\n        self.page.console(scripts.SetScripts.set_zoom(17))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        self.page.build_callout.open_firm_list()\n        self.page.build_callout.open_firm_by_id(firm_id)\n"
  },
  {
    "path": "functional-tests/tests/geo_clicker_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util.scripts import SetScripts\nfrom classes.util.scripts import GetScripts\nfrom classes.WAPI.dataWorker import GeoData\nfrom classes.WAPI.dataWorker import FirmData\nfrom classes.WAPI.dataWorker import GalleryData\n\n\nclass GeoClicker(MapsAPIBaseTest):\n    \"\"\"\n    Тесты геокликера.\n    В данных тестах проверяется открытие нужных колаутов в соответствии с координатами и зумом.\n    Кроме того для описания переводов используются словари с ключами языков.\n    \"\"\"\n    not_found = {\n        'ru': u\"Это место мы ещё не успели изучить\",\n        'en': u\"We haven't collected info about this place yet\",\n        'cs': u\"O tomto místě zatím nemáme informace\",\n        'es': u\"Todavía no hemos recopilado la información sobre este lugar\",\n        'it': u\"Non disponiamo ancora di informazioni su questo posto\"\n    }\n    city = {\n        'ru': u\"Город\",\n        'en': u\"City\",\n        'cs': u\"Město\",\n        'es': u\"Ciudad\",\n        'it': u\"Сittà\"\n    }\n    district = {\n        'ru': u\"Район\",\n        'en': u\"District\",\n        'cs': u\"Městská část\",\n        'es': u\"Comuna\",\n        'it': u\"Municipalità\"\n    }\n    street = {\n        'ru': u\"Улица\",\n        'en': u\"Street\",\n        'cs': u\"Ulice\",\n        'es': u\"Calle\",\n        'it': u\"Via\"\n    }\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', 54.98, 82.32)\n    ])\n    def callout_unknown_place_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Тест на проверку колаута неизвестного места.\n        1.Перемещаемся к координатам\n        2.Кликаем в центр\n        3.Проверяем открытие калаута\n        4.Проверяем содержимое колаута для всех языков\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.execute_script(SetScripts.pan_to(lat, lng))\n        self.page.map.center_click()\n        self.page.unkown_place.wait_present()\n        self.assertTrue(self.page.unkown_place.is_visible)\n        for lang in self.not_found:\n            self.driver.execute_script(SetScripts.set_lang(lang))\n            header = self.page.unkown_place.header\n            self.assertEqual(self.not_found[lang], header)\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def callout_city_place_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Тест на проверку колаута города.\n        1.Изменяем изначальный зум к 8\n        2.Кликаем в центр\n        3.Проверяем открытие калаута\n        4.Проверяем название города\n        5.Проверяем информацию о геообъекте на всех языках\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.execute_script(SetScripts.set_zoom(8))\n        center = self.driver.execute_script(GetScripts.getCenter)\n        g = GeoData(center, 8)\n        self.page.map.center_click()\n        self.page.place_callout.wait_present()\n        self.assertEqual(self.page.place_callout.header, g.city_name)\n        for lang in self.city:\n            self.driver.execute_script(SetScripts.set_lang(lang))\n            purpose = self.page.place_callout.purpose\n            self.assertEqual(self.city[lang], purpose)\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def callout_district_place_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Тест на проверку колаута района.\n        1.Кликаем в центр\n        2.Проверяем открытие калаута\n        3.Проверяем название района\n        4.Проверяем адрес района\n        5.Проверяем информацию о геообъекте на всех языках\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        center = self.driver.execute_script(GetScripts.getCenter)\n        self.page.map.center_click()\n        self.page.addresed_place_callout.wait_present()\n        zoom = self.driver.execute_script(GetScripts.getZoom)\n        g = GeoData(center, zoom)\n        district_addr = g.place_address\n        callout_addr = self.page.addresed_place_callout.drilldown\n        self.assertEqual(self.page.addresed_place_callout.header, g.district_name)\n        self.assertEqual(callout_addr, district_addr)\n        for lang in self.district:\n            self.driver.execute_script(SetScripts.set_lang(lang))\n            purpose = self.page.addresed_place_callout.purpose\n            self.assertEqual(self.district[lang], purpose)\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', 54.9802611969944, 82.89837956428528)\n\n    ])\n    def callout_building_name_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Проверка здания с названием.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие названия в заголовке\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.driver.execute_script(SetScripts.pan_to(lat, lng))\n        self.driver.execute_script(SetScripts.set_zoom(18))\n        self.page.map.center_click()\n        center = self.driver.execute_script(GetScripts.getCenter)\n        self.page.build_callout.wait_present()\n        g = GeoData(center, 18)\n        self.assertEqual(g.build_name, self.page.build_callout.header)\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', 54.98511556781472, 82.85259425640108)\n\n    ])\n    def callout_building_without_name_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Проверка здания без названия.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие адреса в заголовке\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.set_zoom(18))\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.map.center_click()\n        center = self.page.console(GetScripts.getCenter)\n        g = GeoData(center, 18)\n        self.page.build_callout.wait_present()\n        self.assertEqual(g.build_name, self.page.build_callout.header)\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', 54.98127706190138, 82.88240969181062)\n    ])\n    def callout_attraction_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Проверка калаута достопремичательности.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие калаута\n        6.Проверяем заголовок калаута\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.console(SetScripts.set_zoom(18))\n        self.page.map.center_click()\n        self.page.attraction_callout.wait_present()\n        center = self.page.console(GetScripts.getCenter)\n        g = GeoData(center, 18)\n        self.assertTrue(self.page.attraction_callout.is_visible)\n        self.assertEqual(g.attraction_name, self.page.attraction_callout.header)\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', 54.9833825909448, 82.89679169654848)\n    ])\n    def callout_street_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Проверка калаута улицы.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие калаута\n        5.Проверяем название улицы\n        6.Проверяем расположение улицы\n        7.Проверяем информацию о геообъекте на всех языках\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.console(SetScripts.set_zoom(18))\n        self.page.map.center_click()\n        center = self.page.console(GetScripts.getCenter)\n        g = GeoData(center, 18)\n        self.page.addresed_place_callout.wait_present()\n        self.assertTrue(self.page.addresed_place_callout.is_visible)\n        self.assertEqual(g.street_name, self.page.addresed_place_callout.header)\n        self.assertEqual(self.page.addresed_place_callout.drilldown, g.street_address)\n        for lang in self.street:\n            self.page.console(SetScripts.set_lang(lang))\n            self.assertEqual(self.page.addresed_place_callout.purpose, self.street[lang])\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', '54.986870015252265', '82.8704744636')\n    ])\n    def callout_attraction_text_test(self, url, lat, lng):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        Проверка калаута памятника с текстом.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие калаута\n        6.Проверяем заголовок калаута\n        7.Проверяем наличие враппера\n        8.Проверяем текст\n        9.Кликаем во враппер\n        10.Проверяем отсутствие враппера\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.set_zoom(18))\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.map.center_click()\n        self.page.attraction_callout_wrapped.wait_present()\n        center = self.page.console(GetScripts.getCenter)\n        g = GeoData(center, 18)\n        self.assertTrue(self.page.attraction_callout_wrapped.is_visible)\n        self.assertEqual(g.attraction_name, self.page.attraction_callout.header)\n        self.assertTrue(self.page.attraction_callout_wrapped.wrapper())\n        self.assertEqual(g.attraction_description, self.page.attraction_callout_wrapped.text)\n        self.page.attraction_callout_wrapped.unwrap()\n        self.assertFalse(self.page.attraction_callout_wrapped.wrapper())\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', '54.98088611087379', '82.89719912975313', 141265770417218)\n    ])\n    def callout_poi_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        :param firm_id:\n        Проверка калаута POI.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие калаута\n        6.Проверяем заголовок калаута\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.set_zoom(18))\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.map.center_click()\n        self.page.firm_callout.wait_present()\n        f = FirmData(firm_id)\n        self.assertEqual(self.page.firm_callout.header, f.firm_name)\n\n    @dataprovider([\n        (config.aut['local'] + u'/base.html', '-33.44692090822703', '-70.65750718116762', 14215121979385186)\n    ])\n    def callout_poi_gallery_test(self, url, lat, lng, firm_id):\n        \"\"\"\n        :param url: Адрес страницы\n        :param lat: Широта\n        :param lng: Долгота\n        :param firm_id:\n        Проверка калаута памятника с текстом.\n        1.Перемещаемся к координатам\n        2.Изменяем изначальный зум к 18\n        3.Кликаем в центр\n        4.Проверяем наличие калаута\n        6.Проверяем заголовок калаута\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.console(SetScripts.pan_to(lat, lng))\n        self.page.console(SetScripts.set_zoom(19))\n        self.page.map.center_click()\n        self.page.build_callout.wait_present()\n        g = GalleryData(firm_id)\n        self.assertEqual(self.page.build_callout.header, g.gallery_name)\n"
  },
  {
    "path": "functional-tests/tests/loader_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util.scripts import SetScripts\n\n\nclass LoaderTest(MapsAPIBaseTest):\n    \"\"\"\n    Тесты параметров лоадера mapsapi\n    \"\"\"\n    @dataprovider([\n        (config.aut['local'] + u'/lazyLoad.html')\n    ])\n    def loader_dg_then_add_app_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Тест на проверку ленивой загрузки\n        1.Открываем страницу\n        2.Проверяем отсутсвие скрипта\n        3.Выполняем DG.then\n        4.Проверяем наличие скрипта\n        \"\"\"\n        self.driver.get(url)\n        self.assertTrue(not self.page.sources.app_js_present)\n        self.driver.execute_script(SetScripts.dg_then())\n        self.assertTrue(self.page.sources.app_js_present)\n\n    @dataprovider([\n        (config.aut['local'] + u'/notLazyLoad.html')\n    ])\n    def loader_lazy_false_add_app_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Тест на проверку ленивой загрузки\n        1.Открываем страницу\n        4.Проверяем наличие скрипта\n        \"\"\"\n        self.driver.get(url)\n        self.assertTrue(self.page.sources.app_js_present)\n"
  },
  {
    "path": "functional-tests/tests/marker_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util.scripts import SetScripts\nfrom classes.util.scripts import GetScripts\n\n\nclass Marker(MapsAPIBaseTest):\n\n    @dataprovider([\n        config.aut['local'] + u'/demo.html'\n    ])\n    def marker_to_balloon_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка появления балуна при клике в маркер\n        1.Кликаем в контрол закрытия балуна\n        2.Кликаем в маркер\n        3.Проверяем наличие балуна\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.balloon_crossed.wait_present()\n        self.page.balloon_crossed.close()\n        self.page.marker.wait_present()\n        self.page.marker.click()\n        self.page.balloon_crossed.wait_present()\n        self.assertTrue(self.page.balloon_crossed.is_visible)\n\n    @dataprovider([\n        config.aut['local'] + u'/draggableMarker.html'\n    ])\n    def marker_drag_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка изменения координат маркера\n        1.Драгаем маркер на 10px вниз и вправо\n        2.Проверяем значение абзацев с координатами\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.marker.drag_marker(10, 10)\n        lat = self.page.marker.get_lat()\n        lng = self.page.marker.get_lng()\n        self.assertEqual(lat, '54.981')\n        self.assertEqual(lng, '82.891')\n\n    @dataprovider([\n        config.aut['local'] + u'/markerLabels.html'\n    ])\n    def marker_static_label_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка наличия статического лэйбла у маркера\n        1.Проверяем наличие лейбла у маркера\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.assertEqual(self.page.marker.get_labels()[0].text, u'static')\n\n    @dataprovider([\n        config.aut['local'] + u'/markerLabels.html'\n    ])\n    def marker_dynamic_label_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка наличия стандартного лейбла у маркера\n        1.Наводим мышь на маркер\n        2.Проверяем наличие лейбла\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.marker.hover_marker(1)\n        text = self.page.marker.get_labels()[1].text\n        self.assertEqual(text, u'default')\n\n    @dataprovider([\n        config.aut['local'] + u'/demo.html'\n    ])\n    def marker_program_open_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка возможности програмного открытия маркеров\n        1.Закрываем колаут\n        2.Открываем его программно\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.balloon_crossed.close()\n        self.page.console(SetScripts.open_marker())\n        self.assertTrue(self.page.balloon_crossed.is_visible)\n\n    @dataprovider([\n        config.aut['local'] + u'/groupMarkerEvent.html'\n    ])\n    def marker_group_events_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка обработки событиев у маркеров\n        1.Кликаем в маркер 3\n        2.Проверяем изменение координат карты\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.marker.click(2)\n        center = self.page.console(GetScripts.getCenter)\n        lat = '%.3f' % center['lat']\n        lng = '%.3f' % center['lng']\n        self.assertEqual(lat, self.page.marker.get_lat('marker3'))\n        self.assertEqual(lng, self.page.marker.get_lng('marker3'))\n\n    @dataprovider([\n        config.aut['local'] + u'/groupMarkerEvent.html'\n    ])\n    def marker_group_bounds_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка подстройки границ под положение маркеров\n        1.Выставляем большой зум\n        2.Выполняем fitBounds по маркерам\n        2.Проверяем изменение координат карты и зума\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        self.page.map.set_zoom(17)\n        self.page.console('map.fitBounds(group.getBounds())')\n        center = self.page.console(GetScripts.getCenter)\n        lat = '%.3f' % center['lat']\n        lng = '%.3f' % center['lng']\n        self.assertEqual(lat, '54.914')\n        self.assertEqual(lng, '82.976')\n"
  },
  {
    "path": "functional-tests/tests/ruler_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util import scripts\n\n\nclass Ruler(MapsAPIBaseTest):\n    \"\"\"\n    Тесты на линейку\n    \"\"\"\n    def ruler_control(self):\n        \"\"\"\n        Проверка контрола линеки\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Проверяем наличие вершин линейки\n        4.Кликаем в контрол линейки\n        5.Проверяем отсутсвие вершин линейки\n        \"\"\"\n        pass\n\n    def ruler_two_vertexes(self):\n        \"\"\"\n        Проверка появления ребер линейки\n        1.Кликаем в контрол\n        2.Кликаем в центр карты\n        3.Кликаем левее на 150px\n        4.Проверяем наличие 2х вершин\n        5.Проверяем расстояние\n        5.Проверяем наличие ребра\n        \"\"\"\n        pass\n\n    def ruler_vertex_in_middle(self):\n        \"\"\"\n        Проверка добаления не крайних вершин\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликаем на 300px левее\n        4.Кликаем на 150px правее\n        5.Проверяем наличие 3х вершин\n        6.Проверяем что узел добавился в середину\n        \"\"\"\n        pass\n\n    def ruler_vertex_in_end(self):\n        \"\"\"\n        Проверка добаления точки в конце\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликаем на 150px левее\n        4.Кликаем на 150px левее\n        5.Проверяем наличие 3х вершин\n        6.Проверяем что узел добавился в конец\n        \"\"\"\n        pass\n\n    def ruler_hover_vertex(self):\n        \"\"\"\n        Проверка ховера не полседнего узла\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликаем на 150px левее\n        4.Кликаем на 150px левее\n        5.Перемещаем курсор на 150px правее\n        6.Проверяем появление маркера\n        7.Проверяем расстояние\n        8.Перемещаем на 150px правее\n        9.Провяем наличие маркера\n        10.Проверяем расстояние на 0\n        \"\"\"\n        pass\n\n    def ruler_hover_line(self):\n        \"\"\"\n        Проверка ховера линии\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликаем на 300px левее\n        4.Перемещаем на 150px правее\n        5.Проверяем наличе маркера\n        \"\"\"\n        pass\n\n    def ruler_delete_last(self):\n        \"\"\"\n        Проверка удаления единственного узла\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Ховерим узел\n        4.Кликаем в крест в маркере\n        5.Проверяем отсутствие узлов\n        \"\"\"\n        pass\n\n    def ruler_delete_first_in_two(self):\n        \"\"\"\n        Проверка удаления первого в случае двух узлов\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Удаляем первый узел\n        5.Проверяем что остался только один узел\n        6.Проверяем что узел остался на месте 2го\n        7.Проверяем наличие маркера и значение в '0м'\n        \"\"\"\n        pass\n\n    def ruler_delete_last_in_two(self):\n        \"\"\"\n        Проверка удаления первого в случае двух узлов\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Удаляем второй узел\n        5.Проверяем что остался только один узел\n        6.Проверяем что узел остался на месте 1го\n        7.Проверяем наличие маркера и значение в '0м'\n        \"\"\"\n        pass\n\n    def ruler_delete_last_in_many(self):\n        \"\"\"\n        Проверка удаления последнего (3 и более узла)\n        1.Кликам в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Кликам на 150px левее\n        5.Удаляем последний\n        6.Проверяем что маркер появился на втором\n        \"\"\"\n        pass\n\n    def ruler_delete_first_in_many(self):\n        \"\"\"\n        Проверка удаления первого (3 и более узла)\n        1.Кликам в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Кликам на 150px левее\n        5.Удаляем первый\n        6.Ховерим второй\n        7.Проверяем маркер и '0м'\n        \"\"\"\n        pass\n\n    def ruler_delete_middle_in_many(self):\n        \"\"\"\n        Проверка удаления среднего\n        1.Кликаем в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликаем на 150px левее и 150px выше\n        4.Кликаем на 150px левее и 150px ниже\n        5.Удаляем второй узел\n        6.Проверяем что вершины 2\n        7.Проверяем что ребро 1\n        8.Проверяем расстояние в маркере последней вершины\n        \"\"\"\n        pass\n\n    def ruler_drag_last(self):\n        \"\"\"\n        Проверка драга последнего\n        1.Кликам в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Кликам на 150px левее\n        5.Перемещаем последний узел на 100px\n        6.Проверяем что переместился нужный узел\n        7.Проверяем значения расстояния в последнем маркере\n        \"\"\"\n        pass\n\n    def ruler_drag_first(self):\n        \"\"\"\n        Проверка драга первого\n        1.Кликам в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Кликам на 150px левее\n        5.Перемещаем первий узел на 100px\n        6.Проверяем что переместился нужный узел\n        7.Проверяем значения расстояния в последнем\n        8.Проверяем значение расстояния в первом на 0\n        \"\"\"\n        pass\n\n    def ruler_drag_middle(self):\n        \"\"\"\n        Проверка драга среднего\n        1.Кликам в контрол линейки\n        2.Кликаем в центр карты\n        3.Кликам на 150px левее\n        4.Кликам на 150px левее\n        5.Перемещаем средний узел на 100px вверх\n        6.Проверяем что переместился нужный узел\n        7.Проверяем значения расстояния\n        \"\"\"\n        pass\n"
  },
  {
    "path": "functional-tests/tests/zoom_test.py",
    "content": "# -*- coding: utf-8 -*-\nfrom classes.mapsapi_base_test import MapsAPIBaseTest\nfrom config import config\nfrom lode_runner.dataprovider import dataprovider\nfrom classes.util.scripts import GetScripts\n\n\nclass Zoom(MapsAPIBaseTest):\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def zoomIn_click_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка контрола зума +.\n        1.Получаем зум страницы\n        2.Кликаем в контрол +\n        3.Проверяем что зум стал на единицу больше\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        zoom_start = self.page.console(GetScripts.getZoom)\n        self.page.zoom_control_in.zoom_in_click()\n        zoom_end = self.page.console(GetScripts.getZoom)\n        self.assertEqual(zoom_end - zoom_start, 1)\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def zoomOut_click_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проерка контрола зума -.\n        1.Получаем зум страницы\n        2.Кликаем в контрол -\n        3.Проверяем что зум стал на единицу меньше\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        zoom_start = self.page.console(GetScripts.getZoom)\n        self.page.zoom_control_out.zoom_out_click()\n        zoom_end = self.page.console(GetScripts.getZoom)\n        self.assertEqual(zoom_end - zoom_start, -1)\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def zoomIn_dbclick_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка зума даблкликом.\n        1.Получаем зум страницы\n        2.Кликаем в контрол -\n        3.Проверяем что зум стал на единицу меньше\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        zoom_start = self.page.console(GetScripts.getZoom)\n        self.page.map.center_dbclick()\n        zoom_end = self.page.console(GetScripts.getZoom)\n        self.assertEqual(zoom_end - zoom_start, 1)\n\n    @dataprovider([\n        config.aut['local'] + u'/base.html'\n    ])\n    def zoomIn_shift_select_test(self, url):\n        \"\"\"\n        :param url: Адрес страницы\n        Проверка зума селектом с shift.\n        1.Получаем зум страницы\n        2.Выделяем облость с зажатым shift и отпускаем\n        3.Проверяем изменение зума\n        \"\"\"\n        self.driver.get(url)\n        self.page.map.wait_init()\n        zoom_start = self.page.console(GetScripts.getZoom)\n        self.page.map.zoom_selection()\n        zoom_end = self.page.console(GetScripts.getZoom)\n        self.assertEqual(zoom_end - zoom_start, 1)\n"
  },
  {
    "path": "gulp/deps/build.html",
    "content": "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n    <title>Maps API 2.0 Build Helper</title>\r\n\r\n    <script type=\"text/javascript\" src=\"deps.js\"></script>\r\n\r\n    <script type=\"text/javascript\">\r\n        var buffDeps = deps;\r\n    </script>\r\n\r\n    <script type=\"text/javascript\">\r\n        for (var key in buffDeps) {\r\n            deps[key] = buffDeps[key];\r\n        }\r\n    </script>\r\n\r\n\r\n    <style type=\"text/css\">\r\n        body {\r\n            font: 12px/1.4 Verdana, sans-serif;\r\n            text-align: center;\r\n            padding: 2em 0;\r\n        }\r\n\r\n        #container {\r\n            text-align: left;\r\n            margin: 0 auto;\r\n            width: 780px;\r\n        }\r\n\r\n        #deplist {\r\n            list-style: none;\r\n            padding: 0;\r\n        }\r\n\r\n        #deplist li {\r\n            padding-top: 7px;\r\n            padding-bottom: 7px;\r\n            border-bottom: 1px solid #ddd;\r\n        }\r\n\r\n        #deplist li.heading {\r\n            border: none;\r\n            background: #ddd;\r\n            padding: 5px 10px;\r\n            margin-top: 25px;\r\n            border-radius: 5px;\r\n        }\r\n\r\n        #deplist input {\r\n            float: left;\r\n            margin-right: 5px;\r\n            display: inline;\r\n        }\r\n\r\n        #deplist label {\r\n            float: left;\r\n            width: 160px;\r\n            font-weight: bold;\r\n        }\r\n\r\n        #deplist div {\r\n            display: table-cell;\r\n            height: 1%;\r\n        }\r\n\r\n        #deplist .desc {\r\n        }\r\n\r\n        #deplist .deps {\r\n            color: #777;\r\n        }\r\n\r\n        #command,\r\n        #command2 {\r\n            width: 100%;\r\n        }\r\n\r\n        #toolbar {\r\n            padding-bottom: 10px;\r\n            border-bottom: 1px solid #ddd;\r\n        }\r\n\r\n        h2 {\r\n            margin-top: 2em;\r\n        }\r\n    </style>\r\n</head>\r\n<body>\r\n<div id=\"container\">\r\n    <h1>Maps API 2.0 Build Helper</h1>\r\n\r\n    <p id=\"toolbar\">\r\n        <a id=\"select-all\" href=\"#all\">Select All</a> |\r\n        <a id=\"deselect-all\" href=\"#none\">Deselect All</a>\r\n    </p>\r\n\r\n    <ul id=\"deplist\"></ul>\r\n\r\n    <h2>Building local Maps API 2.0 using Node and Gulp</h2>\r\n    <ol>\r\n        <li><a href=\"http://nodejs.org/#download\">Download and install Node</a></li>\r\n        <li>Run this in the command line:<br/>\r\n\t\t\t<pre><code>npm install -g gulp\r\nnpm install</code></pre>\r\n        </li>\r\n        <li>Run this command inside the app directory: <br/><input type=\"text\" id=\"command\"/>\r\n    </ol>\r\n    <h2>Get URL of custom build Maps API 2.0: </h2>\r\n    <ol>\r\n        <li>URL: <br/><input type=\"text\" id=\"command2\"/></li>\r\n    </ol>\r\n</div>\r\n\r\n<script type=\"text/javascript\">\r\n    var deplist = document.getElementById('deplist'),\r\n            commandInput = document.getElementById('command'),\r\n            commandInput2 = document.getElementById('command2');\r\n\r\n    document.getElementById('select-all').onclick = function () {\r\n        var checks = deplist.getElementsByTagName('input');\r\n        for (var i = 0; i < checks.length; i++) {\r\n            checks[i].checked = true;\r\n        }\r\n        updateCommand();\r\n        return false;\r\n    };\r\n\r\n    document.getElementById('deselect-all').onclick = function () {\r\n        var checks = deplist.getElementsByTagName('input');\r\n        for (var i = 0; i < checks.length; i++) {\r\n            if (!checks[i].disabled) {\r\n                checks[i].checked = false;\r\n            }\r\n        }\r\n        updateCommand();\r\n        return false;\r\n    };\r\n\r\n    function updateCommand() {\r\n        var checks = deplist.getElementsByTagName('input');\r\n        var compsStr = '';\r\n\r\n        for (var i = 0, len = checks.length; i < len; i++) {\r\n            if (checks[i].checked) {\r\n                if (compsStr === '') {\r\n                    compsStr += checks[i].id;\r\n                } else {\r\n                    compsStr += ',' + checks[i].id;\r\n                }\r\n            }\r\n        }\r\n\r\n        commandInput.value = 'gulp build --pkg ' + compsStr;\r\n        commandInput2.value = 'http://maps.api.2gis.ru/2.0/loader.js?pkg=' + compsStr;\r\n    }\r\n\r\n    function inputSelect() {\r\n        this.focus();\r\n        this.select();\r\n    }\r\n    ;\r\n\r\n    commandInput.onclick = inputSelect;\r\n\r\n    function onCheckboxChange() {\r\n        if (this.checked) {\r\n            var depDeps = deps[this.id].deps;\r\n            if (depDeps) {\r\n                for (var i = 0; i < depDeps.length; i++) {\r\n                    var check = document.getElementById(depDeps[i]);\r\n                    if (!check.checked) {\r\n                        check.checked = true;\r\n                        check.onchange();\r\n                    }\r\n                }\r\n            }\r\n        } else {\r\n            var checks = deplist.getElementsByTagName('input');\r\n            for (var i = 0; i < checks.length; i++) {\r\n                var dep = deps[checks[i].id];\r\n                if (!dep.deps) {\r\n                    continue;\r\n                }\r\n                for (var j = 0; j < dep.deps.length; j++) {\r\n                    if (dep.deps[j] === this.id) {\r\n                        if (checks[i].checked) {\r\n                            checks[i].checked = false;\r\n                            checks[i].onchange();\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        updateCommand();\r\n    }\r\n\r\n    for (var name in deps) {\r\n        var li = document.createElement('li');\r\n\r\n        if (deps[name].heading) {\r\n            var heading = document.createElement('li');\r\n            heading.className = 'heading';\r\n            heading.appendChild(document.createTextNode(deps[name].heading));\r\n            deplist.appendChild(heading);\r\n        }\r\n\r\n        var div = document.createElement('div');\r\n\r\n        var label = document.createElement('label');\r\n\r\n        var check = document.createElement('input');\r\n        check.type = 'checkbox';\r\n        check.id = name;\r\n        label.appendChild(check);\r\n        check.onchange = onCheckboxChange;\r\n\r\n        if (name == 'Core') {\r\n            check.checked = true;\r\n            check.disabled = true;\r\n        }\r\n\r\n        label.appendChild(document.createTextNode(name));\r\n        label.htmlFor = name;\r\n\r\n        li.appendChild(label);\r\n\r\n        var desc = document.createElement('span');\r\n        desc.className = 'desc';\r\n        desc.appendChild(document.createTextNode(deps[name].desc));\r\n\r\n        var depText = deps[name].deps && deps[name].deps.join(', ');\r\n        if (depText) {\r\n            var depspan = document.createElement('span');\r\n            depspan.className = 'deps';\r\n            depspan.appendChild(document.createTextNode('Deps: ' + depText));\r\n        }\r\n\r\n        div.appendChild(desc);\r\n        div.appendChild(document.createElement('br'));\r\n        if (depText) {\r\n            div.appendChild(depspan);\r\n        }\r\n\r\n        li.appendChild(div);\r\n\r\n        deplist.appendChild(li);\r\n    }\r\n    updateCommand();\r\n</script>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "gulp/deps/deps.js",
    "content": "var deps = {\n    DGCore: {\n        desc: 'Main module',\n        src: [\n            '../vendors/polyfills/es5.js',\n            '../vendors/polyfills/promise.js',\n            'DGCore/src/DGCore.js',\n            'DGCore/src/DGthen.js',\n            'DGCore/src/DGplugin.js'\n        ],\n        less: {\n            all: [\n                '../node_modules/leaflet/dist/leaflet.css',\n                'DGCore/skin/basic/less/dg-core.less'\n            ]\n        },\n        heading: '2GIS modules'\n    },\n\n    DGAjax: {\n        desc: '2GIS Ajax module',\n        src: ['DGAjax/src/DGAjax.js'],\n        deps: ['DGCore']\n    },\n\n    DGLabel: {\n        desc: '2GIS Label module',\n        src: [\n            'DGLabel/src/DGLabel.js',\n            'DGLabel/src/Marker.DGLabel.js',\n            'DGLabel/src/Path.DGLabel.js',\n            'DGLabel/src/Entrance.DGLabel.js'\n        ],\n        less: {\n            all: ['DGLabel/skin/{skin}/less/dg-label.less']\n        },\n        deps: ['DGCore', 'DGEntrance']\n    },\n\n    DGWkt: {\n        desc: 'WKT parser module',\n        src: [\n            'DGWkt/DGWkt.js'\n        ],\n        deps: ['DGCore']\n    },\n\n    DGPopup: {\n        desc: '2GIS Popup module',\n        src: [\n            'DGPopup/skin/basic/skin.config.js',\n            'DGPopup/src/DGPopup.js'\n        ],\n        less: {\n            all: [\n                'DGPopup/skin/{skin}/less/leaflet.less',\n                '../vendors/baron/baron.css',\n                'DGPopup/skin/{skin}/less/scroller.less',\n                'DGPopup/skin/{skin}/less/dg-popup.less'\n            ],\n            ie: [\n                'DGPopup/skin/{skin}/less/leaflet.ie.less',\n                'DGPopup/skin/{skin}/less/dg-popup.ie.less'\n            ]\n        },\n        deps: ['DGCore']\n    },\n\n    DGCustomization: {\n        desc: 'LeafLet customization module',\n        src: [\n            'DGCustomization/skin/basic/skin.config.js',\n            'DGCustomization/src/DGCustomization.js',\n            'DGCustomization/src/DGMap.js',\n            'DGCustomization/src/DGMap.BaseLayer.js',\n            'DGCustomization/src/DGMap.ApiKeyValidator.js',\n            'DGCustomization/src/DGMap.TilesCheck.js',\n            'DGCustomization/src/DGMap.Drag.js',\n            'DGCustomization/src/DGPolyUtil.js',\n            'DGCustomization/src/DGMobileImprove.js'\n        ],\n        less: {\n            all: [\n                'DGCustomization/skin/{skin}/less/leaflet.less',\n                '../vendors/baron/baron.css',\n                'DGCustomization/skin/{skin}/less/scroller.less',\n                'DGCustomization/skin/{skin}/less/dg-customization.less'\n            ],\n            ie: [\n                'DGCustomization/skin/{skin}/less/leaflet.ie.less',\n                'DGCustomization/skin/{skin}/less/dg-customization.ie.less'\n            ]\n        },\n        deps: ['DGCore', 'DGLocale', 'DGRoundControl', 'DGProjectDetector', 'DGMuseum']\n    },\n\n    DGZoomControl: {\n        desc: '2GIS zoom control module',\n        src: [\n            'DGZoomControl/src/DGZoomControl.js',\n            'DGZoomControl/lang/ru.js',\n            'DGZoomControl/lang/it.js',\n            'DGZoomControl/lang/cs.js',\n            'DGZoomControl/lang/en.js',\n            'DGZoomControl/lang/es.js',\n            'DGZoomControl/lang/ar.js'\n        ],\n        less: {\n            all: [\n                'DGZoomControl/skin/{skin}/less/dg-zoom-control.less'\n            ]\n        },\n        deps: ['DGCore', 'DGLocale', 'DGRoundControl']\n    },\n\n    DGAttribution: {\n        desc: '2GIS copyright',\n        src: [\n            'DGAttribution/src/DGAttribution.js',\n            'DGAttribution/lang/ru.js',\n            'DGAttribution/lang/it.js',\n            'DGAttribution/lang/cs.js',\n            'DGAttribution/lang/en.js',\n            'DGAttribution/lang/es.js',\n            'DGAttribution/lang/ar.js'\n        ],\n        less: {\n            all: [\n                'DGAttribution/skin/{skin}/less/dg-mapcopyright.less'\n            ]\n        },\n        deps: ['DGCore', 'DGDust', 'DGLocale']\n    },\n\n    DGLocale: {\n        desc: 'Localization module',\n        src: [\n            'DGLocale/src/DGDictionary.js',\n            'DGLocale/src/DGLocale.js'\n        ],\n        deps: ['DGCore', 'DGProjectDetector']\n    },\n\n    DGLocation: {\n        desc: 'Location control module',\n        src: [\n            'DGLocation/src/DGLocation.js',\n            'DGLocation/lang/ru.js',\n            'DGLocation/lang/it.js',\n            'DGLocation/lang/cs.js',\n            'DGLocation/lang/en.js',\n            'DGLocation/lang/es.js',\n            'DGLocation/lang/ar.js'\n        ],\n        less: {\n            all: [\n                'DGLocation/skin/{skin}/less/dg-location.less',\n                'DGLocation/skin/{skin}/less/dg-control-round.less'\n            ]\n        },\n        deps: ['DGCore', 'DGLocale', 'DGLabel', 'DGRoundControl']\n    },\n\n    DGFullScreen: {\n        desc: 'Full screen module',\n        src: [\n            'DGFullScreen/src/DGScreenfull.js',\n            'DGFullScreen/src/DGFullScreen.js',\n            'DGFullScreen/lang/ru.js',\n            'DGFullScreen/lang/it.js',\n            'DGFullScreen/lang/cs.js',\n            'DGFullScreen/lang/en.js',\n            'DGFullScreen/lang/es.js',\n            'DGFullScreen/lang/ar.js'\n        ],\n        less: {\n            all: [\n                'DGFullScreen/skin/{skin}/less/dg-fullscreen.less',\n                'DGFullScreen/skin/{skin}/less/dg-control-round.less'\n            ],\n            ie: ['DGFullScreen/skin/{skin}/less/dg-fullscreen.ie.less']\n        },\n        deps: ['DGCore', 'DGLocale', 'DGRoundControl']\n    },\n\n    DGProjectDetector: {\n        desc: '2GIS project detector module',\n        src: ['DGProjectDetector/src/DGProjectDetector.js'],\n        deps: ['DGCore', 'DGWkt']\n    },\n\n    DGMeta: {\n        desc: '2GIS additional metalayers support',\n        src: [\n            'DGMeta/src/DGMeta.Layer.js',\n            'DGMeta/src/DGMeta.Origin.js'\n        ],\n        deps: ['DGAjax', 'DGCore', 'DGCustomization', 'DGWkt', 'DGProjectDetector']\n    },\n\n    DGPoi: {\n        desc: '2GIS POI module',\n        src: ['DGPoi/src/DGPoi.js'],\n        deps: ['DGMeta', 'DGLabel']\n    },\n\n    DGGeoclicker: {\n        desc: '2GIS Geoclicker',\n        less: {\n            all: [\n                'DGGeoclicker/skin/{skin}/less/dg-building-callout.less',\n                'DGGeoclicker/skin/{skin}/less/dg-map-geoclicker.less',\n                'DGGeoclicker/skin/{skin}/less/dg-preloader.less',\n                'DGGeoclicker/skin/{skin}/less/dg-popup.less',\n                'DGGeoclicker/skin/{skin}/less/dg-firm-card.less',\n                'DGGeoclicker/skin/{skin}/less/dg-schedule.less',\n                'DGGeoclicker/skin/{skin}/less/dg-link.less'\n            ],\n            ie: [\n                'DGGeoclicker/skin/{skin}/less/dg-popup.ie.less',\n                'DGGeoclicker/skin/{skin}/less/dg-schedule.ie.less'\n            ]\n        },\n        src: [\n            'DGGeoclicker/src/DGGeoclicker.js',\n            'DGGeoclicker/src/ClampHelper.js',\n            'DGGeoclicker/src/provider/Provider.js',\n            'DGGeoclicker/src/provider/CatalogApi.js',\n            'DGGeoclicker/src/handler/Handler.js',\n            'DGGeoclicker/src/handler/Default.js',\n            'DGGeoclicker/src/handler/ApiError.js',\n            'DGGeoclicker/src/handler/CityArea.js',\n            'DGGeoclicker/src/handler/House.js',\n            'DGGeoclicker/src/handler/House.View.js',\n            'DGGeoclicker/src/handler/POI.js',\n            'DGGeoclicker/src/handler/Sight.js',\n            'DGGeoclicker/src/View.js',\n            'DGGeoclicker/src/Controller.js',\n            'DGGeoclicker/lang/it.js',\n            'DGGeoclicker/lang/ru.js',\n            'DGGeoclicker/lang/en.js',\n            'DGGeoclicker/lang/cs.js',\n            'DGGeoclicker/lang/es.js',\n\n            '../vendors/firmcard/src/FirmCard.js',\n            '../vendors/firmcard/src/FirmCard.DataHelper.js',\n            '../vendors/firmcard/src/FirmList.js',\n            '../vendors/firmcard/src/Schedule.js',\n            '../vendors/firmcard/src/Dictionary.js'\n        ],\n        deps: ['DGAjax', 'DGCore', 'DGDust', 'DGLocale', 'DGPoi', 'DGEntrance', 'DGProjectDetector', 'DGPopup']\n    },\n\n    DGDust: {\n        desc: '2GIS Template',\n        src: [\n            'DGDust/src/DGDust.js'\n        ],\n        deps: ['DGCore']\n    },\n\n    DGEntrance: {\n        desc: '2GIS Entrances',\n        src: [\n            'DGEntrance/src/DGMetric.js',\n            'DGEntrance/src/DGVertexTransform.js',\n            'DGEntrance/src/DGArrowPathTransform.js',\n            'DGEntrance/src/DGArrowTipTransform.js',\n            'DGEntrance/src/DGComplexPath.js',\n            'DGEntrance/src/DGRenderer.js',\n            'DGEntrance/src/DGBezierCurves.js',\n            'DGEntrance/src/DGAnimation.js',\n            'DGEntrance/src/DGEntrance.js',\n            'DGEntrance/src/DGEntranceArrow.js',\n            'DGEntrance/src/DGEntranceArrowShape.js'\n        ],\n        deps: ['DGCore', 'DGWkt', 'DGProjectDetector']\n    },\n\n\n    DGRoundControl: {\n        desc: 'Control helper',\n        src: ['DGRoundControl/src/DGRoundControl.js'],\n        less: {\n            all: ['DGRoundControl/skin/{skin}/less/dg-control-round.less']\n        },\n        deps: ['DGCore', 'DGLocale']\n    },\n\n    DGTraffic: {\n        desc: 'Traffic',\n        src: [\n            'DGTraffic/src/DGTraffic.js',\n            'DGTraffic/lang/ru.js',\n            'DGTraffic/lang/it.js',\n            'DGTraffic/lang/cs.js',\n            'DGTraffic/lang/es.js',\n            'DGTraffic/lang/en.js',\n            'DGTraffic/lang/ar.js'\n        ],\n        deps: ['DGMeta', 'DGLabel', 'DGLocale']\n    },\n\n    DGTrafficControl: {\n        desc: 'Traffic control module',\n        src: [\n            'DGTrafficControl/src/Control.Traffic.js',\n            'DGTrafficControl/lang/ru.js',\n            'DGTrafficControl/lang/it.js',\n            'DGTrafficControl/lang/cs.js',\n            'DGTrafficControl/lang/es.js',\n            'DGTrafficControl/lang/en.js',\n            'DGTrafficControl/lang/ar.js'\n        ],\n        less: {\n            all: [\n                'DGTrafficControl/skin/{skin}/less/dg-control-round.less',\n                'DGTrafficControl/skin/{skin}/less/dg-traffic-control.less'\n            ],\n            ie: ['DGTrafficControl/skin/{skin}/less/dg-traffic-control.ie.less']\n        },\n        deps: ['DGTraffic', 'DGRoundControl']\n    },\n\n    DGRuler: {\n        desc: 'Ruler module',\n        src: [\n            'DGRuler/src/Ruler.js',\n            'DGRuler/src/LayeredMarker.js',\n            'DGRuler/src/GeometryStyles.js',\n            'DGRuler/lang/ru.js',\n            'DGRuler/lang/it.js',\n            'DGRuler/lang/cs.js',\n            'DGRuler/lang/es.js',\n            'DGRuler/lang/en.js',\n            'DGRuler/lang/ar.js'\n        ],\n        less: {\n            all: ['DGRuler/skin/{skin}/less/dg-ruler.less'],\n            ie: ['DGRuler/skin/{skin}/less/dg-ruler.ie.less']\n        },\n        deps: ['DGCore', 'DGLocale']\n    },\n\n    DGRulerControl: {\n        desc: 'Ruler control module',\n        src: [\n            'DGRulerControl/src/Control.Ruler.js',\n            'DGRulerControl/lang/ru.js',\n            'DGRulerControl/lang/it.js',\n            'DGRulerControl/lang/cs.js',\n            'DGRulerControl/lang/es.js',\n            'DGRulerControl/lang/en.js',\n            'DGRulerControl/lang/ar.js'\n        ],\n        less: {\n            all: ['DGRulerControl/skin/{skin}/less/dg-control-round.less']\n        },\n        deps: ['DGRuler', 'DGRoundControl']\n    },\n\n    DGMuseum: {\n        desc: 'Museum module',\n        src: [\n            'DGMuseum/src/DGMuseum.js'\n        ],\n        less: {\n            all: ['DGMuseum/skin/{skin}/less/dg-museum.less']\n        }\n    }\n};\n\nif (typeof module !== 'undefined' && module.exports) {\n    module.exports = deps;\n}\n"
  },
  {
    "path": "gulp/deps/index.js",
    "content": "var fs = require('fs');\nvar glob = require('glob');\nvar path = require('path');\nvar imageSize = require('image-size');\n\nvar init = function(config) {\n    var packages = config.packages;\n\n    // Generates a list of modules by pkg\n    function getModulesList(pkg, modules, isLeaflet) { //(String|Null)->Array\n        modules = modules || config.source.deps;\n\n        var modulesListOrig = [];\n        var modulesListRes = [];\n        var loadedModules = {};\n\n        if (typeof pkg === 'boolean') {\n            throw new Error('pkg param can\\'t be empty');\n        }\n\n        // Package name with no empty modules list on packs.js (example: 'base')\n        if (pkg && pkg in packages && packages[pkg].modules.length > 0) {\n            modulesListOrig = packages[pkg].modules;\n\n            // Modules list (example: 'Core,JSONP,TileLayer')\n        } else if (pkg && pkg.indexOf(',') !== -1) {\n            modulesListOrig = pkg.split(',');\n\n            // Modules single (example: 'Core')\n        } else if (pkg && pkg in modules) {\n            modulesListOrig.push(pkg);\n\n            // Others (null / full package)\n        } else {\n            modulesListOrig = modulesListOrig.concat(Object.keys(modules));\n        }\n\n        if (!isLeaflet) {\n            modulesListOrig = modulesListOrig.concat(config.coreModules);\n        }\n\n        function processModule(name) {\n            var module = modules[name];\n\n            if (module && module.deps) {\n                module.deps.forEach(processModule);\n            }\n\n            if (!loadedModules[name]) {\n                modulesListRes.push(name);\n                loadedModules[name] = true;\n            }\n        }\n\n        modulesListOrig.forEach(processModule);\n\n        return modulesListRes;\n    }\n\n    function getJSFiles(options) {\n        options = options || {};\n\n        var source = config[options.source || 'source'];\n        var modules = source.deps;\n        var sourcePath = source.path;\n        var isLeaflet = options.source === 'leaflet';\n\n        return getModulesList(options.pkg, modules, isLeaflet)\n            .map(function(name) {\n                return modules[name];\n            })\n            .map(function(module) {\n                return module.src;\n            })\n            .reduce(function(array, items) {\n                return array.concat(items);\n            })\n            .filter(function(item, index, list) { //filter dublicates\n                return list.indexOf(item) == index;\n            })\n            .map(function(file) {\n                return sourcePath + file;\n            });\n    }\n\n    function getCSSFiles(options) {\n        options = options || {};\n\n        var source = config[options.source || 'source'];\n        var modules = source.deps;\n        var sourcePath = source.path;\n        var skin = options.skin || config.appConfig.defaultSkin;\n\n        return getModulesList(options.pkg, modules)\n            .map(function(name) {\n                return modules[name];\n            })\n            .map(function(module) {\n                return module[options.type || 'less'];\n            })\n            .filter(Boolean)\n            .reduce(function(array, item) {\n                var items = [];\n\n                if (!options.excludeBaseCss && item.all) {\n                    items.push(item.all);\n                }\n\n                if (options.ie8 && item.ie) {\n                    items.push(item.ie);\n                }\n\n                return array.concat(items);\n            }, [])\n            .reduce(function(array, items) {\n                return array.concat(items);\n            }, [])\n            .reduce(function(array, item) { // if css have skin, we add basic theme\n                if (item.indexOf('{skin}') !== -1) {\n                    array.push(item.replace('{skin}', 'basic'));\n                }\n\n                return array.concat(item);\n            }, [])\n            .map(function(file) { // add selected theme\n                return file.replace('{skin}', skin);\n            })\n            .map(function(file) {\n                return sourcePath + file;\n            })\n            .filter(fs.existsSync);\n    }\n\n    function getImgGlob(options) {\n        options = options || {};\n\n        var source = config[options.source || 'source'];\n        var modules = source.deps;\n\n        return getModulesList(options.pkg, modules)\n            .map(function(name) {\n                return 'src/' + name + '/**/img/**/*.{png,gif,jpg,jpeg,svg}';\n            });\n    }\n\n    // Build string with Less variables and imports\n    function lessHeader(options) {\n        options = options || {};\n\n        var header = '';\n\n        if (options.variables) {\n            Object.keys(options.variables).forEach(function(varableName) {\n                header = header + '\\n' + '@' + varableName + ': ' + options.variables[varableName] + ';';\n            });\n        }\n\n        var importsBase = '';\n\n        if (typeof options.importsBase === 'string' && options.importsBase.length) {\n            importsBase = options.importsBase.replace(/\\/*$/, '/');\n        }\n\n        if (options.imports) {\n            for (var i = 0, type = '', imoportPath = ''; i < options.imports.length; i++) {\n                type = options.imports[i].replace(/^.*\\:/, '');\n                imoportPath = options.imports[i].replace(/\\:.*$/, '');\n\n                header = header + '\\n' + '@import (' + type + ') \\'' + importsBase + imoportPath + '\\';';\n            }\n        }\n\n        return header;\n    }\n\n    // Scans the project for skins directories to get skins names\n    function getSkinsList() {\n        var skinsDirectories = glob.sync(__dirname + '/../../src/**/skin/*');\n        var skins = [];\n\n        skinsDirectories.forEach(function(directory) {\n            var skinName = path.basename(directory);\n\n            if (skins.indexOf(skinName) === -1) {\n                skins.push(skinName);\n            }\n        });\n\n        return skins;\n    }\n\n    // Gets images per skin formats statistics\n    function getImagesFilesStats(skins) {\n        skins = skins || getSkinsList();\n\n        var perSkinStats = {};\n        var imgModulesGlobs = getImgGlob();\n\n        imgModulesGlobs.forEach(function(imgGlob) {\n            glob.sync(imgGlob).forEach(function(imagePath) {\n                var skinName = imagePath.split('/')[3];\n                var extname = path.extname(imagePath);\n                var name = path.basename(imagePath, extname);\n                var imageDimensions;\n\n                if (skins.indexOf(skinName) === -1) {\n                    return; // continue\n                }\n\n                if (!(skinName in perSkinStats)) {\n                    perSkinStats[skinName] = {};\n                }\n\n                if (!(name in perSkinStats[skinName])) {\n                    perSkinStats[skinName][name] = {};\n                }\n\n                if (extname === '.svg') {\n                    perSkinStats[skinName][name].hasVectorVersion = true;\n                } else {\n                    perSkinStats[skinName][name].extension = extname.replace('.', '');\n\n                    imageDimensions = imageSize(imagePath);\n\n                    perSkinStats[skinName][name].width = imageDimensions.width;\n                    perSkinStats[skinName][name].height = imageDimensions.height;\n                }\n            });\n        });\n\n        return perSkinStats;\n    }\n\n    // Analyzes Less, gets images usage statistics per skin\n    function getImagesUsageStats(skins) {\n        skins = skins || getSkinsList();\n\n        var perSkinStats = {};\n\n        skins.forEach(function(skinName) {\n            var stats = {};\n\n            var statsFilePath = __dirname + '/../tmp/less/images-usage-statistics.' + skinName + '.less';\n            var statsFileContent = fs.readFileSync(statsFilePath).toString();\n            var preparedStatsFileContent = statsFileContent.slice(6).replace(/\\;/g, ','); // 6 is 'stats '.length\n\n            var rawStats = Function('return ' + preparedStatsFileContent + ';')();\n\n            stats.repeatable = rawStats.repeatable.split(',');\n            stats.notRepeatableSprited = rawStats.notRepeatableSprited.split(',');\n            stats.notRepeatableNotSprited = rawStats.notRepeatableNotSprited.split(',');\n            // Repeatable images can be used as no-repeatable images,\n            // so we should exclude repeatable images from no-repeatable images list\n            stats.notRepeatableSprited = rawStats.notRepeatableSprited.split(',').filter(function(name) {\n                return stats.repeatable.indexOf(name) === -1;\n            });\n\n            perSkinStats[skinName] = stats;\n        });\n\n        return perSkinStats;\n    }\n\n    return {\n        getModulesList: getModulesList,\n\n        getJSFiles: getJSFiles,\n        getCSSFiles: getCSSFiles,\n\n        lessHeader: lessHeader,\n\n        getSkinsList: getSkinsList,\n\n        getImagesFilesStats: getImagesFilesStats,\n        getImagesUsageStats: getImagesUsageStats,\n\n        getImgGlob: getImgGlob\n    };\n};\n\n\nif (typeof module !== 'undefined' && module.exports) {\n    module.exports = init;\n}\n"
  },
  {
    "path": "gulp/deps/packs.js",
    "content": "var packages = {\n\n    basic: {\n        name: 'Basic package',\n        desc: 'Provides basic functionality: map, markers, popups, geometries',\n        modules: ['DGCustomization', 'DGFullScreen', 'DGAttribution', 'DGAjax', 'DGPopup', 'DGZoomControl']\n    },\n\n    full: {\n        name: 'Full package',\n        desc: 'Complete package. Includes all the features of 2GIS Maps API',\n        modules: []\n    }\n\n};\n\nif (typeof module !== 'undefined' && module.exports) {\n    module.exports = packages;\n}\n"
  },
  {
    "path": "gulp/sprite-template.mustache",
    "content": "\n{{#items}}\n.spriteData('{{name}}') {\n    @backgroundImage: '{{{escaped_image}}}';\n    @backgroundPosition: {{px.offset_x}} {{px.offset_y}};\n    @backgroundPositionLeft: {{px.offset_x}};\n    @backgroundPositionTop: {{px.offset_y}};\n    @width: {{px.width}};\n    @height: {{px.height}};\n    @totalWidth: {{px.total_width}};\n    @totalHeight: {{px.total_height}};\n    }\n\n.isSprited(@name) when (@name = '{{name}}') {\n    @isSprited: true;\n    }\n\n{{/items}}\n"
  },
  {
    "path": "gulp/tasks/build.js",
    "content": "var { buildEnd } = require('../util/buildEnd.js');\nvar config = require('../../app/config.js');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\nvar { clean } = require('./clean');\nvar { buildStyles } = require('./buildStyles');\nvar { buildScripts } = require('./buildScripts');\nvar { doc } = require('./doc');\nvar { loader } = require('./loader');\nvar { copyAssets } = require('./copyAssets');\nvar { copyIndexPage } = require('./copyIndexPage');\n\nfunction npmConfigModify(done) {\n    if (argv.npm) {\n        // Disable local config for npm builds\n        config.appConfig = config.mainConfig;\n\n        // Make npm builds https-only\n        config.appConfig.protocol = 'https:';\n    }\n    done();\n}\n\nexports.build = gulp.series(npmConfigModify, clean, buildStyles, gulp.parallel(\n    buildScripts,\n    doc,\n    loader,\n    copyAssets,\n    copyIndexPage\n), buildEnd);\n"
  },
  {
    "path": "gulp/tasks/buildLeaflet.js",
    "content": "var concat = require('gulp-concat');\nvar gulp = require('gulp');\nvar log = require('fancy-log');\nvar argv = require('minimist')(process.argv.slice(2));\nvar path = require('path');\n\nvar config = require('../../app/config.js');\nvar deps = require('../deps')(config);\n\nfunction getLeafletFiles(compsBase32) {\n    var memo = {},\n        deps = require('leaflet/build/deps.js').deps,\n        comps;\n\n    if (compsBase32) {\n        comps = parseInt(compsBase32, 32).toString(2).split('');\n        log('Managing dependencies...');\n    }\n\n    function addFiles(srcs) {\n        for (var j = 0, len = srcs.length; j < len; j++) {\n            memo[srcs[j]] = true;\n        }\n    }\n\n    for (var i in deps) {\n        if (comps) {\n            if (parseInt(comps.pop(), 2) === 1) {\n                log(' * ' + i);\n                addFiles(deps[i].src);\n            } else {\n                log('   ' + i);\n            }\n        } else {\n            addFiles(deps[i].src);\n        }\n    }\n\n    log('\\n');\n\n    var files = [];\n\n    for (var src in memo) {\n        files.push('src/' + src);\n    }\n\n    return files;\n}\n\n// leaflet-custom-build parameter for set id of leaflet build. See more in leaflet/build/build.html\nexports.buildLeaflet = function buildLeaflet() {\n    var leafletCustomBuild = argv['leaflet-custom-build'];\n    return (leafletCustomBuild ? gulp.src(getLeafletFiles(leafletCustomBuild).map(function (file) {\n        return path.resolve(path.join(__dirname, '../../node_modules/leaflet/', file))\n    })) : gulp.src(deps.getJSFiles({source: 'leaflet'})))\n        .pipe(concat('leaflet-src.js'))\n        .pipe(gulp.dest('node_modules/leaflet/dist/'));\n};\n"
  },
  {
    "path": "gulp/tasks/buildScripts.js",
    "content": "var config = require('../../app/config.js');\nvar stat = require('../util/stat');\nvar source = require('vinyl-source-stream');\nvar derequire = require('gulp-derequire');\nvar browserify = require('browserify');\nvar buffer = require('vinyl-buffer');\nvar uglify = require('gulp-uglify');\nvar header = require('gulp-header');\nvar mergeStream = require('merge-stream');\nvar gulpif = require('gulp-if');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\nvar path = require('path');\nvar map = require('map-stream');\nvar insert = require('gulp-insert');\nvar sourcemaps = require('gulp-sourcemaps');\nvar { concatScripts } = require('./concatScripts');\n\nfunction buildScripts() {\n    var isCustom = argv.pkg || argv.skin;\n    var packages;\n\n    if (global.isTestBuild) {\n        packages = ['full'];\n    } else if (isCustom) {\n        packages = [argv.pkg || 'full'];\n    } else {\n        packages = Object.keys(config.packages);\n    }\n\n    return mergeStream(packages.map(function(pkg) {\n        var name = 'script.' + (!isCustom ? pkg + '.' : '') + 'js';\n        var src = path.join('gulp', 'tmp', 'js', name);\n\n        var bundler = browserify(src, {\n            debug: !argv.release,\n            entry: true,\n            standalone: argv.npm ? 'DG': false,\n            cache: {},\n            packageCache: {},\n            sourceMaps: argv.release\n        });\n\n        bundler.transform('browserify-css', {\n            autoInject: true,\n            minify: true\n        });\n\n        return bundler.bundle()\n            .pipe(source(name))\n            .pipe(buffer())\n            .pipe(derequire())\n            .pipe(gulpif(argv.release, sourcemaps.init()))\n            .pipe(gulpif(argv.release, uglify()))\n            .pipe(gulpif(argv.release, header(config.copyright)))\n            .pipe(gulpif(\n                Boolean(argv['leaflet-custom-build']),\n                insert.prepend('// leaflet-custom-build: ' + argv['leaflet-custom-build'] + '\\n')\n            ))\n            .pipe(gulpif(argv.release, sourcemaps.write('./')))\n            .pipe(map(stat.save))\n            .pipe(gulp.dest('dist/js/'));\n    }));\n}\n\nexports.buildScripts = gulp.series(concatScripts, buildScripts);\n"
  },
  {
    "path": "gulp/tasks/buildStyles.js",
    "content": "var gulp = require('gulp');\n\nvar { destCSS } = require('../util/destCSS');\nvar { collectImagesStats } = require('./collectImagesStats');\nvar { generateSprites } = require('./generateSprites');\nvar { imageMinify } = require('./imageMinify');\n\nexports.buildStyles = gulp.series(gulp.parallel(\n    collectImagesStats,\n    generateSprites,\n    imageMinify\n), destCSS);\n"
  },
  {
    "path": "gulp/tasks/buildTest.js",
    "content": "var gulp = require('gulp');\n\nvar { buildEnd } = require('../util/buildEnd.js');\nvar { buildStyles } = require('./buildStyles');\nvar { buildScripts } = require('./buildScripts');\nvar { doc } = require('./doc');\nvar { clean } = require('./clean');\nvar { loader } = require('./loader');\nvar { copyAssets } = require('./copyAssets');\nvar { copyIndexPage } = require('./copyIndexPage');\n\nfunction enableTestBuild(done) {\n    global.isTestBuild = true;\n    done();\n}\n\nexports.buildTest = gulp.series(enableTestBuild, clean, gulp.parallel(\n    buildScripts,\n    buildStyles,\n    doc,\n    loader,\n    copyAssets,\n    copyIndexPage\n), buildEnd);\n"
  },
  {
    "path": "gulp/tasks/clean.js",
    "content": "var del = require('del');\n\nexports.clean = function clean() {\n    return del(['dist', 'gulp/tmp']);\n};\n"
  },
  {
    "path": "gulp/tasks/collectImagesStats.js",
    "content": "var gulp = require('gulp');\nvar fs = require('fs');\nvar mkdirp = require('mkdirp');\n\nvar config = require('../../app/config');\nvar deps = require('../deps')(config);\nvar { copyImg } = require('./copyImg');\n\nfunction collectImagesStats(cb) {\n    var skins = deps.getSkinsList();\n    var imagesStatsPerSkin = deps.getImagesFilesStats(skins);\n\n    mkdirp.sync('./gulp/tmp');\n    mkdirp.sync('./gulp/tmp/less');\n\n    skins.forEach(function(skinName) {\n        var skinImagesFilesStats = imagesStatsPerSkin[skinName];\n\n        var statisticsObject;\n        var statisticsString = '';\n\n        var imageExtension;\n\n        var originalImageName;\n        var originalImageStatisticObject;\n\n        for (var imageName in skinImagesFilesStats) {\n            originalImageName = imageName.replace(/@\\d+(\\.\\d+)?x/, '');\n\n            statisticsObject = skinImagesFilesStats[imageName];\n            originalImageStatisticObject = skinImagesFilesStats[originalImageName];\n\n            imageExtension = (typeof statisticsObject.extension === 'undefined') ? 'svg' : statisticsObject.extension;\n\n            statisticsString += '.imageData(\\'' + imageName + '\\') { ' +\n                '@filename: \\'' + imageName + '\\'; ' +\n                '@extension: \\'' + imageExtension + '\\'; ' +\n                '@hasVectorVersion: ' + !!statisticsObject.hasVectorVersion + '; ' +\n                '@width: ' + statisticsObject.width + 'px; ' +\n                '@height: ' + statisticsObject.height + 'px; ' +\n                '@originalWidth: ' + originalImageStatisticObject.width + 'px; ' +\n                '@originalHeight: ' + originalImageStatisticObject.height + 'px; ' +\n                '}\\n';\n        }\n\n        fs.writeFileSync('./gulp/tmp/less/images-files-statistics.' + skinName + '.less', statisticsString);\n    });\n\n    cb();\n}\n\nexports.collectImagesStats = gulp.series(copyImg, collectImagesStats);\n"
  },
  {
    "path": "gulp/tasks/collectImagesUsageStats.js",
    "content": "var header = require('gulp-header');\nvar rename = require('gulp-rename');\nvar mergeStream = require('merge-stream');\nvar less = require('gulp-less');\nvar gulp = require('gulp');\nvar path = require('path');\nvar glob = require('glob');\n\nvar error = require('../util/error');\nvar config = require('../../app/config');\nvar deps = require('../deps')(config);\n\nexports.collectImagesUsageStats = function collectImagesUsageStats() {\n    var skins = deps.getSkinsList();\n\n    var imagesBasePath = path.resolve(__dirname + '/../../dist/img');\n\n    var statisticsStreams = skins.map(function(skinName) {\n        var skinLessFiles = glob.sync('./src/**/' + skinName + '/less/*.less');\n\n        skinLessFiles.unshift('./src/less/mixins.images-usage-statistics.less');\n        skinLessFiles.unshift('./src/less/mixins.ie8.less');\n\n        skinLessFiles = skinLessFiles.map(function(lessFilePath) {\n            return lessFilePath + ':reference';\n        });\n\n        return gulp.src('src/less/images-usage-statistics.less')\n            .pipe(error.handle())\n            .pipe(header(deps.lessHeader({\n                variables: {\n                    baseURL: '\\'__BASE_URL__\\'',\n                    spritesURL: '\\'__BASE_URL__\\'',\n\n                    ie8: true,\n                    useSprites: true,\n                    mobile: false,\n                    retina: false,\n\n                    skinName: skinName,\n\n                    imagesBasePath: '\\'' + imagesBasePath + '\\''\n                },\n                imports: skinLessFiles\n            })))\n            .pipe(less())\n            .pipe(rename('images-usage-statistics.' + skinName + '.less'))\n            .pipe(gulp.dest('gulp/tmp/less/'));\n    });\n\n    return mergeStream(statisticsStreams);\n};\n"
  },
  {
    "path": "gulp/tasks/concatScripts.js",
    "content": "var sourcemaps = require('gulp-sourcemaps');\nvar streamqueue = require('streamqueue');\nvar concat = require('gulp-concat');\nvar footer = require('gulp-footer');\nvar mergeStream = require('merge-stream');\nvar gulpif = require('gulp-if');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\n\nvar config = require('../../app/config.js');\nvar deps = require('../deps')(config);\n\nvar templateStream = require('../util/templateStream');\nvar projectList = require('../util/projectList');\nvar error = require('../util/error');\nvar { loadProjectList } = require('./loadProjectList');\nvar { buildLeaflet } = require('./buildLeaflet');\n\nfunction getStyleRequireStatement(pack, skin) {\n    return 'require(\"../../../dist/css/styles.' + pack + '.' + skin + '.css\");';\n}\n\nfunction concatScripts() {\n    var isCustom = argv.pkg || argv.skin;\n    var packages;\n\n    if (global.isTestBuild) {\n        packages = ['full'];\n    } else if (isCustom) {\n        packages = [argv.pkg || 'full'];\n    } else {\n        packages = Object.keys(config.packages);\n    }\n\n    if (global.isTestBuild) {\n        // Disable tile loading in test build\n        config.appConfig.tileServer = '';\n    }\n\n    return mergeStream(packages.map(function(pkg) {\n        var stream = streamqueue(\n                {objectMode: true},\n                gulp.src(deps.getJSFiles({pkg: pkg}), {base: '.'}),\n                templateStream(pkg)\n            )\n            .pipe(error.handle())\n            .pipe(gulpif(!argv.release, sourcemaps.init()))\n            .pipe(concat('script.' + (!isCustom ? pkg + '.' : '') + 'js'))\n            .pipe(footer(projectList.get()))\n            .pipe(footer('DG.config = ' + JSON.stringify(config.appConfig) + ';'));\n\n        if (argv.npm) {\n            stream = stream.pipe(footer(getStyleRequireStatement(pkg, 'dark')));\n        }\n\n        return stream\n            .pipe(gulpif(!argv.release, sourcemaps.write()))\n            .pipe(gulp.dest('gulp/tmp/js'));\n    }));\n}\n\nconst projectListTask = argv['project-list'] !== false ? [loadProjectList] : [];\n\nexports.concatScripts = gulp.series(gulp.parallel(\n    ...projectListTask,\n    buildLeaflet\n), concatScripts);\n"
  },
  {
    "path": "gulp/tasks/copyAssets.js",
    "content": "var gulp = require('gulp');\nvar error = require('../util/error');\n\nexports.copyAssets = function copyAssets() {\n    return gulp.src(['assets/**/*'])\n        .pipe(error.handle())\n        .pipe(gulp.dest('dist'));\n};\n"
  },
  {
    "path": "gulp/tasks/copyImg.js",
    "content": "var rename = require('gulp-rename');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\n\nvar error = require('../util/error');\nvar config = require('../../app/config');\nvar deps = require('../deps')(config);\n\nexports.copyImg = function copyImg() {\n    return gulp.src(deps.getImgGlob(argv))\n        .pipe(error.handle())\n        .pipe(rename(function(p) {\n            p.dirname = '';\n        }))\n        .pipe(gulp.dest('dist/img'));\n};\n"
  },
  {
    "path": "gulp/tasks/copyIndexPage.js",
    "content": "var gulp = require('gulp');\nvar error = require('../util/error');\n\nexports.copyIndexPage = function copyIndexPage() {\n    return gulp.src(['app/index.html'])\n        .pipe(error.handle())\n        .pipe(gulp.dest('dist'));\n};\n"
  },
  {
    "path": "gulp/tasks/dev.js",
    "content": "var gulp = require('gulp');\nvar { build } = require('./build');\nvar { server } = require('./server');\nvar { watch } = require('./watch');\n\nexports.dev = gulp.series(build, server, watch);\n"
  },
  {
    "path": "gulp/tasks/doc.js",
    "content": "var gendoc = require('../util/gendoc');\nvar config = require('../../app/config');\n\nexports.doc = function doc(done) {\n    var doc = config.doc;\n\n    gendoc.generateDocumentation(doc.menu, doc.input, doc.output);\n    done();\n};\n"
  },
  {
    "path": "gulp/tasks/generateSprites.js",
    "content": "var spritesmith = require('gulp.spritesmith');\nvar mergeStream = require('merge-stream');\nvar gulp = require('gulp');\n\nvar error = require('../util/error');\nvar config = require('../../app/config');\nvar deps = require('../deps')(config);\nvar { collectImagesUsageStats } = require('./collectImagesUsageStats');\n\nfunction generateSprites() {\n    var skins = deps.getSkinsList();\n    var stats = deps.getImagesUsageStats(skins);\n\n    var statisticsStreams = skins.map(function(skinName) {\n        // Adds comma to make glob’s {} working properly,\n        // even there is only one should be excluded\n        var filesToExclude = stats[skinName].repeatable.join(',') + ',' +\n            stats[skinName].notRepeatableNotSprited.join(',');\n\n        var pngList = [\n            'src/**/' + skinName + '/img/**/*.png',\n            '!src/**/' + skinName + '/img/**/*@2x.png',\n            '!src/**/' + skinName + '/img/**/{' + filesToExclude + '}.png'\n        ];\n        var png2xList = [\n            'src/**/' + skinName + '/img/**/*@2x.png',\n            '!src/**/' + skinName + '/img/**/{' + filesToExclude + '}@2x.png'\n        ];\n        var spriteData = gulp.src(pngList)\n            .pipe(error.handle())\n            .pipe(spritesmith({\n                cssTemplate: 'gulp/sprite-template.mustache',\n                imgName: 'sprite.' + skinName + '.png',\n                cssName: 'sprite.' + skinName + '.less',\n                engine: 'pixelsmith'\n            }));\n        var spriteData2x = gulp.src(png2xList)\n            .pipe(error.handle())\n            .pipe(spritesmith({\n                cssTemplate: 'gulp/sprite-template.mustache',\n                //padding: 1, // генерирует неправильные смещения :(\n                imgName: 'sprite@2x.' + skinName + '.png',\n                cssName: 'sprite@2x.' + skinName + '.less',\n                engine: 'pixelsmith'\n            }));\n\n        return mergeStream(\n            spriteData.img\n                .pipe(gulp.dest('dist/img/')),\n\n            spriteData2x.img\n                .pipe(gulp.dest('dist/img/')),\n\n            spriteData.css\n                .pipe(gulp.dest('gulp/tmp/less/')),\n\n            spriteData2x.css\n                .pipe(gulp.dest('gulp/tmp/less/'))\n        );\n    });\n\n    return mergeStream(statisticsStreams);\n}\n\nexports.generateSprites = gulp.series(collectImagesUsageStats, generateSprites);\n"
  },
  {
    "path": "gulp/tasks/imageMinify.js",
    "content": "var imagemin = require('gulp-imagemin');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulpif = require('gulp-if');\nvar gulp = require('gulp');\nvar { copyAssets } = require('./copyAssets');\nvar { copyImg } = require('./copyImg');\nvar { generateSprites } = require('./generateSprites');\n\nfunction imageMinify() {\n    return gulp.src('dist/img/**/*.{png,gif,jpg,jpeg}')\n        .pipe(gulpif(argv.release, imagemin()))\n        .pipe(gulp.dest('dist/img'));\n}\n\nexports.imageMinify = gulp.series(\n    gulp.parallel(\n        copyAssets,\n        copyImg,\n        generateSprites\n    ),\n    imageMinify,\n);\n"
  },
  {
    "path": "gulp/tasks/lint.js",
    "content": "var gulp = require('gulp');\nvar { lintJS } = require('./lintJS');\nvar { lintCSS } = require('./lintCSS');\n\nexports.lint = gulp.parallel(lintJS, lintCSS);\n"
  },
  {
    "path": "gulp/tasks/lintCSS.js",
    "content": "var gulp = require('gulp');\n\nvar csslint = require('../util/csslint/gulp-csslint');\nvar error = require('../util/error');\nvar {buildStyles} = require('./buildStyles');\n\nfunction lintCSS() {\n    return gulp.src('dist/css/**.css')\n        .pipe(error.handle())\n        .pipe(csslint({\n            'adjoining-classes': false,\n            'box-model': false,\n            'box-sizing': false,\n            'compatible-vendor-prefixes': false,\n            'empty-rules': false,\n            'display-property-grouping': false,\n            'duplicate-background-images': false,\n            'fallback-colors': false,\n            'font-sizes': false,\n            'gradients': false,\n            'important': false,\n            'overqualified-elements': false,\n            'outline-none': false,\n            'regex-selectors': false,\n            'vendor-prefix': false,\n            'unqualified-attributes': false,\n            'zero-units': false\n        }))\n        .pipe(csslint.reporter());\n}\n\nexports.lintCSS = gulp.series(buildStyles, lintCSS);\n"
  },
  {
    "path": "gulp/tasks/lintJS.js",
    "content": "var eslint = require('gulp-eslint');\nvar gulp = require('gulp');\n\nvar error = require('../util/error');\n\nexports.lintJS = function lintJS() {\n    return gulp.src('src/**/src/**/*.js')\n        .pipe(error.handle())\n        .pipe(eslint())\n        .pipe(eslint.format())\n        .pipe(eslint.failAfterError());\n};\n"
  },
  {
    "path": "gulp/tasks/loadProjectList.js",
    "content": "var request = require('request');\nvar PluginError = require('plugin-error');\n\nvar projectList = require('../util/projectList');\nvar config = require('../../app/config.js');\nvar errorNotifier = require('../util/error');\n\nexports.loadProjectList = function loadProjectList(cb) {\n    if (projectList.get()) {\n        return cb();\n    }\n\n    var fields = [\n        'items.bounds',\n        'items.zoom_level',\n        'items.time_zone',\n        'items.code',\n        'items.flags',\n        'items.country_code',\n        'items.domain'\n    ].join(',');\n\n    var protocol = config.appConfig.protocol;\n    var apiServer = config.appConfig.webApiServer;\n    var apiVersion = config.appConfig.webApiVersion;\n    var apiKey = config.appConfig.webApiKey;\n\n    var url = protocol + apiServer + '/' + apiVersion + '/region/list?key=' + apiKey + '&fields=' + fields;\n\n    request(url, function(err, res, body) {\n        if (err) {\n            var error = new PluginError({\n                plugin: 'loadProjectList',\n                message: err\n            });\n\n            errorNotifier.notify(error);\n\n            return cb();\n        }\n\n        var data = JSON.parse(body);\n\n        var projects = data.result.items;\n\n        var projectListString = 'DG.fallbackProjectsList = JSON.parse(\\'' +\n            JSON.stringify(projects) +\n            '\\');';\n\n        projectList.set(projectListString);\n\n        cb();\n    });\n};\n"
  },
  {
    "path": "gulp/tasks/loader.js",
    "content": "var gulp = require('gulp');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulpif = require('gulp-if');\nvar uglify = require('gulp-uglify');\nvar replace = require('gulp-replace');\n\nvar error = require('../util/error');\nvar config = require('../../app/config.js');\n\nexports.loader = function loader() {\n    var originalBaseUrl = config.appConfig.protocol + config.appConfig.baseUrl;\n\n    return gulp.src('app/loader.js')\n        .pipe(error.handle())\n        .pipe(replace(/__ORIGINAL_BASE_URL__/g, originalBaseUrl))\n        .pipe(gulpif(argv.release, uglify()))\n        .pipe(gulp.dest('dist'));\n};\n"
  },
  {
    "path": "gulp/tasks/rebuildStyles.js",
    "content": "var { destCSS } = require('../util/destCSS');\n\nexports.rebuildStyles = destCSS;\n"
  },
  {
    "path": "gulp/tasks/server.js",
    "content": "var spawn = require('child_process').spawn;\n\nvar nodeServer = null;\n\nexports.server = function server(cb) {\n    function start() {\n        nodeServer = spawn('node', ['app'], {stdio: 'inherit'});\n        cb();\n    }\n\n    if (nodeServer) {\n        nodeServer.once('close', start);\n        nodeServer.kill();\n    } else {\n        start();\n    }\n};\n\nprocess.on('exit', function() {\n    if (nodeServer) {\n        nodeServer.kill();\n    }\n});\n"
  },
  {
    "path": "gulp/tasks/test.js",
    "content": "var Server = require('karma').Server;\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\nvar path = require('path');\nvar glob = require('glob');\nvar log = require('fancy-log');\nvar _ = require('lodash');\n\nvar { buildTest } = require('./buildTest');\n\nvar test = require('../../test/test');\nvar excludedTests = require('../../test/excludedTests.js') || [];\n\nvar isTestDebug = argv.d || argv.debug;\nvar testRequirements = isTestDebug ? [] : [buildTest];\nvar itemsInChunk = 10; // items in chunk by default\n\nfunction performTest(done) {\n    var cliOptions = _.cloneDeep(argv);\n    var modulesToTest = [];\n    var currentChunk = 0;\n\n    var sourcesList = [\n        'dist/js/script.full.js',\n        'node_modules/leaflet/spec/after.js',\n        'node_modules/happen/happen.js',\n        'node_modules/prosthetic-hand/dist/prosthetic-hand.js',\n        'node_modules/leaflet/spec/suites/SpecHelper.js',\n        'node_modules/mock-geolocation/dist/geolocate.js',\n        'test/after.js'\n    ];\n\n    if ('m' in cliOptions) {\n        modulesToTest = cliOptions.m.split(',');\n    }\n\n    if ('module' in cliOptions) {\n        modulesToTest = cliOptions.module.split(',');\n    }\n\n    var modulesToTestSourceList = [];\n\n    if (modulesToTest.length) {\n        modulesToTest.forEach(function(moduleName) {\n            modulesToTestSourceList = modulesToTestSourceList.concat(glob.sync('src/' + moduleName + '/test/*Spec.js'));\n        });\n    } else {\n        modulesToTestSourceList = modulesToTestSourceList.concat(glob.sync('src/**/test/*Spec.js'));\n    }\n    modulesToTestSourceList = modulesToTestSourceList.concat(glob.sync('node_modules/leaflet/spec/suites/**/*Spec.js'));\n\n    modulesToTestSourceList = _.difference(modulesToTestSourceList, excludedTests);\n\n    var splittedModules = _.chunk(modulesToTestSourceList, itemsInChunk);\n\n    var numberOfChunks = splittedModules.length;\n\n    log('\\nITEMS IN CHUNK: ' + itemsInChunk);\n    log('NUMBER OF CHUNKS: ' + numberOfChunks);\n\n    // Flag of existing errors.\n    var totalErr = false;\n\n    // Function will be run recursive, because need execute chunks in order.\n    function startServer(err) {\n        totalErr = err || totalErr;\n        log('\\nCHUNK #' + currentChunk.toString());\n\n        var localeSourceList = sourcesList.concat(splittedModules[currentChunk]);\n        currentChunk++;\n\n        localeSourceList.push('node_modules/leaflet/spec/suites/SpecHelper.js');\n\n        function localDone(errDone) {\n            totalErr = errDone || totalErr;\n            done(totalErr);\n        }\n\n        new Server({\n            files: localeSourceList,\n            configFile: path.join(__dirname, '../../test/karma.conf.js'),\n            browsers: test.getBrowsers(),\n            reporters: test.getReporters(isTestDebug),\n            junitReporter: test.getJunitReporter(),\n            action: 'run',\n            preprocessors: {\n                'gulp/tmp/testJS/src/**/*.js': ['coverage']\n            },\n            singleRun: true\n            // Function localDone will be executed in the last iteration.\n        }, currentChunk === numberOfChunks ? localDone : startServer).start();\n    }\n    startServer();\n}\n\nexports.test = gulp.series(...testRequirements, performTest);\n"
  },
  {
    "path": "gulp/tasks/watch.js",
    "content": "var gulp = require('gulp');\n\nvar { doc } = require('./doc');\nvar { copyAssets } = require('./copyAssets');\nvar { server } = require('./server');\nvar { buildScripts } = require('./buildScripts');\nvar { rebuildStyles } = require('./rebuildStyles');\nvar { build } = require('./build');\nvar { loader } = require('./loader');\nvar { copyIndexPage } = require('./copyIndexPage');\n\nexports.watch = function watch() {\n    gulp.watch('src/doc/**/*.*', doc);\n\n    gulp.watch('assets/**/*', gulp.series(copyAssets, server));\n\n    gulp.watch([\n        'src/**/*.js',\n        'vendors/leaflet/src/**/*.*'\n    ], gulp.series(buildScripts, server));\n\n    gulp.watch('src/**/*.less', gulp.series(rebuildStyles, server));\n\n    gulp.watch('config.main.json', gulp.series(build, server));\n\n    gulp.watch(['app/index.js', 'config.local.json'], server);\n\n    gulp.watch('app/loader.js', gulp.series(loader, server));\n\n    gulp.watch('app/index.html', gulp.series(copyIndexPage, server));\n};\n"
  },
  {
    "path": "gulp/util/buildCSS.js",
    "content": "var autoprefixer = require('gulp-autoprefixer');\nvar clean = require('gulp-clean-css');\nvar remember = require('gulp-remember');\nvar concat = require('gulp-concat');\nvar header = require('gulp-header');\nvar cache = require('gulp-cached');\nvar gulpif = require('gulp-if');\nvar less = require('gulp-less');\nvar argv = require('minimist')(process.argv.slice(2));\nvar map = require('map-stream');\nvar gulp = require('gulp');\nvar path = require('path');\nvar fs = require('fs');\n\nvar config = require('../../app/config.js');\nvar deps = require('../deps')(config);\nvar stat = require('../util/stat');\nvar error = require('./error');\n\nexports.buildCSS = function(options) {\n    var imagesBasePath = path.resolve(__dirname + '/../../dist/img');\n    var baseURL = config.appConfig.protocol + config.appConfig.baseUrl;\n    var lessList = deps.getCSSFiles(options);\n\n    var lessHeaderImports;\n    if (options.isTest) {\n        lessHeaderImports = [\n            './src/less/mixins.less:reference',\n            './src/less/mixins.ie8.less:reference'\n        ];\n    } else {\n        lessHeaderImports = [\n            './gulp/tmp/less/sprite.basic.less:reference',\n            './gulp/tmp/less/sprite@2x.basic.less:reference',\n            './gulp/tmp/less/sprite.' + options.skin + '.less:reference',\n            './gulp/tmp/less/sprite@2x.' + options.skin + '.less:reference',\n\n            './gulp/tmp/less/images-files-statistics.basic.less:reference',\n            './gulp/tmp/less/images-files-statistics.' + options.skin + '.less:reference',\n\n            './src/less/mixins.less:reference',\n            './src/less/mixins.ie8.less:reference'\n        ];\n    }\n\n    lessHeaderImports = lessHeaderImports.filter(function(src) {\n        var lessFileSrc = src.split(':')[0];\n\n        try {\n            return fs.readFileSync(path.join(__dirname, '../..', lessFileSrc));\n        } catch (e) {\n            return false;\n        }\n    });\n\n    var lessPrerequirements = deps.lessHeader({\n        variables: {\n            baseURL: \"'\" + baseURL + \"'\",\n            skinName: options.skin,\n            ie8: options.ie8,\n            imagesBasePath: \"'\" + imagesBasePath + \"'\"\n        },\n\n        imports: lessHeaderImports\n    });\n\n    return gulp.src(lessList)\n        .pipe(error.handle())\n        .pipe(cache('css.' + options.suffix))\n        .pipe(header(lessPrerequirements))\n        .pipe(less())\n        .pipe(autoprefixer({browsers: ['last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4']}))\n        .pipe(remember('css.' + options.suffix))\n        .pipe(concat('styles.' + (options.suffix ? options.suffix + '.' : '') + 'css'))\n        .pipe(gulpif(argv.release, clean()))\n        .pipe(header(config.copyright))\n        .pipe(map(stat.save));\n};\n"
  },
  {
    "path": "gulp/util/buildEnd.js",
    "content": "var argv = require('minimist')(process.argv.slice(2));\nvar log = require('fancy-log');\n\nvar stat = require('./stat');\nvar config = require('../../app/config');\nvar deps = require('../deps')(config);\n\nexports.buildEnd = function buildEnd(done) {\n    log('Build contains the next modules:');\n\n    deps.getModulesList(argv.pkg).forEach(function(module) {\n        log('- ' + module);\n    });\n\n    if (argv.sprite == 'true') {\n        log('Builded with sprites');\n    } else if (argv.base64 != 'false' && typeof argv.base64 != 'undefined') {\n        log('Builded with base64 encode');\n    }\n\n    log('\\nDist files statistic:');\n\n    var statValues = stat.get();\n\n    Object.keys(statValues).forEach(function(file) {\n        log('- ' + file + ': ' + statValues[file]);\n    });\n\n    log('Build successfully complete');\n    done();\n};\n"
  },
  {
    "path": "gulp/util/csslint/gulp-csslint.js",
    "content": "var log = require('fancy-log');\nvar PluginError = require('plugin-error');\nvar es = require('event-stream');\nvar fs = require('fs');\nvar csslint = require('./lib/csslint').CSSLint;\n\nvar formatOutput = function (report, file, options) {\n    if (!report.messages.length) {\n        return {\n            success: true\n        };\n    }\n\n    var filePath = file.path || 'stdin';\n\n    // Handle errors\n    var results = report.messages.map(function (err) {\n        if (!err) {\n            return;\n        }\n\n        return {\n            file: filePath,\n            error: err\n        };\n    }).filter(function (err) {\n        return err;\n    });\n\n    var output = {\n        errorCount: results.length,\n        success: false,\n        results: results,\n        options: options\n    };\n\n    return output;\n};\n\nvar cssLintPlugin = function (options) {\n    if (!options) {\n        options = {};\n    }\n\n    var ruleset = {};\n\n    // Read CSSLint options from a specified csslintrc file.\n    if (typeof options == 'string') {\n        // Don't catch readFile errors, let them bubble up\n        var externalOptions = fs.readFileSync('./' + options);\n\n        try {\n            options = JSON.parse(externalOptions);\n        } catch(err) {\n            throw new Error('Error parsing csslintrc: ' + err);\n        }\n    }\n\n    // Build a list of all available rules\n    csslint.getRules().forEach(function (rule) {\n        ruleset[rule.id] = 1;\n    });\n\n    for (var rule in options) {\n        if (!options[rule]) {\n            // Remove rules that are turned off\n            delete ruleset[rule];\n        } else {\n            ruleset[rule] = options[rule];\n        }\n    }\n\n    return es.map(function (file, cb) {\n        var report = csslint.verify(String(file.contents), ruleset);\n\n        // send status down-stream\n        file.csslint = formatOutput(report, file, options);\n\n        cb(null, file);\n    });\n};\n\nvar defaultReporter = function (file) {\n    var errorCount = file.csslint.errorCount;\n    var plural = errorCount == 1 ? '' : 's';\n\n    log(errorCount + ' error' + plural + ' found in ' + file.path);\n\n    file.csslint.results.forEach(function (result) {\n        var message = result.error;\n\n        log('[' + (typeof message.line != 'undefined'\n                ? 'L' + message.line + ':' + 'C' + message.col\n                : 'GENERAL'\n            ) + '] ' + message.message + ' ' + message.rule.desc + ' (' + message.rule.id + ')'\n        );\n    });\n};\n\ncssLintPlugin.reporter = function (customReporter) {\n    var reporter = defaultReporter;\n\n    if (typeof customReporter == 'function') {\n        reporter = customReporter;\n    }\n\n    if (typeof reporter == 'undefined') {\n        throw new Error('Invalid reporter');\n    }\n\n    return es.map(function (file, cb) {\n        // Only report if CSSLint was ran and errors were found\n        if (file.csslint && !file.csslint.success) {\n            reporter(file);\n        }\n\n        return cb(null, file);\n    });\n};\n\ncssLintPlugin.failReporter = function () {\n    return es.map(function (file, cb) {\n        // Nothing to report or no errors\n        if (!file.csslint || file.csslint.success) {\n            return cb(null, file);\n        }\n\n        return cb(new PluginError('gulp-csslint', 'CSSLint failed for ' + file.relative), file);\n    });\n};\n\nmodule.exports = cssLintPlugin;\n"
  },
  {
    "path": "gulp/util/csslint/lib/csslint.js",
    "content": "/*!\nCSSLint\nCopyright (c) 2013 Nicole Sullivan and Nicholas C. Zakas. All rights reserved.\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\n*/\n/* Build: v0.10.0 15-August-2013 01:07:22 */\nvar parserlib = require(\"./parserlib\");\n/**\n * Main CSSLint object.\n * @class CSSLint\n * @static\n * @extends parserlib.util.EventTarget\n */\n/*global parserlib, Reporter*/\nvar CSSLint = (function(){\n\n    var rules           = [],\n        formatters      = [],\n        embeddedRuleset = /\\/\\*csslint([^\\*]*)\\*\\//,\n        api             = new parserlib.util.EventTarget();\n\n    api.version = \"0.10.0\";\n\n    //-------------------------------------------------------------------------\n    // Rule Management\n    //-------------------------------------------------------------------------\n\n    /**\n     * Adds a new rule to the engine.\n     * @param {Object} rule The rule to add.\n     * @method addRule\n     */\n    api.addRule = function(rule){\n        rules.push(rule);\n        rules[rule.id] = rule;\n    };\n\n    /**\n     * Clears all rule from the engine.\n     * @method clearRules\n     */\n    api.clearRules = function(){\n        rules = [];\n    };\n\n    /**\n     * Returns the rule objects.\n     * @return An array of rule objects.\n     * @method getRules\n     */\n    api.getRules = function(){\n        return [].concat(rules).sort(function(a,b){\n            return a.id > b.id ? 1 : 0;\n        });\n    };\n\n    /**\n     * Returns a ruleset configuration object with all current rules.\n     * @return A ruleset object.\n     * @method getRuleset\n     */\n    api.getRuleset = function() {\n        var ruleset = {},\n            i = 0,\n            len = rules.length;\n\n        while (i < len){\n            ruleset[rules[i++].id] = 1;    //by default, everything is a warning\n        }\n\n        return ruleset;\n    };\n\n    /**\n     * Returns a ruleset object based on embedded rules.\n     * @param {String} text A string of css containing embedded rules.\n     * @param {Object} ruleset A ruleset object to modify.\n     * @return {Object} A ruleset object.\n     * @method getEmbeddedRuleset\n     */\n    function applyEmbeddedRuleset(text, ruleset){\n        var valueMap,\n            embedded = text && text.match(embeddedRuleset),\n            rules = embedded && embedded[1];\n\n        if (rules) {\n            valueMap = {\n                \"true\": 2,  // true is error\n                \"\": 1,      // blank is warning\n                \"false\": 0, // false is ignore\n\n                \"2\": 2,     // explicit error\n                \"1\": 1,     // explicit warning\n                \"0\": 0      // explicit ignore\n            };\n\n            rules.toLowerCase().split(\",\").forEach(function(rule){\n                var pair = rule.split(\":\"),\n                    property = pair[0] || \"\",\n                    value = pair[1] || \"\";\n\n                ruleset[property.trim()] = valueMap[value.trim()];\n            });\n        }\n\n        return ruleset;\n    }\n\n    //-------------------------------------------------------------------------\n    // Formatters\n    //-------------------------------------------------------------------------\n\n    /**\n     * Adds a new formatter to the engine.\n     * @param {Object} formatter The formatter to add.\n     * @method addFormatter\n     */\n    api.addFormatter = function(formatter) {\n        // formatters.push(formatter);\n        formatters[formatter.id] = formatter;\n    };\n\n    /**\n     * Retrieves a formatter for use.\n     * @param {String} formatId The name of the format to retrieve.\n     * @return {Object} The formatter or undefined.\n     * @method getFormatter\n     */\n    api.getFormatter = function(formatId){\n        return formatters[formatId];\n    };\n\n    /**\n     * Formats the results in a particular format for a single file.\n     * @param {Object} result The results returned from CSSLint.verify().\n     * @param {String} filename The filename for which the results apply.\n     * @param {String} formatId The name of the formatter to use.\n     * @param {Object} options (Optional) for special output handling.\n     * @return {String} A formatted string for the results.\n     * @method format\n     */\n    api.format = function(results, filename, formatId, options) {\n        var formatter = this.getFormatter(formatId),\n            result = null;\n\n        if (formatter){\n            result = formatter.startFormat();\n            result += formatter.formatResults(results, filename, options || {});\n            result += formatter.endFormat();\n        }\n\n        return result;\n    };\n\n    /**\n     * Indicates if the given format is supported.\n     * @param {String} formatId The ID of the format to check.\n     * @return {Boolean} True if the format exists, false if not.\n     * @method hasFormat\n     */\n    api.hasFormat = function(formatId){\n        return formatters.hasOwnProperty(formatId);\n    };\n\n    //-------------------------------------------------------------------------\n    // Verification\n    //-------------------------------------------------------------------------\n\n    /**\n     * Starts the verification process for the given CSS text.\n     * @param {String} text The CSS text to verify.\n     * @param {Object} ruleset (Optional) List of rules to apply. If null, then\n     *      all rules are used. If a rule has a value of 1 then it's a warning,\n     *      a value of 2 means it's an error.\n     * @return {Object} Results of the verification.\n     * @method verify\n     */\n    api.verify = function(text, ruleset){\n\n        var i       = 0,\n            len     = rules.length,\n            reporter,\n            lines,\n            report,\n            parser = new parserlib.css.Parser({ starHack: true, ieFilters: true,\n                                                underscoreHack: true, strict: false });\n\n        // normalize line endings\n        lines = text.replace(/\\n\\r?/g, \"$split$\").split('$split$');\n\n        if (!ruleset){\n            ruleset = this.getRuleset();\n        }\n\n        if (embeddedRuleset.test(text)){\n            ruleset = applyEmbeddedRuleset(text, ruleset);\n        }\n\n        reporter = new Reporter(lines, ruleset);\n\n        ruleset.errors = 2;       //always report parsing errors as errors\n        for (i in ruleset){\n            if(ruleset.hasOwnProperty(i) && ruleset[i]){\n                if (rules[i]){\n                    rules[i].init(parser, reporter);\n                }\n            }\n        }\n\n\n        //capture most horrible error type\n        try {\n            parser.parse(text);\n        } catch (ex) {\n            reporter.error(\"Fatal error, cannot continue: \" + ex.message, ex.line, ex.col, {});\n        }\n\n        report = {\n            messages    : reporter.messages,\n            stats       : reporter.stats,\n            ruleset     : reporter.ruleset\n        };\n\n        //sort by line numbers, rollups at the bottom\n        report.messages.sort(function (a, b){\n            if (a.rollup && !b.rollup){\n                return 1;\n            } else if (!a.rollup && b.rollup){\n                return -1;\n            } else {\n                return a.line - b.line;\n            }\n        });\n\n        return report;\n    };\n\n    //-------------------------------------------------------------------------\n    // Publish the API\n    //-------------------------------------------------------------------------\n\n    return api;\n\n})();\n\n/*global CSSLint*/\n/**\n * An instance of Report is used to report results of the\n * verification back to the main API.\n * @class Reporter\n * @constructor\n * @param {String[]} lines The text lines of the source.\n * @param {Object} ruleset The set of rules to work with, including if\n *      they are errors or warnings.\n */\nfunction Reporter(lines, ruleset){\n\n    /**\n     * List of messages being reported.\n     * @property messages\n     * @type String[]\n     */\n    this.messages = [];\n\n    /**\n     * List of statistics being reported.\n     * @property stats\n     * @type String[]\n     */\n    this.stats = [];\n\n    /**\n     * Lines of code being reported on. Used to provide contextual information\n     * for messages.\n     * @property lines\n     * @type String[]\n     */\n    this.lines = lines;\n\n    /**\n     * Information about the rules. Used to determine whether an issue is an\n     * error or warning.\n     * @property ruleset\n     * @type Object\n     */\n    this.ruleset = ruleset;\n}\n\nReporter.prototype = {\n\n    //restore constructor\n    constructor: Reporter,\n\n    /**\n     * Report an error.\n     * @param {String} message The message to store.\n     * @param {int} line The line number.\n     * @param {int} col The column number.\n     * @param {Object} rule The rule this message relates to.\n     * @method error\n     */\n    error: function(message, line, col, rule){\n        this.messages.push({\n            type    : \"error\",\n            line    : line,\n            col     : col,\n            message : message,\n            evidence: this.lines[line-1],\n            rule    : rule || {}\n        });\n    },\n\n    /**\n     * Report an warning.\n     * @param {String} message The message to store.\n     * @param {int} line The line number.\n     * @param {int} col The column number.\n     * @param {Object} rule The rule this message relates to.\n     * @method warn\n     * @deprecated Use report instead.\n     */\n    warn: function(message, line, col, rule){\n        this.report(message, line, col, rule);\n    },\n\n    /**\n     * Report an issue.\n     * @param {String} message The message to store.\n     * @param {int} line The line number.\n     * @param {int} col The column number.\n     * @param {Object} rule The rule this message relates to.\n     * @method report\n     */\n    report: function(message, line, col, rule){\n        this.messages.push({\n            type    : this.ruleset[rule.id] == 2 ? \"error\" : \"warning\",\n            line    : line,\n            col     : col,\n            message : message,\n            evidence: this.lines[line-1],\n            rule    : rule\n        });\n    },\n\n    /**\n     * Report some informational text.\n     * @param {String} message The message to store.\n     * @param {int} line The line number.\n     * @param {int} col The column number.\n     * @param {Object} rule The rule this message relates to.\n     * @method info\n     */\n    info: function(message, line, col, rule){\n        this.messages.push({\n            type    : \"info\",\n            line    : line,\n            col     : col,\n            message : message,\n            evidence: this.lines[line-1],\n            rule    : rule\n        });\n    },\n\n    /**\n     * Report some rollup error information.\n     * @param {String} message The message to store.\n     * @param {Object} rule The rule this message relates to.\n     * @method rollupError\n     */\n    rollupError: function(message, rule){\n        this.messages.push({\n            type    : \"error\",\n            rollup  : true,\n            message : message,\n            rule    : rule\n        });\n    },\n\n    /**\n     * Report some rollup warning information.\n     * @param {String} message The message to store.\n     * @param {Object} rule The rule this message relates to.\n     * @method rollupWarn\n     */\n    rollupWarn: function(message, rule){\n        this.messages.push({\n            type    : \"warning\",\n            rollup  : true,\n            message : message,\n            rule    : rule\n        });\n    },\n\n    /**\n     * Report a statistic.\n     * @param {String} name The name of the stat to store.\n     * @param {Variant} value The value of the stat.\n     * @method stat\n     */\n    stat: function(name, value){\n        this.stats[name] = value;\n    }\n};\n\n//expose for testing purposes\nCSSLint._Reporter = Reporter;\n\n/*global CSSLint*/\n\n/*\n * Utility functions that make life easier.\n */\nCSSLint.Util = {\n    /*\n     * Adds all properties from supplier onto receiver,\n     * overwriting if the same name already exists on\n     * reciever.\n     * @param {Object} The object to receive the properties.\n     * @param {Object} The object to provide the properties.\n     * @return {Object} The receiver\n     */\n    mix: function(receiver, supplier){\n        var prop;\n\n        for (prop in supplier){\n            if (supplier.hasOwnProperty(prop)){\n                receiver[prop] = supplier[prop];\n            }\n        }\n\n        return prop;\n    },\n\n    /*\n     * Polyfill for array indexOf() method.\n     * @param {Array} values The array to search.\n     * @param {Variant} value The value to search for.\n     * @return {int} The index of the value if found, -1 if not.\n     */\n    indexOf: function(values, value){\n        if (values.indexOf){\n            return values.indexOf(value);\n        } else {\n            for (var i=0, len=values.length; i < len; i++){\n                if (values[i] === value){\n                    return i;\n                }\n            }\n            return -1;\n        }\n    },\n\n    /*\n     * Polyfill for array forEach() method.\n     * @param {Array} values The array to operate on.\n     * @param {Function} func The function to call on each item.\n     * @return {void}\n     */\n    forEach: function(values, func) {\n        if (values.forEach){\n            return values.forEach(func);\n        } else {\n            for (var i=0, len=values.length; i < len; i++){\n                func(values[i], i, values);\n            }\n        }\n    }\n};\n/*global CSSLint*/\n/*\n * Rule: Don't use adjoining classes (.foo.bar).\n */\nCSSLint.addRule({\n\n    //rule information\n    id: \"adjoining-classes\",\n    name: \"Disallow adjoining classes\",\n    desc: \"Don't use adjoining classes.\",\n    browsers: \"IE6\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                classCount,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n                for (j=0; j < selector.parts.length; j++){\n                    part = selector.parts[j];\n                    if (part.type == parser.SELECTOR_PART_TYPE){\n                        classCount = 0;\n                        for (k=0; k < part.modifiers.length; k++){\n                            modifier = part.modifiers[k];\n                            if (modifier.type == \"class\"){\n                                classCount++;\n                            }\n                            if (classCount > 1){\n                                reporter.report(\"Don't use adjoining classes.\", part.line, part.col, rule);\n                            }\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n});\n/*global CSSLint*/\n\n/*\n * Rule: Don't use width or height when using padding or border.\n */\nCSSLint.addRule({\n\n    //rule information\n    id: \"box-model\",\n    name: \"Beware of broken box size\",\n    desc: \"Don't use width or height when using padding or border.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            widthProperties = {\n                border: 1,\n                \"border-left\": 1,\n                \"border-right\": 1,\n                padding: 1,\n                \"padding-left\": 1,\n                \"padding-right\": 1\n            },\n            heightProperties = {\n                border: 1,\n                \"border-bottom\": 1,\n                \"border-top\": 1,\n                padding: 1,\n                \"padding-bottom\": 1,\n                \"padding-top\": 1\n            },\n            properties,\n            boxSizing = false;\n\n        function startRule(){\n            properties = {};\n            boxSizing = false;\n        }\n\n        function endRule(){\n            var prop, value;\n\n            if (!boxSizing) {\n                if (properties.height){\n                    for (prop in heightProperties){\n                        if (heightProperties.hasOwnProperty(prop) && properties[prop]){\n                            value = properties[prop].value;\n                            //special case for padding\n                            if (!(prop == \"padding\" && value.parts.length === 2 && value.parts[0].value === 0)){\n                                reporter.report(\"Using height with \" + prop + \" can sometimes make elements larger than you expect.\", properties[prop].line, properties[prop].col, rule);\n                            }\n                        }\n                    }\n                }\n\n                if (properties.width){\n                    for (prop in widthProperties){\n                        if (widthProperties.hasOwnProperty(prop) && properties[prop]){\n                            value = properties[prop].value;\n\n                            if (!(prop == \"padding\" && value.parts.length === 2 && value.parts[1].value === 0)){\n                                reporter.report(\"Using width with \" + prop + \" can sometimes make elements larger than you expect.\", properties[prop].line, properties[prop].col, rule);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startpage\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase();\n\n            if (heightProperties[name] || widthProperties[name]){\n                if (!/^0\\S*$/.test(event.value) && !(name == \"border\" && event.value == \"none\")){\n                    properties[name] = { line: event.property.line, col: event.property.col, value: event.value };\n                }\n            } else {\n                if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)){\n                    properties[name] = 1;\n                } else if (name == \"box-sizing\") {\n                    boxSizing = true;\n                }\n            }\n\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n        parser.addListener(\"endpage\", endRule);\n        parser.addListener(\"endpagemargin\", endRule);\n        parser.addListener(\"endkeyframerule\", endRule);\n    }\n\n});\n/*global CSSLint*/\n\n/*\n * Rule: box-sizing doesn't work in IE6 and IE7.\n */\nCSSLint.addRule({\n\n    //rule information\n    id: \"box-sizing\",\n    name: \"Disallow use of box-sizing\",\n    desc: \"The box-sizing properties isn't supported in IE6 and IE7.\",\n    browsers: \"IE6, IE7\",\n    tags: [\"Compatibility\"],\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase();\n\n            if (name == \"box-sizing\"){\n                reporter.report(\"The box-sizing property isn't supported in IE6 and IE7.\", event.line, event.col, rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE\n * (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"bulletproof-font-face\",\n    name: \"Use the bulletproof @font-face syntax\",\n    desc: \"Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0,\n            fontFaceRule = false,\n            firstSrc     = true,\n            ruleFailed    = false,\n            line, col;\n\n        // Mark the start of a @font-face declaration so we only test properties inside it\n        parser.addListener(\"startfontface\", function(event){\n            fontFaceRule = true;\n        });\n\n        parser.addListener(\"property\", function(event){\n            // If we aren't inside an @font-face declaration then just return\n            if (!fontFaceRule) {\n                return;\n            }\n\n            var propertyName = event.property.toString().toLowerCase(),\n                value        = event.value.toString();\n\n            // Set the line and col numbers for use in the endfontface listener\n            line = event.line;\n            col  = event.col;\n\n            // This is the property that we care about, we can ignore the rest\n            if (propertyName === 'src') {\n                var regex = /^\\s?url\\(['\"].+\\.eot\\?.*['\"]\\)\\s*format\\(['\"]embedded-opentype['\"]\\).*$/i;\n\n                // We need to handle the advanced syntax with two src properties\n                if (!value.match(regex) && firstSrc) {\n                    ruleFailed = true;\n                    firstSrc = false;\n                } else if (value.match(regex) && !firstSrc) {\n                    ruleFailed = false;\n                }\n            }\n\n\n        });\n\n        // Back to normal rules that we don't need to test\n        parser.addListener(\"endfontface\", function(event){\n            fontFaceRule = false;\n\n            if (ruleFailed) {\n                reporter.report(\"@font-face declaration doesn't follow the fontspring bulletproof syntax.\", line, col, rule);\n            }\n        });\n    }\n});\n/*\n * Rule: Include all compatible vendor prefixes to reach a wider\n * range of users.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"compatible-vendor-prefixes\",\n    name: \"Require compatible vendor prefixes\",\n    desc: \"Include all compatible vendor prefixes to reach a wider range of users.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function (parser, reporter) {\n        var rule = this,\n            compatiblePrefixes,\n            properties,\n            prop,\n            variations,\n            prefixed,\n            i,\n            len,\n            inKeyFrame = false,\n            arrayPush = Array.prototype.push,\n            applyTo = [];\n\n        // See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details\n        compatiblePrefixes = {\n            \"animation\"                  : \"webkit moz\",\n            \"animation-delay\"            : \"webkit moz\",\n            \"animation-direction\"        : \"webkit moz\",\n            \"animation-duration\"         : \"webkit moz\",\n            \"animation-fill-mode\"        : \"webkit moz\",\n            \"animation-iteration-count\"  : \"webkit moz\",\n            \"animation-name\"             : \"webkit moz\",\n            \"animation-play-state\"       : \"webkit moz\",\n            \"animation-timing-function\"  : \"webkit moz\",\n            \"appearance\"                 : \"webkit moz\",\n            \"border-end\"                 : \"webkit moz\",\n            \"border-end-color\"           : \"webkit moz\",\n            \"border-end-style\"           : \"webkit moz\",\n            \"border-end-width\"           : \"webkit moz\",\n            \"border-image\"               : \"webkit moz o\",\n            \"border-radius\"              : \"webkit\",\n            \"border-start\"               : \"webkit moz\",\n            \"border-start-color\"         : \"webkit moz\",\n            \"border-start-style\"         : \"webkit moz\",\n            \"border-start-width\"         : \"webkit moz\",\n            \"box-align\"                  : \"webkit moz ms\",\n            \"box-direction\"              : \"webkit moz ms\",\n            \"box-flex\"                   : \"webkit moz ms\",\n            \"box-lines\"                  : \"webkit ms\",\n            \"box-ordinal-group\"          : \"webkit moz ms\",\n            \"box-orient\"                 : \"webkit moz ms\",\n            \"box-pack\"                   : \"webkit moz ms\",\n            \"box-sizing\"                 : \"webkit moz\",\n            \"box-shadow\"                 : \"webkit moz\",\n            \"column-count\"               : \"webkit moz ms\",\n            \"column-gap\"                 : \"webkit moz ms\",\n            \"column-rule\"                : \"webkit moz ms\",\n            \"column-rule-color\"          : \"webkit moz ms\",\n            \"column-rule-style\"          : \"webkit moz ms\",\n            \"column-rule-width\"          : \"webkit moz ms\",\n            \"column-width\"               : \"webkit moz ms\",\n            \"hyphens\"                    : \"epub moz\",\n            \"line-break\"                 : \"webkit ms\",\n            \"margin-end\"                 : \"webkit moz\",\n            \"margin-start\"               : \"webkit moz\",\n            \"marquee-speed\"              : \"webkit wap\",\n            \"marquee-style\"              : \"webkit wap\",\n            \"padding-end\"                : \"webkit moz\",\n            \"padding-start\"              : \"webkit moz\",\n            \"tab-size\"                   : \"moz o\",\n            \"text-size-adjust\"           : \"webkit ms\",\n            \"transform\"                  : \"webkit moz ms o\",\n            \"transform-origin\"           : \"webkit moz ms o\",\n            \"transition\"                 : \"webkit moz o\",\n            \"transition-delay\"           : \"webkit moz o\",\n            \"transition-duration\"        : \"webkit moz o\",\n            \"transition-property\"        : \"webkit moz o\",\n            \"transition-timing-function\" : \"webkit moz o\",\n            \"user-modify\"                : \"webkit moz\",\n            \"user-select\"                : \"webkit moz ms\",\n            \"word-break\"                 : \"epub ms\",\n            \"writing-mode\"               : \"epub ms\"\n        };\n\n\n        for (prop in compatiblePrefixes) {\n            if (compatiblePrefixes.hasOwnProperty(prop)) {\n                variations = [];\n                prefixed = compatiblePrefixes[prop].split(' ');\n                for (i = 0, len = prefixed.length; i < len; i++) {\n                    variations.push('-' + prefixed[i] + '-' + prop);\n                }\n                compatiblePrefixes[prop] = variations;\n                arrayPush.apply(applyTo, variations);\n            }\n        }\n\n        parser.addListener(\"startrule\", function () {\n            properties = [];\n        });\n\n        parser.addListener(\"startkeyframes\", function (event) {\n            inKeyFrame = event.prefix || true;\n        });\n\n        parser.addListener(\"endkeyframes\", function (event) {\n            inKeyFrame = false;\n        });\n\n        parser.addListener(\"property\", function (event) {\n            var name = event.property;\n            if (CSSLint.Util.indexOf(applyTo, name.text) > -1) {\n\n                // e.g., -moz-transform is okay to be alone in @-moz-keyframes\n                if (!inKeyFrame || typeof inKeyFrame != \"string\" ||\n                        name.text.indexOf(\"-\" + inKeyFrame + \"-\") !== 0) {\n                    properties.push(name);\n                }\n            }\n        });\n\n        parser.addListener(\"endrule\", function (event) {\n            if (!properties.length) {\n                return;\n            }\n\n            var propertyGroups = {},\n                i,\n                len,\n                name,\n                prop,\n                variations,\n                value,\n                full,\n                actual,\n                item,\n                propertiesSpecified;\n\n            for (i = 0, len = properties.length; i < len; i++) {\n                name = properties[i];\n\n                for (prop in compatiblePrefixes) {\n                    if (compatiblePrefixes.hasOwnProperty(prop)) {\n                        variations = compatiblePrefixes[prop];\n                        if (CSSLint.Util.indexOf(variations, name.text) > -1) {\n                            if (!propertyGroups[prop]) {\n                                propertyGroups[prop] = {\n                                    full : variations.slice(0),\n                                    actual : [],\n                                    actualNodes: []\n                                };\n                            }\n                            if (CSSLint.Util.indexOf(propertyGroups[prop].actual, name.text) === -1) {\n                                propertyGroups[prop].actual.push(name.text);\n                                propertyGroups[prop].actualNodes.push(name);\n                            }\n                        }\n                    }\n                }\n            }\n\n            for (prop in propertyGroups) {\n                if (propertyGroups.hasOwnProperty(prop)) {\n                    value = propertyGroups[prop];\n                    full = value.full;\n                    actual = value.actual;\n\n                    if (full.length > actual.length) {\n                        for (i = 0, len = full.length; i < len; i++) {\n                            item = full[i];\n                            if (CSSLint.Util.indexOf(actual, item) === -1) {\n                                propertiesSpecified = (actual.length === 1) ? actual[0] : (actual.length == 2) ? actual.join(\" and \") : actual.join(\", \");\n                                reporter.report(\"The property \" + item + \" is compatible with \" + propertiesSpecified + \" and should be included as well.\", value.actualNodes[0].line, value.actualNodes[0].col, rule);\n                            }\n                        }\n\n                    }\n                }\n            }\n        });\n    }\n});\n/*\n * Rule: Certain properties don't play well with certain display values.\n * - float should not be used with inline-block\n * - height, width, margin-top, margin-bottom, float should not be used with inline\n * - vertical-align should not be used with block\n * - margin, float should not be used with table-*\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"display-property-grouping\",\n    name: \"Require properties appropriate for display\",\n    desc: \"Certain properties shouldn't be used with certain display property values.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        var propertiesToCheck = {\n                display: 1,\n                \"float\": \"none\",\n                height: 1,\n                width: 1,\n                margin: 1,\n                \"margin-left\": 1,\n                \"margin-right\": 1,\n                \"margin-bottom\": 1,\n                \"margin-top\": 1,\n                padding: 1,\n                \"padding-left\": 1,\n                \"padding-right\": 1,\n                \"padding-bottom\": 1,\n                \"padding-top\": 1,\n                \"vertical-align\": 1\n            },\n            properties;\n\n        function reportProperty(name, display, msg){\n            if (properties[name]){\n                if (typeof propertiesToCheck[name] != \"string\" || properties[name].value.toLowerCase() != propertiesToCheck[name]){\n                    reporter.report(msg || name + \" can't be used with display: \" + display + \".\", properties[name].line, properties[name].col, rule);\n                }\n            }\n        }\n\n        function startRule(){\n            properties = {};\n        }\n\n        function endRule(){\n\n            var display = properties.display ? properties.display.value : null;\n            if (display){\n                switch(display){\n\n                    case \"inline\":\n                        //height, width, margin-top, margin-bottom, float should not be used with inline\n                        reportProperty(\"height\", display);\n                        reportProperty(\"width\", display);\n                        reportProperty(\"margin\", display);\n                        reportProperty(\"margin-top\", display);\n                        reportProperty(\"margin-bottom\", display);\n                        reportProperty(\"float\", display, \"display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).\");\n                        break;\n\n                    case \"block\":\n                        //vertical-align should not be used with block\n                        reportProperty(\"vertical-align\", display);\n                        break;\n\n                    case \"inline-block\":\n                        //float should not be used with inline-block\n                        reportProperty(\"float\", display);\n                        break;\n\n                    default:\n                        //margin, float should not be used with table\n                        if (display.indexOf(\"table-\") === 0){\n                            reportProperty(\"margin\", display);\n                            reportProperty(\"margin-left\", display);\n                            reportProperty(\"margin-right\", display);\n                            reportProperty(\"margin-top\", display);\n                            reportProperty(\"margin-bottom\", display);\n                            reportProperty(\"float\", display);\n                        }\n\n                        //otherwise do nothing\n                }\n            }\n\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startpage\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase();\n\n            if (propertiesToCheck[name]){\n                properties[name] = { value: event.value.text, line: event.property.line, col: event.property.col };\n            }\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n        parser.addListener(\"endkeyframerule\", endRule);\n        parser.addListener(\"endpagemargin\", endRule);\n        parser.addListener(\"endpage\", endRule);\n\n    }\n\n});\n/*\n * Rule: Disallow duplicate background-images (using url).\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"duplicate-background-images\",\n    name: \"Disallow duplicate background images\",\n    desc: \"Every background-image should be unique. Use a common class for e.g. sprites.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            stack = {};\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text,\n                value = event.value,\n                i, len;\n\n            if (name.match(/background/i)) {\n                for (i=0, len=value.parts.length; i < len; i++) {\n                    if (value.parts[i].type == 'uri') {\n                        if (typeof stack[value.parts[i].uri] === 'undefined') {\n                            stack[value.parts[i].uri] = event;\n                        }\n                        else {\n                            reporter.report(\"Background image '\" + value.parts[i].uri + \"' was used multiple times, first declared at line \" + stack[value.parts[i].uri].line + \", col \" + stack[value.parts[i].uri].col + \".\", event.line, event.col, rule);\n                        }\n                    }\n                }\n            }\n        });\n    }\n});\n/*\n * Rule: Duplicate properties must appear one after the other. If an already-defined\n * property appears somewhere else in the rule, then it's likely an error.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"duplicate-properties\",\n    name: \"Disallow duplicate properties\",\n    desc: \"Duplicate properties must appear one after the other.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            properties,\n            lastProperty;\n\n        function startRule(event){\n            properties = {};\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startpage\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var property = event.property,\n                name = property.text.toLowerCase();\n\n            if (properties[name] && (lastProperty != name || properties[name] == event.value.text)){\n                reporter.report(\"Duplicate property '\" + event.property + \"' found.\", event.line, event.col, rule);\n            }\n\n            properties[name] = event.value.text;\n            lastProperty = name;\n\n        });\n\n\n    }\n\n});\n/*\n * Rule: Style rules without any properties defined should be removed.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"empty-rules\",\n    name: \"Disallow empty rules\",\n    desc: \"Rules without any properties specified should be removed.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0;\n\n        parser.addListener(\"startrule\", function(){\n            count=0;\n        });\n\n        parser.addListener(\"property\", function(){\n            count++;\n        });\n\n        parser.addListener(\"endrule\", function(event){\n            var selectors = event.selectors;\n            if (count === 0){\n                reporter.report(\"Rule is empty.\", selectors[0].line, selectors[0].col, rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: There should be no syntax errors. (Duh.)\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"errors\",\n    name: \"Parsing Errors\",\n    desc: \"This rule looks for recoverable syntax errors.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"error\", function(event){\n            reporter.error(event.message, event.line, event.col, rule);\n        });\n\n    }\n\n});\n\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"fallback-colors\",\n    name: \"Require fallback colors\",\n    desc: \"For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.\",\n    browsers: \"IE6,IE7,IE8\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            lastProperty,\n            propertiesToCheck = {\n                color: 1,\n                background: 1,\n                \"border-color\": 1,\n                \"border-top-color\": 1,\n                \"border-right-color\": 1,\n                \"border-bottom-color\": 1,\n                \"border-left-color\": 1,\n                border: 1,\n                \"border-top\": 1,\n                \"border-right\": 1,\n                \"border-bottom\": 1,\n                \"border-left\": 1,\n                \"background-color\": 1\n            },\n            properties;\n\n        function startRule(event){\n            properties = {};\n            lastProperty = null;\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startpage\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var property = event.property,\n                name = property.text.toLowerCase(),\n                parts = event.value.parts,\n                i = 0,\n                colorType = \"\",\n                len = parts.length;\n\n            if(propertiesToCheck[name]){\n                while(i < len){\n                    if (parts[i].type == \"color\"){\n                        if (\"alpha\" in parts[i] || \"hue\" in parts[i]){\n\n                            if (/([^\\)]+)\\(/.test(parts[i])){\n                                colorType = RegExp.$1.toUpperCase();\n                            }\n\n                            if (!lastProperty || (lastProperty.property.text.toLowerCase() != name || lastProperty.colorType != \"compat\")){\n                                reporter.report(\"Fallback \" + name + \" (hex or RGB) should precede \" + colorType + \" \" + name + \".\", event.line, event.col, rule);\n                            }\n                        } else {\n                            event.colorType = \"compat\";\n                        }\n                    }\n\n                    i++;\n                }\n            }\n\n            lastProperty = event;\n        });\n\n    }\n\n});\n/*\n * Rule: You shouldn't use more than 10 floats. If you do, there's probably\n * room for some abstraction.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"floats\",\n    name: \"Disallow too many floats\",\n    desc: \"This rule tests if the float property is used too many times\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n        var count = 0;\n\n        //count how many times \"float\" is used\n        parser.addListener(\"property\", function(event){\n            if (event.property.text.toLowerCase() == \"float\" &&\n                    event.value.text.toLowerCase() != \"none\"){\n                count++;\n            }\n        });\n\n        //report the results\n        parser.addListener(\"endstylesheet\", function(){\n            reporter.stat(\"floats\", count);\n            if (count >= 10){\n                reporter.rollupWarn(\"Too many floats (\" + count + \"), you're probably using them for layout. Consider using a grid system instead.\", rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: Avoid too many @font-face declarations in the same stylesheet.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"font-faces\",\n    name: \"Don't use too many web fonts\",\n    desc: \"Too many different web fonts in the same stylesheet.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0;\n\n\n        parser.addListener(\"startfontface\", function(){\n            count++;\n        });\n\n        parser.addListener(\"endstylesheet\", function(){\n            if (count > 5){\n                reporter.rollupWarn(\"Too many @font-face declarations (\" + count + \").\", rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: You shouldn't need more than 9 font-size declarations.\n */\n\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"font-sizes\",\n    name: \"Disallow too many font sizes\",\n    desc: \"Checks the number of font-size declarations.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0;\n\n        //check for use of \"font-size\"\n        parser.addListener(\"property\", function(event){\n            if (event.property == \"font-size\"){\n                count++;\n            }\n        });\n\n        //report the results\n        parser.addListener(\"endstylesheet\", function(){\n            reporter.stat(\"font-sizes\", count);\n            if (count >= 10){\n                reporter.rollupWarn(\"Too many font-size declarations (\" + count + \"), abstraction needed.\", rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: When using a vendor-prefixed gradient, make sure to use them all.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"gradients\",\n    name: \"Require all gradient definitions\",\n    desc: \"When using a vendor-prefixed gradient, make sure to use them all.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            gradients;\n\n        parser.addListener(\"startrule\", function(){\n            gradients = {\n                moz: 0,\n                webkit: 0,\n                oldWebkit: 0,\n                o: 0\n            };\n        });\n\n        parser.addListener(\"property\", function(event){\n\n            if (/\\-(moz|o|webkit)(?:\\-(?:linear|radial))\\-gradient/i.test(event.value)){\n                gradients[RegExp.$1] = 1;\n            } else if (/\\-webkit\\-gradient/i.test(event.value)){\n                gradients.oldWebkit = 1;\n            }\n\n        });\n\n        parser.addListener(\"endrule\", function(event){\n            var missing = [];\n\n            if (!gradients.moz){\n                missing.push(\"Firefox 3.6+\");\n            }\n\n            if (!gradients.webkit){\n                missing.push(\"Webkit (Safari 5+, Chrome)\");\n            }\n\n            if (!gradients.oldWebkit){\n                missing.push(\"Old Webkit (Safari 4+, Chrome)\");\n            }\n\n            if (!gradients.o){\n                missing.push(\"Opera 11.1+\");\n            }\n\n            if (missing.length && missing.length < 4){\n                reporter.report(\"Missing vendor-prefixed CSS gradients for \" + missing.join(\", \") + \".\", event.selectors[0].line, event.selectors[0].col, rule);\n            }\n\n        });\n\n    }\n\n});\n\n/*\n * Rule: Don't use IDs for selectors.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"ids\",\n    name: \"Disallow IDs in selectors\",\n    desc: \"Selectors should not contain IDs.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                idCount,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n                idCount = 0;\n\n                for (j=0; j < selector.parts.length; j++){\n                    part = selector.parts[j];\n                    if (part.type == parser.SELECTOR_PART_TYPE){\n                        for (k=0; k < part.modifiers.length; k++){\n                            modifier = part.modifiers[k];\n                            if (modifier.type == \"id\"){\n                                idCount++;\n                            }\n                        }\n                    }\n                }\n\n                if (idCount == 1){\n                    reporter.report(\"Don't use IDs in selectors.\", selector.line, selector.col, rule);\n                } else if (idCount > 1){\n                    reporter.report(idCount + \" IDs in the selector, really?\", selector.line, selector.col, rule);\n                }\n            }\n\n        });\n    }\n\n});\n/*\n * Rule: Don't use @import, use <link> instead.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"import\",\n    name: \"Disallow @import\",\n    desc: \"Don't use @import, use <link> instead.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"import\", function(event){\n            reporter.report(\"@import prevents parallel downloads, use <link> instead.\", event.line, event.col, rule);\n        });\n\n    }\n\n});\n/*\n * Rule: Make sure !important is not overused, this could lead to specificity\n * war. Display a warning on !important declarations, an error if it's\n * used more at least 10 times.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"important\",\n    name: \"Disallow !important\",\n    desc: \"Be careful when using !important declaration\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0;\n\n        //warn that important is used and increment the declaration counter\n        parser.addListener(\"property\", function(event){\n            if (event.important === true){\n                count++;\n                reporter.report(\"Use of !important\", event.line, event.col, rule);\n            }\n        });\n\n        //if there are more than 10, show an error\n        parser.addListener(\"endstylesheet\", function(){\n            reporter.stat(\"important\", count);\n            if (count >= 10){\n                reporter.rollupWarn(\"Too many !important declarations (\" + count + \"), try to use less than 10 to avoid specificity issues.\", rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: Properties should be known (listed in CSS3 specification) or\n * be a vendor-prefixed property.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"known-properties\",\n    name: \"Require use of known properties\",\n    desc: \"Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase();\n\n            // the check is handled entirely by the parser-lib (https://github.com/nzakas/parser-lib)\n            if (event.invalid) {\n                reporter.report(event.invalid.message, event.line, event.col, rule);\n            }\n\n        });\n    }\n\n});\n/*\n * Rule: outline: none or outline: 0 should only be used in a :focus rule\n *       and only if there are other properties in the same rule.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"outline-none\",\n    name: \"Disallow outline: none\",\n    desc: \"Use of outline: none or outline: 0 should be limited to :focus rules.\",\n    browsers: \"All\",\n    tags: [\"Accessibility\"],\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            lastRule;\n\n        function startRule(event){\n            if (event.selectors){\n                lastRule = {\n                    line: event.line,\n                    col: event.col,\n                    selectors: event.selectors,\n                    propCount: 0,\n                    outline: false\n                };\n            } else {\n                lastRule = null;\n            }\n        }\n\n        function endRule(event){\n            if (lastRule){\n                if (lastRule.outline){\n                    if (lastRule.selectors.toString().toLowerCase().indexOf(\":focus\") == -1){\n                        reporter.report(\"Outlines should only be modified using :focus.\", lastRule.line, lastRule.col, rule);\n                    } else if (lastRule.propCount == 1) {\n                        reporter.report(\"Outlines shouldn't be hidden unless other visual changes are made.\", lastRule.line, lastRule.col, rule);\n                    }\n                }\n            }\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startpage\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase(),\n                value = event.value;\n\n            if (lastRule){\n                lastRule.propCount++;\n                if (name == \"outline\" && (value == \"none\" || value == \"0\")){\n                    lastRule.outline = true;\n                }\n            }\n\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n        parser.addListener(\"endpage\", endRule);\n        parser.addListener(\"endpagemargin\", endRule);\n        parser.addListener(\"endkeyframerule\", endRule);\n\n    }\n\n});\n/*\n * Rule: Don't use classes or IDs with elements (a.foo or a#foo).\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"overqualified-elements\",\n    name: \"Disallow overqualified elements\",\n    desc: \"Don't use classes or IDs with elements (a.foo or a#foo).\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            classes = {};\n\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n\n                for (j=0; j < selector.parts.length; j++){\n                    part = selector.parts[j];\n                    if (part.type == parser.SELECTOR_PART_TYPE){\n                        for (k=0; k < part.modifiers.length; k++){\n                            modifier = part.modifiers[k];\n                            if (part.elementName && modifier.type == \"id\"){\n                                reporter.report(\"Element (\" + part + \") is overqualified, just use \" + modifier + \" without element name.\", part.line, part.col, rule);\n                            } else if (modifier.type == \"class\"){\n\n                                if (!classes[modifier]){\n                                    classes[modifier] = [];\n                                }\n                                classes[modifier].push({ modifier: modifier, part: part });\n                            }\n                        }\n                    }\n                }\n            }\n        });\n\n        parser.addListener(\"endstylesheet\", function(){\n\n            var prop;\n            for (prop in classes){\n                if (classes.hasOwnProperty(prop)){\n\n                    //one use means that this is overqualified\n                    if (classes[prop].length == 1 && classes[prop][0].part.elementName){\n                        reporter.report(\"Element (\" + classes[prop][0].part + \") is overqualified, just use \" + classes[prop][0].modifier + \" without element name.\", classes[prop][0].part.line, classes[prop][0].part.col, rule);\n                    }\n                }\n            }\n        });\n    }\n\n});\n/*\n * Rule: Headings (h1-h6) should not be qualified (namespaced).\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"qualified-headings\",\n    name: \"Disallow qualified headings\",\n    desc: \"Headings should not be qualified (namespaced).\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                i, j;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n\n                for (j=0; j < selector.parts.length; j++){\n                    part = selector.parts[j];\n                    if (part.type == parser.SELECTOR_PART_TYPE){\n                        if (part.elementName && /h[1-6]/.test(part.elementName.toString()) && j > 0){\n                            reporter.report(\"Heading (\" + part.elementName + \") should not be qualified.\", part.line, part.col, rule);\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n});\n/*\n * Rule: Selectors that look like regular expressions are slow and should be avoided.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"regex-selectors\",\n    name: \"Disallow selectors that look like regexs\",\n    desc: \"Selectors that look like regular expressions are slow and should be avoided.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n                for (j=0; j < selector.parts.length; j++){\n                    part = selector.parts[j];\n                    if (part.type == parser.SELECTOR_PART_TYPE){\n                        for (k=0; k < part.modifiers.length; k++){\n                            modifier = part.modifiers[k];\n                            if (modifier.type == \"attribute\"){\n                                if (/([\\~\\|\\^\\$\\*]=)/.test(modifier)){\n                                    reporter.report(\"Attribute selectors with \" + RegExp.$1 + \" are slow!\", modifier.line, modifier.col, rule);\n                                }\n                            }\n\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n});\n/*\n * Rule: Total number of rules should not exceed x.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"rules-count\",\n    name: \"Rules Count\",\n    desc: \"Track how many rules there are.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            count = 0;\n\n        //count each rule\n        parser.addListener(\"startrule\", function(){\n            count++;\n        });\n\n        parser.addListener(\"endstylesheet\", function(){\n            reporter.stat(\"rule-count\", count);\n        });\n    }\n\n});\n/*\n * Rule: Warn people with approaching the IE 4095 limit\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"selector-max-approaching\",\n    name: \"Warn when approaching the 4095 selector limit for IE\",\n    desc: \"Will warn when selector count is >= 3800 selectors.\",\n    browsers: \"IE\",\n\n    //initialization\n    init: function(parser, reporter) {\n        var rule = this, count = 0;\n\n        parser.addListener('startrule', function(event) {\n            count += event.selectors.length;\n        });\n\n        parser.addListener(\"endstylesheet\", function() {\n            if (count >= 3800) {\n                reporter.report(\"You have \" + count + \" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.\",0,0,rule);\n            }\n        });\n    }\n\n});\n\n/*\n * Rule: Warn people past the IE 4095 limit\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"selector-max\",\n    name: \"Error when past the 4095 selector limit for IE\",\n    desc: \"Will error when selector count is > 4095.\",\n    browsers: \"IE\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this, count = 0;\n\n        parser.addListener('startrule',function(event) {\n            count += event.selectors.length;\n        });\n\n        parser.addListener(\"endstylesheet\", function() {\n            if (count > 4095) {\n                reporter.report(\"You have \" + count + \" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.\",0,0,rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: Use shorthand properties where possible.\n *\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"shorthand\",\n    name: \"Require shorthand properties\",\n    desc: \"Use shorthand properties where possible.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            prop, i, len,\n            propertiesToCheck = {},\n            properties,\n            mapping = {\n                \"margin\": [\n                    \"margin-top\",\n                    \"margin-bottom\",\n                    \"margin-left\",\n                    \"margin-right\"\n                ],\n                \"padding\": [\n                    \"padding-top\",\n                    \"padding-bottom\",\n                    \"padding-left\",\n                    \"padding-right\"\n                ]\n            };\n\n        //initialize propertiesToCheck\n        for (prop in mapping){\n            if (mapping.hasOwnProperty(prop)){\n                for (i=0, len=mapping[prop].length; i < len; i++){\n                    propertiesToCheck[mapping[prop][i]] = prop;\n                }\n            }\n        }\n\n        function startRule(event){\n            properties = {};\n        }\n\n        //event handler for end of rules\n        function endRule(event){\n\n            var prop, i, len, total;\n\n            //check which properties this rule has\n            for (prop in mapping){\n                if (mapping.hasOwnProperty(prop)){\n                    total=0;\n\n                    for (i=0, len=mapping[prop].length; i < len; i++){\n                        total += properties[mapping[prop][i]] ? 1 : 0;\n                    }\n\n                    if (total == mapping[prop].length){\n                        reporter.report(\"The properties \" + mapping[prop].join(\", \") + \" can be replaced by \" + prop + \".\", event.line, event.col, rule);\n                    }\n                }\n            }\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n\n        //check for use of \"font-size\"\n        parser.addListener(\"property\", function(event){\n            var name = event.property.toString().toLowerCase(),\n                value = event.value.parts[0].value;\n\n            if (propertiesToCheck[name]){\n                properties[name] = 1;\n            }\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n\n    }\n\n});\n/*\n * Rule: Don't use properties with a star prefix.\n *\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"star-property-hack\",\n    name: \"Disallow properties with a star prefix\",\n    desc: \"Checks for the star property hack (targets IE6/7)\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        //check if property name starts with \"*\"\n        parser.addListener(\"property\", function(event){\n            var property = event.property;\n\n            if (property.hack == \"*\") {\n                reporter.report(\"Property with star prefix found.\", event.property.line, event.property.col, rule);\n            }\n        });\n    }\n});\n/*\n * Rule: Don't use text-indent for image replacement if you need to support rtl.\n *\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"text-indent\",\n    name: \"Disallow negative text-indent\",\n    desc: \"Checks for text indent less than -99px\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            textIndent,\n            direction;\n\n\n        function startRule(event){\n            textIndent = false;\n            direction = \"inherit\";\n        }\n\n        //event handler for end of rules\n        function endRule(event){\n            if (textIndent && direction != \"ltr\"){\n                reporter.report(\"Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.\", textIndent.line, textIndent.col, rule);\n            }\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n\n        //check for use of \"font-size\"\n        parser.addListener(\"property\", function(event){\n            var name = event.property.toString().toLowerCase(),\n                value = event.value;\n\n            if (name == \"text-indent\" && value.parts[0].value < -99){\n                textIndent = event.property;\n            } else if (name == \"direction\" && value == \"ltr\"){\n                direction = \"ltr\";\n            }\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n\n    }\n\n});\n/*\n * Rule: Don't use properties with a underscore prefix.\n *\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"underscore-property-hack\",\n    name: \"Disallow properties with an underscore prefix\",\n    desc: \"Checks for the underscore property hack (targets IE6)\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        //check if property name starts with \"_\"\n        parser.addListener(\"property\", function(event){\n            var property = event.property;\n\n            if (property.hack == \"_\") {\n                reporter.report(\"Property with underscore prefix found.\", event.property.line, event.property.col, rule);\n            }\n        });\n    }\n});\n/*\n * Rule: Headings (h1-h6) should be defined only once.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"unique-headings\",\n    name: \"Headings should only be defined once\",\n    desc: \"Headings should be defined only once.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        var headings =  {\n                h1: 0,\n                h2: 0,\n                h3: 0,\n                h4: 0,\n                h5: 0,\n                h6: 0\n            };\n\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                pseudo,\n                i, j;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n                part = selector.parts[selector.parts.length-1];\n\n                if (part.elementName && /(h[1-6])/i.test(part.elementName.toString())){\n\n                    for (j=0; j < part.modifiers.length; j++){\n                        if (part.modifiers[j].type == \"pseudo\"){\n                            pseudo = true;\n                            break;\n                        }\n                    }\n\n                    if (!pseudo){\n                        headings[RegExp.$1]++;\n                        if (headings[RegExp.$1] > 1) {\n                            reporter.report(\"Heading (\" + part.elementName + \") has already been defined.\", part.line, part.col, rule);\n                        }\n                    }\n                }\n            }\n        });\n\n        parser.addListener(\"endstylesheet\", function(event){\n            var prop,\n                messages = [];\n\n            for (prop in headings){\n                if (headings.hasOwnProperty(prop)){\n                    if (headings[prop] > 1){\n                        messages.push(headings[prop] + \" \" + prop + \"s\");\n                    }\n                }\n            }\n\n            if (messages.length){\n                reporter.rollupWarn(\"You have \" + messages.join(\", \") + \" defined in this stylesheet.\", rule);\n            }\n        });\n    }\n\n});\n/*\n * Rule: Don't use universal selector because it's slow.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"universal-selector\",\n    name: \"Disallow universal selector\",\n    desc: \"The universal selector (*) is known to be slow.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"startrule\", function(event){\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n\n                part = selector.parts[selector.parts.length-1];\n                if (part.elementName == \"*\"){\n                    reporter.report(rule.desc, part.line, part.col, rule);\n                }\n            }\n        });\n    }\n\n});\n/*\n * Rule: Don't use unqualified attribute selectors because they're just like universal selectors.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"unqualified-attributes\",\n    name: \"Disallow unqualified attribute selectors\",\n    desc: \"Unqualified attribute selectors are known to be slow.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        parser.addListener(\"startrule\", function(event){\n\n            var selectors = event.selectors,\n                selector,\n                part,\n                modifier,\n                i, j, k;\n\n            for (i=0; i < selectors.length; i++){\n                selector = selectors[i];\n\n                part = selector.parts[selector.parts.length-1];\n                if (part.type == parser.SELECTOR_PART_TYPE){\n                    for (k=0; k < part.modifiers.length; k++){\n                        modifier = part.modifiers[k];\n                        if (modifier.type == \"attribute\" && (!part.elementName || part.elementName == \"*\")){\n                            reporter.report(rule.desc, part.line, part.col, rule);\n                        }\n                    }\n                }\n\n            }\n        });\n    }\n\n});\n/*\n * Rule: When using a vendor-prefixed property, make sure to\n * include the standard one.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"vendor-prefix\",\n    name: \"Require standard property with vendor prefix\",\n    desc: \"When using a vendor-prefixed property, make sure to include the standard one.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this,\n            properties,\n            num,\n            propertiesToCheck = {\n                \"-webkit-border-radius\": \"border-radius\",\n                \"-webkit-border-top-left-radius\": \"border-top-left-radius\",\n                \"-webkit-border-top-right-radius\": \"border-top-right-radius\",\n                \"-webkit-border-bottom-left-radius\": \"border-bottom-left-radius\",\n                \"-webkit-border-bottom-right-radius\": \"border-bottom-right-radius\",\n\n                \"-o-border-radius\": \"border-radius\",\n                \"-o-border-top-left-radius\": \"border-top-left-radius\",\n                \"-o-border-top-right-radius\": \"border-top-right-radius\",\n                \"-o-border-bottom-left-radius\": \"border-bottom-left-radius\",\n                \"-o-border-bottom-right-radius\": \"border-bottom-right-radius\",\n\n                \"-moz-border-radius\": \"border-radius\",\n                \"-moz-border-radius-topleft\": \"border-top-left-radius\",\n                \"-moz-border-radius-topright\": \"border-top-right-radius\",\n                \"-moz-border-radius-bottomleft\": \"border-bottom-left-radius\",\n                \"-moz-border-radius-bottomright\": \"border-bottom-right-radius\",\n\n                \"-moz-column-count\": \"column-count\",\n                \"-webkit-column-count\": \"column-count\",\n\n                \"-moz-column-gap\": \"column-gap\",\n                \"-webkit-column-gap\": \"column-gap\",\n\n                \"-moz-column-rule\": \"column-rule\",\n                \"-webkit-column-rule\": \"column-rule\",\n\n                \"-moz-column-rule-style\": \"column-rule-style\",\n                \"-webkit-column-rule-style\": \"column-rule-style\",\n\n                \"-moz-column-rule-color\": \"column-rule-color\",\n                \"-webkit-column-rule-color\": \"column-rule-color\",\n\n                \"-moz-column-rule-width\": \"column-rule-width\",\n                \"-webkit-column-rule-width\": \"column-rule-width\",\n\n                \"-moz-column-width\": \"column-width\",\n                \"-webkit-column-width\": \"column-width\",\n\n                \"-webkit-column-span\": \"column-span\",\n                \"-webkit-columns\": \"columns\",\n\n                \"-moz-box-shadow\": \"box-shadow\",\n                \"-webkit-box-shadow\": \"box-shadow\",\n\n                \"-moz-transform\" : \"transform\",\n                \"-webkit-transform\" : \"transform\",\n                \"-o-transform\" : \"transform\",\n                \"-ms-transform\" : \"transform\",\n\n                \"-moz-transform-origin\" : \"transform-origin\",\n                \"-webkit-transform-origin\" : \"transform-origin\",\n                \"-o-transform-origin\" : \"transform-origin\",\n                \"-ms-transform-origin\" : \"transform-origin\",\n\n                \"-moz-box-sizing\" : \"box-sizing\",\n                \"-webkit-box-sizing\" : \"box-sizing\",\n\n                \"-moz-user-select\" : \"user-select\",\n                \"-khtml-user-select\" : \"user-select\",\n                \"-webkit-user-select\" : \"user-select\"\n            };\n\n        //event handler for beginning of rules\n        function startRule(){\n            properties = {};\n            num=1;\n        }\n\n        //event handler for end of rules\n        function endRule(event){\n            var prop,\n                i, len,\n                standard,\n                needed,\n                actual,\n                needsStandard = [];\n\n            for (prop in properties){\n                if (propertiesToCheck[prop]){\n                    needsStandard.push({ actual: prop, needed: propertiesToCheck[prop]});\n                }\n            }\n\n            for (i=0, len=needsStandard.length; i < len; i++){\n                needed = needsStandard[i].needed;\n                actual = needsStandard[i].actual;\n\n                if (!properties[needed]){\n                    reporter.report(\"Missing standard property '\" + needed + \"' to go along with '\" + actual + \"'.\", properties[actual][0].name.line, properties[actual][0].name.col, rule);\n                } else {\n                    //make sure standard property is last\n                    if (properties[needed][0].pos < properties[actual][0].pos){\n                        reporter.report(\"Standard property '\" + needed + \"' should come after vendor-prefixed property '\" + actual + \"'.\", properties[actual][0].name.line, properties[actual][0].name.col, rule);\n                    }\n                }\n            }\n\n        }\n\n        parser.addListener(\"startrule\", startRule);\n        parser.addListener(\"startfontface\", startRule);\n        parser.addListener(\"startpage\", startRule);\n        parser.addListener(\"startpagemargin\", startRule);\n        parser.addListener(\"startkeyframerule\", startRule);\n\n        parser.addListener(\"property\", function(event){\n            var name = event.property.text.toLowerCase();\n\n            if (!properties[name]){\n                properties[name] = [];\n            }\n\n            properties[name].push({ name: event.property, value : event.value, pos:num++ });\n        });\n\n        parser.addListener(\"endrule\", endRule);\n        parser.addListener(\"endfontface\", endRule);\n        parser.addListener(\"endpage\", endRule);\n        parser.addListener(\"endpagemargin\", endRule);\n        parser.addListener(\"endkeyframerule\", endRule);\n    }\n\n});\n/*\n * Rule: You don't need to specify units when a value is 0.\n */\n/*global CSSLint*/\nCSSLint.addRule({\n\n    //rule information\n    id: \"zero-units\",\n    name: \"Disallow units for 0 values\",\n    desc: \"You don't need to specify units when a value is 0.\",\n    browsers: \"All\",\n\n    //initialization\n    init: function(parser, reporter){\n        var rule = this;\n\n        //count how many times \"float\" is used\n        parser.addListener(\"property\", function(event){\n            var parts = event.value.parts,\n                i = 0,\n                len = parts.length;\n\n            while(i < len){\n                if ((parts[i].units || parts[i].type == \"percentage\") && parts[i].value === 0 && parts[i].type != \"time\"){\n                    reporter.report(\"Values of 0 shouldn't have units specified.\", parts[i].line, parts[i].col, rule);\n                }\n                i++;\n            }\n\n        });\n\n    }\n\n});\n/*global CSSLint*/\n(function() {\n\n    /**\n     * Replace special characters before write to output.\n     *\n     * Rules:\n     *  - single quotes is the escape sequence for double-quotes\n     *  - &amp; is the escape sequence for &\n     *  - &lt; is the escape sequence for <\n     *  - &gt; is the escape sequence for >\n     *\n     * @param {String} message to escape\n     * @return escaped message as {String}\n     */\n    var xmlEscape = function(str) {\n        if (!str || str.constructor !== String) {\n            return \"\";\n        }\n\n        return str.replace(/[\\\"&><]/g, function(match) {\n            switch (match) {\n                case \"\\\"\":\n                    return \"&quot;\";\n                case \"&\":\n                    return \"&amp;\";\n                case \"<\":\n                    return \"&lt;\";\n                case \">\":\n                    return \"&gt;\";\n            }\n        });\n    };\n\n    CSSLint.addFormatter({\n        //format information\n        id: \"checkstyle-xml\",\n        name: \"Checkstyle XML format\",\n\n        /**\n         * Return opening root XML tag.\n         * @return {String} to prepend before all results\n         */\n        startFormat: function(){\n            return \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><checkstyle>\";\n        },\n\n        /**\n         * Return closing root XML tag.\n         * @return {String} to append after all results\n         */\n        endFormat: function(){\n            return \"</checkstyle>\";\n        },\n\n        /**\n         * Returns message when there is a file read error.\n         * @param {String} filename The name of the file that caused the error.\n         * @param {String} message The error message\n         * @return {String} The error message.\n         */\n        readError: function(filename, message) {\n            return \"<file name=\\\"\" + xmlEscape(filename) + \"\\\"><error line=\\\"0\\\" column=\\\"0\\\" severty=\\\"error\\\" message=\\\"\" + xmlEscape(message) + \"\\\"></error></file>\";\n        },\n\n        /**\n         * Given CSS Lint results for a file, return output for this format.\n         * @param results {Object} with error and warning messages\n         * @param filename {String} relative file path\n         * @param options {Object} (UNUSED for now) specifies special handling of output\n         * @return {String} output for results\n         */\n        formatResults: function(results, filename, options) {\n            var messages = results.messages,\n                output = [];\n\n            /**\n             * Generate a source string for a rule.\n             * Checkstyle source strings usually resemble Java class names e.g\n             * net.csslint.SomeRuleName\n             * @param {Object} rule\n             * @return rule source as {String}\n             */\n            var generateSource = function(rule) {\n                if (!rule || !('name' in rule)) {\n                    return \"\";\n                }\n                return 'net.csslint.' + rule.name.replace(/\\s/g,'');\n            };\n\n\n\n            if (messages.length > 0) {\n                output.push(\"<file name=\\\"\"+filename+\"\\\">\");\n                CSSLint.Util.forEach(messages, function (message, i) {\n                    //ignore rollups for now\n                    if (!message.rollup) {\n                      output.push(\"<error line=\\\"\" + message.line + \"\\\" column=\\\"\" + message.col + \"\\\" severity=\\\"\" + message.type + \"\\\"\" +\n                          \" message=\\\"\" + xmlEscape(message.message) + \"\\\" source=\\\"\" + generateSource(message.rule) +\"\\\"/>\");\n                    }\n                });\n                output.push(\"</file>\");\n            }\n\n            return output.join(\"\");\n        }\n    });\n\n}());\n/*global CSSLint*/\nCSSLint.addFormatter({\n    //format information\n    id: \"compact\",\n    name: \"Compact, 'porcelain' format\",\n\n    /**\n     * Return content to be printed before all file results.\n     * @return {String} to prepend before all results\n     */\n    startFormat: function() {\n        return \"\";\n    },\n\n    /**\n     * Return content to be printed after all file results.\n     * @return {String} to append after all results\n     */\n    endFormat: function() {\n        return \"\";\n    },\n\n    /**\n     * Given CSS Lint results for a file, return output for this format.\n     * @param results {Object} with error and warning messages\n     * @param filename {String} relative file path\n     * @param options {Object} (Optional) specifies special handling of output\n     * @return {String} output for results\n     */\n    formatResults: function(results, filename, options) {\n        var messages = results.messages,\n            output = \"\";\n        options = options || {};\n\n        /**\n         * Capitalize and return given string.\n         * @param str {String} to capitalize\n         * @return {String} capitalized\n         */\n        var capitalize = function(str) {\n            return str.charAt(0).toUpperCase() + str.slice(1);\n        };\n\n        if (messages.length === 0) {\n            return options.quiet ? \"\" : filename + \": Lint Free!\";\n        }\n\n        CSSLint.Util.forEach(messages, function(message, i) {\n            if (message.rollup) {\n                output += filename + \": \" + capitalize(message.type) + \" - \" + message.message + \"\\n\";\n            } else {\n                output += filename + \": \" + \"line \" + message.line +\n                    \", col \" + message.col + \", \" + capitalize(message.type) + \" - \" + message.message + \"\\n\";\n            }\n        });\n\n        return output;\n    }\n});\n/*global CSSLint*/\nCSSLint.addFormatter({\n    //format information\n    id: \"csslint-xml\",\n    name: \"CSSLint XML format\",\n\n    /**\n     * Return opening root XML tag.\n     * @return {String} to prepend before all results\n     */\n    startFormat: function(){\n        return \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><csslint>\";\n    },\n\n    /**\n     * Return closing root XML tag.\n     * @return {String} to append after all results\n     */\n    endFormat: function(){\n        return \"</csslint>\";\n    },\n\n    /**\n     * Given CSS Lint results for a file, return output for this format.\n     * @param results {Object} with error and warning messages\n     * @param filename {String} relative file path\n     * @param options {Object} (UNUSED for now) specifies special handling of output\n     * @return {String} output for results\n     */\n    formatResults: function(results, filename, options) {\n        var messages = results.messages,\n            output = [];\n\n        /**\n         * Replace special characters before write to output.\n         *\n         * Rules:\n         *  - single quotes is the escape sequence for double-quotes\n         *  - &amp; is the escape sequence for &\n         *  - &lt; is the escape sequence for <\n         *  - &gt; is the escape sequence for >\n         *\n         * @param {String} message to escape\n         * @return escaped message as {String}\n         */\n        var escapeSpecialCharacters = function(str) {\n            if (!str || str.constructor !== String) {\n                return \"\";\n            }\n            return str.replace(/\\\"/g, \"'\").replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n        };\n\n        if (messages.length > 0) {\n            output.push(\"<file name=\\\"\"+filename+\"\\\">\");\n            CSSLint.Util.forEach(messages, function (message, i) {\n                if (message.rollup) {\n                    output.push(\"<issue severity=\\\"\" + message.type + \"\\\" reason=\\\"\" + escapeSpecialCharacters(message.message) + \"\\\" evidence=\\\"\" + escapeSpecialCharacters(message.evidence) + \"\\\"/>\");\n                } else {\n                    output.push(\"<issue line=\\\"\" + message.line + \"\\\" char=\\\"\" + message.col + \"\\\" severity=\\\"\" + message.type + \"\\\"\" +\n                        \" reason=\\\"\" + escapeSpecialCharacters(message.message) + \"\\\" evidence=\\\"\" + escapeSpecialCharacters(message.evidence) + \"\\\"/>\");\n                }\n            });\n            output.push(\"</file>\");\n        }\n\n        return output.join(\"\");\n    }\n});\n/*global CSSLint*/\nCSSLint.addFormatter({\n    //format information\n    id: \"junit-xml\",\n    name: \"JUNIT XML format\",\n\n    /**\n     * Return opening root XML tag.\n     * @return {String} to prepend before all results\n     */\n    startFormat: function(){\n        return \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><testsuites>\";\n    },\n\n    /**\n     * Return closing root XML tag.\n     * @return {String} to append after all results\n     */\n    endFormat: function() {\n        return \"</testsuites>\";\n    },\n\n    /**\n     * Given CSS Lint results for a file, return output for this format.\n     * @param results {Object} with error and warning messages\n     * @param filename {String} relative file path\n     * @param options {Object} (UNUSED for now) specifies special handling of output\n     * @return {String} output for results\n     */\n    formatResults: function(results, filename, options) {\n\n        var messages = results.messages,\n            output = [],\n            tests = {\n                'error': 0,\n                'failure': 0\n            };\n\n        /**\n         * Generate a source string for a rule.\n         * JUNIT source strings usually resemble Java class names e.g\n         * net.csslint.SomeRuleName\n         * @param {Object} rule\n         * @return rule source as {String}\n         */\n        var generateSource = function(rule) {\n            if (!rule || !('name' in rule)) {\n                return \"\";\n            }\n            return 'net.csslint.' + rule.name.replace(/\\s/g,'');\n        };\n\n        /**\n         * Replace special characters before write to output.\n         *\n         * Rules:\n         *  - single quotes is the escape sequence for double-quotes\n         *  - &lt; is the escape sequence for <\n         *  - &gt; is the escape sequence for >\n         *\n         * @param {String} message to escape\n         * @return escaped message as {String}\n         */\n        var escapeSpecialCharacters = function(str) {\n\n            if (!str || str.constructor !== String) {\n                return \"\";\n            }\n\n            return str.replace(/\\\"/g, \"'\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n\n        };\n\n        if (messages.length > 0) {\n\n            messages.forEach(function (message, i) {\n\n                // since junit has no warning class\n                // all issues as errors\n                var type = message.type === 'warning' ? 'error' : message.type;\n\n                //ignore rollups for now\n                if (!message.rollup) {\n\n                    // build the test case seperately, once joined\n                    // we'll add it to a custom array filtered by type\n                    output.push(\"<testcase time=\\\"0\\\" name=\\\"\" + generateSource(message.rule) + \"\\\">\");\n                    output.push(\"<\" + type + \" message=\\\"\" + escapeSpecialCharacters(message.message) + \"\\\"><![CDATA[\" + message.line + ':' + message.col + ':' + escapeSpecialCharacters(message.evidence)  + \"]]></\" + type + \">\");\n                    output.push(\"</testcase>\");\n\n                    tests[type] += 1;\n\n                }\n\n            });\n\n            output.unshift(\"<testsuite time=\\\"0\\\" tests=\\\"\" + messages.length + \"\\\" skipped=\\\"0\\\" errors=\\\"\" + tests.error + \"\\\" failures=\\\"\" + tests.failure + \"\\\" package=\\\"net.csslint\\\" name=\\\"\" + filename + \"\\\">\");\n            output.push(\"</testsuite>\");\n\n        }\n\n        return output.join(\"\");\n\n    }\n});\n/*global CSSLint*/\nCSSLint.addFormatter({\n    //format information\n    id: \"lint-xml\",\n    name: \"Lint XML format\",\n\n    /**\n     * Return opening root XML tag.\n     * @return {String} to prepend before all results\n     */\n    startFormat: function(){\n        return \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><lint>\";\n    },\n\n    /**\n     * Return closing root XML tag.\n     * @return {String} to append after all results\n     */\n    endFormat: function(){\n        return \"</lint>\";\n    },\n\n    /**\n     * Given CSS Lint results for a file, return output for this format.\n     * @param results {Object} with error and warning messages\n     * @param filename {String} relative file path\n     * @param options {Object} (UNUSED for now) specifies special handling of output\n     * @return {String} output for results\n     */\n    formatResults: function(results, filename, options) {\n        var messages = results.messages,\n            output = [];\n\n        /**\n         * Replace special characters before write to output.\n         *\n         * Rules:\n         *  - single quotes is the escape sequence for double-quotes\n         *  - &amp; is the escape sequence for &\n         *  - &lt; is the escape sequence for <\n         *  - &gt; is the escape sequence for >\n         *\n         * @param {String} message to escape\n         * @return escaped message as {String}\n         */\n        var escapeSpecialCharacters = function(str) {\n            if (!str || str.constructor !== String) {\n                return \"\";\n            }\n            return str.replace(/\\\"/g, \"'\").replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n        };\n\n        if (messages.length > 0) {\n\n            output.push(\"<file name=\\\"\"+filename+\"\\\">\");\n            CSSLint.Util.forEach(messages, function (message, i) {\n                if (message.rollup) {\n                    output.push(\"<issue severity=\\\"\" + message.type + \"\\\" reason=\\\"\" + escapeSpecialCharacters(message.message) + \"\\\" evidence=\\\"\" + escapeSpecialCharacters(message.evidence) + \"\\\"/>\");\n                } else {\n                    output.push(\"<issue line=\\\"\" + message.line + \"\\\" char=\\\"\" + message.col + \"\\\" severity=\\\"\" + message.type + \"\\\"\" +\n                        \" reason=\\\"\" + escapeSpecialCharacters(message.message) + \"\\\" evidence=\\\"\" + escapeSpecialCharacters(message.evidence) + \"\\\"/>\");\n                }\n            });\n            output.push(\"</file>\");\n        }\n\n        return output.join(\"\");\n    }\n});\n/*global CSSLint*/\nCSSLint.addFormatter({\n    //format information\n    id: \"text\",\n    name: \"Plain Text\",\n\n    /**\n     * Return content to be printed before all file results.\n     * @return {String} to prepend before all results\n     */\n    startFormat: function() {\n        return \"\";\n    },\n\n    /**\n     * Return content to be printed after all file results.\n     * @return {String} to append after all results\n     */\n    endFormat: function() {\n        return \"\";\n    },\n\n    /**\n     * Given CSS Lint results for a file, return output for this format.\n     * @param results {Object} with error and warning messages\n     * @param filename {String} relative file path\n     * @param options {Object} (Optional) specifies special handling of output\n     * @return {String} output for results\n     */\n    formatResults: function(results, filename, options) {\n        var messages = results.messages,\n            output = \"\";\n        options = options || {};\n\n        if (messages.length === 0) {\n            return options.quiet ? \"\" : \"\\n\\ncsslint: No errors in \" + filename + \".\";\n        }\n\n        output = \"\\n\\ncsslint: There are \" + messages.length  +  \" problems in \" + filename + \".\";\n        var pos = filename.lastIndexOf(\"/\"),\n            shortFilename = filename;\n\n        if (pos === -1){\n            pos = filename.lastIndexOf(\"\\\\\");\n        }\n        if (pos > -1){\n            shortFilename = filename.substring(pos+1);\n        }\n\n        CSSLint.Util.forEach(messages, function (message, i) {\n            output = output + \"\\n\\n\" + shortFilename;\n            if (message.rollup) {\n                output += \"\\n\" + (i+1) + \": \" + message.type;\n                output += \"\\n\" + message.message;\n            } else {\n                output += \"\\n\" + (i+1) + \": \" + message.type + \" at line \" + message.line + \", col \" + message.col;\n                output += \"\\n\" + message.message;\n                output += \"\\n\" + message.evidence;\n            }\n        });\n\n        return output;\n    }\n});\nexports.CSSLint = CSSLint;\n"
  },
  {
    "path": "gulp/util/csslint/lib/parserlib.js",
    "content": "/*!\nParser-Lib\nCopyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.\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\n*/\n/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */\nvar parserlib = {};\n(function(){\n\n/**\n * A generic base to inherit from for any object\n * that needs event handling.\n * @class EventTarget\n * @constructor\n */\nfunction EventTarget(){\n\n    /**\n     * The array of listeners for various events.\n     * @type Object\n     * @property _listeners\n     * @private\n     */\n    this._listeners = {};\n}\n\nEventTarget.prototype = {\n\n    //restore constructor\n    constructor: EventTarget,\n\n    /**\n     * Adds a listener for a given event type.\n     * @param {String} type The type of event to add a listener for.\n     * @param {Function} listener The function to call when the event occurs.\n     * @return {void}\n     * @method addListener\n     */\n    addListener: function(type, listener){\n        if (!this._listeners[type]){\n            this._listeners[type] = [];\n        }\n\n        this._listeners[type].push(listener);\n    },\n\n    /**\n     * Fires an event based on the passed-in object.\n     * @param {Object|String} event An object with at least a 'type' attribute\n     *      or a string indicating the event name.\n     * @return {void}\n     * @method fire\n     */\n    fire: function(event){\n        if (typeof event == \"string\"){\n            event = { type: event };\n        }\n        if (typeof event.target != \"undefined\"){\n            event.target = this;\n        }\n\n        if (typeof event.type == \"undefined\"){\n            throw new Error(\"Event object missing 'type' property.\");\n        }\n\n        if (this._listeners[event.type]){\n\n            //create a copy of the array and use that so listeners can't chane\n            var listeners = this._listeners[event.type].concat();\n            for (var i=0, len=listeners.length; i < len; i++){\n                listeners[i].call(this, event);\n            }\n        }\n    },\n\n    /**\n     * Removes a listener for a given event type.\n     * @param {String} type The type of event to remove a listener from.\n     * @param {Function} listener The function to remove from the event.\n     * @return {void}\n     * @method removeListener\n     */\n    removeListener: function(type, listener){\n        if (this._listeners[type]){\n            var listeners = this._listeners[type];\n            for (var i=0, len=listeners.length; i < len; i++){\n                if (listeners[i] === listener){\n                    listeners.splice(i, 1);\n                    break;\n                }\n            }\n\n\n        }\n    }\n};\n/**\n * Convenient way to read through strings.\n * @namespace parserlib.util\n * @class StringReader\n * @constructor\n * @param {String} text The text to read.\n */\nfunction StringReader(text){\n\n    /**\n     * The input text with line endings normalized.\n     * @property _input\n     * @type String\n     * @private\n     */\n    this._input = text.replace(/\\n\\r?/g, \"\\n\");\n\n\n    /**\n     * The row for the character to be read next.\n     * @property _line\n     * @type int\n     * @private\n     */\n    this._line = 1;\n\n\n    /**\n     * The column for the character to be read next.\n     * @property _col\n     * @type int\n     * @private\n     */\n    this._col = 1;\n\n    /**\n     * The index of the character in the input to be read next.\n     * @property _cursor\n     * @type int\n     * @private\n     */\n    this._cursor = 0;\n}\n\nStringReader.prototype = {\n\n    //restore constructor\n    constructor: StringReader,\n\n    //-------------------------------------------------------------------------\n    // Position info\n    //-------------------------------------------------------------------------\n\n    /**\n     * Returns the column of the character to be read next.\n     * @return {int} The column of the character to be read next.\n     * @method getCol\n     */\n    getCol: function(){\n        return this._col;\n    },\n\n    /**\n     * Returns the row of the character to be read next.\n     * @return {int} The row of the character to be read next.\n     * @method getLine\n     */\n    getLine: function(){\n        return this._line ;\n    },\n\n    /**\n     * Determines if you're at the end of the input.\n     * @return {Boolean} True if there's no more input, false otherwise.\n     * @method eof\n     */\n    eof: function(){\n        return (this._cursor == this._input.length);\n    },\n\n    //-------------------------------------------------------------------------\n    // Basic reading\n    //-------------------------------------------------------------------------\n\n    /**\n     * Reads the next character without advancing the cursor.\n     * @param {int} count How many characters to look ahead (default is 1).\n     * @return {String} The next character or null if there is no next character.\n     * @method peek\n     */\n    peek: function(count){\n        var c = null;\n        count = (typeof count == \"undefined\" ? 1 : count);\n\n        //if we're not at the end of the input...\n        if (this._cursor < this._input.length){\n\n            //get character and increment cursor and column\n            c = this._input.charAt(this._cursor + count - 1);\n        }\n\n        return c;\n    },\n\n    /**\n     * Reads the next character from the input and adjusts the row and column\n     * accordingly.\n     * @return {String} The next character or null if there is no next character.\n     * @method read\n     */\n    read: function(){\n        var c = null;\n\n        //if we're not at the end of the input...\n        if (this._cursor < this._input.length){\n\n            //if the last character was a newline, increment row count\n            //and reset column count\n            if (this._input.charAt(this._cursor) == \"\\n\"){\n                this._line++;\n                this._col=1;\n            } else {\n                this._col++;\n            }\n\n            //get character and increment cursor and column\n            c = this._input.charAt(this._cursor++);\n        }\n\n        return c;\n    },\n\n    //-------------------------------------------------------------------------\n    // Misc\n    //-------------------------------------------------------------------------\n\n    /**\n     * Saves the current location so it can be returned to later.\n     * @method mark\n     * @return {void}\n     */\n    mark: function(){\n        this._bookmark = {\n            cursor: this._cursor,\n            line:   this._line,\n            col:    this._col\n        };\n    },\n\n    reset: function(){\n        if (this._bookmark){\n            this._cursor = this._bookmark.cursor;\n            this._line = this._bookmark.line;\n            this._col = this._bookmark.col;\n            delete this._bookmark;\n        }\n    },\n\n    //-------------------------------------------------------------------------\n    // Advanced reading\n    //-------------------------------------------------------------------------\n\n    /**\n     * Reads up to and including the given string. Throws an error if that\n     * string is not found.\n     * @param {String} pattern The string to read.\n     * @return {String} The string when it is found.\n     * @throws Error when the string pattern is not found.\n     * @method readTo\n     */\n    readTo: function(pattern){\n\n        var buffer = \"\",\n            c;\n\n        /*\n         * First, buffer must be the same length as the pattern.\n         * Then, buffer must end with the pattern or else reach the\n         * end of the input.\n         */\n        while (buffer.length < pattern.length || buffer.lastIndexOf(pattern) != buffer.length - pattern.length){\n            c = this.read();\n            if (c){\n                buffer += c;\n            } else {\n                throw new Error(\"Expected \\\"\" + pattern + \"\\\" at line \" + this._line  + \", col \" + this._col + \".\");\n            }\n        }\n\n        return buffer;\n\n    },\n\n    /**\n     * Reads characters while each character causes the given\n     * filter function to return true. The function is passed\n     * in each character and either returns true to continue\n     * reading or false to stop.\n     * @param {Function} filter The function to read on each character.\n     * @return {String} The string made up of all characters that passed the\n     *      filter check.\n     * @method readWhile\n     */\n    readWhile: function(filter){\n\n        var buffer = \"\",\n            c = this.read();\n\n        while(c !== null && filter(c)){\n            buffer += c;\n            c = this.read();\n        }\n\n        return buffer;\n\n    },\n\n    /**\n     * Reads characters that match either text or a regular expression and\n     * returns those characters. If a match is found, the row and column\n     * are adjusted; if no match is found, the reader's state is unchanged.\n     * reading or false to stop.\n     * @param {String|RegExp} matchter If a string, then the literal string\n     *      value is searched for. If a regular expression, then any string\n     *      matching the pattern is search for.\n     * @return {String} The string made up of all characters that matched or\n     *      null if there was no match.\n     * @method readMatch\n     */\n    readMatch: function(matcher){\n\n        var source = this._input.substring(this._cursor),\n            value = null;\n\n        //if it's a string, just do a straight match\n        if (typeof matcher == \"string\"){\n            if (source.indexOf(matcher) === 0){\n                value = this.readCount(matcher.length);\n            }\n        } else if (matcher instanceof RegExp){\n            if (matcher.test(source)){\n                value = this.readCount(RegExp.lastMatch.length);\n            }\n        }\n\n        return value;\n    },\n\n\n    /**\n     * Reads a given number of characters. If the end of the input is reached,\n     * it reads only the remaining characters and does not throw an error.\n     * @param {int} count The number of characters to read.\n     * @return {String} The string made up the read characters.\n     * @method readCount\n     */\n    readCount: function(count){\n        var buffer = \"\";\n\n        while(count--){\n            buffer += this.read();\n        }\n\n        return buffer;\n    }\n\n};\n/**\n * Type to use when a syntax error occurs.\n * @class SyntaxError\n * @namespace parserlib.util\n * @constructor\n * @param {String} message The error message.\n * @param {int} line The line at which the error occurred.\n * @param {int} col The column at which the error occurred.\n */\nfunction SyntaxError(message, line, col){\n\n    /**\n     * The column at which the error occurred.\n     * @type int\n     * @property col\n     */\n    this.col = col;\n\n    /**\n     * The line at which the error occurred.\n     * @type int\n     * @property line\n     */\n    this.line = line;\n\n    /**\n     * The text representation of the unit.\n     * @type String\n     * @property text\n     */\n    this.message = message;\n\n}\n\n//inherit from Error\nSyntaxError.prototype = new Error();\n/**\n * Base type to represent a single syntactic unit.\n * @class SyntaxUnit\n * @namespace parserlib.util\n * @constructor\n * @param {String} text The text of the unit.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction SyntaxUnit(text, line, col, type){\n\n\n    /**\n     * The column of text on which the unit resides.\n     * @type int\n     * @property col\n     */\n    this.col = col;\n\n    /**\n     * The line of text on which the unit resides.\n     * @type int\n     * @property line\n     */\n    this.line = line;\n\n    /**\n     * The text representation of the unit.\n     * @type String\n     * @property text\n     */\n    this.text = text;\n\n    /**\n     * The type of syntax unit.\n     * @type int\n     * @property type\n     */\n    this.type = type;\n}\n\n/**\n * Create a new syntax unit based solely on the given token.\n * Convenience method for creating a new syntax unit when\n * it represents a single token instead of multiple.\n * @param {Object} token The token object to represent.\n * @return {parserlib.util.SyntaxUnit} The object representing the token.\n * @static\n * @method fromToken\n */\nSyntaxUnit.fromToken = function(token){\n    return new SyntaxUnit(token.value, token.startLine, token.startCol);\n};\n\nSyntaxUnit.prototype = {\n\n    //restore constructor\n    constructor: SyntaxUnit,\n\n    /**\n     * Returns the text representation of the unit.\n     * @return {String} The text representation of the unit.\n     * @method valueOf\n     */\n    valueOf: function(){\n        return this.toString();\n    },\n\n    /**\n     * Returns the text representation of the unit.\n     * @return {String} The text representation of the unit.\n     * @method toString\n     */\n    toString: function(){\n        return this.text;\n    }\n\n};\n/*global StringReader, SyntaxError*/\n\n/**\n * Generic TokenStream providing base functionality.\n * @class TokenStreamBase\n * @namespace parserlib.util\n * @constructor\n * @param {String|StringReader} input The text to tokenize or a reader from\n *      which to read the input.\n */\nfunction TokenStreamBase(input, tokenData){\n\n    /**\n     * The string reader for easy access to the text.\n     * @type StringReader\n     * @property _reader\n     * @private\n     */\n    this._reader = input ? new StringReader(input.toString()) : null;\n\n    /**\n     * Token object for the last consumed token.\n     * @type Token\n     * @property _token\n     * @private\n     */\n    this._token = null;\n\n    /**\n     * The array of token information.\n     * @type Array\n     * @property _tokenData\n     * @private\n     */\n    this._tokenData = tokenData;\n\n    /**\n     * Lookahead token buffer.\n     * @type Array\n     * @property _lt\n     * @private\n     */\n    this._lt = [];\n\n    /**\n     * Lookahead token buffer index.\n     * @type int\n     * @property _ltIndex\n     * @private\n     */\n    this._ltIndex = 0;\n\n    this._ltIndexCache = [];\n}\n\n/**\n * Accepts an array of token information and outputs\n * an array of token data containing key-value mappings\n * and matching functions that the TokenStream needs.\n * @param {Array} tokens An array of token descriptors.\n * @return {Array} An array of processed token data.\n * @method createTokenData\n * @static\n */\nTokenStreamBase.createTokenData = function(tokens){\n\n    var nameMap     = [],\n        typeMap     = {},\n        tokenData     = tokens.concat([]),\n        i            = 0,\n        len            = tokenData.length+1;\n\n    tokenData.UNKNOWN = -1;\n    tokenData.unshift({name:\"EOF\"});\n\n    for (; i < len; i++){\n        nameMap.push(tokenData[i].name);\n        tokenData[tokenData[i].name] = i;\n        if (tokenData[i].text){\n            typeMap[tokenData[i].text] = i;\n        }\n    }\n\n    tokenData.name = function(tt){\n        return nameMap[tt];\n    };\n\n    tokenData.type = function(c){\n        return typeMap[c];\n    };\n\n    return tokenData;\n};\n\nTokenStreamBase.prototype = {\n\n    //restore constructor\n    constructor: TokenStreamBase,\n\n    //-------------------------------------------------------------------------\n    // Matching methods\n    //-------------------------------------------------------------------------\n\n    /**\n     * Determines if the next token matches the given token type.\n     * If so, that token is consumed; if not, the token is placed\n     * back onto the token stream. You can pass in any number of\n     * token types and this will return true if any of the token\n     * types is found.\n     * @param {int|int[]} tokenTypes Either a single token type or an array of\n     *      token types that the next token might be. If an array is passed,\n     *      it's assumed that the token can be any of these.\n     * @param {variant} channel (Optional) The channel to read from. If not\n     *      provided, reads from the default (unnamed) channel.\n     * @return {Boolean} True if the token type matches, false if not.\n     * @method match\n     */\n    match: function(tokenTypes, channel){\n\n        //always convert to an array, makes things easier\n        if (!(tokenTypes instanceof Array)){\n            tokenTypes = [tokenTypes];\n        }\n\n        var tt  = this.get(channel),\n            i   = 0,\n            len = tokenTypes.length;\n\n        while(i < len){\n            if (tt == tokenTypes[i++]){\n                return true;\n            }\n        }\n\n        //no match found, put the token back\n        this.unget();\n        return false;\n    },\n\n    /**\n     * Determines if the next token matches the given token type.\n     * If so, that token is consumed; if not, an error is thrown.\n     * @param {int|int[]} tokenTypes Either a single token type or an array of\n     *      token types that the next token should be. If an array is passed,\n     *      it's assumed that the token must be one of these.\n     * @param {variant} channel (Optional) The channel to read from. If not\n     *      provided, reads from the default (unnamed) channel.\n     * @return {void}\n     * @method mustMatch\n     */\n    mustMatch: function(tokenTypes, channel){\n\n        var token;\n\n        //always convert to an array, makes things easier\n        if (!(tokenTypes instanceof Array)){\n            tokenTypes = [tokenTypes];\n        }\n\n        if (!this.match.apply(this, arguments)){\n            token = this.LT(1);\n            throw new SyntaxError(\"Expected \" + this._tokenData[tokenTypes[0]].name +\n                \" at line \" + token.startLine + \", col \" + token.startCol + \".\", token.startLine, token.startCol);\n        }\n    },\n\n    //-------------------------------------------------------------------------\n    // Consuming methods\n    //-------------------------------------------------------------------------\n\n    /**\n     * Keeps reading from the token stream until either one of the specified\n     * token types is found or until the end of the input is reached.\n     * @param {int|int[]} tokenTypes Either a single token type or an array of\n     *      token types that the next token should be. If an array is passed,\n     *      it's assumed that the token must be one of these.\n     * @param {variant} channel (Optional) The channel to read from. If not\n     *      provided, reads from the default (unnamed) channel.\n     * @return {void}\n     * @method advance\n     */\n    advance: function(tokenTypes, channel){\n\n        while(this.LA(0) !== 0 && !this.match(tokenTypes, channel)){\n            this.get();\n        }\n\n        return this.LA(0);\n    },\n\n    /**\n     * Consumes the next token from the token stream.\n     * @return {int} The token type of the token that was just consumed.\n     * @method get\n     */\n    get: function(channel){\n\n        var tokenInfo   = this._tokenData,\n            reader      = this._reader,\n            value,\n            i           =0,\n            len         = tokenInfo.length,\n            found       = false,\n            token,\n            info;\n\n        //check the lookahead buffer first\n        if (this._lt.length && this._ltIndex >= 0 && this._ltIndex < this._lt.length){\n\n            i++;\n            this._token = this._lt[this._ltIndex++];\n            info = tokenInfo[this._token.type];\n\n            //obey channels logic\n            while((info.channel !== undefined && channel !== info.channel) &&\n                    this._ltIndex < this._lt.length){\n                this._token = this._lt[this._ltIndex++];\n                info = tokenInfo[this._token.type];\n                i++;\n            }\n\n            //here be dragons\n            if ((info.channel === undefined || channel === info.channel) &&\n                    this._ltIndex <= this._lt.length){\n                this._ltIndexCache.push(i);\n                return this._token.type;\n            }\n        }\n\n        //call token retriever method\n        token = this._getToken();\n\n        //if it should be hidden, don't save a token\n        if (token.type > -1 && !tokenInfo[token.type].hide){\n\n            //apply token channel\n            token.channel = tokenInfo[token.type].channel;\n\n            //save for later\n            this._token = token;\n            this._lt.push(token);\n\n            //save space that will be moved (must be done before array is truncated)\n            this._ltIndexCache.push(this._lt.length - this._ltIndex + i);\n\n            //keep the buffer under 5 items\n            if (this._lt.length > 5){\n                this._lt.shift();\n            }\n\n            //also keep the shift buffer under 5 items\n            if (this._ltIndexCache.length > 5){\n                this._ltIndexCache.shift();\n            }\n\n            //update lookahead index\n            this._ltIndex = this._lt.length;\n        }\n\n        /*\n         * Skip to the next token if:\n         * 1. The token type is marked as hidden.\n         * 2. The token type has a channel specified and it isn't the current channel.\n         */\n        info = tokenInfo[token.type];\n        if (info &&\n                (info.hide ||\n                (info.channel !== undefined && channel !== info.channel))){\n            return this.get(channel);\n        } else {\n            //return just the type\n            return token.type;\n        }\n    },\n\n    /**\n     * Looks ahead a certain number of tokens and returns the token type at\n     * that position. This will throw an error if you lookahead past the\n     * end of input, past the size of the lookahead buffer, or back past\n     * the first token in the lookahead buffer.\n     * @param {int} The index of the token type to retrieve. 0 for the\n     *      current token, 1 for the next, -1 for the previous, etc.\n     * @return {int} The token type of the token in the given position.\n     * @method LA\n     */\n    LA: function(index){\n        var total = index,\n            tt;\n        if (index > 0){\n            //TODO: Store 5 somewhere\n            if (index > 5){\n                throw new Error(\"Too much lookahead.\");\n            }\n\n            //get all those tokens\n            while(total){\n                tt = this.get();\n                total--;\n            }\n\n            //unget all those tokens\n            while(total < index){\n                this.unget();\n                total++;\n            }\n        } else if (index < 0){\n\n            if(this._lt[this._ltIndex+index]){\n                tt = this._lt[this._ltIndex+index].type;\n            } else {\n                throw new Error(\"Too much lookbehind.\");\n            }\n\n        } else {\n            tt = this._token.type;\n        }\n\n        return tt;\n\n    },\n\n    /**\n     * Looks ahead a certain number of tokens and returns the token at\n     * that position. This will throw an error if you lookahead past the\n     * end of input, past the size of the lookahead buffer, or back past\n     * the first token in the lookahead buffer.\n     * @param {int} The index of the token type to retrieve. 0 for the\n     *      current token, 1 for the next, -1 for the previous, etc.\n     * @return {Object} The token of the token in the given position.\n     * @method LA\n     */\n    LT: function(index){\n\n        //lookahead first to prime the token buffer\n        this.LA(index);\n\n        //now find the token, subtract one because _ltIndex is already at the next index\n        return this._lt[this._ltIndex+index-1];\n    },\n\n    /**\n     * Returns the token type for the next token in the stream without\n     * consuming it.\n     * @return {int} The token type of the next token in the stream.\n     * @method peek\n     */\n    peek: function(){\n        return this.LA(1);\n    },\n\n    /**\n     * Returns the actual token object for the last consumed token.\n     * @return {Token} The token object for the last consumed token.\n     * @method token\n     */\n    token: function(){\n        return this._token;\n    },\n\n    /**\n     * Returns the name of the token for the given token type.\n     * @param {int} tokenType The type of token to get the name of.\n     * @return {String} The name of the token or \"UNKNOWN_TOKEN\" for any\n     *      invalid token type.\n     * @method tokenName\n     */\n    tokenName: function(tokenType){\n        if (tokenType < 0 || tokenType > this._tokenData.length){\n            return \"UNKNOWN_TOKEN\";\n        } else {\n            return this._tokenData[tokenType].name;\n        }\n    },\n\n    /**\n     * Returns the token type value for the given token name.\n     * @param {String} tokenName The name of the token whose value should be returned.\n     * @return {int} The token type value for the given token name or -1\n     *      for an unknown token.\n     * @method tokenName\n     */\n    tokenType: function(tokenName){\n        return this._tokenData[tokenName] || -1;\n    },\n\n    /**\n     * Returns the last consumed token to the token stream.\n     * @method unget\n     */\n    unget: function(){\n        //if (this._ltIndex > -1){\n        if (this._ltIndexCache.length){\n            this._ltIndex -= this._ltIndexCache.pop();//--;\n            this._token = this._lt[this._ltIndex - 1];\n        } else {\n            throw new Error(\"Too much lookahead.\");\n        }\n    }\n\n};\n\n\nparserlib.util = {\nStringReader: StringReader,\nSyntaxError : SyntaxError,\nSyntaxUnit  : SyntaxUnit,\nEventTarget : EventTarget,\nTokenStreamBase : TokenStreamBase\n};\n})();\n/*\nParser-Lib\nCopyright (c) 2009-2011 Nicholas C. Zakas. All rights reserved.\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\n*/\n/* Version v0.2.5, Build time: 7-May-2014 03:37:38 */\n(function(){\nvar EventTarget = parserlib.util.EventTarget,\nTokenStreamBase = parserlib.util.TokenStreamBase,\nStringReader = parserlib.util.StringReader,\nSyntaxError = parserlib.util.SyntaxError,\nSyntaxUnit  = parserlib.util.SyntaxUnit;\n\nvar Colors = {\n    aliceblue       :\"#f0f8ff\",\n    antiquewhite    :\"#faebd7\",\n    aqua            :\"#00ffff\",\n    aquamarine      :\"#7fffd4\",\n    azure           :\"#f0ffff\",\n    beige           :\"#f5f5dc\",\n    bisque          :\"#ffe4c4\",\n    black           :\"#000000\",\n    blanchedalmond  :\"#ffebcd\",\n    blue            :\"#0000ff\",\n    blueviolet      :\"#8a2be2\",\n    brown           :\"#a52a2a\",\n    burlywood       :\"#deb887\",\n    cadetblue       :\"#5f9ea0\",\n    chartreuse      :\"#7fff00\",\n    chocolate       :\"#d2691e\",\n    coral           :\"#ff7f50\",\n    cornflowerblue  :\"#6495ed\",\n    cornsilk        :\"#fff8dc\",\n    crimson         :\"#dc143c\",\n    cyan            :\"#00ffff\",\n    darkblue        :\"#00008b\",\n    darkcyan        :\"#008b8b\",\n    darkgoldenrod   :\"#b8860b\",\n    darkgray        :\"#a9a9a9\",\n    darkgrey        :\"#a9a9a9\",\n    darkgreen       :\"#006400\",\n    darkkhaki       :\"#bdb76b\",\n    darkmagenta     :\"#8b008b\",\n    darkolivegreen  :\"#556b2f\",\n    darkorange      :\"#ff8c00\",\n    darkorchid      :\"#9932cc\",\n    darkred         :\"#8b0000\",\n    darksalmon      :\"#e9967a\",\n    darkseagreen    :\"#8fbc8f\",\n    darkslateblue   :\"#483d8b\",\n    darkslategray   :\"#2f4f4f\",\n    darkslategrey   :\"#2f4f4f\",\n    darkturquoise   :\"#00ced1\",\n    darkviolet      :\"#9400d3\",\n    deeppink        :\"#ff1493\",\n    deepskyblue     :\"#00bfff\",\n    dimgray         :\"#696969\",\n    dimgrey         :\"#696969\",\n    dodgerblue      :\"#1e90ff\",\n    firebrick       :\"#b22222\",\n    floralwhite     :\"#fffaf0\",\n    forestgreen     :\"#228b22\",\n    fuchsia         :\"#ff00ff\",\n    gainsboro       :\"#dcdcdc\",\n    ghostwhite      :\"#f8f8ff\",\n    gold            :\"#ffd700\",\n    goldenrod       :\"#daa520\",\n    gray            :\"#808080\",\n    grey            :\"#808080\",\n    green           :\"#008000\",\n    greenyellow     :\"#adff2f\",\n    honeydew        :\"#f0fff0\",\n    hotpink         :\"#ff69b4\",\n    indianred       :\"#cd5c5c\",\n    indigo          :\"#4b0082\",\n    ivory           :\"#fffff0\",\n    khaki           :\"#f0e68c\",\n    lavender        :\"#e6e6fa\",\n    lavenderblush   :\"#fff0f5\",\n    lawngreen       :\"#7cfc00\",\n    lemonchiffon    :\"#fffacd\",\n    lightblue       :\"#add8e6\",\n    lightcoral      :\"#f08080\",\n    lightcyan       :\"#e0ffff\",\n    lightgoldenrodyellow  :\"#fafad2\",\n    lightgray       :\"#d3d3d3\",\n    lightgrey       :\"#d3d3d3\",\n    lightgreen      :\"#90ee90\",\n    lightpink       :\"#ffb6c1\",\n    lightsalmon     :\"#ffa07a\",\n    lightseagreen   :\"#20b2aa\",\n    lightskyblue    :\"#87cefa\",\n    lightslategray  :\"#778899\",\n    lightslategrey  :\"#778899\",\n    lightsteelblue  :\"#b0c4de\",\n    lightyellow     :\"#ffffe0\",\n    lime            :\"#00ff00\",\n    limegreen       :\"#32cd32\",\n    linen           :\"#faf0e6\",\n    magenta         :\"#ff00ff\",\n    maroon          :\"#800000\",\n    mediumaquamarine:\"#66cdaa\",\n    mediumblue      :\"#0000cd\",\n    mediumorchid    :\"#ba55d3\",\n    mediumpurple    :\"#9370d8\",\n    mediumseagreen  :\"#3cb371\",\n    mediumslateblue :\"#7b68ee\",\n    mediumspringgreen   :\"#00fa9a\",\n    mediumturquoise :\"#48d1cc\",\n    mediumvioletred :\"#c71585\",\n    midnightblue    :\"#191970\",\n    mintcream       :\"#f5fffa\",\n    mistyrose       :\"#ffe4e1\",\n    moccasin        :\"#ffe4b5\",\n    navajowhite     :\"#ffdead\",\n    navy            :\"#000080\",\n    oldlace         :\"#fdf5e6\",\n    olive           :\"#808000\",\n    olivedrab       :\"#6b8e23\",\n    orange          :\"#ffa500\",\n    orangered       :\"#ff4500\",\n    orchid          :\"#da70d6\",\n    palegoldenrod   :\"#eee8aa\",\n    palegreen       :\"#98fb98\",\n    paleturquoise   :\"#afeeee\",\n    palevioletred   :\"#d87093\",\n    papayawhip      :\"#ffefd5\",\n    peachpuff       :\"#ffdab9\",\n    peru            :\"#cd853f\",\n    pink            :\"#ffc0cb\",\n    plum            :\"#dda0dd\",\n    powderblue      :\"#b0e0e6\",\n    purple          :\"#800080\",\n    red             :\"#ff0000\",\n    rosybrown       :\"#bc8f8f\",\n    royalblue       :\"#4169e1\",\n    saddlebrown     :\"#8b4513\",\n    salmon          :\"#fa8072\",\n    sandybrown      :\"#f4a460\",\n    seagreen        :\"#2e8b57\",\n    seashell        :\"#fff5ee\",\n    sienna          :\"#a0522d\",\n    silver          :\"#c0c0c0\",\n    skyblue         :\"#87ceeb\",\n    slateblue       :\"#6a5acd\",\n    slategray       :\"#708090\",\n    slategrey       :\"#708090\",\n    snow            :\"#fffafa\",\n    springgreen     :\"#00ff7f\",\n    steelblue       :\"#4682b4\",\n    tan             :\"#d2b48c\",\n    teal            :\"#008080\",\n    thistle         :\"#d8bfd8\",\n    tomato          :\"#ff6347\",\n    turquoise       :\"#40e0d0\",\n    violet          :\"#ee82ee\",\n    wheat           :\"#f5deb3\",\n    white           :\"#ffffff\",\n    whitesmoke      :\"#f5f5f5\",\n    yellow          :\"#ffff00\",\n    yellowgreen     :\"#9acd32\",\n    //CSS2 system colors http://www.w3.org/TR/css3-color/#css2-system\n    activeBorder        :\"Active window border.\",\n    activecaption       :\"Active window caption.\",\n    appworkspace        :\"Background color of multiple document interface.\",\n    background          :\"Desktop background.\",\n    buttonface          :\"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.\",\n    buttonhighlight     :\"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.\",\n    buttonshadow        :\"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.\",\n    buttontext          :\"Text on push buttons.\",\n    captiontext         :\"Text in caption, size box, and scrollbar arrow box.\",\n    graytext            :\"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.\",\n    greytext            :\"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.\",\n    highlight           :\"Item(s) selected in a control.\",\n    highlighttext       :\"Text of item(s) selected in a control.\",\n    inactiveborder      :\"Inactive window border.\",\n    inactivecaption     :\"Inactive window caption.\",\n    inactivecaptiontext :\"Color of text in an inactive caption.\",\n    infobackground      :\"Background color for tooltip controls.\",\n    infotext            :\"Text color for tooltip controls.\",\n    menu                :\"Menu background.\",\n    menutext            :\"Text in menus.\",\n    scrollbar           :\"Scroll bar gray area.\",\n    threeddarkshadow    :\"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",\n    threedface          :\"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",\n    threedhighlight     :\"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",\n    threedlightshadow   :\"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",\n    threedshadow        :\"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.\",\n    window              :\"Window background.\",\n    windowframe         :\"Window frame.\",\n    windowtext          :\"Text in windows.\"\n};\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a selector combinator (whitespace, +, >).\n * @namespace parserlib.css\n * @class Combinator\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {String} text The text representation of the unit.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction Combinator(text, line, col){\n\n    SyntaxUnit.call(this, text, line, col, Parser.COMBINATOR_TYPE);\n\n    /**\n     * The type of modifier.\n     * @type String\n     * @property type\n     */\n    this.type = \"unknown\";\n\n    //pretty simple\n    if (/^\\s+$/.test(text)){\n        this.type = \"descendant\";\n    } else if (text == \">\"){\n        this.type = \"child\";\n    } else if (text == \"+\"){\n        this.type = \"adjacent-sibling\";\n    } else if (text == \"~\"){\n        this.type = \"sibling\";\n    }\n\n}\n\nCombinator.prototype = new SyntaxUnit();\nCombinator.prototype.constructor = Combinator;\n\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a media feature, such as max-width:500.\n * @namespace parserlib.css\n * @class MediaFeature\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {SyntaxUnit} name The name of the feature.\n * @param {SyntaxUnit} value The value of the feature or null if none.\n */\nfunction MediaFeature(name, value){\n\n    SyntaxUnit.call(this, \"(\" + name + (value !== null ? \":\" + value : \"\") + \")\", name.startLine, name.startCol, Parser.MEDIA_FEATURE_TYPE);\n\n    /**\n     * The name of the media feature\n     * @type String\n     * @property name\n     */\n    this.name = name;\n\n    /**\n     * The value for the feature or null if there is none.\n     * @type SyntaxUnit\n     * @property value\n     */\n    this.value = value;\n}\n\nMediaFeature.prototype = new SyntaxUnit();\nMediaFeature.prototype.constructor = MediaFeature;\n\n/*global SyntaxUnit, Parser*/\n/**\n * Represents an individual media query.\n * @namespace parserlib.css\n * @class MediaQuery\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {String} modifier The modifier \"not\" or \"only\" (or null).\n * @param {String} mediaType The type of media (i.e., \"print\").\n * @param {Array} parts Array of selectors parts making up this selector.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction MediaQuery(modifier, mediaType, features, line, col){\n\n    SyntaxUnit.call(this, (modifier ? modifier + \" \": \"\") + (mediaType ? mediaType : \"\") + (mediaType && features.length > 0 ? \" and \" : \"\") + features.join(\" and \"), line, col, Parser.MEDIA_QUERY_TYPE);\n\n    /**\n     * The media modifier (\"not\" or \"only\")\n     * @type String\n     * @property modifier\n     */\n    this.modifier = modifier;\n\n    /**\n     * The mediaType (i.e., \"print\")\n     * @type String\n     * @property mediaType\n     */\n    this.mediaType = mediaType;\n\n    /**\n     * The parts that make up the selector.\n     * @type Array\n     * @property features\n     */\n    this.features = features;\n\n}\n\nMediaQuery.prototype = new SyntaxUnit();\nMediaQuery.prototype.constructor = MediaQuery;\n\n/*global Tokens, TokenStream, SyntaxError, Properties, Validation, ValidationError, SyntaxUnit,\n    PropertyValue, PropertyValuePart, SelectorPart, SelectorSubPart, Selector,\n    PropertyName, Combinator, MediaFeature, MediaQuery, EventTarget */\n\n/**\n * A CSS3 parser.\n * @namespace parserlib.css\n * @class Parser\n * @constructor\n * @param {Object} options (Optional) Various options for the parser:\n *      starHack (true|false) to allow IE6 star hack as valid,\n *      underscoreHack (true|false) to interpret leading underscores\n *      as IE6-7 targeting for known properties, ieFilters (true|false)\n *      to indicate that IE < 8 filters should be accepted and not throw\n *      syntax errors.\n */\nfunction Parser(options){\n\n    //inherit event functionality\n    EventTarget.call(this);\n\n\n    this.options = options || {};\n\n    this._tokenStream = null;\n}\n\n//Static constants\nParser.DEFAULT_TYPE = 0;\nParser.COMBINATOR_TYPE = 1;\nParser.MEDIA_FEATURE_TYPE = 2;\nParser.MEDIA_QUERY_TYPE = 3;\nParser.PROPERTY_NAME_TYPE = 4;\nParser.PROPERTY_VALUE_TYPE = 5;\nParser.PROPERTY_VALUE_PART_TYPE = 6;\nParser.SELECTOR_TYPE = 7;\nParser.SELECTOR_PART_TYPE = 8;\nParser.SELECTOR_SUB_PART_TYPE = 9;\n\nParser.prototype = function(){\n\n    var proto = new EventTarget(),  //new prototype\n        prop,\n        additions =  {\n\n            //restore constructor\n            constructor: Parser,\n\n            //instance constants - yuck\n            DEFAULT_TYPE : 0,\n            COMBINATOR_TYPE : 1,\n            MEDIA_FEATURE_TYPE : 2,\n            MEDIA_QUERY_TYPE : 3,\n            PROPERTY_NAME_TYPE : 4,\n            PROPERTY_VALUE_TYPE : 5,\n            PROPERTY_VALUE_PART_TYPE : 6,\n            SELECTOR_TYPE : 7,\n            SELECTOR_PART_TYPE : 8,\n            SELECTOR_SUB_PART_TYPE : 9,\n\n            //-----------------------------------------------------------------\n            // Grammar\n            //-----------------------------------------------------------------\n\n            _stylesheet: function(){\n\n                /*\n                 * stylesheet\n                 *  : [ CHARSET_SYM S* STRING S* ';' ]?\n                 *    [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*\n                 *    [ namespace [S|CDO|CDC]* ]*\n                 *    [ [ ruleset | media | page | font_face | keyframes ] [S|CDO|CDC]* ]*\n                 *  ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    charset     = null,\n                    count,\n                    token,\n                    tt;\n\n                this.fire(\"startstylesheet\");\n\n                //try to read character set\n                this._charset();\n\n                this._skipCruft();\n\n                //try to read imports - may be more than one\n                while (tokenStream.peek() == Tokens.IMPORT_SYM){\n                    this._import();\n                    this._skipCruft();\n                }\n\n                //try to read namespaces - may be more than one\n                while (tokenStream.peek() == Tokens.NAMESPACE_SYM){\n                    this._namespace();\n                    this._skipCruft();\n                }\n\n                //get the next token\n                tt = tokenStream.peek();\n\n                //try to read the rest\n                while(tt > Tokens.EOF){\n\n                    try {\n\n                        switch(tt){\n                            case Tokens.MEDIA_SYM:\n                                this._media();\n                                this._skipCruft();\n                                break;\n                            case Tokens.PAGE_SYM:\n                                this._page();\n                                this._skipCruft();\n                                break;\n                            case Tokens.FONT_FACE_SYM:\n                                this._font_face();\n                                this._skipCruft();\n                                break;\n                            case Tokens.KEYFRAMES_SYM:\n                                this._keyframes();\n                                this._skipCruft();\n                                break;\n                            case Tokens.VIEWPORT_SYM:\n                                this._viewport();\n                                this._skipCruft();\n                                break;\n                            case Tokens.UNKNOWN_SYM:  //unknown @ rule\n                                tokenStream.get();\n                                if (!this.options.strict){\n\n                                    //fire error event\n                                    this.fire({\n                                        type:       \"error\",\n                                        error:      null,\n                                        message:    \"Unknown @ rule: \" + tokenStream.LT(0).value + \".\",\n                                        line:       tokenStream.LT(0).startLine,\n                                        col:        tokenStream.LT(0).startCol\n                                    });\n\n                                    //skip braces\n                                    count=0;\n                                    while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){\n                                        count++;    //keep track of nesting depth\n                                    }\n\n                                    while(count){\n                                        tokenStream.advance([Tokens.RBRACE]);\n                                        count--;\n                                    }\n\n                                } else {\n                                    //not a syntax error, rethrow it\n                                    throw new SyntaxError(\"Unknown @ rule.\", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);\n                                }\n                                break;\n                            case Tokens.S:\n                                this._readWhitespace();\n                                break;\n                            default:\n                                if(!this._ruleset()){\n\n                                    //error handling for known issues\n                                    switch(tt){\n                                        case Tokens.CHARSET_SYM:\n                                            token = tokenStream.LT(1);\n                                            this._charset(false);\n                                            throw new SyntaxError(\"@charset not allowed here.\", token.startLine, token.startCol);\n                                        case Tokens.IMPORT_SYM:\n                                            token = tokenStream.LT(1);\n                                            this._import(false);\n                                            throw new SyntaxError(\"@import not allowed here.\", token.startLine, token.startCol);\n                                        case Tokens.NAMESPACE_SYM:\n                                            token = tokenStream.LT(1);\n                                            this._namespace(false);\n                                            throw new SyntaxError(\"@namespace not allowed here.\", token.startLine, token.startCol);\n                                        default:\n                                            tokenStream.get();  //get the last token\n                                            this._unexpectedToken(tokenStream.token());\n                                    }\n\n                                }\n                        }\n                    } catch(ex) {\n                        if (ex instanceof SyntaxError && !this.options.strict){\n                            this.fire({\n                                type:       \"error\",\n                                error:      ex,\n                                message:    ex.message,\n                                line:       ex.line,\n                                col:        ex.col\n                            });\n                        } else {\n                            throw ex;\n                        }\n                    }\n\n                    tt = tokenStream.peek();\n                }\n\n                if (tt != Tokens.EOF){\n                    this._unexpectedToken(tokenStream.token());\n                }\n\n                this.fire(\"endstylesheet\");\n            },\n\n            _charset: function(emit){\n                var tokenStream = this._tokenStream,\n                    charset,\n                    token,\n                    line,\n                    col;\n\n                if (tokenStream.match(Tokens.CHARSET_SYM)){\n                    line = tokenStream.token().startLine;\n                    col = tokenStream.token().startCol;\n\n                    this._readWhitespace();\n                    tokenStream.mustMatch(Tokens.STRING);\n\n                    token = tokenStream.token();\n                    charset = token.value;\n\n                    this._readWhitespace();\n                    tokenStream.mustMatch(Tokens.SEMICOLON);\n\n                    if (emit !== false){\n                        this.fire({\n                            type:   \"charset\",\n                            charset:charset,\n                            line:   line,\n                            col:    col\n                        });\n                    }\n                }\n            },\n\n            _import: function(emit){\n                /*\n                 * import\n                 *   : IMPORT_SYM S*\n                 *    [STRING|URI] S* media_query_list? ';' S*\n                 */\n\n                var tokenStream = this._tokenStream,\n                    tt,\n                    uri,\n                    importToken,\n                    mediaList   = [];\n\n                //read import symbol\n                tokenStream.mustMatch(Tokens.IMPORT_SYM);\n                importToken = tokenStream.token();\n                this._readWhitespace();\n\n                tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);\n\n                //grab the URI value\n                uri = tokenStream.token().value.replace(/^(?:url\\()?[\"']?([^\"']+?)[\"']?\\)?$/, \"$1\");\n\n                this._readWhitespace();\n\n                mediaList = this._media_query_list();\n\n                //must end with a semicolon\n                tokenStream.mustMatch(Tokens.SEMICOLON);\n                this._readWhitespace();\n\n                if (emit !== false){\n                    this.fire({\n                        type:   \"import\",\n                        uri:    uri,\n                        media:  mediaList,\n                        line:   importToken.startLine,\n                        col:    importToken.startCol\n                    });\n                }\n\n            },\n\n            _namespace: function(emit){\n                /*\n                 * namespace\n                 *   : NAMESPACE_SYM S* [namespace_prefix S*]? [STRING|URI] S* ';' S*\n                 */\n\n                var tokenStream = this._tokenStream,\n                    line,\n                    col,\n                    prefix,\n                    uri;\n\n                //read import symbol\n                tokenStream.mustMatch(Tokens.NAMESPACE_SYM);\n                line = tokenStream.token().startLine;\n                col = tokenStream.token().startCol;\n                this._readWhitespace();\n\n                //it's a namespace prefix - no _namespace_prefix() method because it's just an IDENT\n                if (tokenStream.match(Tokens.IDENT)){\n                    prefix = tokenStream.token().value;\n                    this._readWhitespace();\n                }\n\n                tokenStream.mustMatch([Tokens.STRING, Tokens.URI]);\n                /*if (!tokenStream.match(Tokens.STRING)){\n                    tokenStream.mustMatch(Tokens.URI);\n                }*/\n\n                //grab the URI value\n                uri = tokenStream.token().value.replace(/(?:url\\()?[\"']([^\"']+)[\"']\\)?/, \"$1\");\n\n                this._readWhitespace();\n\n                //must end with a semicolon\n                tokenStream.mustMatch(Tokens.SEMICOLON);\n                this._readWhitespace();\n\n                if (emit !== false){\n                    this.fire({\n                        type:   \"namespace\",\n                        prefix: prefix,\n                        uri:    uri,\n                        line:   line,\n                        col:    col\n                    });\n                }\n\n            },\n\n            _media: function(){\n                /*\n                 * media\n                 *   : MEDIA_SYM S* media_query_list S* '{' S* ruleset* '}' S*\n                 *   ;\n                 */\n                var tokenStream     = this._tokenStream,\n                    line,\n                    col,\n                    mediaList;//       = [];\n\n                //look for @media\n                tokenStream.mustMatch(Tokens.MEDIA_SYM);\n                line = tokenStream.token().startLine;\n                col = tokenStream.token().startCol;\n\n                this._readWhitespace();\n\n                mediaList = this._media_query_list();\n\n                tokenStream.mustMatch(Tokens.LBRACE);\n                this._readWhitespace();\n\n                this.fire({\n                    type:   \"startmedia\",\n                    media:  mediaList,\n                    line:   line,\n                    col:    col\n                });\n\n                while(true) {\n                    if (tokenStream.peek() == Tokens.PAGE_SYM){\n                        this._page();\n                    } else if (tokenStream.peek() == Tokens.FONT_FACE_SYM){\n                        this._font_face();\n                    } else if (tokenStream.peek() == Tokens.VIEWPORT_SYM){\n                        this._viewport();\n                    } else if (!this._ruleset()){\n                        break;\n                    }\n                }\n\n                tokenStream.mustMatch(Tokens.RBRACE);\n                this._readWhitespace();\n\n                this.fire({\n                    type:   \"endmedia\",\n                    media:  mediaList,\n                    line:   line,\n                    col:    col\n                });\n            },\n\n\n            //CSS3 Media Queries\n            _media_query_list: function(){\n                /*\n                 * media_query_list\n                 *   : S* [media_query [ ',' S* media_query ]* ]?\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    mediaList   = [];\n\n\n                this._readWhitespace();\n\n                if (tokenStream.peek() == Tokens.IDENT || tokenStream.peek() == Tokens.LPAREN){\n                    mediaList.push(this._media_query());\n                }\n\n                while(tokenStream.match(Tokens.COMMA)){\n                    this._readWhitespace();\n                    mediaList.push(this._media_query());\n                }\n\n                return mediaList;\n            },\n\n            /*\n             * Note: \"expression\" in the grammar maps to the _media_expression\n             * method.\n\n             */\n            _media_query: function(){\n                /*\n                 * media_query\n                 *   : [ONLY | NOT]? S* media_type S* [ AND S* expression ]*\n                 *   | expression [ AND S* expression ]*\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    type        = null,\n                    ident       = null,\n                    token       = null,\n                    expressions = [];\n\n                if (tokenStream.match(Tokens.IDENT)){\n                    ident = tokenStream.token().value.toLowerCase();\n\n                    //since there's no custom tokens for these, need to manually check\n                    if (ident != \"only\" && ident != \"not\"){\n                        tokenStream.unget();\n                        ident = null;\n                    } else {\n                        token = tokenStream.token();\n                    }\n                }\n\n                this._readWhitespace();\n\n                if (tokenStream.peek() == Tokens.IDENT){\n                    type = this._media_type();\n                    if (token === null){\n                        token = tokenStream.token();\n                    }\n                } else if (tokenStream.peek() == Tokens.LPAREN){\n                    if (token === null){\n                        token = tokenStream.LT(1);\n                    }\n                    expressions.push(this._media_expression());\n                }\n\n                if (type === null && expressions.length === 0){\n                    return null;\n                } else {\n                    this._readWhitespace();\n                    while (tokenStream.match(Tokens.IDENT)){\n                        if (tokenStream.token().value.toLowerCase() != \"and\"){\n                            this._unexpectedToken(tokenStream.token());\n                        }\n\n                        this._readWhitespace();\n                        expressions.push(this._media_expression());\n                    }\n                }\n\n                return new MediaQuery(ident, type, expressions, token.startLine, token.startCol);\n            },\n\n            //CSS3 Media Queries\n            _media_type: function(){\n                /*\n                 * media_type\n                 *   : IDENT\n                 *   ;\n                 */\n                return this._media_feature();\n            },\n\n            /**\n             * Note: in CSS3 Media Queries, this is called \"expression\".\n             * Renamed here to avoid conflict with CSS3 Selectors\n             * definition of \"expression\". Also note that \"expr\" in the\n             * grammar now maps to \"expression\" from CSS3 selectors.\n             * @method _media_expression\n             * @private\n             */\n            _media_expression: function(){\n                /*\n                 * expression\n                 *  : '(' S* media_feature S* [ ':' S* expr ]? ')' S*\n                 *  ;\n                 */\n                var tokenStream = this._tokenStream,\n                    feature     = null,\n                    token,\n                    expression  = null;\n\n                tokenStream.mustMatch(Tokens.LPAREN);\n\n                feature = this._media_feature();\n                this._readWhitespace();\n\n                if (tokenStream.match(Tokens.COLON)){\n                    this._readWhitespace();\n                    token = tokenStream.LT(1);\n                    expression = this._expression();\n                }\n\n                tokenStream.mustMatch(Tokens.RPAREN);\n                this._readWhitespace();\n\n                return new MediaFeature(feature, (expression ? new SyntaxUnit(expression, token.startLine, token.startCol) : null));\n            },\n\n            //CSS3 Media Queries\n            _media_feature: function(){\n                /*\n                 * media_feature\n                 *   : IDENT\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream;\n\n                tokenStream.mustMatch(Tokens.IDENT);\n\n                return SyntaxUnit.fromToken(tokenStream.token());\n            },\n\n            //CSS3 Paged Media\n            _page: function(){\n                /*\n                 * page:\n                 *    PAGE_SYM S* IDENT? pseudo_page? S*\n                 *    '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S*\n                 *    ;\n                 */\n                var tokenStream = this._tokenStream,\n                    line,\n                    col,\n                    identifier  = null,\n                    pseudoPage  = null;\n\n                //look for @page\n                tokenStream.mustMatch(Tokens.PAGE_SYM);\n                line = tokenStream.token().startLine;\n                col = tokenStream.token().startCol;\n\n                this._readWhitespace();\n\n                if (tokenStream.match(Tokens.IDENT)){\n                    identifier = tokenStream.token().value;\n\n                    //The value 'auto' may not be used as a page name and MUST be treated as a syntax error.\n                    if (identifier.toLowerCase() === \"auto\"){\n                        this._unexpectedToken(tokenStream.token());\n                    }\n                }\n\n                //see if there's a colon upcoming\n                if (tokenStream.peek() == Tokens.COLON){\n                    pseudoPage = this._pseudo_page();\n                }\n\n                this._readWhitespace();\n\n                this.fire({\n                    type:   \"startpage\",\n                    id:     identifier,\n                    pseudo: pseudoPage,\n                    line:   line,\n                    col:    col\n                });\n\n                this._readDeclarations(true, true);\n\n                this.fire({\n                    type:   \"endpage\",\n                    id:     identifier,\n                    pseudo: pseudoPage,\n                    line:   line,\n                    col:    col\n                });\n\n            },\n\n            //CSS3 Paged Media\n            _margin: function(){\n                /*\n                 * margin :\n                 *    margin_sym S* '{' declaration [ ';' S* declaration? ]* '}' S*\n                 *    ;\n                 */\n                var tokenStream = this._tokenStream,\n                    line,\n                    col,\n                    marginSym   = this._margin_sym();\n\n                if (marginSym){\n                    line = tokenStream.token().startLine;\n                    col = tokenStream.token().startCol;\n\n                    this.fire({\n                        type: \"startpagemargin\",\n                        margin: marginSym,\n                        line:   line,\n                        col:    col\n                    });\n\n                    this._readDeclarations(true);\n\n                    this.fire({\n                        type: \"endpagemargin\",\n                        margin: marginSym,\n                        line:   line,\n                        col:    col\n                    });\n                    return true;\n                } else {\n                    return false;\n                }\n            },\n\n            //CSS3 Paged Media\n            _margin_sym: function(){\n\n                /*\n                 * margin_sym :\n                 *    TOPLEFTCORNER_SYM |\n                 *    TOPLEFT_SYM |\n                 *    TOPCENTER_SYM |\n                 *    TOPRIGHT_SYM |\n                 *    TOPRIGHTCORNER_SYM |\n                 *    BOTTOMLEFTCORNER_SYM |\n                 *    BOTTOMLEFT_SYM |\n                 *    BOTTOMCENTER_SYM |\n                 *    BOTTOMRIGHT_SYM |\n                 *    BOTTOMRIGHTCORNER_SYM |\n                 *    LEFTTOP_SYM |\n                 *    LEFTMIDDLE_SYM |\n                 *    LEFTBOTTOM_SYM |\n                 *    RIGHTTOP_SYM |\n                 *    RIGHTMIDDLE_SYM |\n                 *    RIGHTBOTTOM_SYM\n                 *    ;\n                 */\n\n                var tokenStream = this._tokenStream;\n\n                if(tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,\n                        Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,\n                        Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,\n                        Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,\n                        Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,\n                        Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,\n                        Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM]))\n                {\n                    return SyntaxUnit.fromToken(tokenStream.token());\n                } else {\n                    return null;\n                }\n\n            },\n\n            _pseudo_page: function(){\n                /*\n                 * pseudo_page\n                 *   : ':' IDENT\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream;\n\n                tokenStream.mustMatch(Tokens.COLON);\n                tokenStream.mustMatch(Tokens.IDENT);\n\n                //TODO: CSS3 Paged Media says only \"left\", \"center\", and \"right\" are allowed\n\n                return tokenStream.token().value;\n            },\n\n            _font_face: function(){\n                /*\n                 * font_face\n                 *   : FONT_FACE_SYM S*\n                 *     '{' S* declaration [ ';' S* declaration ]* '}' S*\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    line,\n                    col;\n\n                //look for @page\n                tokenStream.mustMatch(Tokens.FONT_FACE_SYM);\n                line = tokenStream.token().startLine;\n                col = tokenStream.token().startCol;\n\n                this._readWhitespace();\n\n                this.fire({\n                    type:   \"startfontface\",\n                    line:   line,\n                    col:    col\n                });\n\n                this._readDeclarations(true);\n\n                this.fire({\n                    type:   \"endfontface\",\n                    line:   line,\n                    col:    col\n                });\n            },\n\n            _viewport: function(){\n                /*\n                 * viewport\n                 *   : VIEWPORT_SYM S*\n                 *     '{' S* declaration? [ ';' S* declaration? ]* '}' S*\n                 *   ;\n                 */\n                 var tokenStream = this._tokenStream,\n                    line,\n                    col;\n\n                    tokenStream.mustMatch(Tokens.VIEWPORT_SYM);\n                    line = tokenStream.token().startLine;\n                    col = tokenStream.token().startCol;\n\n                    this._readWhitespace();\n\n                    this.fire({\n                        type:   \"startviewport\",\n                        line:   line,\n                        col:    col\n                    });\n\n                    this._readDeclarations(true);\n\n                    this.fire({\n                        type:   \"endviewport\",\n                        line:   line,\n                        col:    col\n                    });\n\n            },\n\n            _operator: function(inFunction){\n\n                /*\n                 * operator (outside function)\n                 *  : '/' S* | ',' S* | /( empty )/\n                 * operator (inside function)\n                 *  : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/\n                 *  ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    token       = null;\n\n                if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||\n                    (inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))){\n                    token =  tokenStream.token();\n                    this._readWhitespace();\n                }\n                return token ? PropertyValuePart.fromToken(token) : null;\n\n            },\n\n            _combinator: function(){\n\n                /*\n                 * combinator\n                 *  : PLUS S* | GREATER S* | TILDE S* | S+\n                 *  ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    value       = null,\n                    token;\n\n                if(tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])){\n                    token = tokenStream.token();\n                    value = new Combinator(token.value, token.startLine, token.startCol);\n                    this._readWhitespace();\n                }\n\n                return value;\n            },\n\n            _unary_operator: function(){\n\n                /*\n                 * unary_operator\n                 *  : '-' | '+'\n                 *  ;\n                 */\n\n                var tokenStream = this._tokenStream;\n\n                if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])){\n                    return tokenStream.token().value;\n                } else {\n                    return null;\n                }\n            },\n\n            _property: function(){\n\n                /*\n                 * property\n                 *   : IDENT S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    value       = null,\n                    hack        = null,\n                    tokenValue,\n                    token,\n                    line,\n                    col;\n\n                //check for star hack - throws error if not allowed\n                if (tokenStream.peek() == Tokens.STAR && this.options.starHack){\n                    tokenStream.get();\n                    token = tokenStream.token();\n                    hack = token.value;\n                    line = token.startLine;\n                    col = token.startCol;\n                }\n\n                if(tokenStream.match(Tokens.IDENT)){\n                    token = tokenStream.token();\n                    tokenValue = token.value;\n\n                    //check for underscore hack - no error if not allowed because it's valid CSS syntax\n                    if (tokenValue.charAt(0) == \"_\" && this.options.underscoreHack){\n                        hack = \"_\";\n                        tokenValue = tokenValue.substring(1);\n                    }\n\n                    value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));\n                    this._readWhitespace();\n                }\n\n                return value;\n            },\n\n            //Augmented with CSS3 Selectors\n            _ruleset: function(){\n                /*\n                 * ruleset\n                 *   : selectors_group\n                 *     '{' S* declaration? [ ';' S* declaration? ]* '}' S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    tt,\n                    selectors;\n\n\n                /*\n                 * Error Recovery: If even a single selector fails to parse,\n                 * then the entire ruleset should be thrown away.\n                 */\n                try {\n                    selectors = this._selectors_group();\n                } catch (ex){\n                    if (ex instanceof SyntaxError && !this.options.strict){\n\n                        //fire error event\n                        this.fire({\n                            type:       \"error\",\n                            error:      ex,\n                            message:    ex.message,\n                            line:       ex.line,\n                            col:        ex.col\n                        });\n\n                        //skip over everything until closing brace\n                        tt = tokenStream.advance([Tokens.RBRACE]);\n                        if (tt == Tokens.RBRACE){\n                            //if there's a right brace, the rule is finished so don't do anything\n                        } else {\n                            //otherwise, rethrow the error because it wasn't handled properly\n                            throw ex;\n                        }\n\n                    } else {\n                        //not a syntax error, rethrow it\n                        throw ex;\n                    }\n\n                    //trigger parser to continue\n                    return true;\n                }\n\n                //if it got here, all selectors parsed\n                if (selectors){\n\n                    this.fire({\n                        type:       \"startrule\",\n                        selectors:  selectors,\n                        line:       selectors[0].line,\n                        col:        selectors[0].col\n                    });\n\n                    this._readDeclarations(true);\n\n                    this.fire({\n                        type:       \"endrule\",\n                        selectors:  selectors,\n                        line:       selectors[0].line,\n                        col:        selectors[0].col\n                    });\n\n                }\n\n                return selectors;\n\n            },\n\n            //CSS3 Selectors\n            _selectors_group: function(){\n\n                /*\n                 * selectors_group\n                 *   : selector [ COMMA S* selector ]*\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    selectors   = [],\n                    selector;\n\n                selector = this._selector();\n                if (selector !== null){\n\n                    selectors.push(selector);\n                    while(tokenStream.match(Tokens.COMMA)){\n                        this._readWhitespace();\n                        selector = this._selector();\n                        if (selector !== null){\n                            selectors.push(selector);\n                        } else {\n                            this._unexpectedToken(tokenStream.LT(1));\n                        }\n                    }\n                }\n\n                return selectors.length ? selectors : null;\n            },\n\n            //CSS3 Selectors\n            _selector: function(){\n                /*\n                 * selector\n                 *   : simple_selector_sequence [ combinator simple_selector_sequence ]*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    selector    = [],\n                    nextSelector = null,\n                    combinator  = null,\n                    ws          = null;\n\n                //if there's no simple selector, then there's no selector\n                nextSelector = this._simple_selector_sequence();\n                if (nextSelector === null){\n                    return null;\n                }\n\n                selector.push(nextSelector);\n\n                do {\n\n                    //look for a combinator\n                    combinator = this._combinator();\n\n                    if (combinator !== null){\n                        selector.push(combinator);\n                        nextSelector = this._simple_selector_sequence();\n\n                        //there must be a next selector\n                        if (nextSelector === null){\n                            this._unexpectedToken(tokenStream.LT(1));\n                        } else {\n\n                            //nextSelector is an instance of SelectorPart\n                            selector.push(nextSelector);\n                        }\n                    } else {\n\n                        //if there's not whitespace, we're done\n                        if (this._readWhitespace()){\n\n                            //add whitespace separator\n                            ws = new Combinator(tokenStream.token().value, tokenStream.token().startLine, tokenStream.token().startCol);\n\n                            //combinator is not required\n                            combinator = this._combinator();\n\n                            //selector is required if there's a combinator\n                            nextSelector = this._simple_selector_sequence();\n                            if (nextSelector === null){\n                                if (combinator !== null){\n                                    this._unexpectedToken(tokenStream.LT(1));\n                                }\n                            } else {\n\n                                if (combinator !== null){\n                                    selector.push(combinator);\n                                } else {\n                                    selector.push(ws);\n                                }\n\n                                selector.push(nextSelector);\n                            }\n                        } else {\n                            break;\n                        }\n\n                    }\n                } while(true);\n\n                return new Selector(selector, selector[0].line, selector[0].col);\n            },\n\n            //CSS3 Selectors\n            _simple_selector_sequence: function(){\n                /*\n                 * simple_selector_sequence\n                 *   : [ type_selector | universal ]\n                 *     [ HASH | class | attrib | pseudo | negation ]*\n                 *   | [ HASH | class | attrib | pseudo | negation ]+\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n\n                    //parts of a simple selector\n                    elementName = null,\n                    modifiers   = [],\n\n                    //complete selector text\n                    selectorText= \"\",\n\n                    //the different parts after the element name to search for\n                    components  = [\n                        //HASH\n                        function(){\n                            return tokenStream.match(Tokens.HASH) ?\n                                    new SelectorSubPart(tokenStream.token().value, \"id\", tokenStream.token().startLine, tokenStream.token().startCol) :\n                                    null;\n                        },\n                        this._class,\n                        this._attrib,\n                        this._pseudo,\n                        this._negation\n                    ],\n                    i           = 0,\n                    len         = components.length,\n                    component   = null,\n                    found       = false,\n                    line,\n                    col;\n\n\n                //get starting line and column for the selector\n                line = tokenStream.LT(1).startLine;\n                col = tokenStream.LT(1).startCol;\n\n                elementName = this._type_selector();\n                if (!elementName){\n                    elementName = this._universal();\n                }\n\n                if (elementName !== null){\n                    selectorText += elementName;\n                }\n\n                while(true){\n\n                    //whitespace means we're done\n                    if (tokenStream.peek() === Tokens.S){\n                        break;\n                    }\n\n                    //check for each component\n                    while(i < len && component === null){\n                        component = components[i++].call(this);\n                    }\n\n                    if (component === null){\n\n                        //we don't have a selector\n                        if (selectorText === \"\"){\n                            return null;\n                        } else {\n                            break;\n                        }\n                    } else {\n                        i = 0;\n                        modifiers.push(component);\n                        selectorText += component.toString();\n                        component = null;\n                    }\n                }\n\n\n                return selectorText !== \"\" ?\n                        new SelectorPart(elementName, modifiers, selectorText, line, col) :\n                        null;\n            },\n\n            //CSS3 Selectors\n            _type_selector: function(){\n                /*\n                 * type_selector\n                 *   : [ namespace_prefix ]? element_name\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    ns          = this._namespace_prefix(),\n                    elementName = this._element_name();\n\n                if (!elementName){\n                    /*\n                     * Need to back out the namespace that was read due to both\n                     * type_selector and universal reading namespace_prefix\n                     * first. Kind of hacky, but only way I can figure out\n                     * right now how to not change the grammar.\n                     */\n                    if (ns){\n                        tokenStream.unget();\n                        if (ns.length > 1){\n                            tokenStream.unget();\n                        }\n                    }\n\n                    return null;\n                } else {\n                    if (ns){\n                        elementName.text = ns + elementName.text;\n                        elementName.col -= ns.length;\n                    }\n                    return elementName;\n                }\n            },\n\n            //CSS3 Selectors\n            _class: function(){\n                /*\n                 * class\n                 *   : '.' IDENT\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    token;\n\n                if (tokenStream.match(Tokens.DOT)){\n                    tokenStream.mustMatch(Tokens.IDENT);\n                    token = tokenStream.token();\n                    return new SelectorSubPart(\".\" + token.value, \"class\", token.startLine, token.startCol - 1);\n                } else {\n                    return null;\n                }\n\n            },\n\n            //CSS3 Selectors\n            _element_name: function(){\n                /*\n                 * element_name\n                 *   : IDENT\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    token;\n\n                if (tokenStream.match(Tokens.IDENT)){\n                    token = tokenStream.token();\n                    return new SelectorSubPart(token.value, \"elementName\", token.startLine, token.startCol);\n\n                } else {\n                    return null;\n                }\n            },\n\n            //CSS3 Selectors\n            _namespace_prefix: function(){\n                /*\n                 * namespace_prefix\n                 *   : [ IDENT | '*' ]? '|'\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    value       = \"\";\n\n                //verify that this is a namespace prefix\n                if (tokenStream.LA(1) === Tokens.PIPE || tokenStream.LA(2) === Tokens.PIPE){\n\n                    if(tokenStream.match([Tokens.IDENT, Tokens.STAR])){\n                        value += tokenStream.token().value;\n                    }\n\n                    tokenStream.mustMatch(Tokens.PIPE);\n                    value += \"|\";\n\n                }\n\n                return value.length ? value : null;\n            },\n\n            //CSS3 Selectors\n            _universal: function(){\n                /*\n                 * universal\n                 *   : [ namespace_prefix ]? '*'\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    value       = \"\",\n                    ns;\n\n                ns = this._namespace_prefix();\n                if(ns){\n                    value += ns;\n                }\n\n                if(tokenStream.match(Tokens.STAR)){\n                    value += \"*\";\n                }\n\n                return value.length ? value : null;\n\n           },\n\n            //CSS3 Selectors\n            _attrib: function(){\n                /*\n                 * attrib\n                 *   : '[' S* [ namespace_prefix ]? IDENT S*\n                 *         [ [ PREFIXMATCH |\n                 *             SUFFIXMATCH |\n                 *             SUBSTRINGMATCH |\n                 *             '=' |\n                 *             INCLUDES |\n                 *             DASHMATCH ] S* [ IDENT | STRING ] S*\n                 *         ]? ']'\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    value       = null,\n                    ns,\n                    token;\n\n                if (tokenStream.match(Tokens.LBRACKET)){\n                    token = tokenStream.token();\n                    value = token.value;\n                    value += this._readWhitespace();\n\n                    ns = this._namespace_prefix();\n\n                    if (ns){\n                        value += ns;\n                    }\n\n                    tokenStream.mustMatch(Tokens.IDENT);\n                    value += tokenStream.token().value;\n                    value += this._readWhitespace();\n\n                    if(tokenStream.match([Tokens.PREFIXMATCH, Tokens.SUFFIXMATCH, Tokens.SUBSTRINGMATCH,\n                            Tokens.EQUALS, Tokens.INCLUDES, Tokens.DASHMATCH])){\n\n                        value += tokenStream.token().value;\n                        value += this._readWhitespace();\n\n                        tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);\n                        value += tokenStream.token().value;\n                        value += this._readWhitespace();\n                    }\n\n                    tokenStream.mustMatch(Tokens.RBRACKET);\n\n                    return new SelectorSubPart(value + \"]\", \"attribute\", token.startLine, token.startCol);\n                } else {\n                    return null;\n                }\n            },\n\n            //CSS3 Selectors\n            _pseudo: function(){\n\n                /*\n                 * pseudo\n                 *   : ':' ':'? [ IDENT | functional_pseudo ]\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    pseudo      = null,\n                    colons      = \":\",\n                    line,\n                    col;\n\n                if (tokenStream.match(Tokens.COLON)){\n\n                    if (tokenStream.match(Tokens.COLON)){\n                        colons += \":\";\n                    }\n\n                    if (tokenStream.match(Tokens.IDENT)){\n                        pseudo = tokenStream.token().value;\n                        line = tokenStream.token().startLine;\n                        col = tokenStream.token().startCol - colons.length;\n                    } else if (tokenStream.peek() == Tokens.FUNCTION){\n                        line = tokenStream.LT(1).startLine;\n                        col = tokenStream.LT(1).startCol - colons.length;\n                        pseudo = this._functional_pseudo();\n                    }\n\n                    if (pseudo){\n                        pseudo = new SelectorSubPart(colons + pseudo, \"pseudo\", line, col);\n                    }\n                }\n\n                return pseudo;\n            },\n\n            //CSS3 Selectors\n            _functional_pseudo: function(){\n                /*\n                 * functional_pseudo\n                 *   : FUNCTION S* expression ')'\n                 *   ;\n                */\n\n                var tokenStream = this._tokenStream,\n                    value = null;\n\n                if(tokenStream.match(Tokens.FUNCTION)){\n                    value = tokenStream.token().value;\n                    value += this._readWhitespace();\n                    value += this._expression();\n                    tokenStream.mustMatch(Tokens.RPAREN);\n                    value += \")\";\n                }\n\n                return value;\n            },\n\n            //CSS3 Selectors\n            _expression: function(){\n                /*\n                 * expression\n                 *   : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    value       = \"\";\n\n                while(tokenStream.match([Tokens.PLUS, Tokens.MINUS, Tokens.DIMENSION,\n                        Tokens.NUMBER, Tokens.STRING, Tokens.IDENT, Tokens.LENGTH,\n                        Tokens.FREQ, Tokens.ANGLE, Tokens.TIME,\n                        Tokens.RESOLUTION, Tokens.SLASH])){\n\n                    value += tokenStream.token().value;\n                    value += this._readWhitespace();\n                }\n\n                return value.length ? value : null;\n\n            },\n\n            //CSS3 Selectors\n            _negation: function(){\n                /*\n                 * negation\n                 *   : NOT S* negation_arg S* ')'\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    line,\n                    col,\n                    value       = \"\",\n                    arg,\n                    subpart     = null;\n\n                if (tokenStream.match(Tokens.NOT)){\n                    value = tokenStream.token().value;\n                    line = tokenStream.token().startLine;\n                    col = tokenStream.token().startCol;\n                    value += this._readWhitespace();\n                    arg = this._negation_arg();\n                    value += arg;\n                    value += this._readWhitespace();\n                    tokenStream.match(Tokens.RPAREN);\n                    value += tokenStream.token().value;\n\n                    subpart = new SelectorSubPart(value, \"not\", line, col);\n                    subpart.args.push(arg);\n                }\n\n                return subpart;\n            },\n\n            //CSS3 Selectors\n            _negation_arg: function(){\n                /*\n                 * negation_arg\n                 *   : type_selector | universal | HASH | class | attrib | pseudo\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    args        = [\n                        this._type_selector,\n                        this._universal,\n                        function(){\n                            return tokenStream.match(Tokens.HASH) ?\n                                    new SelectorSubPart(tokenStream.token().value, \"id\", tokenStream.token().startLine, tokenStream.token().startCol) :\n                                    null;\n                        },\n                        this._class,\n                        this._attrib,\n                        this._pseudo\n                    ],\n                    arg         = null,\n                    i           = 0,\n                    len         = args.length,\n                    elementName,\n                    line,\n                    col,\n                    part;\n\n                line = tokenStream.LT(1).startLine;\n                col = tokenStream.LT(1).startCol;\n\n                while(i < len && arg === null){\n\n                    arg = args[i].call(this);\n                    i++;\n                }\n\n                //must be a negation arg\n                if (arg === null){\n                    this._unexpectedToken(tokenStream.LT(1));\n                }\n\n                //it's an element name\n                if (arg.type == \"elementName\"){\n                    part = new SelectorPart(arg, [], arg.toString(), line, col);\n                } else {\n                    part = new SelectorPart(null, [arg], arg.toString(), line, col);\n                }\n\n                return part;\n            },\n\n            _declaration: function(){\n\n                /*\n                 * declaration\n                 *   : property ':' S* expr prio?\n                 *   | /( empty )/\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    property    = null,\n                    expr        = null,\n                    prio        = null,\n                    error       = null,\n                    invalid     = null,\n                    propertyName= \"\";\n\n                property = this._property();\n                if (property !== null){\n\n                    tokenStream.mustMatch(Tokens.COLON);\n                    this._readWhitespace();\n\n                    expr = this._expr();\n\n                    //if there's no parts for the value, it's an error\n                    if (!expr || expr.length === 0){\n                        this._unexpectedToken(tokenStream.LT(1));\n                    }\n\n                    prio = this._prio();\n\n                    /*\n                     * If hacks should be allowed, then only check the root\n                     * property. If hacks should not be allowed, treat\n                     * _property or *property as invalid properties.\n                     */\n                    propertyName = property.toString();\n                    if (this.options.starHack && property.hack == \"*\" ||\n                            this.options.underscoreHack && property.hack == \"_\") {\n\n                        propertyName = property.text;\n                    }\n\n                    try {\n                        this._validateProperty(propertyName, expr);\n                    } catch (ex) {\n                        invalid = ex;\n                    }\n\n                    this.fire({\n                        type:       \"property\",\n                        property:   property,\n                        value:      expr,\n                        important:  prio,\n                        line:       property.line,\n                        col:        property.col,\n                        invalid:    invalid\n                    });\n\n                    return true;\n                } else {\n                    return false;\n                }\n            },\n\n            _prio: function(){\n                /*\n                 * prio\n                 *   : IMPORTANT_SYM S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    result      = tokenStream.match(Tokens.IMPORTANT_SYM);\n\n                this._readWhitespace();\n                return result;\n            },\n\n            _expr: function(inFunction){\n                /*\n                 * expr\n                 *   : term [ operator term ]*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    values      = [],\n\t\t\t\t\t//valueParts\t= [],\n                    value       = null,\n                    operator    = null;\n\n                value = this._term(inFunction);\n                if (value !== null){\n\n                    values.push(value);\n\n                    do {\n                        operator = this._operator(inFunction);\n\n                        //if there's an operator, keep building up the value parts\n                        if (operator){\n                            values.push(operator);\n                        } /*else {\n                            //if there's not an operator, you have a full value\n\t\t\t\t\t\t\tvalues.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));\n\t\t\t\t\t\t\tvalueParts = [];\n\t\t\t\t\t\t}*/\n\n                        value = this._term(inFunction);\n\n                        if (value === null){\n                            break;\n                        } else {\n                            values.push(value);\n                        }\n                    } while(true);\n                }\n\n\t\t\t\t//cleanup\n                /*if (valueParts.length){\n                    values.push(new PropertyValue(valueParts, valueParts[0].line, valueParts[0].col));\n                }*/\n\n                return values.length > 0 ? new PropertyValue(values, values[0].line, values[0].col) : null;\n            },\n\n            _term: function(inFunction){\n\n                /*\n                 * term\n                 *   : unary_operator?\n                 *     [ NUMBER S* | PERCENTAGE S* | LENGTH S* | ANGLE S* |\n                 *       TIME S* | FREQ S* | function | ie_function ]\n                 *   | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    unary       = null,\n                    value       = null,\n                    endChar     = null,\n                    token,\n                    line,\n                    col;\n\n                //returns the operator or null\n                unary = this._unary_operator();\n                if (unary !== null){\n                    line = tokenStream.token().startLine;\n                    col = tokenStream.token().startCol;\n                }\n\n                //exception for IE filters\n                if (tokenStream.peek() == Tokens.IE_FUNCTION && this.options.ieFilters){\n\n                    value = this._ie_function();\n                    if (unary === null){\n                        line = tokenStream.token().startLine;\n                        col = tokenStream.token().startCol;\n                    }\n\n                //see if it's a simple block\n                } else if (inFunction && tokenStream.match([Tokens.LPAREN, Tokens.LBRACE, Tokens.LBRACKET])){\n\n                    token = tokenStream.token();\n                    endChar = token.endChar;\n                    value = token.value + this._expr(inFunction).text;\n                    if (unary === null){\n                        line = tokenStream.token().startLine;\n                        col = tokenStream.token().startCol;\n                    }\n                    tokenStream.mustMatch(Tokens.type(endChar));\n                    value += endChar;\n                    this._readWhitespace();\n\n                //see if there's a simple match\n                } else if (tokenStream.match([Tokens.NUMBER, Tokens.PERCENTAGE, Tokens.LENGTH,\n                        Tokens.ANGLE, Tokens.TIME,\n                        Tokens.FREQ, Tokens.STRING, Tokens.IDENT, Tokens.URI, Tokens.UNICODE_RANGE])){\n\n                    value = tokenStream.token().value;\n                    if (unary === null){\n                        line = tokenStream.token().startLine;\n                        col = tokenStream.token().startCol;\n                    }\n                    this._readWhitespace();\n                } else {\n\n                    //see if it's a color\n                    token = this._hexcolor();\n                    if (token === null){\n\n                        //if there's no unary, get the start of the next token for line/col info\n                        if (unary === null){\n                            line = tokenStream.LT(1).startLine;\n                            col = tokenStream.LT(1).startCol;\n                        }\n\n                        //has to be a function\n                        if (value === null){\n\n                            /*\n                             * This checks for alpha(opacity=0) style of IE\n                             * functions. IE_FUNCTION only presents progid: style.\n                             */\n                            if (tokenStream.LA(3) == Tokens.EQUALS && this.options.ieFilters){\n                                value = this._ie_function();\n                            } else {\n                                value = this._function();\n                            }\n                        }\n\n                        /*if (value === null){\n                            return null;\n                            //throw new Error(\"Expected identifier at line \" + tokenStream.token().startLine + \", character \" +  tokenStream.token().startCol + \".\");\n                        }*/\n\n                    } else {\n                        value = token.value;\n                        if (unary === null){\n                            line = token.startLine;\n                            col = token.startCol;\n                        }\n                    }\n\n                }\n\n                return value !== null ?\n                        new PropertyValuePart(unary !== null ? unary + value : value, line, col) :\n                        null;\n\n            },\n\n            _function: function(){\n\n                /*\n                 * function\n                 *   : FUNCTION S* expr ')' S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    functionText = null,\n                    expr        = null,\n                    lt;\n\n                if (tokenStream.match(Tokens.FUNCTION)){\n                    functionText = tokenStream.token().value;\n                    this._readWhitespace();\n                    expr = this._expr(true);\n                    functionText += expr;\n\n                    //START: Horrible hack in case it's an IE filter\n                    if (this.options.ieFilters && tokenStream.peek() == Tokens.EQUALS){\n                        do {\n\n                            if (this._readWhitespace()){\n                                functionText += tokenStream.token().value;\n                            }\n\n                            //might be second time in the loop\n                            if (tokenStream.LA(0) == Tokens.COMMA){\n                                functionText += tokenStream.token().value;\n                            }\n\n                            tokenStream.match(Tokens.IDENT);\n                            functionText += tokenStream.token().value;\n\n                            tokenStream.match(Tokens.EQUALS);\n                            functionText += tokenStream.token().value;\n\n                            //functionText += this._term();\n                            lt = tokenStream.peek();\n                            while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){\n                                tokenStream.get();\n                                functionText += tokenStream.token().value;\n                                lt = tokenStream.peek();\n                            }\n                        } while(tokenStream.match([Tokens.COMMA, Tokens.S]));\n                    }\n\n                    //END: Horrible Hack\n\n                    tokenStream.match(Tokens.RPAREN);\n                    functionText += \")\";\n                    this._readWhitespace();\n                }\n\n                return functionText;\n            },\n\n            _ie_function: function(){\n\n                /* (My own extension)\n                 * ie_function\n                 *   : IE_FUNCTION S* IDENT '=' term [S* ','? IDENT '=' term]+ ')' S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    functionText = null,\n                    expr        = null,\n                    lt;\n\n                //IE function can begin like a regular function, too\n                if (tokenStream.match([Tokens.IE_FUNCTION, Tokens.FUNCTION])){\n                    functionText = tokenStream.token().value;\n\n                    do {\n\n                        if (this._readWhitespace()){\n                            functionText += tokenStream.token().value;\n                        }\n\n                        //might be second time in the loop\n                        if (tokenStream.LA(0) == Tokens.COMMA){\n                            functionText += tokenStream.token().value;\n                        }\n\n                        tokenStream.match(Tokens.IDENT);\n                        functionText += tokenStream.token().value;\n\n                        tokenStream.match(Tokens.EQUALS);\n                        functionText += tokenStream.token().value;\n\n                        //functionText += this._term();\n                        lt = tokenStream.peek();\n                        while(lt != Tokens.COMMA && lt != Tokens.S && lt != Tokens.RPAREN){\n                            tokenStream.get();\n                            functionText += tokenStream.token().value;\n                            lt = tokenStream.peek();\n                        }\n                    } while(tokenStream.match([Tokens.COMMA, Tokens.S]));\n\n                    tokenStream.match(Tokens.RPAREN);\n                    functionText += \")\";\n                    this._readWhitespace();\n                }\n\n                return functionText;\n            },\n\n            _hexcolor: function(){\n                /*\n                 * There is a constraint on the color that it must\n                 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])\n                 * after the \"#\"; e.g., \"#000\" is OK, but \"#abcd\" is not.\n                 *\n                 * hexcolor\n                 *   : HASH S*\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    token = null,\n                    color;\n\n                if(tokenStream.match(Tokens.HASH)){\n\n                    //need to do some validation here\n\n                    token = tokenStream.token();\n                    color = token.value;\n                    if (!/#[a-f0-9]{3,6}/i.test(color)){\n                        throw new SyntaxError(\"Expected a hex color but found '\" + color + \"' at line \" + token.startLine + \", col \" + token.startCol + \".\", token.startLine, token.startCol);\n                    }\n                    this._readWhitespace();\n                }\n\n                return token;\n            },\n\n            //-----------------------------------------------------------------\n            // Animations methods\n            //-----------------------------------------------------------------\n\n            _keyframes: function(){\n\n                /*\n                 * keyframes:\n                 *   : KEYFRAMES_SYM S* keyframe_name S* '{' S* keyframe_rule* '}' {\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    token,\n                    tt,\n                    name,\n                    prefix = \"\";\n\n                tokenStream.mustMatch(Tokens.KEYFRAMES_SYM);\n                token = tokenStream.token();\n                if (/^@\\-([^\\-]+)\\-/.test(token.value)) {\n                    prefix = RegExp.$1;\n                }\n\n                this._readWhitespace();\n                name = this._keyframe_name();\n\n                this._readWhitespace();\n                tokenStream.mustMatch(Tokens.LBRACE);\n\n                this.fire({\n                    type:   \"startkeyframes\",\n                    name:   name,\n                    prefix: prefix,\n                    line:   token.startLine,\n                    col:    token.startCol\n                });\n\n                this._readWhitespace();\n                tt = tokenStream.peek();\n\n                //check for key\n                while(tt == Tokens.IDENT || tt == Tokens.PERCENTAGE) {\n                    this._keyframe_rule();\n                    this._readWhitespace();\n                    tt = tokenStream.peek();\n                }\n\n                this.fire({\n                    type:   \"endkeyframes\",\n                    name:   name,\n                    prefix: prefix,\n                    line:   token.startLine,\n                    col:    token.startCol\n                });\n\n                this._readWhitespace();\n                tokenStream.mustMatch(Tokens.RBRACE);\n\n            },\n\n            _keyframe_name: function(){\n\n                /*\n                 * keyframe_name:\n                 *   : IDENT\n                 *   | STRING\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    token;\n\n                tokenStream.mustMatch([Tokens.IDENT, Tokens.STRING]);\n                return SyntaxUnit.fromToken(tokenStream.token());\n            },\n\n            _keyframe_rule: function(){\n\n                /*\n                 * keyframe_rule:\n                 *   : key_list S*\n                 *     '{' S* declaration [ ';' S* declaration ]* '}' S*\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    token,\n                    keyList = this._key_list();\n\n                this.fire({\n                    type:   \"startkeyframerule\",\n                    keys:   keyList,\n                    line:   keyList[0].line,\n                    col:    keyList[0].col\n                });\n\n                this._readDeclarations(true);\n\n                this.fire({\n                    type:   \"endkeyframerule\",\n                    keys:   keyList,\n                    line:   keyList[0].line,\n                    col:    keyList[0].col\n                });\n\n            },\n\n            _key_list: function(){\n\n                /*\n                 * key_list:\n                 *   : key [ S* ',' S* key]*\n                 *   ;\n                 */\n                var tokenStream = this._tokenStream,\n                    token,\n                    key,\n                    keyList = [];\n\n                //must be least one key\n                keyList.push(this._key());\n\n                this._readWhitespace();\n\n                while(tokenStream.match(Tokens.COMMA)){\n                    this._readWhitespace();\n                    keyList.push(this._key());\n                    this._readWhitespace();\n                }\n\n                return keyList;\n            },\n\n            _key: function(){\n                /*\n                 * There is a restriction that IDENT can be only \"from\" or \"to\".\n                 *\n                 * key\n                 *   : PERCENTAGE\n                 *   | IDENT\n                 *   ;\n                 */\n\n                var tokenStream = this._tokenStream,\n                    token;\n\n                if (tokenStream.match(Tokens.PERCENTAGE)){\n                    return SyntaxUnit.fromToken(tokenStream.token());\n                } else if (tokenStream.match(Tokens.IDENT)){\n                    token = tokenStream.token();\n\n                    if (/from|to/i.test(token.value)){\n                        return SyntaxUnit.fromToken(token);\n                    }\n\n                    tokenStream.unget();\n                }\n\n                //if it gets here, there wasn't a valid token, so time to explode\n                this._unexpectedToken(tokenStream.LT(1));\n            },\n\n            //-----------------------------------------------------------------\n            // Helper methods\n            //-----------------------------------------------------------------\n\n            /**\n             * Not part of CSS grammar, but useful for skipping over\n             * combination of white space and HTML-style comments.\n             * @return {void}\n             * @method _skipCruft\n             * @private\n             */\n            _skipCruft: function(){\n                while(this._tokenStream.match([Tokens.S, Tokens.CDO, Tokens.CDC])){\n                    //noop\n                }\n            },\n\n            /**\n             * Not part of CSS grammar, but this pattern occurs frequently\n             * in the official CSS grammar. Split out here to eliminate\n             * duplicate code.\n             * @param {Boolean} checkStart Indicates if the rule should check\n             *      for the left brace at the beginning.\n             * @param {Boolean} readMargins Indicates if the rule should check\n             *      for margin patterns.\n             * @return {void}\n             * @method _readDeclarations\n             * @private\n             */\n            _readDeclarations: function(checkStart, readMargins){\n                /*\n                 * Reads the pattern\n                 * S* '{' S* declaration [ ';' S* declaration ]* '}' S*\n                 * or\n                 * S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S*\n                 * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect.\n                 * A semicolon is only necessary following a declaration is there's another declaration\n                 * or margin afterwards.\n                 */\n                var tokenStream = this._tokenStream,\n                    tt;\n\n\n                this._readWhitespace();\n\n                if (checkStart){\n                    tokenStream.mustMatch(Tokens.LBRACE);\n                }\n\n                this._readWhitespace();\n\n                try {\n\n                    while(true){\n\n                        if (tokenStream.match(Tokens.SEMICOLON) || (readMargins && this._margin())){\n                            //noop\n                        } else if (this._declaration()){\n                            if (!tokenStream.match(Tokens.SEMICOLON)){\n                                break;\n                            }\n                        } else {\n                            break;\n                        }\n\n                        //if ((!this._margin() && !this._declaration()) || !tokenStream.match(Tokens.SEMICOLON)){\n                        //    break;\n                        //}\n                        this._readWhitespace();\n                    }\n\n                    tokenStream.mustMatch(Tokens.RBRACE);\n                    this._readWhitespace();\n\n                } catch (ex) {\n                    if (ex instanceof SyntaxError && !this.options.strict){\n\n                        //fire error event\n                        this.fire({\n                            type:       \"error\",\n                            error:      ex,\n                            message:    ex.message,\n                            line:       ex.line,\n                            col:        ex.col\n                        });\n\n                        //see if there's another declaration\n                        tt = tokenStream.advance([Tokens.SEMICOLON, Tokens.RBRACE]);\n                        if (tt == Tokens.SEMICOLON){\n                            //if there's a semicolon, then there might be another declaration\n                            this._readDeclarations(false, readMargins);\n                        } else if (tt != Tokens.RBRACE){\n                            //if there's a right brace, the rule is finished so don't do anything\n                            //otherwise, rethrow the error because it wasn't handled properly\n                            throw ex;\n                        }\n\n                    } else {\n                        //not a syntax error, rethrow it\n                        throw ex;\n                    }\n                }\n\n            },\n\n            /**\n             * In some cases, you can end up with two white space tokens in a\n             * row. Instead of making a change in every function that looks for\n             * white space, this function is used to match as much white space\n             * as necessary.\n             * @method _readWhitespace\n             * @return {String} The white space if found, empty string if not.\n             * @private\n             */\n            _readWhitespace: function(){\n\n                var tokenStream = this._tokenStream,\n                    ws = \"\";\n\n                while(tokenStream.match(Tokens.S)){\n                    ws += tokenStream.token().value;\n                }\n\n                return ws;\n            },\n\n\n            /**\n             * Throws an error when an unexpected token is found.\n             * @param {Object} token The token that was found.\n             * @method _unexpectedToken\n             * @return {void}\n             * @private\n             */\n            _unexpectedToken: function(token){\n                throw new SyntaxError(\"Unexpected token '\" + token.value + \"' at line \" + token.startLine + \", col \" + token.startCol + \".\", token.startLine, token.startCol);\n            },\n\n            /**\n             * Helper method used for parsing subparts of a style sheet.\n             * @return {void}\n             * @method _verifyEnd\n             * @private\n             */\n            _verifyEnd: function(){\n                if (this._tokenStream.LA(1) != Tokens.EOF){\n                    this._unexpectedToken(this._tokenStream.LT(1));\n                }\n            },\n\n            //-----------------------------------------------------------------\n            // Validation methods\n            //-----------------------------------------------------------------\n            _validateProperty: function(property, value){\n                Validation.validate(property, value);\n            },\n\n            //-----------------------------------------------------------------\n            // Parsing methods\n            //-----------------------------------------------------------------\n\n            parse: function(input){\n                this._tokenStream = new TokenStream(input, Tokens);\n                this._stylesheet();\n            },\n\n            parseStyleSheet: function(input){\n                //just passthrough\n                return this.parse(input);\n            },\n\n            parseMediaQuery: function(input){\n                this._tokenStream = new TokenStream(input, Tokens);\n                var result = this._media_query();\n\n                //if there's anything more, then it's an invalid selector\n                this._verifyEnd();\n\n                //otherwise return result\n                return result;\n            },\n\n            /**\n             * Parses a property value (everything after the semicolon).\n             * @return {parserlib.css.PropertyValue} The property value.\n             * @throws parserlib.util.SyntaxError If an unexpected token is found.\n             * @method parserPropertyValue\n             */\n            parsePropertyValue: function(input){\n\n                this._tokenStream = new TokenStream(input, Tokens);\n                this._readWhitespace();\n\n                var result = this._expr();\n\n                //okay to have a trailing white space\n                this._readWhitespace();\n\n                //if there's anything more, then it's an invalid selector\n                this._verifyEnd();\n\n                //otherwise return result\n                return result;\n            },\n\n            /**\n             * Parses a complete CSS rule, including selectors and\n             * properties.\n             * @param {String} input The text to parser.\n             * @return {Boolean} True if the parse completed successfully, false if not.\n             * @method parseRule\n             */\n            parseRule: function(input){\n                this._tokenStream = new TokenStream(input, Tokens);\n\n                //skip any leading white space\n                this._readWhitespace();\n\n                var result = this._ruleset();\n\n                //skip any trailing white space\n                this._readWhitespace();\n\n                //if there's anything more, then it's an invalid selector\n                this._verifyEnd();\n\n                //otherwise return result\n                return result;\n            },\n\n            /**\n             * Parses a single CSS selector (no comma)\n             * @param {String} input The text to parse as a CSS selector.\n             * @return {Selector} An object representing the selector.\n             * @throws parserlib.util.SyntaxError If an unexpected token is found.\n             * @method parseSelector\n             */\n            parseSelector: function(input){\n\n                this._tokenStream = new TokenStream(input, Tokens);\n\n                //skip any leading white space\n                this._readWhitespace();\n\n                var result = this._selector();\n\n                //skip any trailing white space\n                this._readWhitespace();\n\n                //if there's anything more, then it's an invalid selector\n                this._verifyEnd();\n\n                //otherwise return result\n                return result;\n            },\n\n            /**\n             * Parses an HTML style attribute: a set of CSS declarations\n             * separated by semicolons.\n             * @param {String} input The text to parse as a style attribute\n             * @return {void}\n             * @method parseStyleAttribute\n             */\n            parseStyleAttribute: function(input){\n                input += \"}\"; // for error recovery in _readDeclarations()\n                this._tokenStream = new TokenStream(input, Tokens);\n                this._readDeclarations();\n            }\n        };\n\n    //copy over onto prototype\n    for (prop in additions){\n        if (additions.hasOwnProperty(prop)){\n            proto[prop] = additions[prop];\n        }\n    }\n\n    return proto;\n}();\n\n\n/*\nnth\n  : S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? |\n         ['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*\n  ;\n*/\n/*global Validation, ValidationTypes, ValidationError*/\nvar Properties = {\n\n    //A\n    \"align-items\"                   : \"flex-start | flex-end | center | baseline | stretch\",\n    \"align-content\"                 : \"flex-start | flex-end | center | space-between | space-around | stretch\",\n    \"align-self\"                    : \"auto | flex-start | flex-end | center | baseline | stretch\",\n    \"-webkit-align-items\"           : \"flex-start | flex-end | center | baseline | stretch\",\n    \"-webkit-align-content\"         : \"flex-start | flex-end | center | space-between | space-around | stretch\",\n    \"-webkit-align-self\"            : \"auto | flex-start | flex-end | center | baseline | stretch\",\n    \"alignment-adjust\"              : \"auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>\",\n    \"alignment-baseline\"            : \"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",\n    \"animation\"                     : 1,\n    \"animation-delay\"               : { multi: \"<time>\", comma: true },\n    \"animation-direction\"           : { multi: \"normal | alternate\", comma: true },\n    \"animation-duration\"            : { multi: \"<time>\", comma: true },\n    \"animation-fill-mode\"           : { multi: \"none | forwards | backwards | both\", comma: true },\n    \"animation-iteration-count\"     : { multi: \"<number> | infinite\", comma: true },\n    \"animation-name\"                : { multi: \"none | <ident>\", comma: true },\n    \"animation-play-state\"          : { multi: \"running | paused\", comma: true },\n    \"animation-timing-function\"     : 1,\n\n    //vendor prefixed\n    \"-moz-animation-delay\"               : { multi: \"<time>\", comma: true },\n    \"-moz-animation-direction\"           : { multi: \"normal | alternate\", comma: true },\n    \"-moz-animation-duration\"            : { multi: \"<time>\", comma: true },\n    \"-moz-animation-iteration-count\"     : { multi: \"<number> | infinite\", comma: true },\n    \"-moz-animation-name\"                : { multi: \"none | <ident>\", comma: true },\n    \"-moz-animation-play-state\"          : { multi: \"running | paused\", comma: true },\n\n    \"-ms-animation-delay\"               : { multi: \"<time>\", comma: true },\n    \"-ms-animation-direction\"           : { multi: \"normal | alternate\", comma: true },\n    \"-ms-animation-duration\"            : { multi: \"<time>\", comma: true },\n    \"-ms-animation-iteration-count\"     : { multi: \"<number> | infinite\", comma: true },\n    \"-ms-animation-name\"                : { multi: \"none | <ident>\", comma: true },\n    \"-ms-animation-play-state\"          : { multi: \"running | paused\", comma: true },\n\n    \"-webkit-animation-delay\"               : { multi: \"<time>\", comma: true },\n    \"-webkit-animation-direction\"           : { multi: \"normal | alternate\", comma: true },\n    \"-webkit-animation-duration\"            : { multi: \"<time>\", comma: true },\n    \"-webkit-animation-fill-mode\"           : { multi: \"none | forwards | backwards | both\", comma: true },\n    \"-webkit-animation-iteration-count\"     : { multi: \"<number> | infinite\", comma: true },\n    \"-webkit-animation-name\"                : { multi: \"none | <ident>\", comma: true },\n    \"-webkit-animation-play-state\"          : { multi: \"running | paused\", comma: true },\n\n    \"-o-animation-delay\"               : { multi: \"<time>\", comma: true },\n    \"-o-animation-direction\"           : { multi: \"normal | alternate\", comma: true },\n    \"-o-animation-duration\"            : { multi: \"<time>\", comma: true },\n    \"-o-animation-iteration-count\"     : { multi: \"<number> | infinite\", comma: true },\n    \"-o-animation-name\"                : { multi: \"none | <ident>\", comma: true },\n    \"-o-animation-play-state\"          : { multi: \"running | paused\", comma: true },\n\n    \"appearance\"                    : \"icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit\",\n    \"azimuth\"                       : function (expression) {\n        var simple      = \"<angle> | leftwards | rightwards | inherit\",\n            direction   = \"left-side | far-left | left | center-left | center | center-right | right | far-right | right-side\",\n            behind      = false,\n            valid       = false,\n            part;\n\n        if (!ValidationTypes.isAny(expression, simple)) {\n            if (ValidationTypes.isAny(expression, \"behind\")) {\n                behind = true;\n                valid = true;\n            }\n\n            if (ValidationTypes.isAny(expression, direction)) {\n                valid = true;\n                if (!behind) {\n                    ValidationTypes.isAny(expression, \"behind\");\n                }\n            }\n        }\n\n        if (expression.hasNext()) {\n            part = expression.next();\n            if (valid) {\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                throw new ValidationError(\"Expected (<'azimuth'>) but found '\" + part + \"'.\", part.line, part.col);\n            }\n        }\n    },\n\n    //B\n    \"backface-visibility\"           : \"visible | hidden\",\n    \"background\"                    : 1,\n    \"background-attachment\"         : { multi: \"<attachment>\", comma: true },\n    \"background-clip\"               : { multi: \"<box>\", comma: true },\n    \"background-color\"              : \"<color> | inherit\",\n    \"background-image\"              : { multi: \"<bg-image>\", comma: true },\n    \"background-origin\"             : { multi: \"<box>\", comma: true },\n    \"background-position\"           : { multi: \"<bg-position>\", comma: true },\n    \"background-repeat\"             : { multi: \"<repeat-style>\" },\n    \"background-size\"               : { multi: \"<bg-size>\", comma: true },\n    \"baseline-shift\"                : \"baseline | sub | super | <percentage> | <length>\",\n    \"behavior\"                      : 1,\n    \"binding\"                       : 1,\n    \"bleed\"                         : \"<length>\",\n    \"bookmark-label\"                : \"<content> | <attr> | <string>\",\n    \"bookmark-level\"                : \"none | <integer>\",\n    \"bookmark-state\"                : \"open | closed\",\n    \"bookmark-target\"               : \"none | <uri> | <attr>\",\n    \"border\"                        : \"<border-width> || <border-style> || <color>\",\n    \"border-bottom\"                 : \"<border-width> || <border-style> || <color>\",\n    \"border-bottom-color\"           : \"<color> | inherit\",\n    \"border-bottom-left-radius\"     :  \"<x-one-radius>\",\n    \"border-bottom-right-radius\"    :  \"<x-one-radius>\",\n    \"border-bottom-style\"           : \"<border-style>\",\n    \"border-bottom-width\"           : \"<border-width>\",\n    \"border-collapse\"               : \"collapse | separate | inherit\",\n    \"border-color\"                  : { multi: \"<color> | inherit\", max: 4 },\n    \"border-image\"                  : 1,\n    \"border-image-outset\"           : { multi: \"<length> | <number>\", max: 4 },\n    \"border-image-repeat\"           : { multi: \"stretch | repeat | round\", max: 2 },\n    \"border-image-slice\"            : function(expression) {\n\n        var valid   = false,\n            numeric = \"<number> | <percentage>\",\n            fill    = false,\n            count   = 0,\n            max     = 4,\n            part;\n\n        if (ValidationTypes.isAny(expression, \"fill\")) {\n            fill = true;\n            valid = true;\n        }\n\n        while (expression.hasNext() && count < max) {\n            valid = ValidationTypes.isAny(expression, numeric);\n            if (!valid) {\n                break;\n            }\n            count++;\n        }\n\n\n        if (!fill) {\n            ValidationTypes.isAny(expression, \"fill\");\n        } else {\n            valid = true;\n        }\n\n        if (expression.hasNext()) {\n            part = expression.next();\n            if (valid) {\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                throw new ValidationError(\"Expected ([<number> | <percentage>]{1,4} && fill?) but found '\" + part + \"'.\", part.line, part.col);\n            }\n        }\n    },\n    \"border-image-source\"           : \"<image> | none\",\n    \"border-image-width\"            : { multi: \"<length> | <percentage> | <number> | auto\", max: 4 },\n    \"border-left\"                   : \"<border-width> || <border-style> || <color>\",\n    \"border-left-color\"             : \"<color> | inherit\",\n    \"border-left-style\"             : \"<border-style>\",\n    \"border-left-width\"             : \"<border-width>\",\n    \"border-radius\"                 : function(expression) {\n\n        var valid   = false,\n            simple = \"<length> | <percentage> | inherit\",\n            slash   = false,\n            fill    = false,\n            count   = 0,\n            max     = 8,\n            part;\n\n        while (expression.hasNext() && count < max) {\n            valid = ValidationTypes.isAny(expression, simple);\n            if (!valid) {\n\n                if (expression.peek() == \"/\" && count > 0 && !slash) {\n                    slash = true;\n                    max = count + 5;\n                    expression.next();\n                } else {\n                    break;\n                }\n            }\n            count++;\n        }\n\n        if (expression.hasNext()) {\n            part = expression.next();\n            if (valid) {\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                throw new ValidationError(\"Expected (<'border-radius'>) but found '\" + part + \"'.\", part.line, part.col);\n            }\n        }\n    },\n    \"border-right\"                  : \"<border-width> || <border-style> || <color>\",\n    \"border-right-color\"            : \"<color> | inherit\",\n    \"border-right-style\"            : \"<border-style>\",\n    \"border-right-width\"            : \"<border-width>\",\n    \"border-spacing\"                : { multi: \"<length> | inherit\", max: 2 },\n    \"border-style\"                  : { multi: \"<border-style>\", max: 4 },\n    \"border-top\"                    : \"<border-width> || <border-style> || <color>\",\n    \"border-top-color\"              : \"<color> | inherit\",\n    \"border-top-left-radius\"        : \"<x-one-radius>\",\n    \"border-top-right-radius\"       : \"<x-one-radius>\",\n    \"border-top-style\"              : \"<border-style>\",\n    \"border-top-width\"              : \"<border-width>\",\n    \"border-width\"                  : { multi: \"<border-width>\", max: 4 },\n    \"bottom\"                        : \"<margin-width> | inherit\",\n    \"-moz-box-align\"                : \"start | end | center | baseline | stretch\",\n    \"-moz-box-decoration-break\"     : \"slice |clone\",\n    \"-moz-box-direction\"            : \"normal | reverse | inherit\",\n    \"-moz-box-flex\"                 : \"<number>\",\n    \"-moz-box-flex-group\"           : \"<integer>\",\n    \"-moz-box-lines\"                : \"single | multiple\",\n    \"-moz-box-ordinal-group\"        : \"<integer>\",\n    \"-moz-box-orient\"               : \"horizontal | vertical | inline-axis | block-axis | inherit\",\n    \"-moz-box-pack\"                 : \"start | end | center | justify\",\n    \"-webkit-box-align\"             : \"start | end | center | baseline | stretch\",\n    \"-webkit-box-decoration-break\"  : \"slice |clone\",\n    \"-webkit-box-direction\"         : \"normal | reverse | inherit\",\n    \"-webkit-box-flex\"              : \"<number>\",\n    \"-webkit-box-flex-group\"        : \"<integer>\",\n    \"-webkit-box-lines\"             : \"single | multiple\",\n    \"-webkit-box-ordinal-group\"     : \"<integer>\",\n    \"-webkit-box-orient\"            : \"horizontal | vertical | inline-axis | block-axis | inherit\",\n    \"-webkit-box-pack\"              : \"start | end | center | justify\",\n    \"box-shadow\"                    : function (expression) {\n        var result      = false,\n            part;\n\n        if (!ValidationTypes.isAny(expression, \"none\")) {\n            Validation.multiProperty(\"<shadow>\", expression, true, Infinity);\n        } else {\n            if (expression.hasNext()) {\n                part = expression.next();\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            }\n        }\n    },\n    \"box-sizing\"                    : \"content-box | border-box | inherit\",\n    \"break-after\"                   : \"auto | always | avoid | left | right | page | column | avoid-page | avoid-column\",\n    \"break-before\"                  : \"auto | always | avoid | left | right | page | column | avoid-page | avoid-column\",\n    \"break-inside\"                  : \"auto | avoid | avoid-page | avoid-column\",\n\n    //C\n    \"caption-side\"                  : \"top | bottom | inherit\",\n    \"clear\"                         : \"none | right | left | both | inherit\",\n    \"clip\"                          : 1,\n    \"color\"                         : \"<color> | inherit\",\n    \"color-profile\"                 : 1,\n    \"column-count\"                  : \"<integer> | auto\",                      //http://www.w3.org/TR/css3-multicol/\n    \"column-fill\"                   : \"auto | balance\",\n    \"column-gap\"                    : \"<length> | normal\",\n    \"column-rule\"                   : \"<border-width> || <border-style> || <color>\",\n    \"column-rule-color\"             : \"<color>\",\n    \"column-rule-style\"             : \"<border-style>\",\n    \"column-rule-width\"             : \"<border-width>\",\n    \"column-span\"                   : \"none | all\",\n    \"column-width\"                  : \"<length> | auto\",\n    \"columns\"                       : 1,\n    \"content\"                       : 1,\n    \"counter-increment\"             : 1,\n    \"counter-reset\"                 : 1,\n    \"crop\"                          : \"<shape> | auto\",\n    \"cue\"                           : \"cue-after | cue-before | inherit\",\n    \"cue-after\"                     : 1,\n    \"cue-before\"                    : 1,\n    \"cursor\"                        : 1,\n\n    //D\n    \"direction\"                     : \"ltr | rtl | inherit\",\n    \"display\"                       : \"inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex\",\n    \"dominant-baseline\"             : 1,\n    \"drop-initial-after-adjust\"     : \"central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>\",\n    \"drop-initial-after-align\"      : \"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",\n    \"drop-initial-before-adjust\"    : \"before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>\",\n    \"drop-initial-before-align\"     : \"caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical\",\n    \"drop-initial-size\"             : \"auto | line | <length> | <percentage>\",\n    \"drop-initial-value\"            : \"initial | <integer>\",\n\n    //E\n    \"elevation\"                     : \"<angle> | below | level | above | higher | lower | inherit\",\n    \"empty-cells\"                   : \"show | hide | inherit\",\n\n    //F\n    \"fill\"                          : \"<color>\",\n    \"filter\"                        : 1,\n    \"fit\"                           : \"fill | hidden | meet | slice\",\n    \"fit-position\"                  : 1,\n    \"flex\"                          : \"<flex>\",\n    \"flex-basis\"                    : \"<width>\",\n    \"flex-direction\"                : \"row | row-reverse | column | column-reverse\",\n    \"flex-flow\"                     : \"<flex-direction> || <flex-wrap>\",\n    \"flex-grow\"                     : \"<number>\",\n    \"flex-shrink\"                   : \"<number>\",\n    \"flex-wrap\"                     : \"nowrap | wrap | wrap-reverse\",\n    \"-webkit-flex\"                  : \"<flex>\",\n    \"-webkit-flex-basis\"            : \"<width>\",\n    \"-webkit-flex-direction\"        : \"row | row-reverse | column | column-reverse\",\n    \"-webkit-flex-flow\"             : \"<flex-direction> || <flex-wrap>\",\n    \"-webkit-flex-grow\"             : \"<number>\",\n    \"-webkit-flex-shrink\"           : \"<number>\",\n    \"-webkit-flex-wrap\"             : \"nowrap | wrap | wrap-reverse\",\n    \"-ms-flex\"                      : \"<flex>\",\n    \"-ms-flex-align\"                : \"start | end | center | stretch | baseline\",\n    \"-ms-flex-direction\"            : \"row | row-reverse | column | column-reverse | inherit\",\n    \"-ms-flex-order\"                : \"<number>\",\n    \"-ms-flex-pack\"                 : \"start | end | center | justify\",\n    \"-ms-flex-wrap\"                 : \"nowrap | wrap | wrap-reverse\",\n    \"float\"                         : \"left | right | none | inherit\",\n    \"float-offset\"                  : 1,\n    \"font\"                          : 1,\n    \"font-family\"                   : 1,\n    \"font-size\"                     : \"<absolute-size> | <relative-size> | <length> | <percentage> | inherit\",\n    \"font-size-adjust\"              : \"<number> | none | inherit\",\n    \"font-stretch\"                  : \"normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit\",\n    \"font-style\"                    : \"normal | italic | oblique | inherit\",\n    \"font-variant\"                  : \"normal | small-caps | inherit\",\n    \"font-weight\"                   : \"normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit\",\n\n    //G\n    \"grid-cell-stacking\"            : \"columns | rows | layer\",\n    \"grid-column\"                   : 1,\n    \"grid-columns\"                  : 1,\n    \"grid-column-align\"             : \"start | end | center | stretch\",\n    \"grid-column-sizing\"            : 1,\n    \"grid-column-span\"              : \"<integer>\",\n    \"grid-flow\"                     : \"none | rows | columns\",\n    \"grid-layer\"                    : \"<integer>\",\n    \"grid-row\"                      : 1,\n    \"grid-rows\"                     : 1,\n    \"grid-row-align\"                : \"start | end | center | stretch\",\n    \"grid-row-span\"                 : \"<integer>\",\n    \"grid-row-sizing\"               : 1,\n\n    //H\n    \"hanging-punctuation\"           : 1,\n    \"height\"                        : \"<margin-width> | <content-sizing> | inherit\",\n    \"hyphenate-after\"               : \"<integer> | auto\",\n    \"hyphenate-before\"              : \"<integer> | auto\",\n    \"hyphenate-character\"           : \"<string> | auto\",\n    \"hyphenate-lines\"               : \"no-limit | <integer>\",\n    \"hyphenate-resource\"            : 1,\n    \"hyphens\"                       : \"none | manual | auto\",\n\n    //I\n    \"icon\"                          : 1,\n    \"image-orientation\"             : \"angle | auto\",\n    \"image-rendering\"               : 1,\n    \"image-resolution\"              : 1,\n    \"inline-box-align\"              : \"initial | last | <integer>\",\n\n    //J\n    \"justify-content\"               : \"flex-start | flex-end | center | space-between | space-around\",\n    \"-webkit-justify-content\"       : \"flex-start | flex-end | center | space-between | space-around\",\n\n    //L\n    \"left\"                          : \"<margin-width> | inherit\",\n    \"letter-spacing\"                : \"<length> | normal | inherit\",\n    \"line-height\"                   : \"<number> | <length> | <percentage> | normal | inherit\",\n    \"line-break\"                    : \"auto | loose | normal | strict\",\n    \"line-stacking\"                 : 1,\n    \"line-stacking-ruby\"            : \"exclude-ruby | include-ruby\",\n    \"line-stacking-shift\"           : \"consider-shifts | disregard-shifts\",\n    \"line-stacking-strategy\"        : \"inline-line-height | block-line-height | max-height | grid-height\",\n    \"list-style\"                    : 1,\n    \"list-style-image\"              : \"<uri> | none | inherit\",\n    \"list-style-position\"           : \"inside | outside | inherit\",\n    \"list-style-type\"               : \"disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit\",\n\n    //M\n    \"margin\"                        : { multi: \"<margin-width> | inherit\", max: 4 },\n    \"margin-bottom\"                 : \"<margin-width> | inherit\",\n    \"margin-left\"                   : \"<margin-width> | inherit\",\n    \"margin-right\"                  : \"<margin-width> | inherit\",\n    \"margin-top\"                    : \"<margin-width> | inherit\",\n    \"mark\"                          : 1,\n    \"mark-after\"                    : 1,\n    \"mark-before\"                   : 1,\n    \"marks\"                         : 1,\n    \"marquee-direction\"             : 1,\n    \"marquee-play-count\"            : 1,\n    \"marquee-speed\"                 : 1,\n    \"marquee-style\"                 : 1,\n    \"max-height\"                    : \"<length> | <percentage> | <content-sizing> | none | inherit\",\n    \"max-width\"                     : \"<length> | <percentage> | <content-sizing> | none | inherit\",\n    \"min-height\"                    : \"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit\",\n    \"min-width\"                     : \"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit\",\n    \"move-to\"                       : 1,\n\n    //N\n    \"nav-down\"                      : 1,\n    \"nav-index\"                     : 1,\n    \"nav-left\"                      : 1,\n    \"nav-right\"                     : 1,\n    \"nav-up\"                        : 1,\n\n    //O\n    \"opacity\"                       : \"<number> | inherit\",\n    \"order\"                         : \"<integer>\",\n    \"-webkit-order\"                 : \"<integer>\",\n    \"orphans\"                       : \"<integer> | inherit\",\n    \"outline\"                       : 1,\n    \"outline-color\"                 : \"<color> | invert | inherit\",\n    \"outline-offset\"                : 1,\n    \"outline-style\"                 : \"<border-style> | inherit\",\n    \"outline-width\"                 : \"<border-width> | inherit\",\n    \"overflow\"                      : \"visible | hidden | scroll | auto | inherit\",\n    \"overflow-style\"                : 1,\n    \"overflow-wrap\"                 : \"normal | break-word\",\n    \"overflow-x\"                    : 1,\n    \"overflow-y\"                    : 1,\n\n    //P\n    \"padding\"                       : { multi: \"<padding-width> | inherit\", max: 4 },\n    \"padding-bottom\"                : \"<padding-width> | inherit\",\n    \"padding-left\"                  : \"<padding-width> | inherit\",\n    \"padding-right\"                 : \"<padding-width> | inherit\",\n    \"padding-top\"                   : \"<padding-width> | inherit\",\n    \"page\"                          : 1,\n    \"page-break-after\"              : \"auto | always | avoid | left | right | inherit\",\n    \"page-break-before\"             : \"auto | always | avoid | left | right | inherit\",\n    \"page-break-inside\"             : \"auto | avoid | inherit\",\n    \"page-policy\"                   : 1,\n    \"pause\"                         : 1,\n    \"pause-after\"                   : 1,\n    \"pause-before\"                  : 1,\n    \"perspective\"                   : 1,\n    \"perspective-origin\"            : 1,\n    \"phonemes\"                      : 1,\n    \"pitch\"                         : 1,\n    \"pitch-range\"                   : 1,\n    \"play-during\"                   : 1,\n    \"pointer-events\"                : \"auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit\",\n    \"position\"                      : \"static | relative | absolute | fixed | inherit\",\n    \"presentation-level\"            : 1,\n    \"punctuation-trim\"              : 1,\n\n    //Q\n    \"quotes\"                        : 1,\n\n    //R\n    \"rendering-intent\"              : 1,\n    \"resize\"                        : 1,\n    \"rest\"                          : 1,\n    \"rest-after\"                    : 1,\n    \"rest-before\"                   : 1,\n    \"richness\"                      : 1,\n    \"right\"                         : \"<margin-width> | inherit\",\n    \"rotation\"                      : 1,\n    \"rotation-point\"                : 1,\n    \"ruby-align\"                    : 1,\n    \"ruby-overhang\"                 : 1,\n    \"ruby-position\"                 : 1,\n    \"ruby-span\"                     : 1,\n\n    //S\n    \"size\"                          : 1,\n    \"speak\"                         : \"normal | none | spell-out | inherit\",\n    \"speak-header\"                  : \"once | always | inherit\",\n    \"speak-numeral\"                 : \"digits | continuous | inherit\",\n    \"speak-punctuation\"             : \"code | none | inherit\",\n    \"speech-rate\"                   : 1,\n    \"src\"                           : 1,\n    \"stress\"                        : 1,\n    \"string-set\"                    : 1,\n\n    \"stroke\"                        : 1,\n    \"stroke-dasharray\"              : 1,\n\n    \"table-layout\"                  : \"auto | fixed | inherit\",\n    \"tab-size\"                      : \"<integer> | <length>\",\n    \"target\"                        : 1,\n    \"target-name\"                   : 1,\n    \"target-new\"                    : 1,\n    \"target-position\"               : 1,\n    \"text-align\"                    : \"left | right | center | justify | inherit\" ,\n    \"text-align-last\"               : 1,\n    \"text-decoration\"               : 1,\n    \"text-emphasis\"                 : 1,\n    \"text-height\"                   : 1,\n    \"text-indent\"                   : \"<length> | <percentage> | inherit\",\n    \"text-justify\"                  : \"auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida\",\n    \"text-outline\"                  : 1,\n    \"text-overflow\"                 : 1,\n    \"text-rendering\"                : \"auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit\",\n    \"text-shadow\"                   : 1,\n    \"text-transform\"                : \"capitalize | uppercase | lowercase | none | inherit\",\n    \"text-wrap\"                     : \"normal | none | avoid\",\n    \"top\"                           : \"<margin-width> | inherit\",\n    \"-ms-touch-action\"              : \"auto | none | pan-x | pan-y\",\n    \"touch-action\"                  : \"auto | none | pan-x | pan-y\",\n    \"transform\"                     : 1,\n    \"transform-origin\"              : 1,\n    \"transform-style\"               : 1,\n    \"transition\"                    : 1,\n    \"transition-delay\"              : 1,\n    \"transition-duration\"           : 1,\n    \"transition-property\"           : 1,\n    \"transition-timing-function\"    : 1,\n\n    //U\n    \"unicode-bidi\"                  : \"normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit\",\n    \"user-modify\"                   : \"read-only | read-write | write-only | inherit\",\n    \"user-select\"                   : \"none | text | toggle | element | elements | all | inherit\",\n\n    //V\n    \"vertical-align\"                : \"auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>\",\n    \"visibility\"                    : \"visible | hidden | collapse | inherit\",\n    \"voice-balance\"                 : 1,\n    \"voice-duration\"                : 1,\n    \"voice-family\"                  : 1,\n    \"voice-pitch\"                   : 1,\n    \"voice-pitch-range\"             : 1,\n    \"voice-rate\"                    : 1,\n    \"voice-stress\"                  : 1,\n    \"voice-volume\"                  : 1,\n    \"volume\"                        : 1,\n\n    //W\n    \"white-space\"                   : \"normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap\", //http://perishablepress.com/wrapping-content/\n    \"white-space-collapse\"          : 1,\n    \"widows\"                        : \"<integer> | inherit\",\n    \"width\"                         : \"<length> | <percentage> | <content-sizing> | auto | inherit\",\n    \"will-change\"                   : 1,\n    \"word-break\"                    : \"normal | keep-all | break-all\",\n    \"word-spacing\"                  : \"<length> | normal | inherit\",\n    \"word-wrap\"                     : \"normal | break-word\",\n    \"writing-mode\"                  : \"horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit\",\n\n    //Z\n    \"z-index\"                       : \"<integer> | auto | inherit\",\n    \"zoom\"                          : \"<number> | <percentage> | normal\"\n};\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a selector combinator (whitespace, +, >).\n * @namespace parserlib.css\n * @class PropertyName\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {String} text The text representation of the unit.\n * @param {String} hack The type of IE hack applied (\"*\", \"_\", or null).\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction PropertyName(text, hack, line, col){\n\n    SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_NAME_TYPE);\n\n    /**\n     * The type of IE hack applied (\"*\", \"_\", or null).\n     * @type String\n     * @property hack\n     */\n    this.hack = hack;\n\n}\n\nPropertyName.prototype = new SyntaxUnit();\nPropertyName.prototype.constructor = PropertyName;\nPropertyName.prototype.toString = function(){\n    return (this.hack ? this.hack : \"\") + this.text;\n};\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a single part of a CSS property value, meaning that it represents\n * just everything single part between \":\" and \";\". If there are multiple values\n * separated by commas, this type represents just one of the values.\n * @param {String[]} parts An array of value parts making up this value.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n * @namespace parserlib.css\n * @class PropertyValue\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n */\nfunction PropertyValue(parts, line, col){\n\n    SyntaxUnit.call(this, parts.join(\" \"), line, col, Parser.PROPERTY_VALUE_TYPE);\n\n    /**\n     * The parts that make up the selector.\n     * @type Array\n     * @property parts\n     */\n    this.parts = parts;\n\n}\n\nPropertyValue.prototype = new SyntaxUnit();\nPropertyValue.prototype.constructor = PropertyValue;\n\n/*global SyntaxUnit, Parser*/\n/**\n * A utility class that allows for easy iteration over the various parts of a\n * property value.\n * @param {parserlib.css.PropertyValue} value The property value to iterate over.\n * @namespace parserlib.css\n * @class PropertyValueIterator\n * @constructor\n */\nfunction PropertyValueIterator(value){\n\n    /**\n     * Iterator value\n     * @type int\n     * @property _i\n     * @private\n     */\n    this._i = 0;\n\n    /**\n     * The parts that make up the value.\n     * @type Array\n     * @property _parts\n     * @private\n     */\n    this._parts = value.parts;\n\n    /**\n     * Keeps track of bookmarks along the way.\n     * @type Array\n     * @property _marks\n     * @private\n     */\n    this._marks = [];\n\n    /**\n     * Holds the original property value.\n     * @type parserlib.css.PropertyValue\n     * @property value\n     */\n    this.value = value;\n\n}\n\n/**\n * Returns the total number of parts in the value.\n * @return {int} The total number of parts in the value.\n * @method count\n */\nPropertyValueIterator.prototype.count = function(){\n    return this._parts.length;\n};\n\n/**\n * Indicates if the iterator is positioned at the first item.\n * @return {Boolean} True if positioned at first item, false if not.\n * @method isFirst\n */\nPropertyValueIterator.prototype.isFirst = function(){\n    return this._i === 0;\n};\n\n/**\n * Indicates if there are more parts of the property value.\n * @return {Boolean} True if there are more parts, false if not.\n * @method hasNext\n */\nPropertyValueIterator.prototype.hasNext = function(){\n    return (this._i < this._parts.length);\n};\n\n/**\n * Marks the current spot in the iteration so it can be restored to\n * later on.\n * @return {void}\n * @method mark\n */\nPropertyValueIterator.prototype.mark = function(){\n    this._marks.push(this._i);\n};\n\n/**\n * Returns the next part of the property value or null if there is no next\n * part. Does not move the internal counter forward.\n * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next\n * part.\n * @method peek\n */\nPropertyValueIterator.prototype.peek = function(count){\n    return this.hasNext() ? this._parts[this._i + (count || 0)] : null;\n};\n\n/**\n * Returns the next part of the property value or null if there is no next\n * part.\n * @return {parserlib.css.PropertyValuePart} The next part of the property value or null if there is no next\n * part.\n * @method next\n */\nPropertyValueIterator.prototype.next = function(){\n    return this.hasNext() ? this._parts[this._i++] : null;\n};\n\n/**\n * Returns the previous part of the property value or null if there is no\n * previous part.\n * @return {parserlib.css.PropertyValuePart} The previous part of the\n * property value or null if there is no next part.\n * @method previous\n */\nPropertyValueIterator.prototype.previous = function(){\n    return this._i > 0 ? this._parts[--this._i] : null;\n};\n\n/**\n * Restores the last saved bookmark.\n * @return {void}\n * @method restore\n */\nPropertyValueIterator.prototype.restore = function(){\n    if (this._marks.length){\n        this._i = this._marks.pop();\n    }\n};\n\n/*global SyntaxUnit, Parser, Colors*/\n/**\n * Represents a single part of a CSS property value, meaning that it represents\n * just one part of the data between \":\" and \";\".\n * @param {String} text The text representation of the unit.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n * @namespace parserlib.css\n * @class PropertyValuePart\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n */\nfunction PropertyValuePart(text, line, col){\n\n    SyntaxUnit.call(this, text, line, col, Parser.PROPERTY_VALUE_PART_TYPE);\n\n    /**\n     * Indicates the type of value unit.\n     * @type String\n     * @property type\n     */\n    this.type = \"unknown\";\n\n    //figure out what type of data it is\n\n    var temp;\n\n    //it is a measurement?\n    if (/^([+\\-]?[\\d\\.]+)([a-z]+)$/i.test(text)){  //dimension\n        this.type = \"dimension\";\n        this.value = +RegExp.$1;\n        this.units = RegExp.$2;\n\n        //try to narrow down\n        switch(this.units.toLowerCase()){\n\n            case \"em\":\n            case \"rem\":\n            case \"ex\":\n            case \"px\":\n            case \"cm\":\n            case \"mm\":\n            case \"in\":\n            case \"pt\":\n            case \"pc\":\n            case \"ch\":\n            case \"vh\":\n            case \"vw\":\n            case \"vmax\":\n            case \"vmin\":\n                this.type = \"length\";\n                break;\n\n            case \"deg\":\n            case \"rad\":\n            case \"grad\":\n                this.type = \"angle\";\n                break;\n\n            case \"ms\":\n            case \"s\":\n                this.type = \"time\";\n                break;\n\n            case \"hz\":\n            case \"khz\":\n                this.type = \"frequency\";\n                break;\n\n            case \"dpi\":\n            case \"dpcm\":\n                this.type = \"resolution\";\n                break;\n\n            //default\n\n        }\n\n    } else if (/^([+\\-]?[\\d\\.]+)%$/i.test(text)){  //percentage\n        this.type = \"percentage\";\n        this.value = +RegExp.$1;\n    } else if (/^([+\\-]?\\d+)$/i.test(text)){  //integer\n        this.type = \"integer\";\n        this.value = +RegExp.$1;\n    } else if (/^([+\\-]?[\\d\\.]+)$/i.test(text)){  //number\n        this.type = \"number\";\n        this.value = +RegExp.$1;\n\n    } else if (/^#([a-f0-9]{3,6})/i.test(text)){  //hexcolor\n        this.type = \"color\";\n        temp = RegExp.$1;\n        if (temp.length == 3){\n            this.red    = parseInt(temp.charAt(0)+temp.charAt(0),16);\n            this.green  = parseInt(temp.charAt(1)+temp.charAt(1),16);\n            this.blue   = parseInt(temp.charAt(2)+temp.charAt(2),16);\n        } else {\n            this.red    = parseInt(temp.substring(0,2),16);\n            this.green  = parseInt(temp.substring(2,4),16);\n            this.blue   = parseInt(temp.substring(4,6),16);\n        }\n    } else if (/^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)/i.test(text)){ //rgb() color with absolute numbers\n        this.type   = \"color\";\n        this.red    = +RegExp.$1;\n        this.green  = +RegExp.$2;\n        this.blue   = +RegExp.$3;\n    } else if (/^rgb\\(\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*\\)/i.test(text)){ //rgb() color with percentages\n        this.type   = \"color\";\n        this.red    = +RegExp.$1 * 255 / 100;\n        this.green  = +RegExp.$2 * 255 / 100;\n        this.blue   = +RegExp.$3 * 255 / 100;\n    } else if (/^rgba\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //rgba() color with absolute numbers\n        this.type   = \"color\";\n        this.red    = +RegExp.$1;\n        this.green  = +RegExp.$2;\n        this.blue   = +RegExp.$3;\n        this.alpha  = +RegExp.$4;\n    } else if (/^rgba\\(\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //rgba() color with percentages\n        this.type   = \"color\";\n        this.red    = +RegExp.$1 * 255 / 100;\n        this.green  = +RegExp.$2 * 255 / 100;\n        this.blue   = +RegExp.$3 * 255 / 100;\n        this.alpha  = +RegExp.$4;\n    } else if (/^hsl\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*\\)/i.test(text)){ //hsl()\n        this.type   = \"color\";\n        this.hue    = +RegExp.$1;\n        this.saturation = +RegExp.$2 / 100;\n        this.lightness  = +RegExp.$3 / 100;\n    } else if (/^hsla\\(\\s*(\\d+)\\s*,\\s*(\\d+)%\\s*,\\s*(\\d+)%\\s*,\\s*([\\d\\.]+)\\s*\\)/i.test(text)){ //hsla() color with percentages\n        this.type   = \"color\";\n        this.hue    = +RegExp.$1;\n        this.saturation = +RegExp.$2 / 100;\n        this.lightness  = +RegExp.$3 / 100;\n        this.alpha  = +RegExp.$4;\n    } else if (/^url\\([\"']?([^\\)\"']+)[\"']?\\)/i.test(text)){ //URI\n        this.type   = \"uri\";\n        this.uri    = RegExp.$1;\n    } else if (/^([^\\(]+)\\(/i.test(text)){\n        this.type   = \"function\";\n        this.name   = RegExp.$1;\n        this.value  = text;\n    } else if (/^[\"'][^\"']*[\"']/.test(text)){    //string\n        this.type   = \"string\";\n        this.value  = eval(text);\n    } else if (Colors[text.toLowerCase()]){  //named color\n        this.type   = \"color\";\n        temp        = Colors[text.toLowerCase()].substring(1);\n        this.red    = parseInt(temp.substring(0,2),16);\n        this.green  = parseInt(temp.substring(2,4),16);\n        this.blue   = parseInt(temp.substring(4,6),16);\n    } else if (/^[\\,\\/]$/.test(text)){\n        this.type   = \"operator\";\n        this.value  = text;\n    } else if (/^[a-z\\-_\\u0080-\\uFFFF][a-z0-9\\-_\\u0080-\\uFFFF]*$/i.test(text)){\n        this.type   = \"identifier\";\n        this.value  = text;\n    }\n\n}\n\nPropertyValuePart.prototype = new SyntaxUnit();\nPropertyValuePart.prototype.constructor = PropertyValuePart;\n\n/**\n * Create a new syntax unit based solely on the given token.\n * Convenience method for creating a new syntax unit when\n * it represents a single token instead of multiple.\n * @param {Object} token The token object to represent.\n * @return {parserlib.css.PropertyValuePart} The object representing the token.\n * @static\n * @method fromToken\n */\nPropertyValuePart.fromToken = function(token){\n    return new PropertyValuePart(token.value, token.startLine, token.startCol);\n};\nvar Pseudos = {\n    \":first-letter\": 1,\n    \":first-line\":   1,\n    \":before\":       1,\n    \":after\":        1\n};\n\nPseudos.ELEMENT = 1;\nPseudos.CLASS = 2;\n\nPseudos.isElement = function(pseudo){\n    return pseudo.indexOf(\"::\") === 0 || Pseudos[pseudo.toLowerCase()] == Pseudos.ELEMENT;\n};\n/*global SyntaxUnit, Parser, Specificity*/\n/**\n * Represents an entire single selector, including all parts but not\n * including multiple selectors (those separated by commas).\n * @namespace parserlib.css\n * @class Selector\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {Array} parts Array of selectors parts making up this selector.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction Selector(parts, line, col){\n\n    SyntaxUnit.call(this, parts.join(\" \"), line, col, Parser.SELECTOR_TYPE);\n\n    /**\n     * The parts that make up the selector.\n     * @type Array\n     * @property parts\n     */\n    this.parts = parts;\n\n    /**\n     * The specificity of the selector.\n     * @type parserlib.css.Specificity\n     * @property specificity\n     */\n    this.specificity = Specificity.calculate(this);\n\n}\n\nSelector.prototype = new SyntaxUnit();\nSelector.prototype.constructor = Selector;\n\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a single part of a selector string, meaning a single set of\n * element name and modifiers. This does not include combinators such as\n * spaces, +, >, etc.\n * @namespace parserlib.css\n * @class SelectorPart\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {String} elementName The element name in the selector or null\n *      if there is no element name.\n * @param {Array} modifiers Array of individual modifiers for the element.\n *      May be empty if there are none.\n * @param {String} text The text representation of the unit.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction SelectorPart(elementName, modifiers, text, line, col){\n\n    SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_PART_TYPE);\n\n    /**\n     * The tag name of the element to which this part\n     * of the selector affects.\n     * @type String\n     * @property elementName\n     */\n    this.elementName = elementName;\n\n    /**\n     * The parts that come after the element name, such as class names, IDs,\n     * pseudo classes/elements, etc.\n     * @type Array\n     * @property modifiers\n     */\n    this.modifiers = modifiers;\n\n}\n\nSelectorPart.prototype = new SyntaxUnit();\nSelectorPart.prototype.constructor = SelectorPart;\n\n/*global SyntaxUnit, Parser*/\n/**\n * Represents a selector modifier string, meaning a class name, element name,\n * element ID, pseudo rule, etc.\n * @namespace parserlib.css\n * @class SelectorSubPart\n * @extends parserlib.util.SyntaxUnit\n * @constructor\n * @param {String} text The text representation of the unit.\n * @param {String} type The type of selector modifier.\n * @param {int} line The line of text on which the unit resides.\n * @param {int} col The column of text on which the unit resides.\n */\nfunction SelectorSubPart(text, type, line, col){\n\n    SyntaxUnit.call(this, text, line, col, Parser.SELECTOR_SUB_PART_TYPE);\n\n    /**\n     * The type of modifier.\n     * @type String\n     * @property type\n     */\n    this.type = type;\n\n    /**\n     * Some subparts have arguments, this represents them.\n     * @type Array\n     * @property args\n     */\n    this.args = [];\n\n}\n\nSelectorSubPart.prototype = new SyntaxUnit();\nSelectorSubPart.prototype.constructor = SelectorSubPart;\n\n/*global Pseudos, SelectorPart*/\n/**\n * Represents a selector's specificity.\n * @namespace parserlib.css\n * @class Specificity\n * @constructor\n * @param {int} a Should be 1 for inline styles, zero for stylesheet styles\n * @param {int} b Number of ID selectors\n * @param {int} c Number of classes and pseudo classes\n * @param {int} d Number of element names and pseudo elements\n */\nfunction Specificity(a, b, c, d){\n    this.a = a;\n    this.b = b;\n    this.c = c;\n    this.d = d;\n}\n\nSpecificity.prototype = {\n    constructor: Specificity,\n\n    /**\n     * Compare this specificity to another.\n     * @param {Specificity} other The other specificity to compare to.\n     * @return {int} -1 if the other specificity is larger, 1 if smaller, 0 if equal.\n     * @method compare\n     */\n    compare: function(other){\n        var comps = [\"a\", \"b\", \"c\", \"d\"],\n            i, len;\n\n        for (i=0, len=comps.length; i < len; i++){\n            if (this[comps[i]] < other[comps[i]]){\n                return -1;\n            } else if (this[comps[i]] > other[comps[i]]){\n                return 1;\n            }\n        }\n\n        return 0;\n    },\n\n    /**\n     * Creates a numeric value for the specificity.\n     * @return {int} The numeric value for the specificity.\n     * @method valueOf\n     */\n    valueOf: function(){\n        return (this.a * 1000) + (this.b * 100) + (this.c * 10) + this.d;\n    },\n\n    /**\n     * Returns a string representation for specificity.\n     * @return {String} The string representation of specificity.\n     * @method toString\n     */\n    toString: function(){\n        return this.a + \",\" + this.b + \",\" + this.c + \",\" + this.d;\n    }\n\n};\n\n/**\n * Calculates the specificity of the given selector.\n * @param {parserlib.css.Selector} The selector to calculate specificity for.\n * @return {parserlib.css.Specificity} The specificity of the selector.\n * @static\n * @method calculate\n */\nSpecificity.calculate = function(selector){\n\n    var i, len,\n        part,\n        b=0, c=0, d=0;\n\n    function updateValues(part){\n\n        var i, j, len, num,\n            elementName = part.elementName ? part.elementName.text : \"\",\n            modifier;\n\n        if (elementName && elementName.charAt(elementName.length-1) != \"*\") {\n            d++;\n        }\n\n        for (i=0, len=part.modifiers.length; i < len; i++){\n            modifier = part.modifiers[i];\n            switch(modifier.type){\n                case \"class\":\n                case \"attribute\":\n                    c++;\n                    break;\n\n                case \"id\":\n                    b++;\n                    break;\n\n                case \"pseudo\":\n                    if (Pseudos.isElement(modifier.text)){\n                        d++;\n                    } else {\n                        c++;\n                    }\n                    break;\n\n                case \"not\":\n                    for (j=0, num=modifier.args.length; j < num; j++){\n                        updateValues(modifier.args[j]);\n                    }\n            }\n         }\n    }\n\n    for (i=0, len=selector.parts.length; i < len; i++){\n        part = selector.parts[i];\n\n        if (part instanceof SelectorPart){\n            updateValues(part);\n        }\n    }\n\n    return new Specificity(0, b, c, d);\n};\n/*global Tokens, TokenStreamBase*/\n\nvar h = /^[0-9a-fA-F]$/,\n    nonascii = /^[\\u0080-\\uFFFF]$/,\n    nl = /\\n|\\r\\n|\\r|\\f/;\n\n//-----------------------------------------------------------------------------\n// Helper functions\n//-----------------------------------------------------------------------------\n\n\nfunction isHexDigit(c){\n    return c !== null && h.test(c);\n}\n\nfunction isDigit(c){\n    return c !== null && /\\d/.test(c);\n}\n\nfunction isWhitespace(c){\n    return c !== null && /\\s/.test(c);\n}\n\nfunction isNewLine(c){\n    return c !== null && nl.test(c);\n}\n\nfunction isNameStart(c){\n    return c !== null && (/[a-z_\\u0080-\\uFFFF\\\\]/i.test(c));\n}\n\nfunction isNameChar(c){\n    return c !== null && (isNameStart(c) || /[0-9\\-\\\\]/.test(c));\n}\n\nfunction isIdentStart(c){\n    return c !== null && (isNameStart(c) || /\\-\\\\/.test(c));\n}\n\nfunction mix(receiver, supplier){\n\tfor (var prop in supplier){\n\t\tif (supplier.hasOwnProperty(prop)){\n\t\t\treceiver[prop] = supplier[prop];\n\t\t}\n\t}\n\treturn receiver;\n}\n\n//-----------------------------------------------------------------------------\n// CSS Token Stream\n//-----------------------------------------------------------------------------\n\n\n/**\n * A token stream that produces CSS tokens.\n * @param {String|Reader} input The source of text to tokenize.\n * @constructor\n * @class TokenStream\n * @namespace parserlib.css\n */\nfunction TokenStream(input){\n\tTokenStreamBase.call(this, input, Tokens);\n}\n\nTokenStream.prototype = mix(new TokenStreamBase(), {\n\n    /**\n     * Overrides the TokenStreamBase method of the same name\n     * to produce CSS tokens.\n     * @param {variant} channel The name of the channel to use\n     *      for the next token.\n     * @return {Object} A token object representing the next token.\n     * @method _getToken\n     * @private\n     */\n    _getToken: function(channel){\n\n        var c,\n            reader = this._reader,\n            token   = null,\n            startLine   = reader.getLine(),\n            startCol    = reader.getCol();\n\n        c = reader.read();\n\n\n        while(c){\n            switch(c){\n\n                /*\n                 * Potential tokens:\n                 * - COMMENT\n                 * - SLASH\n                 * - CHAR\n                 */\n                case \"/\":\n\n                    if(reader.peek() == \"*\"){\n                        token = this.commentToken(c, startLine, startCol);\n                    } else {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - DASHMATCH\n                 * - INCLUDES\n                 * - PREFIXMATCH\n                 * - SUFFIXMATCH\n                 * - SUBSTRINGMATCH\n                 * - CHAR\n                 */\n                case \"|\":\n                case \"~\":\n                case \"^\":\n                case \"$\":\n                case \"*\":\n                    if(reader.peek() == \"=\"){\n                        token = this.comparisonToken(c, startLine, startCol);\n                    } else {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - STRING\n                 * - INVALID\n                 */\n                case \"\\\"\":\n                case \"'\":\n                    token = this.stringToken(c, startLine, startCol);\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - HASH\n                 * - CHAR\n                 */\n                case \"#\":\n                    if (isNameChar(reader.peek())){\n                        token = this.hashToken(c, startLine, startCol);\n                    } else {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - DOT\n                 * - NUMBER\n                 * - DIMENSION\n                 * - PERCENTAGE\n                 */\n                case \".\":\n                    if (isDigit(reader.peek())){\n                        token = this.numberToken(c, startLine, startCol);\n                    } else {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - CDC\n                 * - MINUS\n                 * - NUMBER\n                 * - DIMENSION\n                 * - PERCENTAGE\n                 */\n                case \"-\":\n                    if (reader.peek() == \"-\"){  //could be closing HTML-style comment\n                        token = this.htmlCommentEndToken(c, startLine, startCol);\n                    } else if (isNameStart(reader.peek())){\n                        token = this.identOrFunctionToken(c, startLine, startCol);\n                    } else {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - IMPORTANT_SYM\n                 * - CHAR\n                 */\n                case \"!\":\n                    token = this.importantToken(c, startLine, startCol);\n                    break;\n\n                /*\n                 * Any at-keyword or CHAR\n                 */\n                case \"@\":\n                    token = this.atRuleToken(c, startLine, startCol);\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - NOT\n                 * - CHAR\n                 */\n                case \":\":\n                    token = this.notToken(c, startLine, startCol);\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - CDO\n                 * - CHAR\n                 */\n                case \"<\":\n                    token = this.htmlCommentStartToken(c, startLine, startCol);\n                    break;\n\n                /*\n                 * Potential tokens:\n                 * - UNICODE_RANGE\n                 * - URL\n                 * - CHAR\n                 */\n                case \"U\":\n                case \"u\":\n                    if (reader.peek() == \"+\"){\n                        token = this.unicodeRangeToken(c, startLine, startCol);\n                        break;\n                    }\n                    /* falls through */\n                default:\n\n                    /*\n                     * Potential tokens:\n                     * - NUMBER\n                     * - DIMENSION\n                     * - LENGTH\n                     * - FREQ\n                     * - TIME\n                     * - EMS\n                     * - EXS\n                     * - ANGLE\n                     */\n                    if (isDigit(c)){\n                        token = this.numberToken(c, startLine, startCol);\n                    } else\n\n                    /*\n                     * Potential tokens:\n                     * - S\n                     */\n                    if (isWhitespace(c)){\n                        token = this.whitespaceToken(c, startLine, startCol);\n                    } else\n\n                    /*\n                     * Potential tokens:\n                     * - IDENT\n                     */\n                    if (isIdentStart(c)){\n                        token = this.identOrFunctionToken(c, startLine, startCol);\n                    } else\n\n                    /*\n                     * Potential tokens:\n                     * - CHAR\n                     * - PLUS\n                     */\n                    {\n                        token = this.charToken(c, startLine, startCol);\n                    }\n\n\n\n\n\n\n            }\n\n            //make sure this token is wanted\n            //TODO: check channel\n            break;\n        }\n\n        if (!token && c === null){\n            token = this.createToken(Tokens.EOF,null,startLine,startCol);\n        }\n\n        return token;\n    },\n\n    //-------------------------------------------------------------------------\n    // Methods to create tokens\n    //-------------------------------------------------------------------------\n\n    /**\n     * Produces a token based on available data and the current\n     * reader position information. This method is called by other\n     * private methods to create tokens and is never called directly.\n     * @param {int} tt The token type.\n     * @param {String} value The text value of the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @param {Object} options (Optional) Specifies a channel property\n     *      to indicate that a different channel should be scanned\n     *      and/or a hide property indicating that the token should\n     *      be hidden.\n     * @return {Object} A token object.\n     * @method createToken\n     */\n    createToken: function(tt, value, startLine, startCol, options){\n        var reader = this._reader;\n        options = options || {};\n\n        return {\n            value:      value,\n            type:       tt,\n            channel:    options.channel,\n            endChar:    options.endChar,\n            hide:       options.hide || false,\n            startLine:  startLine,\n            startCol:   startCol,\n            endLine:    reader.getLine(),\n            endCol:     reader.getCol()\n        };\n    },\n\n    //-------------------------------------------------------------------------\n    // Methods to create specific tokens\n    //-------------------------------------------------------------------------\n\n    /**\n     * Produces a token for any at-rule. If the at-rule is unknown, then\n     * the token is for a single \"@\" character.\n     * @param {String} first The first character for the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method atRuleToken\n     */\n    atRuleToken: function(first, startLine, startCol){\n        var rule    = first,\n            reader  = this._reader,\n            tt      = Tokens.CHAR,\n            valid   = false,\n            ident,\n            c;\n\n        /*\n         * First, mark where we are. There are only four @ rules,\n         * so anything else is really just an invalid token.\n         * Basically, if this doesn't match one of the known @\n         * rules, just return '@' as an unknown token and allow\n         * parsing to continue after that point.\n         */\n        reader.mark();\n\n        //try to find the at-keyword\n        ident = this.readName();\n        rule = first + ident;\n        tt = Tokens.type(rule.toLowerCase());\n\n        //if it's not valid, use the first character only and reset the reader\n        if (tt == Tokens.CHAR || tt == Tokens.UNKNOWN){\n            if (rule.length > 1){\n                tt = Tokens.UNKNOWN_SYM;\n            } else {\n                tt = Tokens.CHAR;\n                rule = first;\n                reader.reset();\n            }\n        }\n\n        return this.createToken(tt, rule, startLine, startCol);\n    },\n\n    /**\n     * Produces a character token based on the given character\n     * and location in the stream. If there's a special (non-standard)\n     * token name, this is used; otherwise CHAR is used.\n     * @param {String} c The character for the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method charToken\n     */\n    charToken: function(c, startLine, startCol){\n        var tt = Tokens.type(c);\n        var opts = {};\n\n        if (tt == -1){\n            tt = Tokens.CHAR;\n        } else {\n            opts.endChar = Tokens[tt].endChar;\n        }\n\n        return this.createToken(tt, c, startLine, startCol, opts);\n    },\n\n    /**\n     * Produces a character token based on the given character\n     * and location in the stream. If there's a special (non-standard)\n     * token name, this is used; otherwise CHAR is used.\n     * @param {String} first The first character for the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method commentToken\n     */\n    commentToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            comment = this.readComment(first);\n\n        return this.createToken(Tokens.COMMENT, comment, startLine, startCol);\n    },\n\n    /**\n     * Produces a comparison token based on the given character\n     * and location in the stream. The next character must be\n     * read and is already known to be an equals sign.\n     * @param {String} c The character for the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method comparisonToken\n     */\n    comparisonToken: function(c, startLine, startCol){\n        var reader  = this._reader,\n            comparison  = c + reader.read(),\n            tt      = Tokens.type(comparison) || Tokens.CHAR;\n\n        return this.createToken(tt, comparison, startLine, startCol);\n    },\n\n    /**\n     * Produces a hash token based on the specified information. The\n     * first character provided is the pound sign (#) and then this\n     * method reads a name afterward.\n     * @param {String} first The first character (#) in the hash name.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method hashToken\n     */\n    hashToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            name    = this.readName(first);\n\n        return this.createToken(Tokens.HASH, name, startLine, startCol);\n    },\n\n    /**\n     * Produces a CDO or CHAR token based on the specified information. The\n     * first character is provided and the rest is read by the function to determine\n     * the correct token to create.\n     * @param {String} first The first character in the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method htmlCommentStartToken\n     */\n    htmlCommentStartToken: function(first, startLine, startCol){\n        var reader      = this._reader,\n            text        = first;\n\n        reader.mark();\n        text += reader.readCount(3);\n\n        if (text == \"<!--\"){\n            return this.createToken(Tokens.CDO, text, startLine, startCol);\n        } else {\n            reader.reset();\n            return this.charToken(first, startLine, startCol);\n        }\n    },\n\n    /**\n     * Produces a CDC or CHAR token based on the specified information. The\n     * first character is provided and the rest is read by the function to determine\n     * the correct token to create.\n     * @param {String} first The first character in the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method htmlCommentEndToken\n     */\n    htmlCommentEndToken: function(first, startLine, startCol){\n        var reader      = this._reader,\n            text        = first;\n\n        reader.mark();\n        text += reader.readCount(2);\n\n        if (text == \"-->\"){\n            return this.createToken(Tokens.CDC, text, startLine, startCol);\n        } else {\n            reader.reset();\n            return this.charToken(first, startLine, startCol);\n        }\n    },\n\n    /**\n     * Produces an IDENT or FUNCTION token based on the specified information. The\n     * first character is provided and the rest is read by the function to determine\n     * the correct token to create.\n     * @param {String} first The first character in the identifier.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method identOrFunctionToken\n     */\n    identOrFunctionToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            ident   = this.readName(first),\n            tt      = Tokens.IDENT;\n\n        //if there's a left paren immediately after, it's a URI or function\n        if (reader.peek() == \"(\"){\n            ident += reader.read();\n            if (ident.toLowerCase() == \"url(\"){\n                tt = Tokens.URI;\n                ident = this.readURI(ident);\n\n                //didn't find a valid URL or there's no closing paren\n                if (ident.toLowerCase() == \"url(\"){\n                    tt = Tokens.FUNCTION;\n                }\n            } else {\n                tt = Tokens.FUNCTION;\n            }\n        } else if (reader.peek() == \":\"){  //might be an IE function\n\n            //IE-specific functions always being with progid:\n            if (ident.toLowerCase() == \"progid\"){\n                ident += reader.readTo(\"(\");\n                tt = Tokens.IE_FUNCTION;\n            }\n        }\n\n        return this.createToken(tt, ident, startLine, startCol);\n    },\n\n    /**\n     * Produces an IMPORTANT_SYM or CHAR token based on the specified information. The\n     * first character is provided and the rest is read by the function to determine\n     * the correct token to create.\n     * @param {String} first The first character in the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method importantToken\n     */\n    importantToken: function(first, startLine, startCol){\n        var reader      = this._reader,\n            important   = first,\n            tt          = Tokens.CHAR,\n            temp,\n            c;\n\n        reader.mark();\n        c = reader.read();\n\n        while(c){\n\n            //there can be a comment in here\n            if (c == \"/\"){\n\n                //if the next character isn't a star, then this isn't a valid !important token\n                if (reader.peek() != \"*\"){\n                    break;\n                } else {\n                    temp = this.readComment(c);\n                    if (temp === \"\"){    //broken!\n                        break;\n                    }\n                }\n            } else if (isWhitespace(c)){\n                important += c + this.readWhitespace();\n            } else if (/i/i.test(c)){\n                temp = reader.readCount(8);\n                if (/mportant/i.test(temp)){\n                    important += c + temp;\n                    tt = Tokens.IMPORTANT_SYM;\n\n                }\n                break;  //we're done\n            } else {\n                break;\n            }\n\n            c = reader.read();\n        }\n\n        if (tt == Tokens.CHAR){\n            reader.reset();\n            return this.charToken(first, startLine, startCol);\n        } else {\n            return this.createToken(tt, important, startLine, startCol);\n        }\n\n\n    },\n\n    /**\n     * Produces a NOT or CHAR token based on the specified information. The\n     * first character is provided and the rest is read by the function to determine\n     * the correct token to create.\n     * @param {String} first The first character in the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method notToken\n     */\n    notToken: function(first, startLine, startCol){\n        var reader      = this._reader,\n            text        = first;\n\n        reader.mark();\n        text += reader.readCount(4);\n\n        if (text.toLowerCase() == \":not(\"){\n            return this.createToken(Tokens.NOT, text, startLine, startCol);\n        } else {\n            reader.reset();\n            return this.charToken(first, startLine, startCol);\n        }\n    },\n\n    /**\n     * Produces a number token based on the given character\n     * and location in the stream. This may return a token of\n     * NUMBER, EMS, EXS, LENGTH, ANGLE, TIME, FREQ, DIMENSION,\n     * or PERCENTAGE.\n     * @param {String} first The first character for the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method numberToken\n     */\n    numberToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            value   = this.readNumber(first),\n            ident,\n            tt      = Tokens.NUMBER,\n            c       = reader.peek();\n\n        if (isIdentStart(c)){\n            ident = this.readName(reader.read());\n            value += ident;\n\n            if (/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(ident)){\n                tt = Tokens.LENGTH;\n            } else if (/^deg|^rad$|^grad$/i.test(ident)){\n                tt = Tokens.ANGLE;\n            } else if (/^ms$|^s$/i.test(ident)){\n                tt = Tokens.TIME;\n            } else if (/^hz$|^khz$/i.test(ident)){\n                tt = Tokens.FREQ;\n            } else if (/^dpi$|^dpcm$/i.test(ident)){\n                tt = Tokens.RESOLUTION;\n            } else {\n                tt = Tokens.DIMENSION;\n            }\n\n        } else if (c == \"%\"){\n            value += reader.read();\n            tt = Tokens.PERCENTAGE;\n        }\n\n        return this.createToken(tt, value, startLine, startCol);\n    },\n\n    /**\n     * Produces a string token based on the given character\n     * and location in the stream. Since strings may be indicated\n     * by single or double quotes, a failure to match starting\n     * and ending quotes results in an INVALID token being generated.\n     * The first character in the string is passed in and then\n     * the rest are read up to and including the final quotation mark.\n     * @param {String} first The first character in the string.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method stringToken\n     */\n    stringToken: function(first, startLine, startCol){\n        var delim   = first,\n            string  = first,\n            reader  = this._reader,\n            prev    = first,\n            tt      = Tokens.STRING,\n            c       = reader.read();\n\n        while(c){\n            string += c;\n\n            //if the delimiter is found with an escapement, we're done.\n            if (c == delim && prev != \"\\\\\"){\n                break;\n            }\n\n            //if there's a newline without an escapement, it's an invalid string\n            if (isNewLine(reader.peek()) && c != \"\\\\\"){\n                tt = Tokens.INVALID;\n                break;\n            }\n\n            //save previous and get next\n            prev = c;\n            c = reader.read();\n        }\n\n        //if c is null, that means we're out of input and the string was never closed\n        if (c === null){\n            tt = Tokens.INVALID;\n        }\n\n        return this.createToken(tt, string, startLine, startCol);\n    },\n\n    unicodeRangeToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            value   = first,\n            temp,\n            tt      = Tokens.CHAR;\n\n        //then it should be a unicode range\n        if (reader.peek() == \"+\"){\n            reader.mark();\n            value += reader.read();\n            value += this.readUnicodeRangePart(true);\n\n            //ensure there's an actual unicode range here\n            if (value.length == 2){\n                reader.reset();\n            } else {\n\n                tt = Tokens.UNICODE_RANGE;\n\n                //if there's a ? in the first part, there can't be a second part\n                if (value.indexOf(\"?\") == -1){\n\n                    if (reader.peek() == \"-\"){\n                        reader.mark();\n                        temp = reader.read();\n                        temp += this.readUnicodeRangePart(false);\n\n                        //if there's not another value, back up and just take the first\n                        if (temp.length == 1){\n                            reader.reset();\n                        } else {\n                            value += temp;\n                        }\n                    }\n\n                }\n            }\n        }\n\n        return this.createToken(tt, value, startLine, startCol);\n    },\n\n    /**\n     * Produces a S token based on the specified information. Since whitespace\n     * may have multiple characters, this consumes all whitespace characters\n     * into a single token.\n     * @param {String} first The first character in the token.\n     * @param {int} startLine The beginning line for the character.\n     * @param {int} startCol The beginning column for the character.\n     * @return {Object} A token object.\n     * @method whitespaceToken\n     */\n    whitespaceToken: function(first, startLine, startCol){\n        var reader  = this._reader,\n            value   = first + this.readWhitespace();\n        return this.createToken(Tokens.S, value, startLine, startCol);\n    },\n\n\n\n\n    //-------------------------------------------------------------------------\n    // Methods to read values from the string stream\n    //-------------------------------------------------------------------------\n\n    readUnicodeRangePart: function(allowQuestionMark){\n        var reader  = this._reader,\n            part = \"\",\n            c       = reader.peek();\n\n        //first read hex digits\n        while(isHexDigit(c) && part.length < 6){\n            reader.read();\n            part += c;\n            c = reader.peek();\n        }\n\n        //then read question marks if allowed\n        if (allowQuestionMark){\n            while(c == \"?\" && part.length < 6){\n                reader.read();\n                part += c;\n                c = reader.peek();\n            }\n        }\n\n        //there can't be any other characters after this point\n\n        return part;\n    },\n\n    readWhitespace: function(){\n        var reader  = this._reader,\n            whitespace = \"\",\n            c       = reader.peek();\n\n        while(isWhitespace(c)){\n            reader.read();\n            whitespace += c;\n            c = reader.peek();\n        }\n\n        return whitespace;\n    },\n    readNumber: function(first){\n        var reader  = this._reader,\n            number  = first,\n            hasDot  = (first == \".\"),\n            c       = reader.peek();\n\n\n        while(c){\n            if (isDigit(c)){\n                number += reader.read();\n            } else if (c == \".\"){\n                if (hasDot){\n                    break;\n                } else {\n                    hasDot = true;\n                    number += reader.read();\n                }\n            } else {\n                break;\n            }\n\n            c = reader.peek();\n        }\n\n        return number;\n    },\n    readString: function(){\n        var reader  = this._reader,\n            delim   = reader.read(),\n            string  = delim,\n            prev    = delim,\n            c       = reader.peek();\n\n        while(c){\n            c = reader.read();\n            string += c;\n\n            //if the delimiter is found with an escapement, we're done.\n            if (c == delim && prev != \"\\\\\"){\n                break;\n            }\n\n            //if there's a newline without an escapement, it's an invalid string\n            if (isNewLine(reader.peek()) && c != \"\\\\\"){\n                string = \"\";\n                break;\n            }\n\n            //save previous and get next\n            prev = c;\n            c = reader.peek();\n        }\n\n        //if c is null, that means we're out of input and the string was never closed\n        if (c === null){\n            string = \"\";\n        }\n\n        return string;\n    },\n    readURI: function(first){\n        var reader  = this._reader,\n            uri     = first,\n            inner   = \"\",\n            c       = reader.peek();\n\n        reader.mark();\n\n        //skip whitespace before\n        while(c && isWhitespace(c)){\n            reader.read();\n            c = reader.peek();\n        }\n\n        //it's a string\n        if (c == \"'\" || c == \"\\\"\"){\n            inner = this.readString();\n        } else {\n            inner = this.readURL();\n        }\n\n        c = reader.peek();\n\n        //skip whitespace after\n        while(c && isWhitespace(c)){\n            reader.read();\n            c = reader.peek();\n        }\n\n        //if there was no inner value or the next character isn't closing paren, it's not a URI\n        if (inner === \"\" || c != \")\"){\n            uri = first;\n            reader.reset();\n        } else {\n            uri += inner + reader.read();\n        }\n\n        return uri;\n    },\n    readURL: function(){\n        var reader  = this._reader,\n            url     = \"\",\n            c       = reader.peek();\n\n        //TODO: Check for escape and nonascii\n        while (/^[!#$%&\\\\*-~]$/.test(c)){\n            url += reader.read();\n            c = reader.peek();\n        }\n\n        return url;\n\n    },\n    readName: function(first){\n        var reader  = this._reader,\n            ident   = first || \"\",\n            c       = reader.peek();\n\n        while(true){\n            if (c == \"\\\\\"){\n                ident += this.readEscape(reader.read());\n                c = reader.peek();\n            } else if(c && isNameChar(c)){\n                ident += reader.read();\n                c = reader.peek();\n            } else {\n                break;\n            }\n        }\n\n        return ident;\n    },\n\n    readEscape: function(first){\n        var reader  = this._reader,\n            cssEscape = first || \"\",\n            i       = 0,\n            c       = reader.peek();\n\n        if (isHexDigit(c)){\n            do {\n                cssEscape += reader.read();\n                c = reader.peek();\n            } while(c && isHexDigit(c) && ++i < 6);\n        }\n\n        if (cssEscape.length == 3 && /\\s/.test(c) ||\n            cssEscape.length == 7 || cssEscape.length == 1){\n                reader.read();\n        } else {\n            c = \"\";\n        }\n\n        return cssEscape + c;\n    },\n\n    readComment: function(first){\n        var reader  = this._reader,\n            comment = first || \"\",\n            c       = reader.read();\n\n        if (c == \"*\"){\n            while(c){\n                comment += c;\n\n                //look for end of comment\n                if (comment.length > 2 && c == \"*\" && reader.peek() == \"/\"){\n                    comment += reader.read();\n                    break;\n                }\n\n                c = reader.read();\n            }\n\n            return comment;\n        } else {\n            return \"\";\n        }\n\n    }\n});\n\nvar Tokens  = [\n\n    /*\n     * The following token names are defined in CSS3 Grammar: http://www.w3.org/TR/css3-syntax/#lexical\n     */\n\n    //HTML-style comments\n    { name: \"CDO\"},\n    { name: \"CDC\"},\n\n    //ignorables\n    { name: \"S\", whitespace: true/*, channel: \"ws\"*/},\n    { name: \"COMMENT\", comment: true, hide: true, channel: \"comment\" },\n\n    //attribute equality\n    { name: \"INCLUDES\", text: \"~=\"},\n    { name: \"DASHMATCH\", text: \"|=\"},\n    { name: \"PREFIXMATCH\", text: \"^=\"},\n    { name: \"SUFFIXMATCH\", text: \"$=\"},\n    { name: \"SUBSTRINGMATCH\", text: \"*=\"},\n\n    //identifier types\n    { name: \"STRING\"},\n    { name: \"IDENT\"},\n    { name: \"HASH\"},\n\n    //at-keywords\n    { name: \"IMPORT_SYM\", text: \"@import\"},\n    { name: \"PAGE_SYM\", text: \"@page\"},\n    { name: \"MEDIA_SYM\", text: \"@media\"},\n    { name: \"FONT_FACE_SYM\", text: \"@font-face\"},\n    { name: \"CHARSET_SYM\", text: \"@charset\"},\n    { name: \"NAMESPACE_SYM\", text: \"@namespace\"},\n    { name: \"VIEWPORT_SYM\", text: [\"@viewport\", \"@-ms-viewport\"]},\n    { name: \"UNKNOWN_SYM\" },\n    //{ name: \"ATKEYWORD\"},\n\n    //CSS3 animations\n    { name: \"KEYFRAMES_SYM\", text: [ \"@keyframes\", \"@-webkit-keyframes\", \"@-moz-keyframes\", \"@-o-keyframes\" ] },\n\n    //important symbol\n    { name: \"IMPORTANT_SYM\"},\n\n    //measurements\n    { name: \"LENGTH\"},\n    { name: \"ANGLE\"},\n    { name: \"TIME\"},\n    { name: \"FREQ\"},\n    { name: \"DIMENSION\"},\n    { name: \"PERCENTAGE\"},\n    { name: \"NUMBER\"},\n\n    //functions\n    { name: \"URI\"},\n    { name: \"FUNCTION\"},\n\n    //Unicode ranges\n    { name: \"UNICODE_RANGE\"},\n\n    /*\n     * The following token names are defined in CSS3 Selectors: http://www.w3.org/TR/css3-selectors/#selector-syntax\n     */\n\n    //invalid string\n    { name: \"INVALID\"},\n\n    //combinators\n    { name: \"PLUS\", text: \"+\" },\n    { name: \"GREATER\", text: \">\"},\n    { name: \"COMMA\", text: \",\"},\n    { name: \"TILDE\", text: \"~\"},\n\n    //modifier\n    { name: \"NOT\"},\n\n    /*\n     * Defined in CSS3 Paged Media\n     */\n    { name: \"TOPLEFTCORNER_SYM\", text: \"@top-left-corner\"},\n    { name: \"TOPLEFT_SYM\", text: \"@top-left\"},\n    { name: \"TOPCENTER_SYM\", text: \"@top-center\"},\n    { name: \"TOPRIGHT_SYM\", text: \"@top-right\"},\n    { name: \"TOPRIGHTCORNER_SYM\", text: \"@top-right-corner\"},\n    { name: \"BOTTOMLEFTCORNER_SYM\", text: \"@bottom-left-corner\"},\n    { name: \"BOTTOMLEFT_SYM\", text: \"@bottom-left\"},\n    { name: \"BOTTOMCENTER_SYM\", text: \"@bottom-center\"},\n    { name: \"BOTTOMRIGHT_SYM\", text: \"@bottom-right\"},\n    { name: \"BOTTOMRIGHTCORNER_SYM\", text: \"@bottom-right-corner\"},\n    { name: \"LEFTTOP_SYM\", text: \"@left-top\"},\n    { name: \"LEFTMIDDLE_SYM\", text: \"@left-middle\"},\n    { name: \"LEFTBOTTOM_SYM\", text: \"@left-bottom\"},\n    { name: \"RIGHTTOP_SYM\", text: \"@right-top\"},\n    { name: \"RIGHTMIDDLE_SYM\", text: \"@right-middle\"},\n    { name: \"RIGHTBOTTOM_SYM\", text: \"@right-bottom\"},\n\n    /*\n     * The following token names are defined in CSS3 Media Queries: http://www.w3.org/TR/css3-mediaqueries/#syntax\n     */\n    /*{ name: \"MEDIA_ONLY\", state: \"media\"},\n    { name: \"MEDIA_NOT\", state: \"media\"},\n    { name: \"MEDIA_AND\", state: \"media\"},*/\n    { name: \"RESOLUTION\", state: \"media\"},\n\n    /*\n     * The following token names are not defined in any CSS specification but are used by the lexer.\n     */\n\n    //not a real token, but useful for stupid IE filters\n    { name: \"IE_FUNCTION\" },\n\n    //part of CSS3 grammar but not the Flex code\n    { name: \"CHAR\" },\n\n    //TODO: Needed?\n    //Not defined as tokens, but might as well be\n    {\n        name: \"PIPE\",\n        text: \"|\"\n    },\n    {\n        name: \"SLASH\",\n        text: \"/\"\n    },\n    {\n        name: \"MINUS\",\n        text: \"-\"\n    },\n    {\n        name: \"STAR\",\n        text: \"*\"\n    },\n\n    {\n        name: \"LBRACE\",\n        endChar: \"}\",\n        text: \"{\"\n    },\n    {\n        name: \"RBRACE\",\n        text: \"}\"\n    },\n    {\n        name: \"LBRACKET\",\n        endChar: \"]\",\n        text: \"[\"\n    },\n    {\n        name: \"RBRACKET\",\n        text: \"]\"\n    },\n    {\n        name: \"EQUALS\",\n        text: \"=\"\n    },\n    {\n        name: \"COLON\",\n        text: \":\"\n    },\n    {\n        name: \"SEMICOLON\",\n        text: \";\"\n    },\n\n    {\n        name: \"LPAREN\",\n        endChar: \")\",\n        text: \"(\"\n    },\n    {\n        name: \"RPAREN\",\n        text: \")\"\n    },\n    {\n        name: \"DOT\",\n        text: \".\"\n    }\n];\n\n(function(){\n\n    var nameMap = [],\n        typeMap = {};\n\n    Tokens.UNKNOWN = -1;\n    Tokens.unshift({name:\"EOF\"});\n    for (var i=0, len = Tokens.length; i < len; i++){\n        nameMap.push(Tokens[i].name);\n        Tokens[Tokens[i].name] = i;\n        if (Tokens[i].text){\n            if (Tokens[i].text instanceof Array){\n                for (var j=0; j < Tokens[i].text.length; j++){\n                    typeMap[Tokens[i].text[j]] = i;\n                }\n            } else {\n                typeMap[Tokens[i].text] = i;\n            }\n        }\n    }\n\n    Tokens.name = function(tt){\n        return nameMap[tt];\n    };\n\n    Tokens.type = function(c){\n        return typeMap[c] || -1;\n    };\n\n})();\n\n\n\n//This file will likely change a lot! Very experimental!\n/*global Properties, ValidationTypes, ValidationError, PropertyValueIterator */\nvar Validation = {\n\n    validate: function(property, value){\n\n        //normalize name\n        var name        = property.toString().toLowerCase(),\n            parts       = value.parts,\n            expression  = new PropertyValueIterator(value),\n            spec        = Properties[name],\n            part,\n            valid,\n            j, count,\n            msg,\n            types,\n            last,\n            literals,\n            max, multi, group;\n\n        if (!spec) {\n            if (name.indexOf(\"-\") !== 0){    //vendor prefixed are ok\n                throw new ValidationError(\"Unknown property '\" + property + \"'.\", property.line, property.col);\n            }\n        } else if (typeof spec != \"number\"){\n\n            //initialization\n            if (typeof spec == \"string\"){\n                if (spec.indexOf(\"||\") > -1) {\n                    this.groupProperty(spec, expression);\n                } else {\n                    this.singleProperty(spec, expression, 1);\n                }\n\n            } else if (spec.multi) {\n                this.multiProperty(spec.multi, expression, spec.comma, spec.max || Infinity);\n            } else if (typeof spec == \"function\") {\n                spec(expression);\n            }\n\n        }\n\n    },\n\n    singleProperty: function(types, expression, max, partial) {\n\n        var result      = false,\n            value       = expression.value,\n            count       = 0,\n            part;\n\n        while (expression.hasNext() && count < max) {\n            result = ValidationTypes.isAny(expression, types);\n            if (!result) {\n                break;\n            }\n            count++;\n        }\n\n        if (!result) {\n            if (expression.hasNext() && !expression.isFirst()) {\n                part = expression.peek();\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                 throw new ValidationError(\"Expected (\" + types + \") but found '\" + value + \"'.\", value.line, value.col);\n            }\n        } else if (expression.hasNext()) {\n            part = expression.next();\n            throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n        }\n\n    },\n\n    multiProperty: function (types, expression, comma, max) {\n\n        var result      = false,\n            value       = expression.value,\n            count       = 0,\n            sep         = false,\n            part;\n\n        while(expression.hasNext() && !result && count < max) {\n            if (ValidationTypes.isAny(expression, types)) {\n                count++;\n                if (!expression.hasNext()) {\n                    result = true;\n\n                } else if (comma) {\n                    if (expression.peek() == \",\") {\n                        part = expression.next();\n                    } else {\n                        break;\n                    }\n                }\n            } else {\n                break;\n\n            }\n        }\n\n        if (!result) {\n            if (expression.hasNext() && !expression.isFirst()) {\n                part = expression.peek();\n                throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                part = expression.previous();\n                if (comma && part == \",\") {\n                    throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n                } else {\n                    throw new ValidationError(\"Expected (\" + types + \") but found '\" + value + \"'.\", value.line, value.col);\n                }\n            }\n\n        } else if (expression.hasNext()) {\n            part = expression.next();\n            throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n        }\n\n    },\n\n    groupProperty: function (types, expression, comma) {\n\n        var result      = false,\n            value       = expression.value,\n            typeCount   = types.split(\"||\").length,\n            groups      = { count: 0 },\n            partial     = false,\n            name,\n            part;\n\n        while(expression.hasNext() && !result) {\n            name = ValidationTypes.isAnyOfGroup(expression, types);\n            if (name) {\n\n                //no dupes\n                if (groups[name]) {\n                    break;\n                } else {\n                    groups[name] = 1;\n                    groups.count++;\n                    partial = true;\n\n                    if (groups.count == typeCount || !expression.hasNext()) {\n                        result = true;\n                    }\n                }\n            } else {\n                break;\n            }\n        }\n\n        if (!result) {\n            if (partial && expression.hasNext()) {\n                    part = expression.peek();\n                    throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n            } else {\n                throw new ValidationError(\"Expected (\" + types + \") but found '\" + value + \"'.\", value.line, value.col);\n            }\n        } else if (expression.hasNext()) {\n            part = expression.next();\n            throw new ValidationError(\"Expected end of value but found '\" + part + \"'.\", part.line, part.col);\n        }\n    }\n\n\n\n};\n/**\n * Type to use when a validation error occurs.\n * @class ValidationError\n * @namespace parserlib.util\n * @constructor\n * @param {String} message The error message.\n * @param {int} line The line at which the error occurred.\n * @param {int} col The column at which the error occurred.\n */\nfunction ValidationError(message, line, col){\n\n    /**\n     * The column at which the error occurred.\n     * @type int\n     * @property col\n     */\n    this.col = col;\n\n    /**\n     * The line at which the error occurred.\n     * @type int\n     * @property line\n     */\n    this.line = line;\n\n    /**\n     * The text representation of the unit.\n     * @type String\n     * @property text\n     */\n    this.message = message;\n\n}\n\n//inherit from Error\nValidationError.prototype = new Error();\n//This file will likely change a lot! Very experimental!\n/*global Properties, Validation, ValidationError, PropertyValueIterator, console*/\nvar ValidationTypes = {\n\n    isLiteral: function (part, literals) {\n        var text = part.text.toString().toLowerCase(),\n            args = literals.split(\" | \"),\n            i, len, found = false;\n\n        for (i=0,len=args.length; i < len && !found; i++){\n            if (text == args[i].toLowerCase()){\n                found = true;\n            }\n        }\n\n        return found;\n    },\n\n    isSimple: function(type) {\n        return !!this.simple[type];\n    },\n\n    isComplex: function(type) {\n        return !!this.complex[type];\n    },\n\n    /**\n     * Determines if the next part(s) of the given expression\n     * are any of the given types.\n     */\n    isAny: function (expression, types) {\n        var args = types.split(\" | \"),\n            i, len, found = false;\n\n        for (i=0,len=args.length; i < len && !found && expression.hasNext(); i++){\n            found = this.isType(expression, args[i]);\n        }\n\n        return found;\n    },\n\n    /**\n     * Determines if the next part(s) of the given expression\n     * are one of a group.\n     */\n    isAnyOfGroup: function(expression, types) {\n        var args = types.split(\" || \"),\n            i, len, found = false;\n\n        for (i=0,len=args.length; i < len && !found; i++){\n            found = this.isType(expression, args[i]);\n        }\n\n        return found ? args[i-1] : false;\n    },\n\n    /**\n     * Determines if the next part(s) of the given expression\n     * are of a given type.\n     */\n    isType: function (expression, type) {\n        var part = expression.peek(),\n            result = false;\n\n        if (type.charAt(0) != \"<\") {\n            result = this.isLiteral(part, type);\n            if (result) {\n                expression.next();\n            }\n        } else if (this.simple[type]) {\n            result = this.simple[type](part);\n            if (result) {\n                expression.next();\n            }\n        } else {\n            result = this.complex[type](expression);\n        }\n\n        return result;\n    },\n\n\n\n    simple: {\n\n        \"<absolute-size>\": function(part){\n            return ValidationTypes.isLiteral(part, \"xx-small | x-small | small | medium | large | x-large | xx-large\");\n        },\n\n        \"<attachment>\": function(part){\n            return ValidationTypes.isLiteral(part, \"scroll | fixed | local\");\n        },\n\n        \"<attr>\": function(part){\n            return part.type == \"function\" && part.name == \"attr\";\n        },\n\n        \"<bg-image>\": function(part){\n            return this[\"<image>\"](part) || this[\"<gradient>\"](part) || part == \"none\" || part == \"inherit\";\n        },\n\n        \"<gradient>\": function(part) {\n            return part.type == \"function\" && /^(?:\\-(?:ms|moz|o|webkit)\\-)?(?:repeating\\-)?(?:radial\\-|linear\\-)?gradient/i.test(part);\n        },\n\n        \"<box>\": function(part){\n            return ValidationTypes.isLiteral(part, \"padding-box | border-box | content-box\");\n        },\n\n        \"<content>\": function(part){\n            return part.type == \"function\" && part.name == \"content\";\n        },\n\n        \"<relative-size>\": function(part){\n            return ValidationTypes.isLiteral(part, \"smaller | larger\");\n        },\n\n        //any identifier\n        \"<ident>\": function(part){\n            return part.type == \"identifier\";\n        },\n\n        \"<length>\": function(part){\n            if (part.type == \"function\" && /^(?:\\-(?:ms|moz|o|webkit)\\-)?calc/i.test(part)){\n                return true;\n            }else{\n                return part.type == \"length\" || part.type == \"number\" || part.type == \"integer\" || part == \"0\";\n            }\n        },\n\n        \"<color>\": function(part){\n            return part.type == \"color\" || part == \"transparent\";\n        },\n\n        \"<number>\": function(part){\n            return part.type == \"number\" || this[\"<integer>\"](part);\n        },\n\n        \"<integer>\": function(part){\n            return part.type == \"integer\";\n        },\n\n        \"<line>\": function(part){\n            return part.type == \"integer\";\n        },\n\n        \"<angle>\": function(part){\n            return part.type == \"angle\";\n        },\n\n        \"<uri>\": function(part){\n            return part.type == \"uri\";\n        },\n\n        \"<image>\": function(part){\n            return this[\"<uri>\"](part);\n        },\n\n        \"<percentage>\": function(part){\n            return part.type == \"percentage\" || part == \"0\";\n        },\n\n        \"<border-width>\": function(part){\n            return this[\"<length>\"](part) || ValidationTypes.isLiteral(part, \"thin | medium | thick\");\n        },\n\n        \"<border-style>\": function(part){\n            return ValidationTypes.isLiteral(part, \"none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset\");\n        },\n\n        \"<content-sizing>\": function(part){ // http://www.w3.org/TR/css3-sizing/#width-height-keywords\n            return ValidationTypes.isLiteral(part, \"fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content\");\n        },\n\n        \"<margin-width>\": function(part){\n            return this[\"<length>\"](part) || this[\"<percentage>\"](part) || ValidationTypes.isLiteral(part, \"auto\");\n        },\n\n        \"<padding-width>\": function(part){\n            return this[\"<length>\"](part) || this[\"<percentage>\"](part);\n        },\n\n        \"<shape>\": function(part){\n            return part.type == \"function\" && (part.name == \"rect\" || part.name == \"inset-rect\");\n        },\n\n        \"<time>\": function(part) {\n            return part.type == \"time\";\n        },\n\n        \"<flex-grow>\": function(part){\n            return this[\"<number>\"](part);\n        },\n\n        \"<flex-shrink>\": function(part){\n            return this[\"<number>\"](part);\n        },\n\n        \"<width>\": function(part){\n            return this[\"<margin-width>\"](part);\n        },\n\n        \"<flex-basis>\": function(part){\n            return this[\"<width>\"](part);\n        },\n\n        \"<flex-direction>\": function(part){\n            return ValidationTypes.isLiteral(part, \"row | row-reverse | column | column-reverse\");\n        },\n\n        \"<flex-wrap>\": function(part){\n            return ValidationTypes.isLiteral(part, \"nowrap | wrap | wrap-reverse\");\n        }\n    },\n\n    complex: {\n\n        \"<bg-position>\": function(expression){\n            var types   = this,\n                result  = false,\n                numeric = \"<percentage> | <length>\",\n                xDir    = \"left | right\",\n                yDir    = \"top | bottom\",\n                count = 0,\n                hasNext = function() {\n                    return expression.hasNext() && expression.peek() != \",\";\n                };\n\n            while (expression.peek(count) && expression.peek(count) != \",\") {\n                count++;\n            }\n\n/*\n<position> = [\n  [ left | center | right | top | bottom | <percentage> | <length> ]\n|\n  [ left | center | right | <percentage> | <length> ]\n  [ top | center | bottom | <percentage> | <length> ]\n|\n  [ center | [ left | right ] [ <percentage> | <length> ]? ] &&\n  [ center | [ top | bottom ] [ <percentage> | <length> ]? ]\n]\n*/\n\n            if (count < 3) {\n                if (ValidationTypes.isAny(expression, xDir + \" | center | \" + numeric)) {\n                        result = true;\n                        ValidationTypes.isAny(expression, yDir + \" | center | \" + numeric);\n                } else if (ValidationTypes.isAny(expression, yDir)) {\n                        result = true;\n                        ValidationTypes.isAny(expression, xDir + \" | center\");\n                }\n            } else {\n                if (ValidationTypes.isAny(expression, xDir)) {\n                    if (ValidationTypes.isAny(expression, yDir)) {\n                        result = true;\n                        ValidationTypes.isAny(expression, numeric);\n                    } else if (ValidationTypes.isAny(expression, numeric)) {\n                        if (ValidationTypes.isAny(expression, yDir)) {\n                            result = true;\n                            ValidationTypes.isAny(expression, numeric);\n                        } else if (ValidationTypes.isAny(expression, \"center\")) {\n                            result = true;\n                        }\n                    }\n                } else if (ValidationTypes.isAny(expression, yDir)) {\n                    if (ValidationTypes.isAny(expression, xDir)) {\n                        result = true;\n                        ValidationTypes.isAny(expression, numeric);\n                    } else if (ValidationTypes.isAny(expression, numeric)) {\n                        if (ValidationTypes.isAny(expression, xDir)) {\n                                result = true;\n                                ValidationTypes.isAny(expression, numeric);\n                        } else if (ValidationTypes.isAny(expression, \"center\")) {\n                            result = true;\n                        }\n                    }\n                } else if (ValidationTypes.isAny(expression, \"center\")) {\n                    if (ValidationTypes.isAny(expression, xDir + \" | \" + yDir)) {\n                        result = true;\n                        ValidationTypes.isAny(expression, numeric);\n                    }\n                }\n            }\n\n            return result;\n        },\n\n        \"<bg-size>\": function(expression){\n            //<bg-size> = [ <length> | <percentage> | auto ]{1,2} | cover | contain\n            var types   = this,\n                result  = false,\n                numeric = \"<percentage> | <length> | auto\",\n                part,\n                i, len;\n\n            if (ValidationTypes.isAny(expression, \"cover | contain\")) {\n                result = true;\n            } else if (ValidationTypes.isAny(expression, numeric)) {\n                result = true;\n                ValidationTypes.isAny(expression, numeric);\n            }\n\n            return result;\n        },\n\n        \"<repeat-style>\": function(expression){\n            //repeat-x | repeat-y | [repeat | space | round | no-repeat]{1,2}\n            var result  = false,\n                values  = \"repeat | space | round | no-repeat\",\n                part;\n\n            if (expression.hasNext()){\n                part = expression.next();\n\n                if (ValidationTypes.isLiteral(part, \"repeat-x | repeat-y\")) {\n                    result = true;\n                } else if (ValidationTypes.isLiteral(part, values)) {\n                    result = true;\n\n                    if (expression.hasNext() && ValidationTypes.isLiteral(expression.peek(), values)) {\n                        expression.next();\n                    }\n                }\n            }\n\n            return result;\n\n        },\n\n        \"<shadow>\": function(expression) {\n            //inset? && [ <length>{2,4} && <color>? ]\n            var result  = false,\n                count   = 0,\n                inset   = false,\n                color   = false,\n                part;\n\n            if (expression.hasNext()) {\n\n                if (ValidationTypes.isAny(expression, \"inset\")){\n                    inset = true;\n                }\n\n                if (ValidationTypes.isAny(expression, \"<color>\")) {\n                    color = true;\n                }\n\n                while (ValidationTypes.isAny(expression, \"<length>\") && count < 4) {\n                    count++;\n                }\n\n\n                if (expression.hasNext()) {\n                    if (!color) {\n                        ValidationTypes.isAny(expression, \"<color>\");\n                    }\n\n                    if (!inset) {\n                        ValidationTypes.isAny(expression, \"inset\");\n                    }\n\n                }\n\n                result = (count >= 2 && count <= 4);\n\n            }\n\n            return result;\n        },\n\n        \"<x-one-radius>\": function(expression) {\n            //[ <length> | <percentage> ] [ <length> | <percentage> ]?\n            var result  = false,\n                simple = \"<length> | <percentage> | inherit\";\n\n            if (ValidationTypes.isAny(expression, simple)){\n                result = true;\n                ValidationTypes.isAny(expression, simple);\n            }\n\n            return result;\n        },\n\n        \"<flex>\": function(expression) {\n            // http://www.w3.org/TR/2014/WD-css-flexbox-1-20140325/#flex-property\n            // none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]\n            // Valid syntaxes, according to https://developer.mozilla.org/en-US/docs/Web/CSS/flex#Syntax\n            // * none\n            // * <flex-grow>\n            // * <flex-basis>\n            // * <flex-grow> <flex-basis>\n            // * <flex-grow> <flex-shrink>\n            // * <flex-grow> <flex-shrink> <flex-basis>\n            // * inherit\n            var part,\n                result = false;\n            if (ValidationTypes.isAny(expression, \"none | inherit\")) {\n                result = true;\n            } else {\n                if (ValidationTypes.isType(expression, \"<flex-grow>\")) {\n                    if (expression.peek()) {\n                        if (ValidationTypes.isType(expression, \"<flex-shrink>\")) {\n                            if (expression.peek()) {\n                                result = ValidationTypes.isType(expression, \"<flex-basis>\");\n                            } else {\n                                result = true;\n                            }\n                        } else if (ValidationTypes.isType(expression, \"<flex-basis>\")) {\n                            result = expression.peek() === null;\n                        }\n                    } else {\n                        result = true;\n                    }\n                } else if (ValidationTypes.isType(expression, \"<flex-basis>\")) {\n                    result = true;\n                }\n            }\n\n            if (!result) {\n                // Generate a more verbose error than \"Expected <flex>...\"\n                part = expression.peek();\n                throw new ValidationError(\"Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '\" + expression.value.text + \"'.\", part.line, part.col);\n            }\n\n            return result;\n        }\n    }\n};\n\nparserlib.css = {\nColors              :Colors,\nCombinator          :Combinator,\nParser              :Parser,\nPropertyName        :PropertyName,\nPropertyValue       :PropertyValue,\nPropertyValuePart   :PropertyValuePart,\nMediaFeature        :MediaFeature,\nMediaQuery          :MediaQuery,\nSelector            :Selector,\nSelectorPart        :SelectorPart,\nSelectorSubPart     :SelectorSubPart,\nSpecificity         :Specificity,\nTokenStream         :TokenStream,\nTokens              :Tokens,\nValidationError     :ValidationError\n};\n})();\n\n(function(){\nfor(var prop in parserlib){\nexports[prop] = parserlib[prop];\n}\n})();\n"
  },
  {
    "path": "gulp/util/destCSS.js",
    "content": "var mergeStream = require('merge-stream');\nvar argv = require('minimist')(process.argv.slice(2));\nvar gulp = require('gulp');\n\nvar config = require('../../app/config');\nvar { buildCSS } = require('../util/buildCSS');\n\nexports.destCSS = function destCSS() {\n    var buildRules = [];\n\n    var skins = config.skins;\n    var packages = Object.keys(config.packages);\n    var browsers = ['', 'ie8'];\n\n    if (argv.pkg || argv.skin) {\n        // Custom build\n        buildRules = browsers.map(function(browser) {\n            return {\n                suffix: browser === 'ie8' ? 'ie8' : null,\n                pkg: argv.pkg || 'full',\n                skin: argv.skin || config.appConfig.defaultSkin,\n                ie8: browser === 'ie8',\n                isTest: global.isTestBuild\n            };\n        });\n    } else {\n        packages.forEach(function(pkg) {\n            skins.forEach(function(skin) {\n                browsers.forEach(function(browser) {\n                    buildRules.push({\n                        suffix: [pkg, skin, browser].join('.').replace(/\\.$/, ''),\n                        pkg: pkg,\n                        skin: skin,\n                        ie8: browser === 'ie8',\n                        isTest: global.isTestBuild\n                    });\n                });\n            });\n        });\n    }\n\n    return mergeStream(buildRules.map(function(buildRule) {\n        return buildCSS(buildRule).pipe(gulp.dest('dist/css/'));\n    }));\n};\n"
  },
  {
    "path": "gulp/util/error.js",
    "content": "var plumber = require('gulp-plumber');\nvar notify = require('gulp-notify');\n\nfunction errorNotify(err) {\n    var args = Array.prototype.slice.call(arguments);\n\n    // Send error to notification center with gulp-notify\n    notify.onError({\n        title: 'Build Error',\n        message: '<%= error.message %>'\n    }, function() {\n        console.error('Build failure');\n\n        if (err.stack) {\n            console.error(err.stack);\n        }\n\n        process.exit(1);\n    }).apply(this, args);\n}\n\nfunction errorHandle() {\n    return plumber({\n        errorHandler: errorNotify\n    });\n}\n\nmodule.exports = {\n    notify: errorNotify,\n    handle: errorHandle\n};\n"
  },
  {
    "path": "gulp/util/gendoc.js",
    "content": "var fs = require('fs'),\n    marked = require('marked'),\n    mkdirp = require('mkdirp');\n\nfunction walkItem(menu, callback) { // (Object, Function)\n    for (var item in menu) {\n        var content = menu[item].content;\n        if (content) {\n            if (content.ru && content.ru._src) {\n                callback(menu[item].content.ru._src);\n            }\n            if (content.en && content.en._src) {\n                callback(menu[item].content.en._src);\n            }\n        }\n        if (menu[item].children) {\n            walkItem(menu[item].children, callback);\n        }\n    }\n}\n\nfunction getMdFileNames() { // (Object) -> Object\n    var menu = require('../../src/menu.json'),\n        result = [];\n    walkItem(menu, function(filepath) {\n        result.push(filepath);\n    });\n    return result;\n}\n\nfunction getMdFilesData(list, subdir) { // (Array, String) -> Array\n    var sorce = [],\n        dir = subdir || '',\n        listLeng = list.length;\n\n    for (var i = 0; i < listLeng; i++) {\n        var fullFilePath = dir + list[i];\n        if (fs.existsSync(fullFilePath)) {\n            var md = {};\n            md.path = list[i];\n            md.content = fs.readFileSync(fullFilePath);\n            sorce.push(md);\n        }\n\n    }\n    return sorce;\n}\n\nfunction copyConfigFile(filepath, destpath) { // (String, String)\n    var configName = filepath.match(/[^/]+$/)[0];\n\n    mkdirp(destpath, function() {\n        fs.writeFileSync(destpath + '/' + configName, fs.readFileSync(filepath));\n    });\n}\n\nfunction writeFile(dir, htmlFileName, html) {\n    mkdirp(dir, function() {\n        fs.writeFileSync(dir + '/' + htmlFileName, html);\n    });\n}\n\n// Usage: generateDocumentation('menu.json', './src', './doc')\nfunction generateDocumentation(config, rootPath, destPath) { // (Object, String, String)\n    var mdFileNames = getMdFileNames(),\n        mdData = getMdFilesData(mdFileNames, rootPath);\n\n    for (var i = 0, leng = mdData.length; i < leng; i++) {\n        (function(i) {\n            var mdFilePath = mdData[i].path,\n                htmlFileName = mdFilePath.match(/([\\w_-]+)\\.md$/i)[1] + '.html',\n                pluginDirName = mdFilePath.match(/\\/?(.*)\\/[.\\w_-]+$/)[1],\n                renderer = new marked.Renderer(),\n                tocHtml = generateTableOfContents(marked.lexer(mdData[i].content.toString())),\n                headerRepeats = {},\n                dir = destPath + '/' + pluginDirName + '/',\n                html;\n\n            renderer.listitem = function(text) {\n                return '<li><div class=\"restore-color\">' + text + '</div></li>';\n            };\n\n            renderer.heading = function(text, level) {\n                if (typeof headerRepeats[text] === 'undefined') {\n                    headerRepeats[text] = 0;\n                } else {\n                    headerRepeats[text]++;\n                }\n                return '<h' + level + ' id=\"' + getHeaderId(text, headerRepeats[text]) + '\">' + text + '</h' + level + '>';\n            };\n\n            html = marked(mdData[i].content.toString(), {\n                renderer: renderer\n            });\n\n            html = html.replace('<ul>', '<ul class=\"list-v-disc\">');\n            html = html.replace(/\\{toc}/g, tocHtml);\n\n            writeFile(dir, htmlFileName, html);\n        })(i);\n    }\n\n    copyConfigFile(config, destPath);\n}\n\nfunction generateTableOfContents(tokens) { // (Array) -> String\n    // generate ToC for H2, H3, ...\n    var prevDepth = 2,\n        startH = prevDepth,\n        tocHtml = '',\n        headers = [],\n        headerRepeats = {};\n\n    // extract headers from all tokens\n    tokens.forEach(function(token) {\n        if (token.type === 'heading' && token.depth > startH) headers.push(token);\n    });\n\n    // assign number for each header\n    headers.forEach(function(header) {\n        if (typeof headerRepeats[header.text] === 'undefined') {\n            headerRepeats[header.text] = 0;\n        }\n        else {\n            headerRepeats[header.text]++;\n        }\n        header.num = headerRepeats[header.text];\n    });\n\n    // generate html\n    for (var j = 0; j < headers.length; j++) {\n        var header = headers[j],\n            nextHeader = headers[j+1];\n\n        header.text = '<a href=\"#' + getHeaderId(header.text, header.num) + '\">' + header.text + '</a>';\n\n        if (header.depth > prevDepth) { // enter to the list\n            tocHtml += prevDepth === startH ? '<ul class=\"page-contents\">' : '<ul>';\n            tocHtml += '<li>' + header.text;\n        }\n        else if (header.depth === prevDepth) { // move by list\n            tocHtml += '<li>' + header.text;\n        }\n        else if (header.depth < prevDepth) {\n            tocHtml += '</ul></li>';\n            tocHtml += '<li>' + header.text;\n        }\n\n        // if hasn't childs\n        if (typeof nextHeader === 'undefined' || nextHeader.depth <= header.depth) {\n            tocHtml += '</li>';\n        }\n        // if last header\n        if (typeof nextHeader === 'undefined') {\n            tocHtml += '</ul>';\n        }\n\n        prevDepth = header.depth;\n    }\n    tocHtml = '<dl class=\"api-incut\">' + tocHtml + '</dl>';\n\n    return tocHtml;\n}\n\nfunction getHeaderId(text, num) { // (String, Number) -> String\n    var id = text.toLowerCase().replace(' ', '-');\n    id = id.replace('.', '');\n    id = num > 0 ? id + '-' + num : id;\n    return id;\n}\n\nexports.generateDocumentation = generateDocumentation;\n"
  },
  {
    "path": "gulp/util/projectList.js",
    "content": "var projectList;\n\nmodule.exports = {\n    set: function(val) {\n        projectList = val;\n    },\n    get: function() {\n        return projectList;\n    }\n};\n"
  },
  {
    "path": "gulp/util/stat.js",
    "content": "var prettyBytes = require('pretty-bytes');\nvar path = require('path');\n\nvar stat = {};\n\nfunction save(file, cb) {\n    var name = path.basename(file.path.split('/').pop());\n\n    stat[name] = prettyBytes(file.contents.length);\n\n    cb(null, file);\n}\n\nfunction get() {\n    return stat;\n}\n\nmodule.exports = {\n    save: save,\n    get: get\n};\n"
  },
  {
    "path": "gulp/util/templateStream.js",
    "content": "var path = require('path');\nvar gulp = require('gulp');\nvar dust = require('gulp-dust');\n\nvar config = require('../../app/config.js');\nvar deps = require('../deps')(config);\n\nmodule.exports = function(pkg) {\n    var templateList = deps.getModulesList(pkg)\n        .map(function(moduleName) {\n            return 'src/' + moduleName + '/templates/*.dust';\n        });\n\n    return gulp.src(templateList).pipe(dust({\n        name: function(file) {\n            var moduleName = path.basename(path.dirname(path.dirname(file.path)));\n            var templateName = path.basename(file.relative, '.dust');\n\n            return moduleName + '/' + templateName;\n        }\n    }));\n};\n"
  },
  {
    "path": "gulpfile.js",
    "content": "const { build } = require('./gulp/tasks/build');\nconst { lint } = require('./gulp/tasks/lint');\nconst { test } = require('./gulp/tasks/test');\nconst { dev } = require('./gulp/tasks/dev');\nconst { clean } = require('./gulp/tasks/clean');\n\nmodule.exports = {\n    build,\n    lint,\n    test,\n    dev,\n    clean,\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"2gis-maps\",\n  \"version\": \"4.0.12\",\n  \"description\": \"Interactive 2GIS maps API, based on Leaflet\",\n  \"license\": \"SEE LICENSE IN FILE\",\n  \"keywords\": [\n    \"2gis\",\n    \"map\",\n    \"api\"\n  ],\n  \"scripts\": {\n    \"test\": \"gulp lint && gulp test\",\n    \"start\": \"npm run build && node app\",\n    \"build\": \"gulp build --release\",\n    \"dev\": \"gulp dev\",\n    \"lint\": \"gulp lint\",\n    \"pub\": \"gulp clean && gulp build --npm --release && npm publish\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git@github.com:2gis/mapsapi.git\"\n  },\n  \"main\": \"dist/js/script.full.js\",\n  \"dependencies\": {\n    \"cors\": \"^2.7.1\",\n    \"dotenv\": \"^8.6.0\",\n    \"dustjs-helpers\": \"1.7.3\",\n    \"dustjs-linkedin\": \"3.0.1\",\n    \"express\": \"^4.13.4\",\n    \"html5shiv\": \"^3.7.3\",\n    \"leaflet\": \"1.0.1\",\n    \"lodash\": \"4.17.21\"\n  },\n  \"devDependencies\": {\n    \"browserify\": \"^13.0.1\",\n    \"browserify-css\": \"^0.9.1\",\n    \"coveralls\": \"^2.11.9\",\n    \"del\": \"^5.1.0\",\n    \"event-stream\": \"^3.3.2\",\n    \"fancy-log\": \"^1.3.2\",\n    \"glob\": \"^7.0.3\",\n    \"gulp\": \"^4.0.2\",\n    \"gulp-autoprefixer\": \"^3.1.0\",\n    \"gulp-cached\": \"^1.1.0\",\n    \"gulp-clean-css\": \"^2.0.4\",\n    \"gulp-concat\": \"^2.6.0\",\n    \"gulp-derequire\": \"^2.1.0\",\n    \"gulp-dust\": \"^3.0.0\",\n    \"gulp-eslint\": \"^6.0.0\",\n    \"gulp-flatten\": \"0.2.0\",\n    \"gulp-footer\": \"^1.0.5\",\n    \"gulp-header\": \"1.8.2\",\n    \"gulp-if\": \"^2.0.0\",\n    \"gulp-imagemin\": \"^2.4.0\",\n    \"gulp-insert\": \"^0.5.0\",\n    \"gulp-less\": \"^3.0.5\",\n    \"gulp-notify\": \"^3.2.0\",\n    \"gulp-plumber\": \"^1.2.1\",\n    \"gulp-remember\": \"^0.3.0\",\n    \"gulp-rename\": \"^1.2.2\",\n    \"gulp-replace\": \"^0.5.4\",\n    \"gulp-sourcemaps\": \"^2.6.5\",\n    \"gulp-uglify\": \"^1.5.4\",\n    \"gulp.spritesmith\": \"^6.2.1\",\n    \"happen\": \"~0.3.0\",\n    \"image-size\": \"0.5.0\",\n    \"karma\": \"^0.13.22\",\n    \"karma-chrome-launcher\": \"^0.2.0\",\n    \"karma-coverage\": \"^0.5.5\",\n    \"karma-expect\": \"^1.1.0\",\n    \"karma-firefox-launcher\": \"^0.1.0\",\n    \"karma-mocha\": \"^0.2.0\",\n    \"karma-mocha-reporter\": \"^2.0.0\",\n    \"karma-opera-launcher\": \"^0.3.0\",\n    \"karma-phantomjs-launcher\": \"^1.0.0\",\n    \"karma-sinon\": \"^1.0.4\",\n    \"less\": \"^2.6.1\",\n    \"map-stream\": \"0.1.0\",\n    \"marked\": \"0.3.5\",\n    \"merge-stream\": \"^2.0.0\",\n    \"minimist\": \"^1.2.0\",\n    \"mkdirp\": \"0.5.1\",\n    \"mocha\": \"^2.4.5\",\n    \"mock-geolocation\": \"^1.0.11\",\n    \"optimist\": \"^0.6.1\",\n    \"phantomjs-prebuilt\": \"2.1.11\",\n    \"pixelsmith\": \"^2.1.0\",\n    \"plugin-error\": \"^1.0.1\",\n    \"pretty-bytes\": \"^4.0.2\",\n    \"prosthetic-hand\": \"^1.3.0\",\n    \"request\": \"^2.70.0\",\n    \"sinon\": \"^1.17.3\",\n    \"streamqueue\": \"^1.1.1\",\n    \"vinyl-buffer\": \"^1.0.0\",\n    \"vinyl-source-stream\": \"^2.0.0\"\n  }\n}\n"
  },
  {
    "path": "src/DGAjax/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>DGAjax & DGPromise demo</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n</head>\n<body>\n\n<div id=\"map\" style=\"width: 100%; height: 400px; border: 1px solid #ccc;\"></div>\n\n<script type=\"text/javascript\">\n\n    // Avoid `console` errors in browsers that lack a console.\n    (function() {\n        var method;\n        var noop = function () {};\n        var methods = [\n            'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',\n            'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',\n            'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',\n            'timeStamp', 'trace', 'warn'\n        ];\n        var length = methods.length;\n        var console = (window.console = window.console || {});\n\n        while (length--) {\n            method = methods[length];\n\n            if (!console[method]) {\n                console[method] = noop;\n            }\n        }\n    }());\n\n    DG.then(function () {\n\n        var map = new DG.Map('map', {\n            center: new DG.LatLng(54.980206086231, 82.898068362003),\n            zoom: 17,\n            geoclicker: true,\n            key: DG.config.key || 'Your API access key'\n        });\n\n        function test_get(){\n            console.group('Test XHR GET');\n            return DG.ajax('http://catalog.api.2gis.ru/2.0/search', {\n                type: 'get',\n                data: {\n                    key: 'ruregt3044',\n                    type: 'filial',\n                    house: 141373143572328,\n                    page: 1\n                },\n                success: function(data) {\n                    console.log('success', data);\n                },\n                error: function(error) {\n                    console.warn('error', error);\n                }\n            }).then(\n                function(data) {\n                    console.log('promise resolve', data);\n                    console.groupEnd();\n                },\n                function(error) {\n                    console.warn('promise reject', error);\n                    console.groupEnd();\n                }\n            );\n        }\n\n        function test_post(){\n            console.group('Test XHR POST');\n            return DG.ajax('http://catalog.api.2gis.ru/2.0/search', {\n                type: 'post',\n                data: {\n                    key: 'ruregt3044',\n                    type: 'filial',\n                    house: 141373143572328,\n                    page: 1\n                },\n                success: function(data) {\n                    console.log('success', data);\n                },\n                error: function(error) {\n                    console.warn('error', error);\n                }\n            }).then(\n                function(data) {\n                    console.log('promise resolve', data);\n                    console.groupEnd();\n                },\n                function(error) {\n                    console.warn('promise reject', error);\n                    console.groupEnd();\n                }\n            );\n        }\n\n        DG.DomEvent.addListener( DG.DomUtil.get('sendRequest'), 'click', function(){\n            test_get().then(test_post).then(function(){\n                console.info('Everything seems to be ok!');\n            });\n        });\n\n    });\n</script>\n<button id=\"sendRequest\">Сделать запрос</button>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGAjax/src/DGAjax.js",
    "content": "DG.ajax = (function() {\n\n    var win = window,\n        doc = document,\n\n        rurl = /^([\\w.+-]+:)?(?:\\/\\/([^\\/?#:]*)(?::(\\d+)|)|)/,\n        twoHundo = /^20\\d$/,\n\n        // Document location\n        ajaxLocParts,\n        ajaxLocation,\n\n        byTag = 'getElementsByTagName',\n        readyState = 'readyState',\n        contentType = 'Content-Type',\n        requestedWith = 'X-Requested-With',\n        head = doc[byTag]('head')[0],\n        uniqid = 0,\n        callbackPrefix = 'l_dg_ajax_callback_' + (+new Date()),\n        lastValue, // data stored by the most recent JSONP callback\n        xmlHttpRequest = 'XMLHttpRequest',\n        xDomainRequest = 'XDomainRequest', // IE 8 and 9 only\n        noop = function() {},\n        defaultHeaders = {\n            contentType: 'application/x-www-form-urlencoded',\n            requestedWith: xmlHttpRequest,\n            accept: {\n                '*':  'text/javascript, text/html, application/xml, text/xml, */*',\n                xml:  'application/xml, text/xml',\n                html: 'text/html',\n                text: 'text/plain',\n                json: 'application/json, text/javascript',\n                js:   'application/javascript, text/javascript'\n            }\n        },\n        /*global XDomainRequest:false */\n        xhr = function(o) {\n            // is it x-domain\n            if (o.crossDomain === true) {\n                var xhr = win[xmlHttpRequest] ? new XMLHttpRequest() : null;\n                if (xhr && 'withCredentials' in xhr) {\n                    return xhr;\n                } else if (win[xDomainRequest]) {\n                    return new XDomainRequest();\n                } else {\n                    throw new Error('Browser does not support cross-origin requests');\n                }\n            } else {\n                return new XMLHttpRequest();\n            }\n        },\n\n        globalSetupOptions = {\n            dataFilter: function(data) {\n                return data;\n            }\n        };\n\n    // IE may throw an exception when accessing\n    // a field from window.location if document.domain has been set\n    try {\n        ajaxLocation = location.href;\n    } catch (e) {\n        // Use the href attribute of an A element\n        // since IE will modify it given document.location\n        ajaxLocation = document.createElement('a');\n        ajaxLocation.href = '';\n        ajaxLocation = ajaxLocation.href;\n    }\n\n    // Segment location into parts\n    ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || [];\n\n    function handleReadyState(r, success, error) {\n        return function() {\n            // use _aborted to mitigate against IE err c00c023f\n            // (can't read props on aborted request objects)\n            if (r._aborted) {\n                return error(r.request);\n            }\n            if (r.request && r.request[readyState] === 4) {\n                r.request.onreadystatechange = noop;\n                if (twoHundo.test(r.request.status)) {\n                    success(r.request);\n                } else {\n                    error(r.request);\n                }\n            }\n        };\n    }\n\n    function setHeaders(http, o) {\n        var headers = o.headers || {},\n            h;\n\n        headers.Accept = headers.Accept || defaultHeaders.accept[o.dataType] || defaultHeaders.accept['*'];\n\n        // breaks cross-origin requests with legacy browsers\n        if (!o.crossDomain && !headers[requestedWith]) {\n            headers[requestedWith] = defaultHeaders.requestedWith;\n        }\n        if (!headers[contentType]) {\n            headers[contentType] = o.contentType || defaultHeaders.contentType;\n        }\n        for (h in headers) {\n            if (headers.hasOwnProperty(h) && 'setRequestHeader' in http) {\n                http.setRequestHeader(h, headers[h]);\n            }\n        }\n    }\n\n    function setCredentials(http, o) {\n        if (typeof o.withCredentials !== 'undefined' && typeof http.withCredentials !== 'undefined') {\n            http.withCredentials = !!o.withCredentials;\n        }\n    }\n\n    function generalCallback(data) {\n        lastValue = data;\n    }\n\n    function urlappend(url, s) {\n        return url + (/\\?/.test(url) ? '&' : '?') + s;\n    }\n\n    function handleJsonp(o, fn, err, url) {\n        var reqId = uniqid++,\n            cbkey = o.jsonpCallback || 'callback', // the 'callback' key\n            cbval = o.jsonpCallbackName || callbackPrefix,\n            cbreg = new RegExp('((^|\\\\?|&)' + cbkey + ')=([^&]+)'),\n            match = url.match(cbreg),\n            script = doc.createElement('script'),\n            loaded = 0,\n            isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1;\n\n        if (match) {\n            if (match[3] === '?') {\n                url = url.replace(cbreg, '$1=' + cbval); // wildcard callback func name\n            } else {\n                cbval = match[3]; // provided callback func name\n            }\n        } else {\n            url = urlappend(url, cbkey + '=' + cbval); // no callback details, add 'em\n        }\n\n        win[cbval] = generalCallback;\n\n        script.type = 'text/javascript';\n        script.src = url;\n        script.async = true;\n        if (typeof script.onreadystatechange !== 'undefined' && !isIE10) {\n            // need this for IE due to out-of-order onreadystatechange(), binding script\n            // execution to an event listener gives us control over when the script\n            // is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html\n            //\n            // if this hack is used in IE10 jsonp callback are never called\n            script.event = 'onclick';\n            script.htmlFor = script.id = '_request_' + reqId;\n        }\n\n        script.onerror = function() {\n            script.onerror = script.onload = script.onreadystatechange = null;\n            err({}, 'Request unknown error', {});\n            lastValue = undefined;\n            head.removeChild(script);\n            loaded = 1;\n        };\n        script.onload = script.onreadystatechange = function() {\n            if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {\n                return false;\n            }\n            script.onerror = script.onload = script.onreadystatechange = null;\n            if (script.onclick) {\n                script.onclick();\n            }\n            // Call the user callback with the last value stored and clean up values and scripts.\n            fn(lastValue);\n            lastValue = undefined;\n            head.removeChild(script);\n            loaded = 1;\n        };\n\n        // Add the script to the DOM head\n        head.appendChild(script);\n\n        // Enable JSONP timeout\n        return {\n            abort: function() {\n                script.onerror = script.onload = script.onreadystatechange = null;\n                err({}, 'Request is aborted: timeout', {});\n                lastValue = undefined;\n                head.removeChild(script);\n                loaded = 1;\n            }\n        };\n    }\n\n    function getRequest(fn, err) {\n        var o = this.options,\n            method = (o.type || 'GET').toUpperCase(),\n            url = typeof o === 'string' ? o : o.url,\n            // convert non-string objects to query-string form unless o.processData is false\n            data = (o.processData !== false && o.data && typeof o.data !== 'string') ? Ajax.toQueryString(o.data) : (o.data || null),\n            http,\n            sendWait = false;\n\n        // if we're working on a GET request and we have data then we should append\n        // query string to end of URL and not post data\n        if ((o.type === 'jsonp' || method === 'GET') && data) {\n            url = urlappend(url, data);\n            data = null;\n        }\n\n        if (o.type === 'jsonp') {\n            return handleJsonp(o, fn, err, url);\n        }\n\n        http = xhr(o);\n        http.open(method, url, o.async !== false);\n\n        setHeaders(http, o);\n        setCredentials(http, o);\n\n        if (win[xDomainRequest] && http instanceof win[xDomainRequest]) {\n            http.onload = fn;\n            http.onprogress = function() {};\n            http.ontimeout = function() {};\n            http.onerror = err;\n            sendWait = true;\n        } else {\n            http.onreadystatechange = handleReadyState(this, fn, err);\n        }\n        if (sendWait) {\n            setTimeout(function() {\n                http.send(data);\n            }, 200);\n        } else {\n            http.send(data);\n        }\n        return http;\n    }\n\n    function buildParams(prefix, obj, traditional, add) {\n        var name, i, v,\n            rbracket = /\\[\\]$/;\n\n        if (DG.Util.isArray(obj)) {\n        // Serialize array item.\n            for (i = 0; obj && i < obj.length; i++) {\n                v = obj[i];\n                if (traditional || rbracket.test(prefix)) {\n                    // Treat each array item as a scalar.\n                    add(prefix, v);\n                } else {\n                    buildParams(prefix + '[' + (typeof v === 'object' ? i : '') + ']', v, traditional, add);\n                }\n            }\n        } else if (obj && obj.toString() === '[object Object]') {\n            // Serialize object item.\n            for (name in obj) {\n                if (obj.hasOwnProperty(name)) {\n                    buildParams(prefix + '[' + name + ']', obj[name], traditional, add);\n                }\n            }\n        } else {\n            // Serialize scalar item.\n            add(prefix, obj);\n        }\n    }\n\n    function setType(url) {\n        var m = url.match(/\\.(json|jsonp|html|xml)(\\?|$)/);\n        return m ? m[1] : 'js';\n    }\n\n    function isCrossDomain(url) {\n        var parts = rurl.exec(url.toLowerCase());\n        return !!(parts &&\n                (parts[1] !== ajaxLocParts[1] || parts[2] !== ajaxLocParts[2] ||\n                    (parts[3] || (parts[1] === 'http:' ? '80' : '443')) !==\n                        (ajaxLocParts[3] || (ajaxLocParts[1] === 'http:' ? '80' : '443')))\n        );\n    }\n\n    function doRequest(o) {\n\n        if (!('crossDomain' in o)) {\n            o.crossDomain = isCrossDomain(o.url);\n        }\n\n        var self = {};\n        self.promise = new Promise(function(resolve, reject) {\n            self.abort = function() {\n                self._aborted = true;\n                reject('aborted');\n            };\n\n            self.url = o.url;\n            self.timeout = null;\n            self.options = o;\n\n            self._aborted = false;\n            self._erred = false;\n            self._responseArgs = {};\n\n            var type = o.type === 'jsonp' ? o.type : (o.dataType || setType(self.url));\n\n            if (o.timeout) {\n                self.timeout = setTimeout(function() {\n                    self.abort();\n                }, o.timeout);\n            }\n\n            function complete(resp) {\n                if (o.timeout) {\n                    clearTimeout(self.timeout);\n                }\n                self.timeout = null;\n                if (self._erred) {\n                    reject(resp);\n                } else {\n                    resolve(resp);\n                }\n            }\n\n            function success(resp) {\n                resp = (type !== 'jsonp') ? self.request : resp;\n                // use global data filter on response text\n                var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type),\n                    r = filteredResponse;\n\n                try {\n                    resp.responseText = r;\n                } catch (e) {\n                    // can't assign this in IE<=8, just ignore\n                }\n                /* eslint-disable no-eval */\n                if (r) {\n                    switch (type) {\n                        case 'json':\n                            try {\n                                resp = win.JSON.parse(r);\n                            } catch (err) {\n                                return error(resp, 'Could not parse JSON in response', err);\n                            }\n                            break;\n                        case 'js':\n                            resp = eval('(' + r + ')');\n                            break;\n                        case 'html':\n                            resp = r;\n                            break;\n                        case 'xml':\n                            resp = resp.responseXML && resp.responseXML.parseError && resp.responseXML.parseError.errorCode && resp.responseXML.parseError.reason ? null : resp.responseXML;\n                            break;\n                    }\n                }\n                /* eslint-enable no-eval */\n                self._responseArgs.resp = resp;\n                complete(resp);\n            }\n\n            function error(resp, msg, t) {\n                resp = self.request;\n                self._responseArgs.resp = resp;\n                self._responseArgs.msg = msg;\n                self._responseArgs.t = t;\n                self._erred = true;\n                complete(resp);\n            }\n\n            self.request = getRequest.call(self, success, error);\n        });\n\n        return self;\n    }\n\n    function Ajax(url, options) {\n\n        if (Object.prototype.toString.call(url) === '[object Object]') {\n            options = url;\n            url = undefined;\n        }\n        options = options || {};\n        options.url = url || options.url;\n\n        var requestPromise = doRequest(options),\n            resultPromise = requestPromise.promise;\n\n        if (options.success || options.error || options.complete) {\n            resultPromise.then(options.success, options.error);\n        }\n\n        resultPromise.abort = requestPromise.abort;\n\n        return resultPromise;\n    }\n\n    Ajax.setup = function(options) {\n        options = options || {};\n        for (var k in options) {\n            if (options.hasOwnProperty(k)) {\n                globalSetupOptions[k] = options[k];\n            }\n        }\n    };\n\n    Ajax.toQueryString = function(o, trad) {\n        var prefix, i,\n            traditional = trad || false,\n            s = [],\n            enc = encodeURIComponent,\n            add = function(key, value) {\n                // If value is a function, invoke it and return its value\n                if (typeof value == 'function') {\n                    value = value();\n                } else {\n                    value = value || '';\n                }\n\n                s[s.length] = enc(key) + '=' + enc(value);\n            };\n\n        // If an array was passed in, assume that it is an array of form elements.\n        if (DG.Util.isArray(o)) {\n            for (i = 0; o && i < o.length; i++) {\n                add(o[i].name, o[i].value);\n            }\n        } else {\n            // If traditional, encode the \"old\" way (the way 1.3.2 or older\n            // did it), otherwise encode params recursively.\n            for (prefix in o) {\n                if (o.hasOwnProperty(prefix)) {\n                    buildParams(prefix, o[prefix], traditional, add);\n                }\n            }\n        }\n\n        // spaces should be + according to spec\n        return s.join('&').replace(/%20/g, '+');\n    };\n\n    var testxhr = win[xmlHttpRequest] ? new XMLHttpRequest() : null;\n\n    Ajax.corsSupport = !(!(testxhr && 'withCredentials' in testxhr) && !win[xDomainRequest]) &&\n        // cors not available in IE and with cyrillic domain\n        !(DG.Browser.ie && document.location.host.toLowerCase().search(/[а-я]/) != -1);\n\n    return Ajax;\n})();\n"
  },
  {
    "path": "src/DGAjax/test/DGAjaxSpec.js",
    "content": "describe('DG.ajax', function () {\n\n\tdescribe('#toQueryString', function () {\n\t\tit('([{ name: x, value: y }, ... ]) simple', function () {\n\t\t\tvar arr = [\n\t\t\t\t{ name: 'foo', value: 'bar' },\n\t\t\t\t{ name: 'baz', value: '' },\n\t\t\t\t{ name: 'x', value: -20 },\n\t\t\t\t{ name: 'x', value: 20 }\n\t\t    ];\n\n\t\t\texpect(DG.ajax.toQueryString(arr)).to.be.eql('foo=bar&baz=&x=-20&x=20');\n\t\t});\n\n\t\tit('([{ name: x, value: y }, ... ]) escaping required', function () {\n\t\t\tvar arr = [\n\t\t\t\t{ name: 'dotted.name.intact', value: '$@%' },\n\t\t\t\t{ name: '$ $', value: 20 },\n\t\t\t\t{ name: 'leave britney alone', value: 'waa haa haa' }\n\t\t\t];\n\n\t\t\texpect(DG.ajax.toQueryString(arr)).to.be.eql('dotted.name.intact=%24%40%25&%24+%24=20&leave+britney+alone=waa+haa+haa');\n\t\t});\n\t});\n\n    describe('send request', function() {\n        var xhr, requests, url, data, ajax, spyError, spySuccess, thenSuccess, thenError, clock;\n\n        before(function() {\n            xhr = sinon.useFakeXMLHttpRequest();\n            requests = [];\n\n            xhr.onCreate = function (xhr) {\n                requests.push(xhr);\n            };\n        });\n\n        after(function() {\n            xhr.restore();\n            xhr = requests = url = data = ajax = spyError = spySuccess = thenSuccess = thenError = clock = null;\n        });\n\n        function testSuccess(type) {\n            describe('type: ' + type + ', respond success', function() {\n                before(function() {\n                    url = 'http://test-url.ru';\n                    data = {a: 1, b: 3};\n                    spySuccess = sinon.spy();\n                    spyError = sinon.spy();\n                    thenSuccess = sinon.spy();\n                    thenError = sinon.spy();\n\n                    ajax = DG.ajax(url, {\n                        data: data,\n                        type: type,\n                        success: spySuccess,\n                        error: spyError\n                    }).then(thenSuccess, thenError);\n                });\n\n                after(function() {\n                    requests = [];\n                    url = data = spyError = spySuccess = thenSuccess = thenError = null;\n                });\n\n                it('should only one request', function() {\n                    expect(requests.length).to.be(1);\n                });\n\n                it('should sended request url contain url', function() {\n                    expect(requests[0].url).to.contain(url);\n                });\n\n                it('should call success', function(done) {\n                    requests[0].respond(200, {\"Content-Type\": \"application/json\"}, '[{ \"z\": 10, \"x\": \"20\" }]');\n\n                    setTimeout(function() {\n                        expect(spySuccess.calledOnce).to.be.ok();\n                        done();\n                    }, 0);\n                });\n\n                it('should call thenSuccess', function() {\n                    expect(thenSuccess.calledOnce).to.be.ok();\n                });\n\n                it('shouldn\\'t call error', function() {\n                    expect(spyError.called).not.be.ok();\n                });\n\n                it('shouldn\\'t call thenError', function() {\n                    expect(thenError.called).not.be.ok();\n                });\n            });\n        }\n\n        testSuccess('get');\n        testSuccess('post');\n\n        describe('respond error', function() {\n            before(function() {\n                url = 'http://test-url.ru';\n                data = {a: 1, b: 3};\n                spySuccess = sinon.spy();\n                spyError = sinon.spy();\n                thenSuccess = sinon.spy();\n                thenError = sinon.spy();\n\n                ajax = DG.ajax(url, {\n                    data: data,\n                    type: 'post',\n                    success: spySuccess,\n                    error: spyError\n                }).then(thenSuccess, thenError);\n            });\n\n            after(function() {\n                requests = [];\n                url = data = spyError = spySuccess = thenSuccess = thenError = null;\n            });\n\n            it('shouldn\\'t call success', function(done) {\n                requests[0].respond(400, {\"Content-Type\": \"application/json\"}, '[{ \"z\": 10, \"x\": \"20\" }]');\n\n                setTimeout(function() {\n                    expect(spySuccess.called).not.be.ok();\n                    done();\n                }, 0);\n            });\n\n            it('shouldn\\'t call thenSuccess', function() {\n                expect(thenSuccess.calledOnce).not.be.ok();\n            });\n\n            it('should call error', function() {\n                expect(spyError.calledOnce).to.be.ok();\n            });\n\n            it('should call thenError', function() {\n                expect(thenError.calledOnce).to.be.ok();\n            });\n        });\n\n        describe('check timeout', function() {\n            before(function() {\n                url = 'http://test-url.ru';\n                data = {a: 1, b: 3};\n                spySuccess = sinon.spy();\n                spyError = sinon.spy();\n                thenSuccess = sinon.spy();\n                thenError = sinon.spy();\n\n                ajax = DG.ajax(url, {\n                    data: data,\n                    type: 'post',\n                    success: spySuccess,\n                    error: spyError,\n                    timeout: 10\n                }).then(thenSuccess, thenError);\n            });\n\n            after(function() {\n                requests = [];\n                url = data = spyError = spySuccess = thenSuccess = thenError = clock = null;\n            });\n\n            it('shouldn\\'t call success after timeout', function(done) {\n                setTimeout(function() {\n                    requests[0].respond(200, {\"Content-Type\": \"application/json\"}, '[{ \"z\": 10, \"x\": \"20\" }]');\n\n                    setTimeout(function() {\n                        expect(spySuccess.called).not.be.ok();\n                        expect(thenSuccess.called).not.be.ok();\n                        done();\n                    }, 0);\n                }, 50);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGAttribution/lang/ar.js",
    "content": "DG.Control.Attribution.Dictionary.ar = {\n    license_agreement: 'إتفاقية ترخيص',\n    work_on: 'يعمل بتطبيق 2GIS',\n    has_no_key: 'مطلوب مفتاح للتشغيل الصحيح لـ Raster JS API. المساعدة: api@2gis.ru',\n    open_on: 'Open in 2GIS',\n    route_on: 'Route on 2GIS'\n};\n"
  },
  {
    "path": "src/DGAttribution/lang/cs.js",
    "content": "DG.Control.Attribution.Dictionary.cs = {\n    license_agreement: 'Licenční smlouva',\n    has_no_key: 'Pro správnou funkci Raster JS API je vyžadován klíč. Pomoc: api@2gis.ru',\n    work_on: 'Pracuje na API 2GIS'\n};\n"
  },
  {
    "path": "src/DGAttribution/lang/en.js",
    "content": "DG.Control.Attribution.Dictionary.en = {\n    license_agreement: 'License agreement',\n    has_no_key: 'A key is required for proper operation of Raster JS API. Help: api@2gis.ru',\n    work_on: 'Uses 2GIS API'\n};\n"
  },
  {
    "path": "src/DGAttribution/lang/es.js",
    "content": "DG.Control.Attribution.Dictionary.es = {\n    license_agreement : 'Acuerdo de licencia',\n    has_no_key: 'Se requiere una clave para el funcionamiento correcto de Raster JS API. Ayuda: api@2gis.ru',\n    work_on: '2GIS API'\n};\n"
  },
  {
    "path": "src/DGAttribution/lang/it.js",
    "content": "DG.Control.Attribution.Dictionary.it = {\n    license_agreement : 'Accordo di licenza',\n    has_no_key: 'È richiesta una chiave per il corretto funzionamento di Raster JS API. Aiuto: api@2gis.ru',\n    work_on: '2GIS API'\n};\n"
  },
  {
    "path": "src/DGAttribution/lang/ru.js",
    "content": "DG.Control.Attribution.Dictionary.ru = {\n    license_agreement: 'Лицензионное соглашение',\n    work_on: 'Работает на API 2ГИС',\n    has_no_key: 'Для корректной работы Raster JS API нужен ключ. Помощь: api@2gis.ru',\n    open_on: 'Открыть в 2ГИС',\n    route_on: 'Доехать с 2ГИС'\n};\n"
  },
  {
    "path": "src/DGAttribution/skin/basic/less/dg-mapcopyright.less",
    "content": "/* !important is overused here to protect copyright styles from occasional change */\n\n.dg-attribution {\n    background-color: transparent !important;\n\n    .dg-attribution__copyright {\n        display: flex !important;\n        align-items: center !important;\n        text-align: right !important;\n        white-space: nowrap !important;\n        font-size: 9px !important;\n        font-family: Helvetica, Arial, sans-serif !important;\n    }\n\n    .dg-attribution__links {\n        display: inline-block !important;\n        margin: 0 !important;\n        padding: 0 5px 0 0 !important;\n    }\n\n    .dg-attribution__link-item {\n        padding: 0 !important;\n        list-style-type: none !important;\n    }\n\n    .dg-attribution__warning-message {\n        display: inline-block !important;\n        margin: 0 !important;\n        color: #333 !important;\n        font-family: Helvetica, Arial, sans-serif !important;\n        font-weight: bold !important;\n        white-space: normal;\n    }\n\n    .dg-attribution__logo-url {\n        .notRepeatableBgWithSizes('DGAttribution__logo');\n        margin: 0 3px 0 0 !important;\n    }\n\n    .dg-attribution__open2gis-button {\n        background: #ffffff !important;\n        border-radius: 4px !important;\n        box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2) !important;\n        padding: 4px 6px 4px 4px !important;\n        position: relative !important;\n        display: inline-block !important;\n        box-sizing: border-box !important;\n        text-align: left !important;\n        text-decoration: none !important;\n        line-height: 14px !important;\n        font-style: normal !important;\n        font-weight: 600 !important;\n        font-size: 9px !important;\n        cursor: pointer !important;\n        transition: all .1s !important;\n        height: 22px !important;\n        min-width: 101px !important;\n\n        .no-touch &:hover {\n            transition: background .2s !important;\n            background: #e7f3ff !important;\n        }\n    }\n\n    .dg-attribution__open2gis-icon-button:before {\n        display: inline-block !important;\n        margin: -1px 4px 0 0 !important;\n        width: 12px !important;\n        height: 12px !important;\n        background-size: contain !important;\n        background-repeat: no-repeat !important;\n        content: '' !important;\n        vertical-align: middle !important;\n    }\n\n    .dg-attribution__button-wrapper {\n        margin-left: 3px !important;\n        .dg-attribution__open2gis-button {\n            color: #454C4F !important;\n\n            .no-touch &:hover {\n                color: #286482 !important;\n            }\n        }\n    }\n\n    .dg-attribution__open2gis-button_name_open:before {\n        .notRepeatableBgWithSizes('DGAttribution_pin');\n    }\n}\n\n.leaflet-container .dg-attribution .dg-attribution__link {\n    background: linear-gradient(to right, rgba(8, 8, 8, .3), rgba(8, 8, 8, .3) 100%) 0 95% repeat-x !important;\n    background-size: 10px 1px !important;\n    color: #333 !important;\n    text-decoration: none !important;\n    font-size: 9px !important;\n    font-family: Helvetica, Arial, sans-serif !important;\n    cursor: pointer !important;\n\n    &:hover {\n        background-image: linear-gradient(to right, #080808, #080808 100%) !important;\n        color: #333 !important;\n        text-decoration: none !important;\n    }\n}\n"
  },
  {
    "path": "src/DGAttribution/src/DGAttribution.js",
    "content": "/**\n * Компонент отвечающий за копирайт на карте. В нем выводяться различные ссылки плюс логотип или кнопка.\n *\n * 1. Если в опциях карты передан logotype: true то будет логотип 2GIS\n * 2. Если на карте нет маркеров, то будет кнопка \"Открыть в 2ГИС\" и ссылка на 2ГИС (openLink2gis config.main.json)\n * 3. Если на карте есть 1 маркер, то будет кнопка \"Доехать с 2ГИС\" и ссылка на 2ГИС с параметрами для построения маршрута до этого маркера (ppLink2gis config.main.json)\n *\n * Компонент подписывается на события добавления и удаления слоев в карте, метод _mapEvents).\n * Если добавляется/удаляется маркер, то он добавляется/удаляется в массив _markers,\n * а затем первый маркер из этого массива сохраняется в _markerToRoute.\n * Поиск проезда будет предлагаться до маркера _markerToRoute.\n */\n\nDG.Control.Attribution.include(DG.Locale);\nDG.Control.Attribution.Dictionary = {};\nDG.Control.Attribution.include({\n    options: {\n        position: 'bottomright'\n    },\n\n    _getLink: function(linkType) {\n        /* eslint-disable camelcase */\n        var dictionary = {\n            ru: {\n                copyright_logo: 'https://2gis.ru/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.ru/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.ru/api-rules/',\n                open_link: 'https://2gis.ru',\n            },\n\n            kz: {\n                copyright_logo: 'https://2gis.kz/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.kz/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.kz/api-rules/',\n                open_link: 'https://2gis.kz',\n            },\n\n            it: {\n                copyright_logo: 'https://2gis.it/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.com/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.it/licensing-agreement/',\n                open_link: 'https://2gis.ru',\n            },\n\n            cz: {\n                copyright_logo: 'https://praha.2gis.cz/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.com/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.cz/api-rules/',\n                open_link: 'https://2gis.ru',\n            },\n\n            cl: {\n                copyright_logo: 'https://santiago.2gis.cl/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.com/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.cl/api-rules/',\n                open_link: 'https://2gis.ru',\n            },\n\n            cy: {\n                copyright_logo: 'https://info.2gis.com.cy/lemesos?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'https://dev.2gis.com/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.com.cy/api-rules/',\n                open_link: 'https://2gis.ru',\n            },\n\n            ae: {\n                copyright_logo: 'https://2gis.ae/dubai?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_apilink: 'http://dev.2gis.com/?utm_source=copyright&utm_medium=map&utm_campaign=partners',\n                copyright_license: 'https://law.2gis.ae/api-rules/',\n                open_link: 'https://2gis.ae',\n            }\n        };\n        /* eslint-enable camelcase */\n\n        var countryCode = (this._countryCode in dictionary) ? this._countryCode : 'ru';\n\n        return dictionary[countryCode][linkType];\n    },\n\n    _markerToRoute: undefined,\n    _markers: [],\n\n    _checkMarkerLayers: function() {\n        this._markerToRoute = this._markers.length != 1 ? undefined : this._markers[0];\n        this._update();\n    },\n\n    _mapEvents: {\n\n        layeradd: function(e) {\n            if (e.layer instanceof DG.Marker) {\n                this._markers.push(e.layer)\n                if (this._markers.length <= 2) {\n                    this._checkMarkerLayers();\n                }\n            }\n        },\n\n        layerremove: function(e) {\n            if (e.layer instanceof DG.Marker) {\n                var currentMarkers = [];\n                for (var i = 0; i < this._markers.length; i++) {\n                    if (this._markers[i] !== e.layer) {\n                        currentMarkers.push(this._markers[i])\n                    }\n                }\n                this._markers = currentMarkers;\n                if (this._markers.length <= 1) {\n                    this._checkMarkerLayers();\n                }\n            }\n        },\n\n    },\n\n    onAdd: function(map) {\n        if (!map._copyright) {\n            map._copyright = true;\n            this._first = true;\n        }\n\n        this._isDefaultKey = !map.options.key;\n        this._logotype = map.options.logotype;\n        this._open2gis = this._getLink('open_link')\n\n        this._map.on(this._mapEvents, this);\n\n        map.attributionControl = this;\n        this._container = DG.DomUtil.create('div', 'dg-attribution');\n        DG.DomEvent.disableClickPropagation(this._container);\n\n        for (var i in map._layers) {\n            if (map._layers[i].getAttribution) {\n                this.addAttribution(map._layers[i].getAttribution());\n            }\n        }\n\n        this._update();\n\n        DG.DomEvent\n            .on(this._container, 'touchstart', this._updateLink, this)\n        return this._container;\n    },\n\n    _updateLink: function(e) {\n        if (e.target.name === 'linkButton') {\n            this._open2gis = this._getOpenUrl();\n            e.target.href = this._open2gis;\n        }\n    },\n\n    _update: function(lang, countryCode) {\n        if (!this._map) { return; }\n\n        if (typeof countryCode !== 'undefined') {\n            this._countryCode = countryCode;\n        }\n\n        var attribs = [];\n\n        for (var i in this._attributions) {\n            if (this._attributions[i]) {\n                attribs.push(i);\n            }\n        }\n\n        var prefixAndAttribs = [],\n            copyright = '';\n\n        if (this._first) {\n            copyright = this._getAttributionHTML(lang);\n        }\n\n        if (this.options.prefix) {\n            prefixAndAttribs.push(this.options.prefix);\n        }\n        if (attribs.length) {\n            prefixAndAttribs.push(attribs.join(', '));\n        }\n\n        this._container.innerHTML = copyright + prefixAndAttribs.join(' | ');\n\n    },\n\n\n    _getOpenUrl: function() {\n        if (this._markerToRoute) {\n            return DG.Util.template(DG.config.ppLink2gis, {\n                'gislink': this._getLink('open_link'),\n                'center': this._map.getCenter().lng + ',' + this._map.getCenter().lat,\n                'zoom': this._map.getZoom(),\n                'rsType': this._map.getZoom() > 11 ? 'bus' : 'car',\n                'point': this._markerToRoute._latlng.lng + ',' + this._markerToRoute._latlng.lat\n            });\n        }\n\n        return DG.Util.template(DG.config.openLink2gis, {\n            'gislink': this._getLink('open_link'),\n            'center': this._map.getCenter().lng + ',' + this._map.getCenter().lat,\n            'zoom': this._map.getZoom(),\n        });\n    },\n    _getData: function(lang) {\n        lang = lang || this._map.getLang();\n        var btn =\n        {\n            name: 'open',\n            label: this._markerToRoute ? this.t('route_on') : this.t('open_on'),\n        }\n\n        // Do not show link button if button don't have translate to current language or map options logotype set true\n        var isHideButton = btn.label == 'open_on' || btn.label == 'route_on' || this._logotype;\n\n        return {\n            'logotype': isHideButton,\n            'work_on': this.t('work_on'),\n            'has_no_key': this._isDefaultKey ? this.t('has_no_key') : null,\n            'lang': lang,\n            'copyright_apilink': this._getLink('copyright_apilink'),\n            'copyright_license': this._getLink('copyright_license'),\n            'copyright_logo': this._getLink('copyright_logo'),\n            'open2gis_link': this._open2gis,\n            'open2gis_name': 'linkButton',\n            'license_agreement': this.t('license_agreement'),\n            'dir': lang !== 'ar' ? 'ltr' : 'rtl',\n            'btn': btn\n        };\n    },\n    _getAttributionHTML: function(lang) {\n        return DG.dust('DGAttribution/copyright', this._getData(lang));\n    },\n    _renderTranslation: function(e) {\n        this._update(e.lang);\n    }\n});\n\nDG.Map.addInitHook(function() {\n    if (!this._copyright) {\n        DG.control.attribution().addTo(this);\n    }\n});\n"
  },
  {
    "path": "src/DGAttribution/templates/copyright.dust",
    "content": "<div class=\"dg-attribution__copyright\">\n    <ul class=\"dg-attribution__links\">\n        <li class=\"dg-attribution__link-item\">\n            <a href=\"{copyright_apilink}\" target=\"_blank\" class=\"dg-attribution__link\" dir=\"{dir}\">{work_on}</a>\n        </li>\n        <li class=\"dg-attribution__link-item\">\n            <a href=\"{copyright_license}\" target=\"_blank\" class=\"dg-attribution__link\">{license_agreement}</a>\n        </li>\n        {?has_no_key}\n            <li class=\"dg-attribution__warning-message\">{has_no_key}</li>\n        {/has_no_key}\n    </ul>\n    {?logotype}\n    <a href=\"{copyright_logo}\" target=\"_blank\" class=\"dg-attribution__logo-url\"></a>\n    {:else}\n        {#btn}\n            <div class=\"dg-attribution__button-wrapper\">\n                <a class=\"dg-attribution__open2gis-button_name_{name} dg-attribution__open2gis-button dg-attribution__open2gis-icon-button\"\n                    {?open2gis_link}\n                        href={open2gis_link} target=\"_blank\" name={open2gis_name}\n                    {:else}\n                        href=\"javascript:void(0)\"\n                    {/open2gis_link}\n                    >{label}</a>\n            </div>\n        {/btn}\n    {/logotype}\n</div>\n"
  },
  {
    "path": "src/DGAttribution/test/DGAttributionSpec.js",
    "content": "describe('DG.Control.Attribution', function() {\n    var dictionaryLicense = {\n            ru: 'соглашение',\n            en: 'agreement',\n            it: 'licenza',\n            es: 'licencia',\n            cs: 'smlouva'\n        },\n\n        latLngWithoutProject = [54.83391822270635, 80.34439086914064],\n        latLngCenterNsk = [55.017493, 82.819576],\n\n        mapContainer,\n        map,\n        attribution;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        map = new DG.Map(mapContainer, {\n            center: latLngCenterNsk,\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n        attribution = mapContainer.getElementsByClassName('dg-attribution')[0];\n    });\n\n    after(function() {\n        dictionaryLicense = latLngWithoutProject = latLngCenterNsk = mapContainer = map = attribution = null;\n    });\n\n    describe('check init', function() {\n        it('should html element 2gis copyright', function() {\n            var el = attribution.getElementsByClassName('dg-attribution__copyright');\n\n            expect(el.length).to.be(1);\n        });\n    });\n\n    describe('change languages', function() {\n        after(function() {\n           map.setLang('ru');\n        });\n\n        Object.keys(dictionaryLicense).forEach(function(el) {\n            it('should copyright html ' + el + ' word license', function() {\n                map.setLang(el);\n                expect(attribution.innerHTML).to.contain(dictionaryLicense[el]);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCore/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>DG.then demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n</head>\n<body>\n    <div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n    <script type=\"text/javascript\">\n        var map,\n        balloonHTML;\n\n    DG.then(function () {\n        map = new DG.Map('map', {\n            center: new DG.LatLng(54.980206086231, 82.898068362003),\n            zoom: 15,\n            dgGeoclicker: true,\n            key: DG.config.key || 'Your API access key'\n        });\n        balloonHTML = '<a href=\"http://www.2gis.ru/\" target=\"_blank\">\\n\\\n            <img src=\"2gis-logo.png\" alt=\"2GIS\" title=\"2GIS\" width=\"146\" height=\"70\" style=\"border: none\"></a>\\n\\\n            <p>Компания «ДубльГИС»</p>Тел.: (383) 363-05-55<br />Адрес: г. Новосибирск, Карла Маркса площадь, 7<br />\\n\\\n            (МФК «Сан Сити»), 13 этаж';\n\n        DG.marker([54.980206086231, 82.898068362003]).addTo(map).bindPopup(balloonHTML).openPopup();\n\n    }).then(function () {\n        console.log('second handler');\n    }).then(function () {\n        setTimeout(function (argument) {\n            console.log('still works');\n        }, 2000)\n    });\n\n    setTimeout(function (argument) {\n        DG.then(function(){\n            console.log('deffered handler');\n        }).then(function () {\n            console.log('another one');\n        })\n    }, 4000)\n\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGCore/skin/basic/less/dg-core.less",
    "content": "[class^='dg-'],\n[class^='dg-']:before,\n[class^='dg-']:after {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n    margin: 0;\n    padding: 0;\n    vertical-align: baseline;\n    font-weight: inherit;\n    font-style: inherit;\n    font-size: 1em;\n    font-family: inherit;\n    line-height: 1.2;\n}\n\n[class^='dg-'] > [class^='dg-']:last-child {\n    margin-bottom: 0;\n}\n\n[class^='dg-'] img,\n[class^='dg-'] abbr,\n[class^='dg-'] fieldset {\n    border: 0;\n}\n\n[class^='dg-'] blockquote,\n[class^='dg-'] q {\n    quotes: none;\n}\n\n[class^='dg-'] blockquote:before,\n[class^='dg-'] blockquote:after,\n[class^='dg-'] q:before,\n[class^='dg-'] q:after {\n    content: '';\n    content: none;\n}\n\n[class^='dg-'] ul,\n[class^='dg-'] ol {\n    list-style: none;\n}\n\n[class^='dg-'] table {\n    border-spacing: 0;\n    border-collapse: collapse;\n}\n\n[class^='dg-'] caption,\n[class^='dg-'] th {\n    text-align: left;\n}\n\n[class^='dg-'] th,\n[class^='dg-'] td {\n    vertical-align: middle;\n}\n\n[class^='dg-'] input::-moz-focus-inner,\n[class^='dg-'] button::-moz-focus-inner {\n    padding: 0;\n    border: 0;\n}\n"
  },
  {
    "path": "src/DGCore/src/DGCore.js",
    "content": "require('leaflet');\nrequire('html5shiv');\n\n// DG inheritance\nvar oldDG = window.DG;\nvar DG = new (\n    (function() {\n        var DgApi = function() {},\n            DgApiCore = function() {};\n\n        DgApiCore.prototype = L;\n        DgApi.prototype = new DgApiCore();\n\n        return DgApi;\n    })()\n)();\n\nfor (var prop in oldDG) {\n    if (oldDG.hasOwnProperty(prop) && typeof DG[prop] === 'undefined') {\n        DG[prop] = oldDG[prop];\n    }\n}\n\nwindow.__dgApi__ = window.__dgApi__ || {};\nDG.version = window.__dgApi__.version;\nDG.Icon.Default.imagePath  = '../img/vendors/leaflet';\n\n// Improve IHandler\nDG.Map.include({\n    addHandler: function(name, HandlerClass) {\n        if (!HandlerClass) { return this; }\n\n        var options = this.options[name],\n            param = (options === Object(options)) ? options : null,\n            handler = this[name] = new HandlerClass(this, param);\n\n        this._handlers.push(handler);\n\n        if (options) {\n            handler.enable();\n        }\n\n        return this;\n    }\n});\n\n// Apply class to map container for detect when we dont need hover effects\nDG.Map.addInitHook(function() {\n    if (!DG.Browser.touchEnabled) {\n        DG.DomUtil.addClass(this._container, 'no-touch');\n    }\n});\n\nwindow.DG = DG;\nmodule.exports = DG;\n"
  },
  {
    "path": "src/DGCore/src/DGplugin.js",
    "content": "DG.plugin = function(plugins) {\n    var count,\n        jsReg = new RegExp(/.js$/i),\n        cssReg = new RegExp(/.css$/i);\n\n    return new Promise(function(resolve) {\n        function checkLoading() {\n            count--;\n\n            if (count === 0) {\n                resolve();\n            }\n        }\n\n        function appendJS(link) {\n            var js = document.createElement('script');\n            js.setAttribute('type', 'text/javascript');\n            js.setAttribute('src', link);\n            js.onload = function() {\n                checkLoading();\n            };\n            js.onerror = function() {\n                checkLoading();\n            };\n            // load/error for IE\n            js.onreadystatechange = function() {\n                if (js.readyState === 'complete' || js.readyState === 'loaded') {\n                    checkLoading();\n                }\n            };\n\n            document.getElementsByTagName('head')[0].appendChild(js);\n        }\n\n        function appendCSS(link) {\n            var css = document.createElement('link');\n            css.setAttribute('rel', 'stylesheet');\n            css.setAttribute('type', 'text/css');\n            css.setAttribute('href', link);\n            document.getElementsByTagName('head')[0].appendChild(css);\n\n            checkLoading();\n        }\n\n        function isJs(url) {\n            return jsReg.test(url);\n        }\n\n        function isCss(url) {\n            return cssReg.test(url);\n        }\n\n        function appendAsset(asset) {\n            if (isJs(asset)) {\n                appendJS(asset);\n            } else if (isCss(asset)) {\n                appendCSS(asset);\n            } else {\n                count--;\n            }\n        }\n\n        if (DG.Util.isArray(plugins)) {\n            count = plugins.length;\n            plugins.forEach(function(plugin) {\n                appendAsset(plugin);\n            });\n        }\n\n        if (typeof plugins === 'string') {\n            count = 1;\n            appendAsset(plugins);\n        }\n    });\n};\n"
  },
  {
    "path": "src/DGCore/src/DGthen.js",
    "content": "var handlers = window.__dgApi__.callbacks || [],\n    chain = Promise.resolve();\n\nhandlers.forEach(function(handlers) {\n    chain = chain.then(handlers[0], handlers[1]);\n});\n\nDG.then = function(resolve, reject) {\n    return chain.then(resolve, reject);\n};\n\n// IE8 throw error if `chain.catch`\n/* eslint-disable dot-notation, no-console */\nchain['catch'](function(err) {\n    console.error(err);\n});\n/* eslint-enable dot-notation, no-console */\n"
  },
  {
    "path": "src/DGCustomization/skin/basic/less/dg-customization.less",
    "content": ".dg-customization__marker {\r\n    background-repeat: no-repeat;\r\n\r\n    &:before {\r\n        position: absolute;\r\n        top: 0;\r\n        left: 0;\r\n        width: 100%;\r\n        height: 100%;\r\n        background-image: inherit;\r\n        background-size: contain;\r\n        background-repeat: no-repeat;\r\n        transition: opacity ease-in-out .2s, transform ease-in-out .2s;\r\n        transform: scale(1, 1);\r\n        transform-origin: 50% 100%;\r\n    }\r\n}\r\n\r\n.dg-customization__marker_type_mushroom {\r\n    .notRepeatableBgWithSizes('DGCustomization__marker', true);\r\n    transform-origin: 50% 100%;\r\n    animation: dg-customization__show-marker .2s;\r\n\r\n    &:focus {\r\n        outline: 0;\r\n    }\r\n\r\n    .no-touch &:hover {\r\n        .notRepeatableBg('DGCustomization__markerHover', true);\r\n    }\r\n\r\n    &:active,\r\n    .no-touch &:active {\r\n        .notRepeatableBg('DGCustomization__markerActive', true);\r\n    }\r\n}\r\n\r\n@keyframes dg-customization__show-marker {\r\n    from {\r\n        opacity: 0;\r\n    }\r\n    to {\r\n        opacity: 1;\r\n    }\r\n}\r\n\r\n.dg-customization__marker_appear {\r\n    background-position: 999px;\r\n\r\n    &:before {\r\n        content: '';\r\n    }\r\n}\r\n\r\n.dg-customization__marker_disappear {\r\n    background-position: 999px;\r\n    pointer-events: none;\r\n\r\n    &:before {\r\n        visibility: hidden;\r\n        content: '';\r\n        opacity: 0;\r\n        transform: scale(1.2, 1.8);\r\n        animation: dg-customization__marker-to-callout .2s;\r\n    }\r\n}\r\n\r\n@keyframes dg-customization__marker-to-callout {\r\n    0% {\r\n        visibility: visible;\r\n        opacity: 1;\r\n        transform: scale(1, 1);\r\n    }\r\n    100% {\r\n        visibility: visible;\r\n        opacity: 0;\r\n        transform: scale(1.2, 1.8);\r\n    }\r\n}\r\n\r\n.dg-dragging-false {\r\n    touch-action: auto;\r\n    -ms-touch-action: auto;\r\n}\r\n\r\n.dg-error-message {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 100%;\r\n    background-color: rgba(195,194,179,0.58);\r\n    color: white;\r\n    display: flex;\r\n    justify-content: center;\r\n    align-items: center;\r\n    font-size: 24px;\r\n    text-align: center;\r\n    z-index: 9999;\r\n    font-family: Helvetica, Arial, sans-serif;\r\n    font-weight: Bold;\r\n    pointer-events: none;\r\n    box-sizing: border-box;\r\n    padding: 0 20px;\r\n}\r\n\r\n"
  },
  {
    "path": "src/DGCustomization/skin/basic/less/leaflet.ie.less",
    "content": ".leaflet-right {\n    width: 40px;\n}\n"
  },
  {
    "path": "src/DGCustomization/skin/basic/less/leaflet.less",
    "content": ".leaflet-container {\r\n    z-index: 0;\r\n    background: rgb(247, 243, 223);\r\n    cursor: default;\r\n\r\n    &:fullscreen {\r\n        width: 100% !important;\r\n        height: 100% !important;\r\n    }\r\n}\r\n\r\n.leaflet-dragging,\r\n.leaflet-dragging .leaflet-clickable,\r\n.leaflet-dragging .leaflet-container {\r\n    cursor: move;\r\n}\r\n\r\n.leaflet-control a:focus,\r\n.leaflet-control a {\r\n    outline: none !important;\r\n}\r\n\r\n.leaflet-container .leaflet-control-attribution {\r\n    background-color: transparent;\r\n    box-shadow: none;\r\n}\r\n"
  },
  {
    "path": "src/DGCustomization/skin/basic/skin.config.js",
    "content": "DG.configTheme = DG.configTheme || {};\n\nDG.configTheme.markersData = {\n    iconSize: [22, 34],\n    className: 'dg-customization__marker dg-customization__marker_type_mushroom',\n    iconAnchor: [10, 32]\n};\n"
  },
  {
    "path": "src/DGCustomization/src/DGCustomization.js",
    "content": "// Fix a lot of bugs with pinch-zooming\n// See https://github.com/2gis/mapsapi/issues/327\nDG.Map.mergeOptions({\n    bounceAtZoomLimits: false\n});\n\n//Inject observing localization change\nvar controlAddTo = DG.Control.prototype.addTo;\n\nDG.Control.include({\n    addTo: function(map) {\n        map.on('langchange', this._renderTranslation, this);\n\n        return controlAddTo.call(this, map);\n    },\n    _renderTranslation: function() {}\n});\n\n// Just a copy of toPoint function\n// https://github.com/Leaflet/Leaflet/blob/e079588573d0b0c649df95c3d6005373e87f323a/src/geometry/Point.js#L198-L222\nfunction toPoint(x, y, round) {\n    if (x instanceof DG.Point) {\n        return x;\n    }\n    if (DG.Util.isArray(x)) {\n        return new DG.Point(x[0], x[1]);\n    }\n    if (x === undefined || x === null) {\n        return x;\n    }\n    if (typeof x === 'object' && 'x' in x && 'y' in x) {\n        return new DG.Point(x.x, x.y);\n    }\n    return new DG.Point(x, y, round);\n}\n\n// Add ability to pass HTMLElement in DG.divIcon html parameter\n// See https://github.com/Leaflet/Leaflet/pull/6571\n// TODO: Remove it after updating leaflet at least to v1.5.0\nDG.DivIcon.include({\n    createIcon: function(oldIcon) {\n        var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),\n            options = this.options;\n\n        if (options.html instanceof Element) {\n            DG.DomUtil.empty(div);\n            div.appendChild(options.html);\n        } else {\n            div.innerHTML = options.html !== false ? options.html : '';\n        }\n\n        if (options.bgPos) {\n            var bgPos = toPoint(options.bgPos);\n            div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';\n        }\n        this._setIconStyles(div, 'icon');\n\n        return div;\n    },\n});\n\n// Add some browser detection\nDG.Browser.safari51 = DG.Browser.safari && navigator.userAgent.indexOf('Version/5.1') !== -1;\n\n// DG.Browser.touch checks whether touch events supported or not; touchEnabled checks if it's a touch device\nvar msPointer = navigator.msPointerEnabled && navigator.msMaxTouchPoints && !window.PointerEvent;\nvar pointer = (window.PointerEvent && navigator.pointerEnabled && navigator.maxTouchPoints) || msPointer;\nvar documentTouch = window.DocumentTouch && document instanceof window.DocumentTouch;\nDG.Browser.touchEnabled = pointer || 'ontouchstart' in window || documentTouch;\n\n// Applies 2GIS divIcon to marker\nDG.Marker.prototype.options.icon = DG.divIcon(DG.configTheme.markersData);\n\n// support old option clickable\nvar utilSetOptions = DG.Util.setOptions;\n\nDG.setOptions = L.setOptions = DG.Util.setOptions = function(obj, options) {\n    if (options && typeof options.clickable !== 'undefined') {\n        options.interactive = options.clickable;\n    }\n\n    return utilSetOptions.call(this, obj, options);\n};\n\nDG.Layer.mergeOptions({\n    nonBubblingEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu']\n});\n\nL.Canvas.include({\n    // overwrite the function without mousemove debounce as it breaks metalayers events\n    _initContainer: function() {\n        var container = this._container = document.createElement('canvas');\n\n        L.DomEvent\n            .on(container, 'mousemove', this._onMouseMove, this)\n            .on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)\n            .on(container, 'mouseout', this._handleMouseOut, this);\n\n        this._ctx = container.getContext('2d');\n    }\n});\n\n// Monitor geometry usage\n// TODO: remove after successful research\nif (DG.Path) {\n    var pathInitialize = DG.Path.prototype.onAdd;\n\n    DG.Path.include({\n        onAdd: function(map) {\n            return pathInitialize.call(this, map);\n        },\n    });\n}\n"
  },
  {
    "path": "src/DGCustomization/src/DGMap.ApiKeyValidator.js",
    "content": "DG.ApiKeyValidator = DG.Class.extend({\n    initialize: function(apiKey, mapContainer) {\n        this.apiKey = apiKey;\n        this.endpoint = DG.config.keyServer + apiKey + DG.config.keyServices;\n        this.isLoading = false;\n        this.attempts = 0;\n        this.lastTimeout = undefined;\n        this.request = null;\n        this.MAX_ATTEMPTS = 4;\n        this.keyRequestInterval = [0, 2, 2, 2];\n        this.isErrorWasShown = false;\n        this.mapContainer = mapContainer;\n    },\n\n    validate: function(callback) {\n        if (this.isLoading) {\n            return;\n        }\n\n        this.isLoading = true;\n        this.attempts = 0;\n        this._makeAttempt(callback);\n    },\n\n    validateKeyResponse: function() {\n        this.validate(function(response) {\n            if (!response || this._isResponseInvalid(response)) {\n                this._showError();\n            }\n        }.bind(this));\n    },\n\n    _makeAttempt: function(callback) {\n        if (this.attempts > 0) {\n            this.lastTimeout = window.setTimeout(function() {\n                this._clearLastTimeout();\n                this._executeRequest(callback);\n            }.bind(this), this.keyRequestInterval[this.attempts] * 1000);\n        } else {\n            this._executeRequest(callback);\n        }\n    },\n\n    _isResponseInvalid: function(response) {\n        return (\n            response.meta.code === 400 ||\n            response.meta.code === 404 ||\n            response.result &&\n            (!response.result.service.is_active ||\n                !response.result.is_active ||\n                !['ok', 'exceeded'].includes(response.result.service.status.code)\n            )\n        );\n    },\n\n    _showError: function() {\n\n        if (!this.isErrorWasShown && this.mapContainer) {\n            var errorMessage = DG.DomUtil.create('div', 'dg-error-message');\n            errorMessage.innerHTML = 'Your RasterJS API key is invalid. Please contact api@2gis.com to get RasterJS API key.';\n            this.mapContainer.appendChild(errorMessage);\n            this.isErrorWasShown = true;\n        }\n    },\n\n    _executeRequest: function(callback) {\n        this.request = DG.ajax(this.endpoint, {\n            type: 'GET',\n            success: function(response) {\n                this.isLoading = false;\n                callback(response);\n            }.bind(this),\n            error: function(xhr) {\n                this._handleError(callback, xhr.status);\n            }.bind(this)\n        });\n    },\n\n    _handleError: function(callback, status) {\n        this.attempts++;\n\n        if (this.attempts < this.MAX_ATTEMPTS) {\n            this._makeAttempt(callback);\n        } else {\n            this.isLoading = false;\n            callback({\n                meta: {\n                    code: status,\n                    message: 'Failed to validate API key'\n                },\n            });\n        }\n    },\n\n    _clearLastTimeout: function() {\n        if (this.lastTimeout !== undefined) {\n            clearTimeout(this.lastTimeout);\n            this.lastTimeout = undefined;\n        }\n    },\n\n    destroy: function() {\n        this._clearLastTimeout();\n        this.isLoading = false;\n    }\n});\n"
  },
  {
    "path": "src/DGCustomization/src/DGMap.BaseLayer.js",
    "content": "DG.Map.addInitHook(function() {\n    var errorUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAAA1BMVEX28t5R0k5UAAAAH0lEQVR4Xu3AAQkAAADCMPunNsdhWxwAAAAAAAAAwAEhAAABg2UP5AAAAABJRU5ErkJggg==';\n    var errorRuUrl = DG.config.protocol + DG.config.baseUrl + '/img/nomap_ru.png';\n\n    var TileLayer = DG.Browser.mobile ? DG.MobileTileLayer : DG.TileLayer;\n\n    var BaseLayer = TileLayer.extend({\n        initialize: function(url, options) {\n            this._isDg = true;\n            TileLayer.prototype.initialize.call(this, url, options);\n        },\n\n        getTiles: function() {\n            return this._tiles;\n        }\n    });\n\n    var apiKey = this.options.key || DG.config.key;\n    var mapContainer = this.getContainer();\n    var validator = new DG.ApiKeyValidator(apiKey, mapContainer);\n    var showCommPoi = (this.options.showCommPoi ? '' : '&layerType=nc');\n    validator.validateKeyResponse();\n\n    var protocol = this.options.protocol || DG.config.secureProtocol;\n    // Check that last symbol is colon, and if not add it\n    if (protocol[protocol.length - 1] !== ':') {\n        protocol = protocol + ':';\n    }\n\n    var tileUrl = protocol + (DG.Browser.retina ? DG.config.retinaTileServer : DG.config.tileServer) + showCommPoi;\n    var arabicTileUrl = protocol +\n        (DG.Browser.retina ? DG.config.arabicRetinaTileServer : DG.config.arabicTileServer) + showCommPoi;\n\n    var previewTileUrl = protocol +\n        (DG.Browser.retina ? DG.config.previewRetinaTileServer : DG.config.previewTileServer) + showCommPoi;\n    var arabicPreviewTileUrl = protocol +\n        (DG.Browser.retina ? DG.config.arabicPreviewRetinaTileServer : DG.config.arabicPreviewTileServer) + showCommPoi;\n\n    this.baseLayer = new BaseLayer(tileUrl, {\n        subdomains: '0123',\n        errorTileUrl: this.getLang() === 'ru' ? errorRuUrl : errorUrl,\n        detectRetina: DG.config.detectRetina,\n        maxZoom: 19,\n        maxNativeZoom: 19,\n        zIndex: 0,\n        updateWhenIdle: false, // it's okay with preview tiles\n        previewUrl: previewTileUrl,\n        key: apiKey,\n        crossOrigin: true // force Origin request header\n    });\n\n    var currentTilesLang = ''; // 'ar' | ''\n\n    function updateTileUrl() {\n        var lang = this.getLang();\n        var project = this.projectDetector && this.projectDetector.getProject();\n\n        if (lang === 'ru' && !project) {\n            this.baseLayer.options.errorTileUrl = errorRuUrl;\n        } else {\n            this.baseLayer.options.errorTileUrl = errorUrl;\n        }\n\n        // Change 2GIS tiles for Arabic language in Dubai project\n        if (currentTilesLang === '' && lang === 'ar' && project && project.country_code === 'ae') {\n            currentTilesLang = 'ar';\n            this.baseLayer.setUrl(arabicTileUrl);\n            if (this.baseLayer.setPreviewUrl) {\n                this.baseLayer.setPreviewUrl(arabicPreviewTileUrl);\n            }\n\n        } else if (currentTilesLang === 'ar' && (lang !== 'ar' || (!project || project.country_code !== 'ae'))) {\n            currentTilesLang = '';\n            this.baseLayer.setUrl(tileUrl);\n            if (this.baseLayer.setPreviewUrl) {\n                this.baseLayer.setPreviewUrl(previewTileUrl);\n            }\n        }\n    }\n\n    updateTileUrl.call(this);\n\n    this.baseLayer.addTo(this);\n\n    this.on({\n        langchange: updateTileUrl,\n        projectchange: updateTileUrl,\n        projectleave: updateTileUrl\n    }, this);\n});\n"
  },
  {
    "path": "src/DGCustomization/src/DGMap.Drag.js",
    "content": "/**\n * This customization fixes unwanted inertia movement after sudden drag stops\n * See https://github.com/Leaflet/Leaflet/pull/4048.\n * If this PR ever gets merged, this file can be removed.\n */\nvar onDragEnd = DG.Map.Drag.prototype._onDragEnd;\n\nDG.Map.Drag.include({\n    _rememberTimeAndPosition: function() {\n        var time = this._lastTime = +new Date(),\n            pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;\n\n        this._positions.push(pos);\n        this._times.push(time);\n\n        // Remove all data points older than 50 ms\n        while (time - this._times[0] > 50) {\n            this._positions.shift();\n            this._times.shift();\n        }\n    },\n\n    _onDrag: function(e) {\n        if (this._map.options.inertia) {\n            this._rememberTimeAndPosition();\n        }\n\n        this._map\n            .fire('move', e)\n            .fire('drag', e);\n    },\n\n    _onDragEnd: function() {\n        if (this._map.options.inertia && !DG.Browser.touch) {\n            this._rememberTimeAndPosition();\n        }\n\n        onDragEnd.call(this);\n    }\n});\n"
  },
  {
    "path": "src/DGCustomization/src/DGMap.TilesCheck.js",
    "content": "DG.Map.mergeOptions({\n    tilesCheck: true\n});\n\nDG.Map.TilesCheck = DG.Handler.extend({\n    initialize: function(map) {\n        this._map = map;\n        this._layer = map.baseLayer;\n\n        this._moveStartEventCounter = 0;\n        this._moveEndEventCounter = 0;\n\n        this._loadingEventCounter = 0;\n        this._loadEventCounter = 0;\n    },\n\n    addHooks: function() {\n        this._map.on(this._mapEvents, this);\n        this._layer.on(this._layerEvents, this);\n    },\n\n    removeHooks: function() {\n        this._map.off(this._mapEvents, this);\n        this._layer.off(this._layerEvents, this);\n    },\n\n    _mapEvents: {\n        layeradd: function(e) {\n            if (e.layer == this._layer) {\n                this.enable();\n            }\n        },\n\n        layerremove: function(e) {\n            if (e.layer == this._layer) {\n                this.disable();\n            }\n        },\n\n        movestart: function() {\n            this._stopWaiting();\n\n            this._moveStartEventCounter++;\n            this._isWaiting = true;\n        },\n\n        moveend: function() {\n            this._moveEndEventCounter++;\n\n            if (!this._isWaiting && this._moveStartEventCounter !== this._moveEndEventCounter) { return; }\n\n            this._isMoveEnd = true;\n\n            this._checkWaiting();\n        }\n    },\n\n    _layerEvents: {\n        loading: function() {\n            this._loadingEventCounter++;\n        },\n\n        load: function() {\n            this._loadEventCounter++;\n\n            if (!this._isWaiting && this._loadingEventCounter !== this._loadEventCounter) { return; }\n\n            this._isLoad = true;\n\n            this._checkWaiting();\n        }\n    },\n\n    _stopWaiting: function() {\n        this._isWaiting = false;\n        this._isMoveEnd = false;\n        this._isLoad = false;\n    },\n\n    _checkWaiting: function() {\n        if (this._isWaiting && this._isLoad && this._isMoveEnd) {\n            this._stopWaiting();\n            this._resetCounters();\n            this._checkTiles();\n        }\n    },\n\n    _checkTiles: function() {\n        if (this._map.getTileLayersNumber() !== 0 || !this._map._loaded) { return; }\n\n        var tileZoom = this._layer._tileZoom;\n        var errorUrl = this._layer.options.errorTileUrl;\n        var tiles = this._layer.getTiles();\n\n        for (var i in tiles) {\n            if (tiles[i].coords.z === tileZoom && tiles[i].el.src !== errorUrl) {\n                return;\n            }\n        }\n\n        this._map.zoomOut();\n    },\n\n    _resetCounters: function() {\n        this._moveStartEventCounter = 0;\n        this._moveEndEventCounter = 0;\n\n        this._loadingEventCounter = 0;\n        this._loadEventCounter = 0;\n    }\n});\n\nDG.Map.addInitHook('addHandler', 'tilesCheck', DG.Map.TilesCheck);\n"
  },
  {
    "path": "src/DGCustomization/src/DGMap.js",
    "content": "var initMap = DG.Map.prototype.initialize,\n    panBy = DG.Map.prototype.panBy,\n    getBoundsZoom = DG.Map.prototype.getBoundsZoom,\n    setMaxZoom = DG.Map.prototype.setMaxZoom;\n\n// Restrict zoom level according to 2gis projects, in case if dgTileLayer is only one\nDG.Map.include({\n\n    // number of tileLayers without 2gis layers\n    _tileLayersNumber: 0,\n\n    _mapMaxZoomCache: null,\n\n    //TODO try refactor it after up on new leaflet (> 0.7)\n    initialize: function(id, options) { // (HTMLElement or String, Object)\n        // Override default wheelPxPerZoomLevel value to avoid zooming too fast\n        // on mouse wheel rotation\n        // See https://github.com/2gis/mapsapi/issues/343\n        options = DG.extend({wheelPxPerZoomLevel: 10000}, options);\n\n        this.metaLayers = [];\n\n        initMap.call(this, id, options);\n\n        //  Project must be checked after BaseLayer init which occurs in InitHook (see orig method definition)\n        if (this.options.center && this.options.zoom !== undefined) {\n            this.setView(DG.latLng(this.options.center), this.options.zoom, {reset: true});\n        }\n\n        this._lastMetalayer = {\n            layer: undefined,\n            entity: undefined\n        };\n    },\n\n    setView: function(center, zoom, options) {\n        this._restrictZoom(center, zoom);\n\n        zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);\n        center = this._limitCenter(DG.latLng(center), zoom, this.options.maxBounds);\n        options = options || {};\n\n        if (options.animate) {\n            options.animate = this._testAnimation(center);\n        }\n\n        this._stop();\n\n        if (this._loaded && !options.reset && options !== true) {\n\n            if (options.animate !== undefined) {\n                options.zoom = DG.extend({\n                    animate: options.animate,\n                    duration: options.duration\n                }, options.zoom);\n                options.pan = DG.extend({\n                    animate: options.animate,\n                    duration: options.duration\n                }, options.pan);\n            }\n\n            // try animating pan or zoom\n            var animated = (this._zoom !== zoom) ?\n                this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :\n                this._tryAnimatedPan(center, options.pan);\n\n            if (animated) {\n                // prevent resize handler call, the view will refresh after animation anyway\n                clearTimeout(this._sizeTimer);\n                return this;\n            }\n        }\n\n        // animation didn't start, just reset the map view\n        this._resetView(center, zoom);\n\n        return this;\n    },\n\n    panBy: function(offset, options) {\n        var map = panBy.call(this, offset, options);\n\n        var zoom = this._restrictZoom(this.getCenter());\n        if (this.getZoom() > zoom) {\n            this.setZoom(zoom);\n        }\n\n        return map;\n    },\n\n    getBoundsZoom: function(bounds, inside, padding) {\n        bounds = DG.latLngBounds(bounds);\n        this._restrictZoom(bounds);\n        return getBoundsZoom.call(this, bounds, inside, padding);\n    },\n\n    getTileLayersNumber: function() {\n        return this._tileLayersNumber;\n    },\n\n    setMaxZoom: function(zoom) {\n        this._mapMaxZoomCache = null;\n        return setMaxZoom.call(this, zoom);\n    },\n\n    _testAnimation: function(coords) {//if we jump to other project - disable animation\n        if (this.projectDetector.enabled()) {\n            var projectFrom = this.projectDetector.getProject(),\n                projectTo = this.projectDetector.isProjectHere(coords);\n\n            if (projectFrom && projectTo) {\n                return projectFrom.code === projectTo.code;\n            }\n        }\n\n        return true;\n    },\n\n    _updateTileLayers: function(e) {\n        if (!(e.layer instanceof DG.TileLayer) || e.layer._isDg) { return; }\n\n        if (e.type === 'layeradd') {\n            this._tileLayersNumber++;\n        } else {\n            this._tileLayersNumber--;\n        }\n    },\n\n    _getNewBounds: function(coords, zoom) {\n        if (coords instanceof DG.LatLngBounds) {\n            return coords;\n        }\n\n        var point = this.project(coords, zoom);\n        var screenSize = this.getSize().divideBy(2);\n\n        var sw = this.unproject(point.subtract(screenSize), zoom);\n        var ne = this.unproject(point.add(screenSize), zoom);\n\n        return DG.latLngBounds(sw, ne);\n    },\n\n    _restrictZoom: function(coords, zoom) {\n        if (this._layers &&\n            this.projectDetector.enabled() &&\n            (this._tileLayersNumber === 0)) {\n\n            var mapOptions = this.options,\n                isMapMaxZoom = !!mapOptions.maxZoom,\n                dgTileLayer = this.baseLayer,\n                bounds = this._getNewBounds(coords, zoom),\n                project = this.projectDetector.isProjectHere(bounds);\n\n            if (isMapMaxZoom) {\n                if (!this._mapMaxZoomCache) {\n                    if (this.baseLayer.options.detectRetina && DG.Browser.retina && mapOptions.maxZoom > 0) {\n                        mapOptions.maxZoom--;\n                    }\n\n                    this._mapMaxZoomCache = mapOptions.maxZoom;\n                }\n                mapOptions.maxZoom = (this._mapMaxZoomCache && project) ? this._mapMaxZoomCache :  DG.config.projectLeaveMaxZoom;\n                if (project) {\n                    this._mapMaxZoomCache = mapOptions.maxZoom;\n                }\n\n                return mapOptions.maxZoom;\n            } else {\n                if (project) {\n                    if (dgTileLayer.options.detectRetina && DG.Browser.retina && project.maxZoom > 0) {\n                        dgTileLayer.options.maxZoom = project.maxZoom - 1;\n                    } else {\n                        dgTileLayer.options.maxZoom = project.maxZoom;\n                    }\n                } else {\n                    dgTileLayer.options.maxZoom = DG.config.projectLeaveMaxZoom;\n                }\n\n                dgTileLayer.options.maxNativeZoom = dgTileLayer.options.maxZoom;\n                this._updateZoomLevels();\n\n                return dgTileLayer.options.maxZoom;\n            }\n        }\n    },\n\n    // Added meta layers events processing before map events\n    _fireDOMEvent: function(e, type, targets) {\n        if (e.keyCode === 13) {\n            // https://github.com/Leaflet/Leaflet/issues/5499\n            return;\n        }\n        if (e.type === 'click') {\n            // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).\n            // @event preclick: MouseEvent\n            // Fired before mouse click on the map (sometimes useful when you\n            // want something to happen on click before any existing click\n            // handlers start running).\n            var synth = L.Util.extend({}, e);\n            synth.type = 'preclick';\n            this._fireDOMEvent(synth, synth.type, targets);\n        }\n\n        if (e._stopped) { return; }\n\n        // Find the layer the event is propagating from and its parents.\n        targets = (targets || []).concat(this._findEventTargets(e, type));\n\n        if (!targets.length) { return; }\n\n        var target = targets[0];\n        if (type === 'contextmenu' && target.listens(type, true)) {\n            L.DomEvent.preventDefault(e);\n        }\n\n        // The eventTargets and eventTargetsMapIndex properties are used for fire events continuation to\n        // remaining targets when the event was stopped due to the tile meta data request in progress.\n        // In this case there is need to fire events to remaining targets asynchronously.\n        var data = {\n            originalEvent: e,\n            eventTargets: targets,\n            eventTargetsMapIndex: targets.indexOf(this)\n        };\n\n        if (e.type !== 'keypress') {\n            var isMarker = target instanceof L.Marker;\n            data.containerPoint = isMarker ?\n                this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);\n            data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);\n            data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);\n        }\n\n        for (var i = 0; i < targets.length; i++) {\n            // Check metalayers before dispatch the event to the map\n            if (targets[i] === this) {\n                var metalayer = this._getCurrentMetaLayer(data);\n\n                if (type === 'mousemove') {\n                    if (this._lastMetalayer.entity && metalayer.entity &&\n                        this._lastMetalayer.entity.id === metalayer.entity.id) {\n                        this._fireMetalayerEvent('mousemove', metalayer, data);\n                    } else {\n                        this._fireMetalayerEvent('mouseout', this._lastMetalayer, data);\n                        this._fireMetalayerEvent('mouseover', metalayer, data);\n                        this._fireMetalayerEvent('mousemove', metalayer, data);\n                        this._lastMetalayer = metalayer;\n                    }\n                } else {\n                    this._fireMetalayerEvent(type, metalayer, data);\n                }\n\n                // If the event wasn't stopped in metalayers, dispatch it to the map\n                if (!data.originalEvent._stopped) {\n                    targets[i].fire(type, data, true);\n                }\n            } else {\n                targets[i].fire(type, data, true);\n                if (this._lastMetalayer.entity && data.originalEvent._stopped) {\n                    // fixes L.circle([54.983136831455, 82.897440725094], 200).addTo(map);\n                    this._fireMetalayerEvent('mouseout', this._lastMetalayer, data);\n                    this._lastMetalayer = {\n                        layer: undefined,\n                        entity: undefined\n                    };\n                }\n            }\n\n            if (data.originalEvent._stopped ||\n                (targets[i].options.nonBubblingEvents && L.Util.indexOf(targets[i].options.nonBubblingEvents, type) !== -1)) { return; }\n        }\n    },\n\n    _getCurrentMetaLayer: function(data) {\n        // Not forget for IE8 with srcElement\n        var eventTarget = data.originalEvent.target || data.originalEvent.srcElement;\n        var isClick = data.originalEvent.type === 'click';\n\n        // Suppose that user can interact with the metalayer only if there are no layers between cursor and map\n        if (\n            // For all browsers which support pointer-events: none on tiles\n            eventTarget === this._container ||\n            // And for IE10 or less where targets are tiles\n            DG.Browser.ie && eventTarget.className === 'leaflet-tile leaflet-tile-loaded' ||\n            // The only exception is canvas, because a canvas layer occupies the whole screen\n            eventTarget.tagName === 'CANVAS'\n        ) {\n            for (var j = this.metaLayers.length - 1; j >= 0; j--) {\n                var metaEntity = this.metaLayers[j].getHoveredObject(data);\n                if (metaEntity) {\n                    return {\n                        layer: this.metaLayers[j],\n                        entity: metaEntity\n                    };\n                } else if (isClick) {\n                    // Additional condition for click event, because there may not be the tile meta data.\n                    // E.g. when the tile meta data request in progress. In this case the metalayer must be\n                    // returned without an entity.\n                    return {\n                        layer: this.metaLayers[j],\n                        entity: undefined\n                    }\n                }\n            }\n        }\n        return {\n            layer: undefined,\n            entity: undefined\n        };\n    },\n\n    _fireMetalayerEvent: function(type, metalayer, data) {\n        // There is need to continue if the event type is click, because there may not be the tile meta data.\n        // That's why it will be processed in the metalayer click handler.\n        if (!metalayer.entity && type !== 'click') {\n            return;\n        }\n\n        // There is no need to fire metalayer event if the metalayer is undefined.\n        if (!metalayer.layer) {\n            return;\n        }\n\n        var listener = metalayer.layer.mapEvents[type];\n        if (!listener) {\n            return;\n        }\n        data.entity = metalayer.entity;\n        listener.call(metalayer.layer, data);\n    }\n});\n\nDG.Map.addInitHook(function() {\n    this.on('layeradd layerremove', this._updateTileLayers);\n});\n\n// Set css property touch-action to auto if dragging is false.\n// Need for scrolling page in mobile using our map dom element.\n// todo: I made issue in leaflet https://github.com/Leaflet/Leaflet/issues/4415\nDG.Map.addInitHook(function() {\n    if (this.options.dragging == false && this.options.tap == false) {\n        DG.DomUtil.addClass(this._container, 'dg-dragging-false');\n    }\n});\n"
  },
  {
    "path": "src/DGCustomization/src/DGMobileImprove.js",
    "content": "/**\n * В файле содежатся изменения для ускорения лифлета на мобильных девайсах\n */\n\nif (DG.Browser.mobile) {\n    (function() {\n        /**\n         * Хакаем addClass и removeClass, чтобы они не работали для определённых классов\n         * Сделано так, чтобы не менять кучу методов в кишках лифлета\n         *\n         * leaflet-dragging и leaflet-drag-target вызывает длинный recalculate style\n         */\n        var addClass = L.DomUtil.addClass;\n        L.DomUtil.addClass = function(el, name) {\n            if (name === 'leaflet-dragging' ||\n                name === 'leaflet-drag-target'\n            ) {\n                return;\n            }\n\n            addClass(el, name);\n        };\n\n        var removeClass = L.DomUtil.removeClass;\n        L.DomUtil.removeClass = function(el, name) {\n            if (name === 'leaflet-dragging' ||\n                name === 'leaflet-drag-target'\n            ) {\n                return;\n            }\n\n            removeClass(el, name);\n        }\n\n        L.Draggable.include({\n            /**\n             * Добавлено округление позиции this._startPos.add(offset)._round()\n             * И сравнение с предудыщей if (this._newPos && this._newPos.x == pos.x && this._newPos.y == pos.y) {\n             * Чтобы обновление dom происходило только при реальном изменении\n             * Убраны классы leaflet-dragging и leaflet-drag-target\n             */\n            _onMove: function(e) {\n                // Ignore simulated events, since we handle both touch and\n                // mouse explicitly; otherwise we risk getting duplicates of\n                // touch events, see #4315.\n                // Also ignore the event if disabled; this happens in IE11\n                // under some circumstances, see #3666.\n                if (e._simulated || !this._enabled) { return; }\n\n                if (e.touches && e.touches.length > 1) {\n                    this._moved = true;\n                    return;\n                }\n\n                var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\n                    newPoint = new L.Point(first.clientX, first.clientY),\n                    offset = newPoint.subtract(this._startPoint);\n\n                if (!offset.x && !offset.y) { return; }\n                if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }\n\n                L.DomEvent.preventDefault(e);\n\n                if (!this._moved) {\n                    // @event dragstart: Event\n                    // Fired when a drag starts\n                    this.fire('dragstart');\n\n                    this._moved = true;\n                    this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);\n\n                    this._lastTarget = e.target || e.srcElement;\n                    // IE and Edge do not give the <use> element, so fetch it\n                    // if necessary\n                    if ((window.SVGElementInstance) && (this._lastTarget instanceof window.SVGElementInstance)) {\n                        this._lastTarget = this._lastTarget.correspondingUseElement;\n                    }\n                }\n\n                var pos = this._startPos.add(offset)._round();\n                this._moving = true;\n\n                L.Util.cancelAnimFrame(this._animRequest);\n                this._lastEvent = e;\n\n                if (this._newPos && this._newPos.x == pos.x && this._newPos.y == pos.y) {\n                    return;\n                }\n\n                this._newPos = pos;\n                this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true);\n            }\n        });\n\n        /**\n         * Длительность всех инерций при движении карты теперь 1 секунда\n         */\n        L.Map.Drag.include({\n            _onDragEnd: function(e) {\n                var map = this._map,\n                    options = map.options,\n\n                    noInertia = !options.inertia || this._times.length < 2;\n\n                map.fire('dragend', e);\n\n                if (noInertia) {\n                    map.fire('moveend');\n\n                } else {\n\n                    var direction = this._lastPos.subtract(this._positions[0]),\n                        duration = (this._lastTime - this._times[0]) / 1000,\n                        ease = options.easeLinearity,\n\n                        speedVector = direction.multiplyBy(ease / duration),\n                        speed = speedVector.distanceTo([0, 0]),\n\n                        limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),\n                        limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),\n\n                        decelerationDuration = 1, // limitedSpeed / (options.inertiaDeceleration * ease),\n                        offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();\n\n                    if (!offset.x && !offset.y) {\n                        map.fire('moveend');\n\n                    } else {\n                        offset = map._limitOffset(offset, map.options.maxBounds);\n\n                        L.Util.requestAnimFrame(function() {\n                            map.panBy(offset, {\n                                duration: decelerationDuration,\n                                easeLinearity: ease,\n                                noMoveStart: true,\n                                animate: true\n                            });\n                        });\n                    }\n                }\n            }\n        })\n    })();\n}\n\nL.MobileTileLayer = L.TileLayer.extend({\n    initialize: function(url, options) {\n        L.TileLayer.prototype.initialize.call(this, url, options);\n        this._appleDevice = this._isAppleDevice()\n        this._previewUrl = options.previewUrl;\n    },\n\n    setPreviewUrl: function(url) {\n        this._previewUrl = url;\n        this.redraw();\n    },\n\n    /**\n     * Быстрое навешивание событий, вместо L.DomUtil.on используем простое присваивание\n     */\n    createTile: function(coords, done, url) {\n        var tile = document.createElement('img');\n        tile.onload = L.bind(this._tileOnLoad, this, done, tile);\n        tile.onerror = L.bind(this._tileOnError, this, done, tile);\n\n        if (this.options.crossOrigin) {\n            tile.crossOrigin = '';\n        }\n\n        /*\n         Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons\n         http://www.w3.org/TR/WCAG20-TECHS/H67\n        */\n        tile.alt = '';\n        tile.src = this.getTileUrl(coords, url);\n\n        return tile;\n    },\n\n    /**\n     * Убран класс leaflet-tile\n     * Добавлен хак для превью тайлов\n     */\n    _initTile: function(tile) {\n        tile.style.position = 'absolute';\n\n        var tileSize = this.getTileSize();\n        tile.style.width = tileSize.x + 'px';\n        tile.style.height = tileSize.y + 'px';\n\n        tile.style.visibility = 'hidden';\n        tile.style.pointerEvents = 'none';\n\n        tile.onselectstart = L.Util.falseFn;\n        tile.onmousemove = L.Util.falseFn;\n\n        // without this hack, tiles disappear after zoom on Chrome for Android\n        // https://github.com/Leaflet/Leaflet/issues/2078\n        if (L.Browser.android && !L.Browser.android23) {\n            tile.style.WebkitBackfaceVisibility = 'hidden';\n        }\n\n        return tile;\n    },\n\n    /**\n     * Убран класс leaflet-tile-container\n     */\n    _updateLevels: function() {\n\n        var zoom = this._tileZoom,\n            maxZoom = this.options.maxZoom;\n\n        if (zoom === undefined) { return undefined; }\n\n        for (var z in this._levels) {\n            if (this._levels[z].el.children.length || z === zoom) {\n                this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);\n            } else {\n                L.DomUtil.remove(this._levels[z].el);\n                this._removeTilesAtZoom(z);\n                delete this._levels[z];\n            }\n        }\n\n        var level = this._levels[zoom],\n            map = this._map;\n\n        if (!level) {\n            level = this._levels[zoom] = {};\n\n            level.el = L.DomUtil.create('div', 'leaflet-zoom-animated', this._container);\n\n            level.el.style.zIndex = maxZoom;\n\n            level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();\n            level.zoom = zoom;\n\n            this._setZoomTransform(level, map.getCenter(), map.getZoom());\n\n            // force the browser to consider the newly added element for transition\n            L.Util.falseFn(level.el.offsetWidth);\n        }\n\n        this._level = level;\n\n        return level;\n    },\n\n    /**\n     * Убрано добавление тайлов через documentFragment\n     */\n    _update: function(center) {\n        var map = this._map;\n        if (!map) { return; }\n        var zoom = map.getZoom();\n\n        if (center === undefined) { center = map.getCenter(); }\n        if (this._tileZoom === undefined) { return; }\t// if out of minzoom/maxzoom\n\n        var pixelBounds = this._getTiledPixelBounds(center),\n            tileRange = this._pxBoundsToTileRange(pixelBounds),\n            tileCenter = tileRange.getCenter(),\n            queue = [],\n            margin = this.options.keepBuffer,\n            noPruneRange = new L.Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),\n                tileRange.getTopRight().add([margin, -margin]));\n\n        for (var key in this._tiles) {\n            var c = this._tiles[key].coords;\n            if (c.z !== this._tileZoom || !noPruneRange.contains(L.point(c.x, c.y))) {\n                this._tiles[key].current = false;\n            }\n        }\n\n        // _update just loads more tiles. If the tile zoom level differs too much\n        // from the map's, let _setView reset levels and prune old tiles.\n        if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }\n\n        // create a queue of coordinates to load tiles from\n        for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {\n            for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {\n                var coords = new L.Point(i, j);\n                coords.z = this._tileZoom;\n\n                if (!this._isValidTile(coords)) { continue; }\n\n                var tile = this._tiles[this._tileCoordsToKey(coords)];\n                if (tile) {\n                    tile.current = true;\n                } else {\n                    queue.push(coords);\n                }\n            }\n        }\n\n        // sort tile queue to load tiles in order of their distance to center\n        queue.sort(function(a, b) {\n            return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);\n        });\n\n        if (queue.length !== 0) {\n            // if it's the first batch of tiles to load\n            if (!this._loading) {\n                this._loading = true;\n                // @event loading: Event\n                // Fired when the grid layer starts loading tiles.\n                this.fire('loading');\n            }\n\n            for (i = 0; i < queue.length; i++) {\n                this._addTile(queue[i], this._level.el);\n            }\n        }\n    },\n\n    /**\n     * We don't load preview tile:\n     * - after zoom-in if a tile from a lower zoom is already shown\n     * - after zoom-out if four tiles from a higher zoom is already shown\n     */\n    _needPreviewTile: function(coords) {\n        if (this._tileZoom - this._map.getZoom() > 0) {\n            // zoom in\n            return !this._existTileFromLowerZoom(coords);\n        } else {\n            // zoom out\n            return !this._existTilesFromHigherZoom(coords);\n        }\n    },\n\n    _existTileFromLowerZoom: function(coords) {\n        var coords2 = L.point(coords.x / 2, coords.y / 2)._floor();\n\n        coords2.z = coords.z - 1;\n\n        var key = this._tileCoordsToKey(coords2);\n        var tile = this._tiles[key];\n        return tile && !tile.preview;\n    },\n\n    _existTilesFromHigherZoom: function(coords) {\n        var x = coords.x;\n        var y = coords.y;\n\n        for (var i = 2 * x; i < 2 * x + 2; i++) {\n            for (var j = 2 * y; j < 2 * y + 2; j++) {\n                var c = new L.Point(i, j);\n                c.z = coords.z + 1;\n                var key = this._tileCoordsToKey(c);\n                if (!this._tiles[key]) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    },\n\n    _isAppleDevice: function() {\n        var appleMobileRE = /ip(hone|od)/i;\n        var appleTabletRE = /ipad/i;\n        var touchMacRE = /Macintosh/i;\n\n        var ua = typeof navigator !== 'undefined' ? navigator.userAgent : '';\n\n        if (!ua) {\n            return false;\n        }\n\n        var isAppleMobile = appleMobileRE.test(ua);\n        var isAppleTablet = appleTabletRE.test(ua);\n\n        var isTouchMac =\n            navigator.maxTouchPoints > 1 && touchMacRE.test(ua) && ua.indexOf('Safari') !== -1;\n\n        return isAppleMobile || isAppleTablet || isTouchMac;\n    },\n\n    /**\n     * Добавлена логика с превью тайлами\n     */\n    _addTile: function(coords, container) {\n        var tilePos = this._getTilePos(coords),\n            key = this._tileCoordsToKey(coords);\n\n        var wrapCoords = this._wrapCoords(coords);\n        var needPreview = this._needPreviewTile(wrapCoords);\n\n        var url = needPreview ? this._previewUrl : this._url;\n        var showPreviewForIphone = this._appleDevice && needPreview;\n        var tile = this.createTile(wrapCoords, L.bind(showPreviewForIphone ? this._previewReady : this._tileReady, this, coords), url);\n\n        this._initTile(tile);\n\n        L.DomUtil.setPosition(tile, tilePos);\n\n        // save tile in cache\n        this._tiles[key] = {\n            el: tile,\n            preview: needPreview,\n            coords: coords,\n            current: true\n        };\n\n        container.appendChild(tile);\n        // @event tileloadstart: TileEvent\n        // Fired when a tile is requested and starts loading.\n        this.fire('tileloadstart', {\n            tile: tile,\n            coords: coords\n        });\n    },\n\n    _previewReady: function(coords, err, tile) {\n        if (!this._map) { return; }\n\n        var key = this._tileCoordsToKey(coords);\n\n        tile = this._tiles[key];\n        if (!tile) { return; }\n\n\n        tile.el.onload = L.bind(this._tileReady, this, coords, err, tile);\n        tile.el.onerror = L.bind(this._tileReady, this, coords, err, tile);\n        tile.el.src = this.getTileUrl(coords, this._url);\n    },\n\n    /**\n     * Убран fadeAnimated и класс leaflet-tile-loaded\n     */\n    _tileReady: function(coords, err, tile) {\n        if (!this._map) { return; }\n\n        if (err) {\n            // @event tileerror: TileErrorEvent\n            // Fired when there is an error loading a tile.\n            this.fire('tileerror', {\n                error: err,\n                tile: tile,\n                coords: coords\n            });\n        }\n\n        var key = this._tileCoordsToKey(coords);\n\n        tile = this._tiles[key];\n        if (!tile) { return; }\n\n        if (!this._appleDevice) {\n        // Если у тайла уже есть оригинальная (не пожатая) картинка,\n        // то заменим превью на нее\n            if (tile.originalEl && tile.el.parentNode) {\n                tile.el.parentNode.replaceChild(tile.originalEl, tile.el);\n                tile.el = tile.originalEl;\n\n                tile.originalEl = null;\n                tile.preview = false;\n\n                // Если у тайла есть только превью, то добавим его на карту\n                // И начнем грузить оригинальный\n            } else if (tile.preview) {\n                tile.originalEl = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords), this._url);\n                this._initTile(tile.originalEl);\n                L.DomUtil.setPosition(tile.originalEl, this._getTilePos(coords));\n            }\n        }\n        tile.loaded = +new Date();\n        tile.active = true;\n        this._pruneTiles();\n\n        if (!err) {\n            tile.el.style.visibility = '';\n\n            // @event tileload: TileEvent\n            // Fired when a tile loads.\n            this.fire('tileload', {\n                tile: tile.el,\n                preview: tile.preview,\n                coords: coords\n            });\n        }\n\n        if (this._noTilesToLoad()) {\n            this._loading = false;\n            // @event load: Event\n            // Fired when the grid layer loaded all visible tiles.\n            this.fire('load');\n\n            if (L.Browser.ielt9 || !this._map._fadeAnimated) {\n                L.Util.requestAnimFrame(this._pruneTiles, this);\n            } else {\n                // Wait a bit more than 0.2 secs (the duration of the tile fade-in)\n                // to trigger a pruning.\n                setTimeout(L.bind(this._pruneTiles, this), 250);\n            }\n        }\n    },\n\n    /**\n     * В отличие от оригинального метода, здесь url прокидывается параметром\n     */\n    getTileUrl: function(coords, url) {\n        var data = {\n            r: L.Browser.retina ? '@2x' : '',\n            s: this._getSubdomain(coords),\n            x: coords.x,\n            y: coords.y,\n            z: this._getZoomForUrl()\n        };\n        if (this._map && !this._map.options.crs.infinite) {\n            var invertedY = this._globalTileRange.max.y - coords.y;\n            if (this.options.tms) {\n                data['y'] = invertedY;\n            }\n            data['-y'] = invertedY;\n        }\n\n        return L.Util.template(url, L.extend(data, this.options));\n    },\n});\n"
  },
  {
    "path": "src/DGCustomization/src/DGPolyUtil.js",
    "content": "// from https://github.com/Turfjs/turf-inside/blob/master/index.js\nDG.PolyUtil.inside = function(point, polygon, pointReduce) {\n    pointReduce = pointReduce || DG.PolyUtil._defaultPointReduce;\n    var polys = polygon.coordinates;\n    var pt = pointReduce(point);\n\n    // normalize to multipolygon\n    if (polygon.type === 'Polygon') {\n        polys = [polys];\n    }\n\n    var insidePoly = false;\n    var i = 0;\n    while (i < polys.length && !insidePoly) {\n        // check if it is in the outer ring first\n        if (this._inRing(pt, polys[i][0], pointReduce)) {\n            var inHole = false;\n            var k = 1;\n            // check for the point in any of the holes\n            while (k < polys[i].length && !inHole) {\n                if (this._inRing(pt, polys[i][k], pointReduce)) {\n                    inHole = true;\n                }\n                k++;\n            }\n            if (!inHole)  {\n                insidePoly = true;\n            }\n        }\n        i++;\n    }\n    return insidePoly;\n};\n\n// pt is [x,y] and ring is [[x,y], [x,y],..]\nDG.PolyUtil._inRing = function(pt, ring, pointReduce) {\n    var isInside = false;\n    for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n        var pi = pointReduce(ring[i]);\n        var pj = pointReduce(ring[j]);\n        var xi = pi[0], yi = pi[1];\n        var xj = pj[0], yj = pj[1];\n        var intersect = ((yi > pt[1]) !== (yj > pt[1])) &&\n            (pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi);\n\n        if (intersect) {\n            isInside = !isInside;\n        }\n    }\n    return isInside;\n};\n\nDG.PolyUtil._defaultPointReduce = function(point) {\n    return point;\n};\n"
  },
  {
    "path": "src/DGCustomization/test/CanvasSpec.js",
    "content": "describe('Canvas', function () {\n\n    var c, map, p2ll, latLngs;\n\n    before(function () {\n        c = document.createElement('div');\n        c.style.width = '400px';\n        c.style.height = '400px';\n        c.style.position = 'absolute';\n        c.style.top = '0';\n        c.style.left = '0';\n        document.body.appendChild(c);\n        map = new L.Map(c, {preferCanvas: true, zoomControl: false});\n        map.setView([0, 0], 6);\n        p2ll = function (x, y) {\n            return map.layerPointToLatLng([x, y]);\n        };\n        latLngs = [p2ll(0, 0), p2ll(0, 100), p2ll(100, 100), p2ll(100, 0)];\n    });\n\n    // Remove our layers for run test of leflet.\n    // Set nonBubblingEvents to [],\n    // beacuse in DGCustomization.js we set click is not bubling and test of leflet isn't work\n    before(function () {\n        map.clearLayers();\n        DG.Layer.mergeOptions({\n            nonBubblingEvents: []\n        });\n    });\n\n    after(function () {\n        document.body.removeChild(c);\n    });\n\n    describe(\"#events\", function () {\n        var layer;\n\n        beforeEach(function () {\n            layer = L.polygon(latLngs).addTo(map);\n        });\n\n        afterEach(function () {\n            layer.remove();\n        });\n\n        it(\"should fire event when layer contains mouse\", function () {\n            var spy = sinon.spy();\n            layer.on('click', spy);\n            happen.at('click', 50, 50);  // Click on the layer.\n            expect(spy.callCount).to.eql(1);\n            happen.at('click', 150, 150);  // Click outside layer.\n            expect(spy.callCount).to.eql(1);\n            layer.off(\"click\", spy);\n        });\n\n        it(\"DOM events propagate from canvas polygon to map\", function () {\n            var spy = sinon.spy();\n            map.on(\"click\", spy);\n            happen.at('click', 50, 50);\n            expect(spy.callCount).to.eql(1);\n            map.off(\"click\", spy);\n        });\n\n        it(\"DOM events fired on canvas polygon can be cancelled before being caught by the map\", function () {\n            var mapSpy = sinon.spy();\n            var layerSpy = sinon.spy();\n            map.on(\"click\", mapSpy);\n            layer.on(\"click\", L.DomEvent.stopPropagation).on(\"click\", layerSpy);\n            happen.at('click', 50, 50);\n            expect(layerSpy.callCount).to.eql(1);\n            expect(mapSpy.callCount).to.eql(0);\n            map.off(\"click\", mapSpy);\n            layer.off(\"click\", L.DomEvent.stopPropagation).off(\"click\", layerSpy);\n        });\n\n        it(\"DOM events fired on canvas polygon are propagated only once to the map even when two layers contains the event\", function () {\n            var spy = sinon.spy();\n            var layer2 = L.polygon(latLngs).addTo(map);\n            map.on(\"click\", spy);\n            happen.at('click', 50, 50);\n            expect(spy.callCount).to.eql(1);\n            layer2.remove();\n            map.off(\"click\", spy);\n        });\n\n        it(\"should fire preclick before click\", function () {\n            var clickSpy = sinon.spy();\n            var preclickSpy = sinon.spy();\n            layer.on('click', clickSpy);\n            layer.on('preclick', preclickSpy);\n            layer.once('preclick', function (e) {\n                expect(clickSpy.called).to.be(false);\n            });\n            happen.at('click', 50, 50);  // Click on the layer.\n            expect(clickSpy.callCount).to.eql(1);\n            expect(preclickSpy.callCount).to.eql(1);\n            happen.at('click', 150, 150);  // Click outside layer.\n            expect(clickSpy.callCount).to.eql(1);\n            expect(preclickSpy.callCount).to.eql(1);\n            layer.off();\n        });\n\n        it(\"should not fire click when dragging the map on top of it\", function (done) {\n            var downSpy = sinon.spy();\n            var clickSpy = sinon.spy();\n            var preclickSpy = sinon.spy();\n            layer.on('click', clickSpy);\n            layer.on('preclick', preclickSpy);\n            layer.on('mousedown', downSpy);\n            var hand = new Hand({\n                timing: 'fastframe',\n                onStop: function () {\n                    // Prosthetic does not fire a click when we down+up, but it real world\n                    // browsers would, so let's simulate it.\n                    happen.at('click', 70, 60);\n                    expect(downSpy.called).to.be(true);\n                    expect(clickSpy.called).to.be(false);\n                    expect(preclickSpy.called).to.be(false);\n                    layer.off();\n                    done();\n                }\n            });\n            var mouse = hand.growFinger('mouse');\n\n            // We move 5 pixels first to overcome the 3-pixel threshold of\n            // L.Draggable.\n            mouse.moveTo(50, 50, 0)\n                .down().moveBy(20, 10, 200).up();\n        });\n\n    });\n\n    describe(\"#events(interactive=false)\", function () {\n        var layer;\n\n        beforeEach(function () {\n            layer = L.polygon(latLngs, {interactive: false}).addTo(map);\n        });\n\n        afterEach(function () {\n            layer.remove();\n        });\n\n        it(\"should not fire click when not interactive\", function () {\n            var spy = sinon.spy();\n            layer.on('click', spy);\n            happen.at('click', 50, 50);  // Click on the layer.\n            expect(spy.callCount).to.eql(0);\n            happen.at('click', 150, 150);  // Click outside layer.\n            expect(spy.callCount).to.eql(0);\n            layer.off(\"click\", spy);\n        });\n    });\n\n    describe('#dashArray', function () {\n        it('can add polyline with dashArray', function () {\n            var layer = L.polygon(latLngs, {\n                dashArray: \"5,5\"\n            }).addTo(map);\n        });\n        it('can setStyle with dashArray', function () {\n            var layer = L.polygon(latLngs).addTo(map);\n            layer.setStyle({\n                dashArray: \"5,5\"\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/DGCustomizationSpec.js",
    "content": "describe('DGCustomization', function() {\n    var mapContainer,\n        map;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        map = new DG.Map(mapContainer, {\n            center: [54.980206086231, 82.898068362003],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n\n        document.body.appendChild(mapContainer);\n        map.setLang('ru');\n    });\n\n    after(function() {\n        map.remove();\n        mapContainer.parentElement.removeChild(mapContainer);\n        mapContainer = map = null;\n    });\n\n    describe('DG.Control', function() {\n        it ('change map lang should call _renderTranslation function', function() {\n            var control = DG.control(),\n                spy = sinon.spy();\n\n            control._renderTranslation = spy;\n            map.setLang('en');\n\n            expect(spy).to.be.ok();\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/DGMap.BaseLayerSpec.js",
    "content": "describe('DG.TileLayer', function () {\n    var mapContainer,\n        map;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        map = new DG.Map(mapContainer, {\n            center: [54.980206086231, 82.898068362003],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n    });\n\n    after(function () {\n        map.remove();\n        mapContainer = map = null;\n    });\n\n    describe('check init', function () {\n        it('should be map.baseLayer', function () {\n            expect(map.baseLayer).to.be.a('object');\n        });\n\n        it('should be zIndex 0 on layer container', function () {\n            var layerContainer = map.baseLayer._container;\n\n            expect(Number(layerContainer.style.zIndex)).to.be(0);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/DGMapSpec.js",
    "content": "describe('DGMap', function () {\n    var mapContainer,\n        center = [54.980206086231, 82.898068362003],\n        map,\n        newCenter = [55.01749277152058, 82.92145729064943],\n        moveStartSpy,\n        moveEndSpy;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        map = new DG.Map(mapContainer, {\n            center: center,\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n        document.body.appendChild(mapContainer);\n        map.setLang('ru');\n        map.invalidateSize();\n    });\n\n    after(function () {\n        mapContainer.parentElement.removeChild(mapContainer);\n        mapContainer = map = center = newCenter = moveStartSpy = moveEndSpy = null;\n    });\n\n    describe('#setView', function () {\n        describe('change center without animate', function () {\n            before(function() {\n                map.setView(center, 13, {animate: false});\n\n                moveStartSpy = sinon.spy();\n                moveEndSpy = sinon.spy();\n\n                map.on('movestart', moveStartSpy);\n                map.on('moveend', moveEndSpy);\n\n                map.setView(newCenter, 13, {animate: false});\n            });\n\n            after(function () {\n                map.off('movestart', moveStartSpy);\n                map.off('moveend', moveEndSpy);\n            });\n\n            it('should change center', function () {\n                expect(DG.latLng(newCenter)).to.nearLatLng(map.getCenter());\n            });\n\n            it('should fire movestart event', function () {\n                expect(moveStartSpy.calledOnce).to.be.ok();\n            });\n\n            it('shouldn fire moveend event while animate', function () {\n                expect(moveEndSpy.calledOnce).to.be.ok();\n            });\n        });\n\n        describe('change center with animate = true', function () {\n            before(function () {\n                map.setView(center, 13, {animate: false});\n\n                moveStartSpy = sinon.spy();\n                moveEndSpy = sinon.spy();\n\n                map.on('movestart', moveStartSpy);\n                map.on('moveend', moveEndSpy);\n\n                map.setView(newCenter, 13, {animate: true});\n            });\n\n            after(function () {\n                map.off('movestart', moveStartSpy);\n                map.off('moveend', moveEndSpy);\n            });\n\n            it('should fire movestart event before animate', function () {\n                expect(moveStartSpy.calledOnce).to.be.ok();\n            });\n\n            it('shouldn\\'t fire moveend event while animate', function () {\n                expect(moveEndSpy.calledOnce).not.be.ok();\n            });\n        });\n    });\n\n    describe('#panBy', function () {\n        it('should set zoom to 13 after panBy to place without project', function () {\n            map.setView([55.005582426668404, 82.93081283569337], 18, {animate: false});\n            map.panBy([1e15, 0]);\n            expect(map.getZoom()).to.be(16);\n        });\n    });\n\n    describe('#getBoundsZoom', function () {\n        it('should return 16', function () {\n            // тут должен быть баунд территории, которая не содержить проекта,\n            // при этом такой, что при призуме к нему будет зум > 16\n            var sw = DG.latLng(67.521706581271, 97.5729274749756),\n                ne = DG.latLng(67.52332271114147, 97.57734775543214),\n                b = DG.latLngBounds(sw, ne);\n\n            expect(map.getBoundsZoom(b)).to.be(16); // 16 - это максимальный зум карты в месте где нет проекта\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/GridLayerSpec.js",
    "content": "\ndescribe('GridLayer', function () {\n\n    var div, map;\n\n    beforeEach(function () {\n        div = document.createElement('div');\n        div.style.width = '800px';\n        div.style.height = '600px';\n        div.style.visibility = 'hidden';\n\n        document.body.appendChild(div);\n\n        map = L.map(div);\n    });\n\n    afterEach(function () {\n        document.body.removeChild(div);\n    });\n\n    describe('#redraw', function () {\n        it('can be called before map.setView', function () {\n            var grid = L.gridLayer().addTo(map);\n            expect(grid.redraw()).to.equal(grid);\n        });\n    });\n\n    describe('#setOpacity', function () {\n        it('can be called before map.setView', function () {\n            var grid = L.gridLayer().addTo(map);\n            expect(grid.setOpacity(0.5)).to.equal(grid);\n        });\n\n        it('works when map has fadeAnimated=false (IE8 is exempt)', function (done) {\n            map.remove();\n            map = L.map(div, {fadeAnimation: false}).setView([0, 0], 0);\n\n            var grid = L.gridLayer().setOpacity(0.5).addTo(map);\n            grid.on('load', function () {\n                expect(grid._container.style.opacity).to.equal('0.5');\n                done();\n            });\n        });\n    });\n\n    it('positions tiles correctly with wrapping and bounding', function () {\n\n        map.setView([0, 0], 1);\n\n        var tiles = [];\n\n        var grid = L.gridLayer();\n        grid.createTile = function (coords) {\n            var tile = document.createElement('div');\n            tiles.push({coords: coords, tile: tile});\n            return tile;\n        };\n\n        map.addLayer(grid);\n\n        var loaded = {};\n\n        for (var i = 0; i < tiles.length; i++) {\n            var coords = tiles[i].coords,\n                pos = L.DomUtil.getPosition(tiles[i].tile);\n\n            loaded[pos.x + ':' + pos.y] = [coords.x, coords.y];\n        }\n\n        expect(loaded).to.eql({\n            '144:0': [0, 0],\n            '400:0': [1, 0],\n            '144:256': [0, 1],\n            '400:256': [1, 1],\n            '-112:0': [1, 0],\n            '656:0': [0, 0],\n            '-112:256': [1, 1],\n            '656:256': [0, 1]\n        });\n    });\n\n    describe('tile pyramid', function () {\n        var clock;\n\n        beforeEach(function () {\n            clock = sinon.useFakeTimers();\n        });\n\n        afterEach(function () {\n            clock.restore();\n        });\n\n        it('removes tiles for unused zoom levels', function (done) {\n            map.remove();\n            map = L.map(div, {fadeAnimation: false});\n            map.setView([0, 0], 1);\n\n            var grid = L.gridLayer();\n            var tiles = {};\n\n            grid.createTile = function (coords) {\n                tiles[grid._tileCoordsToKey(coords)] = true;\n                return document.createElement('div');\n            };\n\n            grid.on('tileunload', function (e) {\n                delete tiles[grid._tileCoordsToKey(e.coords)];\n                if (Object.keys(tiles).length === 1) {\n                    var tunKey = Object.keys(tiles)[0];\n                    expect(tunKey === '0:0:0' || tunKey === '1:1:1').to.be.ok();\n                    done();\n                }\n            });\n\n            map.addLayer(grid);\n            map.setZoom(0, {animate: false});\n            clock.tick(250);\n        });\n    });\n\n    describe('#createTile', function () {\n\n        beforeEach(function () {\n            // Simpler sizes to test.\n            div.style.width = '512px';\n            div.style.height = '512px';\n        });\n\n        afterEach(function () {\n            div.style.width = '800px';\n            div.style.height = '600px';\n        });\n\n        // Passes on Firefox, but fails on phantomJS: done is never called.\n        xit('only creates tiles for visible area on zoom in', function (done) {\n            map.remove();\n            map = L.map(div);\n            map.setView([0, 0], 10);\n\n            var grid = L.gridLayer(),\n                count = 0,\n                loadCount = 0;\n            grid.createTile = function (coords) {\n                count++;\n                return document.createElement('div');\n            };\n            var onLoad = function (e) {\n                expect(count).to.eql(4);\n                count = 0;\n                loadCount++;\n                if (loadCount === 1) {  // On layer add.\n                    map.zoomIn();\n                } else {  // On zoom in.\n                    done();\n                }\n            };\n            grid.on('load', onLoad);\n            map.addLayer(grid);\n        });\n\n    });\n\n    describe(\"#onAdd\", function () {\n        it('is called after zoomend on first map load', function () {\n            var layer = L.gridLayer().addTo(map);\n\n            var onAdd = layer.onAdd,\n                onAddSpy = sinon.spy();\n            layer.onAdd = function () {\n                onAdd.apply(this, arguments);\n                onAddSpy();\n            };\n\n            var onReset = sinon.spy();\n            map.on('zoomend', onReset);\n            map.setView([0, 0], 0);\n\n            expect(onReset.calledBefore(onAddSpy)).to.be.ok();\n        });\n    });\n\n    describe(\"#getMaxZoom, #getMinZoom\", function () {\n\n        // Skip because we have base layer with greater zooms.\n        describe.skip(\"when a tilelayer is added to a map with no other layers\", function () {\n            it(\"has the same zoomlevels as the tilelayer\", function () {\n                var maxZoom = 10,\n                    minZoom = 5;\n\n                map.setView([0, 0], 1);\n\n                L.gridLayer({\n                    maxZoom: maxZoom,\n                    minZoom: minZoom\n                }).addTo(map);\n\n                expect(map.getMaxZoom()).to.be(maxZoom);\n                expect(map.getMinZoom()).to.be(minZoom);\n            });\n        });\n\n        describe(\"accessing a tilelayer's properties\", function () {\n            it('provides a container', function () {\n                map.setView([0, 0], 1);\n\n                var layer = L.gridLayer().addTo(map);\n                expect(layer.getContainer()).to.be.ok();\n            });\n        });\n\n        // Skip because we have base layer with greater zooms.\n        describe.skip(\"when a tilelayer is added to a map that already has a tilelayer\", function () {\n            it(\"has its zoomlevels updated to fit the new layer\", function () {\n                map.setView([0, 0], 1);\n\n                L.gridLayer({minZoom: 10, maxZoom: 15}).addTo(map);\n                expect(map.getMinZoom()).to.be(10);\n                expect(map.getMaxZoom()).to.be(15);\n\n                L.gridLayer({minZoom: 5, maxZoom: 10}).addTo(map);\n                expect(map.getMinZoom()).to.be(5);  // changed\n                expect(map.getMaxZoom()).to.be(15); // unchanged\n\n                L.gridLayer({minZoom: 10, maxZoom: 20}).addTo(map);\n                expect(map.getMinZoom()).to.be(5);  // unchanged\n                expect(map.getMaxZoom()).to.be(20); // changed\n\n\n                L.gridLayer({minZoom: 0, maxZoom: 25}).addTo(map);\n                expect(map.getMinZoom()).to.be(0); // changed\n                expect(map.getMaxZoom()).to.be(25); // changed\n            });\n        });\n        describe(\"when a tilelayer is removed from a map\", function () {\n            it(\"has its zoomlevels updated to only fit the layers it currently has\", function () {\n                var tiles = [\n                    L.gridLayer({minZoom: 10, maxZoom: 15}).addTo(map),\n                    L.gridLayer({minZoom: 5, maxZoom: 10}).addTo(map),\n                    L.gridLayer({minZoom: 10, maxZoom: 20}).addTo(map),\n                    L.gridLayer({minZoom: 0, maxZoom: 25}).addTo(map)\n                ];\n                map.whenReady(function () {\n                    expect(map.getMinZoom()).to.be(0);\n                    expect(map.getMaxZoom()).to.be(25);\n\n                    map.removeLayer(tiles[0]);\n                    expect(map.getMinZoom()).to.be(0);\n                    expect(map.getMaxZoom()).to.be(25);\n\n                    map.removeLayer(tiles[3]);\n                    expect(map.getMinZoom()).to.be(5);\n                    expect(map.getMaxZoom()).to.be(20);\n\n                    map.removeLayer(tiles[2]);\n                    expect(map.getMinZoom()).to.be(5);\n                    expect(map.getMaxZoom()).to.be(10);\n\n                    map.removeLayer(tiles[1]);\n                    expect(map.getMinZoom()).to.be(0);\n                    expect(map.getMaxZoom()).to.be(Infinity);\n                });\n            });\n        });\n    });\n\n    describe(\"number of 256px tiles loaded in synchronous non-animated grid @800x600px\", function () {\n        var clock, grid, counts;\n\n        beforeEach(function () {\n            clock = sinon.useFakeTimers();\n\n            grid = L.gridLayer({\n                attribution: 'Grid Layer',\n                tileSize: L.point(256, 256)\n            });\n\n            grid.createTile = function (coords) {\n                var tile = document.createElement('div');\n                tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');\n                tile.style.border = '2px solid red';\n                return tile;\n            };\n\n            counts = {\n                tileload: 0,\n                tileerror: 0,\n                tileloadstart: 0,\n                tileunload: 0\n            };\n\n            grid.on('tileload tileunload tileerror tileloadstart', function (ev) {\n// \t\t\t\tconsole.log(ev.type);\n                counts[ev.type]++;\n            });\n// \t\t\tgrid.on('tileunload', function (ev) {\n// \t\t\t\tconsole.log(ev.type, ev.coords, counts);\n// \t\t\t});\n\n            map.options.fadeAnimation = false;\n            map.options.zoomAnimation = false;\n        });\n\n        afterEach(function () {\n            clock.restore();\n            grid.off();\n            grid = undefined;\n            counts = undefined;\n        });\n\n        it(\"Loads 8 tiles zoom 1\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(8);\n                expect(counts.tileload).to.be(8);\n                expect(counts.tileunload).to.be(0);\n                done();\n            });\n\n            map.addLayer(grid).setView([0, 0], 1);\n            clock.tick(250);\n        });\n\n        it(\"Loads 5 tiles zoom 0\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(5);\n                expect(counts.tileload).to.be(5);\n                expect(counts.tileunload).to.be(0);\n                done();\n            });\n\n            map.addLayer(grid).setView([0, 0], 0);\n            clock.tick(250);\n        });\n\n        it(\"Loads 16 tiles zoom 10\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off();\n\n                done();\n            });\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        it(\"Loads 32, unloads 16 tiles zooming in 10-11\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(32);\n                    expect(counts.tileload).to.be(32);\n                    expect(counts.tileunload).to.be(16);\n                    done();\n                });\n\n                map.setZoom(11, {animate: false});\n                clock.tick(250);\n            });\n\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        it(\"Loads 32, unloads 16 tiles zooming out 11-10\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(32);\n                    expect(counts.tileload).to.be(32);\n                    expect(counts.tileunload).to.be(16);\n                    done();\n                });\n\n                map.setZoom(10, {animate: false});\n                clock.tick(250);\n            });\n\n\n            map.addLayer(grid).setView([0, 0], 11);\n            clock.tick(250);\n        });\n\n\n        it(\"Loads 32, unloads 16 tiles zooming out 18-10\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(32);\n                    expect(counts.tileload).to.be(32);\n                    expect(counts.tileunload).to.be(16);\n                    done();\n                });\n\n                map.setZoom(10, {animate: false});\n                clock.tick(250);\n            });\n\n\n            map.addLayer(grid).setView([0, 0], 18);\n            clock.tick(250);\n        });\n\n    });\n\n    describe(\"number of 256px tiles loaded in synchronous animated grid @800x600px\", function () {\n\n        var clock, grid, counts;\n\n        beforeEach(function () {\n            clock = sinon.useFakeTimers();\n\n            grid = L.gridLayer({\n                attribution: 'Grid Layer',\n                tileSize: L.point(256, 256)\n            });\n\n            grid.createTile = function (coords) {\n                var tile = document.createElement('div');\n                tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');\n                tile.style.border = '2px solid red';\n                return tile;\n            };\n\n            counts = {\n                tileload: 0,\n                tileerror: 0,\n                tileloadstart: 0,\n                tileunload: 0\n            };\n\n            grid.on('tileload tileunload tileerror tileloadstart', function (ev) {\n                counts[ev.type]++;\n            });\n        });\n\n        afterEach(function () {\n            clock.restore();\n            grid.off();\n            grid = undefined;\n            counts = undefined;\n        });\n\n        // Debug helper\n        function logTiles(ev) {\n            var pending = 0;\n            for (var key in grid._tiles) {\n                if (!grid._tiles[key].loaded) { pending++; }\n            }\n            console.log(ev.type + ': ', ev.coords, grid._loading, counts, ' pending: ', pending);\n        }\n\n\n        // animationFrame helper, just runs requestAnimFrame() a given number of times\n        function runFrames(n) {\n            return _runFrames(n)();\n        }\n\n        function _runFrames(n) {\n            if (n) {\n                return function () {\n                    clock.tick(40); // 40msec/frame ~= 25fps\n                    map.fire('_frame');\n                    L.Util.requestAnimFrame(_runFrames(n - 1));\n                };\n            } else {\n                return L.Util.falseFn;\n            }\n        }\n\n        // NOTE: This test has different behaviour in PhantomJS and graphical\n        // browsers due to CSS animations!\n        it.skipInPhantom(\"Loads 32, unloads 16 tiles zooming in 10-11\", function (done) {\n\n// \t\t\tgrid.on('tileload tileunload tileloadstart load', logTiles);\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n// \t\t\t\tgrid.on('load', logTiles);\n                grid.on('load', function () {\n\n                    // We're one frame into the zoom animation, there are\n                    // 16 tiles for z10 plus 16 tiles for z11 covering the\n                    // bounds at the *end* of the zoom-*in* anim\n                    expect(counts.tileloadstart).to.be(32);\n                    expect(counts.tileload).to.be(32);\n                    expect(counts.tileunload).to.be(0);\n\n                    // Wait > 250msec for the tile fade-in animation to complete,\n                    // which triggers the tile pruning\n                    clock.tick(300);\n\n                    // After the zoom-in, the 'outside' 12 tiles (not the 4\n                    // at the center, still in bounds) have been unloaded.\n                    expect(counts.tileunload).to.be(12);\n\n                    L.Util.requestAnimFrame(function () {\n                        expect(counts.tileloadstart).to.be(32);\n                        expect(counts.tileload).to.be(32);\n                        expect(counts.tileunload).to.be(16);\n                        done();\n                    });\n                });\n\n                map.setZoom(11, {animate: true});\n                clock.tick(250);\n            });\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        it(\"Loads 32, unloads 16 tiles zooming in 10-18\", function (done) {\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n\n                    // In this particular scenario, the tile unloads happen in the\n                    // next render frame after the grid's 'load' event.\n                    L.Util.requestAnimFrame(function () {\n                        expect(counts.tileloadstart).to.be(32);\n                        expect(counts.tileload).to.be(32);\n                        expect(counts.tileunload).to.be(16);\n                        done();\n                    });\n                });\n\n                map.setZoom(18, {animate: true});\n                clock.tick(250);\n            });\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        // NOTE: This test has different behaviour in PhantomJS and graphical\n        // browsers due to CSS animations!\n        it.skipInPhantom(\"Loads 32, unloads 16 tiles zooming out 11-10\", function (done) {\n\n// \t\t\tgrid.on('tileload tileunload load', logTiles);\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n// \t\t\t\tgrid.on('load', logTiles);\n                grid.on('load', function () {\n\n                    grid.off('load');\n// \t\t\t\t\tgrid.on('load', logTiles);\n\n                    // We're one frame into the zoom animation, there are\n                    // 16 tiles for z11 plus 4 tiles for z10 covering the\n                    // bounds at the *beginning* of the zoom-*out* anim\n                    expect(counts.tileloadstart).to.be(20);\n                    expect(counts.tileload).to.be(20);\n                    expect(counts.tileunload).to.be(0);\n\n\n                    // Wait > 250msec for the tile fade-in animation to complete,\n                    // which triggers the tile pruning\n                    clock.tick(300);\n                    L.Util.requestAnimFrame(function () {\n                        expect(counts.tileunload).to.be(16);\n\n                        // The next 'load' event happens when the zoom anim is\n                        // complete, and triggers loading of all the z10 tiles.\n                        grid.on('load', function () {\n                            expect(counts.tileloadstart).to.be(32);\n                            expect(counts.tileload).to.be(32);\n                            done();\n                        });\n\n                    });\n                });\n\n                map.setZoom(10, {animate: true});\n                clock.tick(250);\n            });\n\n            map.addLayer(grid).setView([0, 0], 11);\n            clock.tick(250);\n        });\n\n        it(\"Loads 32, unloads 16 tiles zooming out 18-10\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n\n                    // In this particular scenario, the tile unloads happen in the\n                    // next render frame after the grid's 'load' event.\n                    L.Util.requestAnimFrame(function () {\n                        expect(counts.tileloadstart).to.be(32);\n                        expect(counts.tileload).to.be(32);\n                        expect(counts.tileunload).to.be(16);\n                        done();\n                    });\n                });\n\n                map.setZoom(10, {animate: true});\n                clock.tick(250);\n            });\n\n            map.addLayer(grid).setView([0, 0], 18);\n            clock.tick(250);\n        });\n\n        // NOTE: This test has different behaviour in PhantomJS and graphical\n        // browsers due to CSS animations!\n        it.skipInPhantom(\"Loads 290, unloads 275 tiles on MAD-TRD flyTo()\", function (done) {\n\n            this.timeout(10000); // This test takes longer than usual due to frames\n\n            var mad = [40.40, -3.7], trd = [63.41, 10.41];\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(12);\n                expect(counts.tileload).to.be(12);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                map.on('zoomend', function () {\n                    expect(counts.tileloadstart).to.be(290);\n                    expect(counts.tileunload).to.be(275);\n                    expect(counts.tileload).to.be(290);\n                    expect(grid._container.querySelectorAll('div').length).to.be(16);\t// 15 + container\n                    done();\n                });\n\n                map.flyTo(trd, 12, {animate: true});\n\n// \t\t\t\tmap.on('_frame', function () {\n// \t\t\t\t\tconsole.log('frame', counts);\n// \t\t\t\t});\n\n                runFrames(500);\n            });\n\n            map.addLayer(grid).setView(mad, 12);\n            clock.tick(250);\n        });\n\n    });\n\n    describe(\"configurable tile pruning\", function () {\n        var clock, grid, counts;\n\n        beforeEach(function () {\n            clock = sinon.useFakeTimers();\n\n            grid = L.gridLayer({\n                attribution: 'Grid Layer',\n                tileSize: L.point(256, 256)\n            });\n\n            grid.createTile = function (coords) {\n                var tile = document.createElement('div');\n                tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');\n                tile.style.border = '2px solid red';\n                return tile;\n            };\n\n            counts = {\n                tileload: 0,\n                tileerror: 0,\n                tileloadstart: 0,\n                tileunload: 0\n            };\n\n            grid.on('tileload tileunload tileerror tileloadstart', function (ev) {\n// \t\t\t\tconsole.log(ev.type);\n                counts[ev.type]++;\n            });\n// \t\t\tgrid.on('tileunload', function (ev) {\n// \t\t\t\tconsole.log(ev.type, ev.coords, counts);\n// \t\t\t});\n\n            map.options.fadeAnimation = false;\n            map.options.zoomAnimation = false;\n        });\n\n        afterEach(function () {\n            clock.restore();\n            grid.off();\n            grid = undefined;\n            counts = undefined;\n        });\n\n        it(\"Loads map, moves forth by 512 px, keepBuffer = 0\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(28);\n                    expect(counts.tileload).to.be(28);\n                    expect(counts.tileunload).to.be(12);\n                    done();\n                });\n\n                map.panBy([512, 512], {animate: false});\n                clock.tick(250);\n            });\n\n            grid.options.keepBuffer = 0;\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        it(\"Loads map, moves forth and back by 512 px, keepBuffer = 0\", function (done) {\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(28);\n                    expect(counts.tileload).to.be(28);\n                    expect(counts.tileunload).to.be(12);\n\n                    grid.off('load');\n                    grid.on('load', function () {\n                        expect(counts.tileloadstart).to.be(40);\n                        expect(counts.tileload).to.be(40);\n                        expect(counts.tileunload).to.be(24);\n                        done();\n                    });\n\n                    map.panBy([-512, -512], {animate: false});\n                    clock.tick(250);\n                });\n\n                map.panBy([512, 512], {animate: false});\n                clock.tick(250);\n            });\n\n            grid.options.keepBuffer = 0;\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n\n        it(\"Loads map, moves forth and back by 512 px, default keepBuffer\", function (done) {\n\n            var spy = sinon.spy();\n\n            grid.on('load', function () {\n                expect(counts.tileloadstart).to.be(16);\n                expect(counts.tileload).to.be(16);\n                expect(counts.tileunload).to.be(0);\n                grid.off('load');\n\n                grid.on('load', function () {\n                    expect(counts.tileloadstart).to.be(28);\n                    expect(counts.tileload).to.be(28);\n                    expect(counts.tileunload).to.be(0);\n                    grid.off('load');\n\n                    grid.addEventListener('load', spy);\n\n                    map.panBy([-512, -512], {animate: false});\n                    clock.tick(250);\n\n                    expect(spy.called).to.be(false);\n                    done();\n                });\n\n                map.panBy([512, 512], {animate: false});\n                clock.tick(250);\n            });\n\n            map.addLayer(grid).setView([0, 0], 10);\n            clock.tick(250);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/Map.DragSpec.js",
    "content": "describe(\"Map.Drag\", function () {\n\tdescribe(\"#addHook\", function () {\n\t\tit(\"calls the map with dragging enabled\", function () {\n\t\t\tvar container = document.createElement('div');\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true\n\t\t\t});\n\n\t\t\texpect(map.dragging.enabled()).to.be(true);\n\t\t\tmap.setView([0, 0], 0);\n\t\t\texpect(map.dragging.enabled()).to.be(true);\n\t\t});\n\t\tit(\"calls the map with dragging and worldCopyJump enabled\", function () {\n\t\t\tvar container = document.createElement('div');\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tworldCopyJump: true\n\t\t\t});\n\n\t\t\texpect(map.dragging.enabled()).to.be(true);\n\t\t\tmap.setView([0, 0], 0);\n\t\t\texpect(map.dragging.enabled()).to.be(true);\n\t\t});\n\t\tit(\"calls the map with dragging disabled and worldCopyJump enabled; \" +\n\t\t\t\"enables dragging after setting center and zoom\", function () {\n\t\t\tvar container = document.createElement('div');\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: false,\n\t\t\t\tworldCopyJump: true\n\t\t\t});\n\n\t\t\texpect(map.dragging.enabled()).to.be(false);\n\t\t\tmap.setView([0, 0], 0);\n\t\t\tmap.dragging.enable();\n\t\t\texpect(map.dragging.enabled()).to.be(true);\n\t\t});\n\t});\n\n\n\tdescribe(\"mouse events\", function () {\n\t\tit(\"change the center of the map\", function (done) {\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\t\t\t// \t\t\tcontainer.style.background = '#808080';\n\n\t\t\tdocument.body.appendChild(container);\n\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false\n\t\t\t});\n\t\t\tmap.setView([0, 0], 1);\n\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tvar center = map.getCenter();\n\t\t\t\t\tvar zoom = map.getZoom();\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(center.lat).to.be.within(21.9430, 21.9431);\n\t\t\t\t\texpect(center.lng).to.be(-180);\n\t\t\t\t\texpect(zoom).to.be(1);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar mouse = hand.growFinger('mouse');\n\n\t\t\t// We move 5 pixels first to overcome the 3-pixel threshold of\n\t\t\t// L.Draggable.\n\t\t\tmouse.wait(100).moveTo(200, 200, 0)\n\t\t\t\t.down().moveBy(5, 0, 20).moveBy(256, 32, 200).up();\n\t\t});\n\n\t\tit(\"does not change the center of the map when mouse is moved less than the drag threshold\", function (done) {\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\n\t\t\tdocument.body.appendChild(container);\n\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false\n\t\t\t});\n\n\t\t\tvar originalCenter = L.latLng(0, 0);\n\t\t\tmap.setView(originalCenter, 1);\n\n\t\t\tvar spy = sinon.spy();\n\t\t\tmap.on('drag', spy);\n\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tvar center = map.getCenter();\n\t\t\t\t\tvar zoom = map.getZoom();\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(center).to.eql(originalCenter); // Expect center point to be the same as before the click\n\t\t\t\t\texpect(spy.callCount).to.eql(0); // No drag event should have been fired.\n\t\t\t\t\texpect(zoom).to.be(1);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar mouse = hand.growFinger('mouse');\n\n\t\t\t// We move 2 pixels to stay below the default 3-pixel threshold of\n\t\t\t// L.Draggable. This should result in a click and not a drag.\n\t\t\tmouse.wait(100).moveTo(200, 200, 0)\n\t\t\t\t.down().moveBy(1, 0, 20).moveBy(1, 0, 200).up();\n\t\t});\n\n\t\tit(\"does not change the center of the map when drag is disabled on click\", function (done) {\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\n\t\t\tdocument.body.appendChild(container);\n\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false\n\t\t\t});\n\t\t\tvar originalCenter = L.latLng(0, 0);\n\t\t\tmap.setView(originalCenter, 1);\n\n\t\t\tmap.on('mousedown', function () {\n\t\t\t\tmap.dragging.disable();\n\t\t\t});\n\t\t\tvar spy = sinon.spy();\n\t\t\tmap.on('drag', spy);\n\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tvar center = map.getCenter();\n\t\t\t\t\tvar zoom = map.getZoom();\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(center).to.eql(originalCenter); // Expect center point to be the same as before the click\n\t\t\t\t\texpect(spy.callCount).to.eql(0); // No drag event should have been fired.\n\t\t\t\t\texpect(zoom).to.be(1);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar mouse = hand.growFinger('mouse');\n\n\t\t\t// We move 5 pixels first to overcome the 3-pixel threshold of\n\t\t\t// L.Draggable.\n\t\t\tmouse.wait(100).moveTo(200, 200, 0)\n\t\t\t\t.down().moveBy(5, 0, 20).moveBy(256, 32, 200).up();\n\t\t});\n\t});\n\n\tdescribe(\"touch events\", function () {\n\t\tit.skipIfNotTouch(\"change the center of the map\", function (done) {\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\t\t\t// \t\t\tcontainer.style.background = '#808080';\n\n\t\t\tdocument.body.appendChild(container);\n\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false\n\t\t\t});\n\t\t\tmap.setView([0, 0], 1);\n\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tvar center = map.getCenter();\n\t\t\t\t\tvar zoom = map.getZoom();\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(center.lat).to.be.within(21.9430, 21.9431);\n\t\t\t\t\texpect(center.lng).to.be(-180);\n\t\t\t\t\texpect(zoom).to.be(1);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar toucher = hand.growFinger('touch');\n\n\t\t\t// We move 5 pixels first to overcome the 3-pixel threshold of\n\t\t\t// L.Draggable.\n\t\t\ttoucher.wait(100).moveTo(200, 200, 0)\n\t\t\t\t.down().moveBy(5, 0, 20).moveBy(256, 32, 200).up();\n\t\t});\n\n\t\tit(\"does not change the center of the map when finger is moved less than the drag threshold\", function (done) {\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\n\t\t\tdocument.body.appendChild(container);\n\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false\n\t\t\t});\n\n\t\t\tvar originalCenter = L.latLng(0, 0);\n\t\t\tmap.setView(originalCenter, 1);\n\n\t\t\tvar spy = sinon.spy();\n\t\t\tmap.on('drag', spy);\n\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tvar center = map.getCenter();\n\t\t\t\t\tvar zoom = map.getZoom();\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(center).to.eql(originalCenter); // Expect center point to be the same as before the click\n\t\t\t\t\texpect(spy.callCount).to.eql(0); // No drag event should have been fired.\n\t\t\t\t\texpect(zoom).to.be(1);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar toucher = hand.growFinger('touch');\n\n\t\t\t// We move 2 pixels to stay below the default 3-pixel threshold of\n\t\t\t// L.Draggable. This should result in a click and not a drag.\n\t\t\ttoucher.wait(100).moveTo(200, 200, 0)\n\t\t\t\t.down().moveBy(1, 0, 20).moveBy(1, 0, 200).up();\n\t\t});\n\n\t\tit.skipIfNotTouch('reset itself after touchend', function (done) {\n\n\t\t\tvar container = document.createElement('div');\n\t\t\tcontainer.style.width = container.style.height = '600px';\n\t\t\tcontainer.style.top = container.style.left = 0;\n\t\t\tcontainer.style.position = 'absolute';\n\t\t\tdocument.body.appendChild(container);\n\t\t\tvar map = new L.Map(container, {\n\t\t\t\tdragging: true,\n\t\t\t\tinertia: false,\n\t\t\t\tzoomAnimation: false\t// If true, the test has to wait extra 250msec\n\t\t\t});\n\t\t\tmap.setView([0, 0], 1);\n\n\t\t\t// Change default events order to make the tap comming before the touchzoom.\n\t\t\t// See #4315\n\t\t\tmap.dragging.disable();\n\t\t\tmap.dragging.enable();\n\n\t\t\tvar center = map.getCenter(),\n\t\t\tzoom = map.getZoom();\n\n\n\t\t\tvar mouseHand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\tdocument.body.removeChild(container);\n\t\t\t\t\texpect(map.getCenter().lat).to.be(center.lat);\n\t\t\t\t\texpect(map.getCenter().lng).to.be.within(center.lng - 0.05, center.lng + 0.05);\n\t\t\t\t\texpect(map.getZoom()).to.eql(zoom);\n\n\t\t\t\t\tdone();\n\t\t\t\t}\n\t\t\t});\n\t\t\tvar mouse = mouseHand.growFinger('mouse');\n\t\t\tvar hand = new Hand({\n\t\t\t\ttiming: 'fastframe',\n\t\t\t\tonStop: function () {\n\t\t\t\t\texpect(map.getCenter()).not.to.eql(center);\n\t\t\t\t\texpect(map.getZoom()).not.to.eql(zoom);\n\t\t\t\t\tcenter = map.getCenter();\n\t\t\t\t\tzoom = map.getZoom();\n\t\t\t\t\tmouse.moveTo(220, 220, 0).moveBy(200, 0, 2000);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar f1 = hand.growFinger('touch');\n\t\t\tvar f2 = hand.growFinger('touch');\n\n\t\t\thand.sync(5);\n\t\t\tf1.wait(100).moveTo(275, 300, 0)\n\t\t\t\t.down().moveBy(-200, 0, 1000).up(200);\n\t\t\t// This finger should touch me map after the other one.\n\t\t\tf2.wait(110).moveTo(325, 300, 0)\n\t\t\t\t.down().moveBy(210, 0, 1000).up(200);\n\n\t\t});\n\n\t});\n\n});\n"
  },
  {
    "path": "src/DGCustomization/test/MapSpec.js",
    "content": "describe(\"Map\", function () {\n    var map,\n        spy;\n    beforeEach(function () {\n        map = L.map(document.createElement('div'));\n    });\n\n    // Remove our layers.\n    beforeEach(function () {\n        map.clearLayers();\n    });\n\n    describe(\"#remove\", function () {\n        it(\"fires an unload event if loaded\", function () {\n            var container = document.createElement('div'),\n                map = new L.Map(container).setView([0, 0], 0),\n                spy = sinon.spy();\n            map.on('unload', spy);\n            map.remove();\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"fires no unload event if not loaded\", function () {\n            var container = document.createElement('div'),\n                map = new L.Map(container),\n                spy = sinon.spy();\n            map.on('unload', spy);\n            map.remove();\n            expect(spy.called).not.to.be.ok();\n        });\n\n        describe(\"corner case checking\", function () {\n            it(\"throws an exception upon reinitialization\", function () {\n                var container = document.createElement('div'),\n                    map = new L.Map(container);\n                expect(function () {\n                    L.map(container);\n                }).to.throwException(function (e) {\n                    expect(e.message).to.eql(\"Map container is already initialized.\");\n                });\n                map.remove();\n            });\n\n            it(\"throws an exception if a container is not found\", function () {\n                expect(function () {\n                    L.map('nonexistentdivelement');\n                }).to.throwException(function (e) {\n                    expect(e.message).to.eql(\"Map container not found.\");\n                });\n                map.remove();\n            });\n        });\n\n        it(\"undefines container._leaflet\", function () {\n            var container = document.createElement('div'),\n                map = new L.Map(container);\n            map.remove();\n            expect(container._leaflet).to.be(undefined);\n        });\n\n        it(\"unbinds events\", function () {\n            var container = document.createElement('div'),\n                map = new L.Map(container).setView([0, 0], 1),\n                spy = sinon.spy();\n\n            map.on('click dblclick mousedown mouseup mousemove', spy);\n            map.remove();\n\n            happen.click(container);\n            happen.dblclick(container);\n            happen.mousedown(container);\n            happen.mouseup(container);\n            happen.mousemove(container);\n\n            expect(spy.called).to.not.be.ok();\n        });\n    });\n\n    describe('#getCenter', function () {\n        it('throws if not set before', function () {\n            expect(function () {\n                map.getCenter();\n            }).to.throwError();\n        });\n\n        it('returns a precise center when zoomed in after being set (#426)', function () {\n            var center = L.latLng(10, 10);\n            map.setView(center, 1);\n            map.setZoom(19);\n            expect(map.getCenter()).to.eql(center);\n        });\n\n        it('returns correct center after invalidateSize (#1919)', function () {\n            map.setView(L.latLng(10, 10), 1);\n            map.invalidateSize();\n            expect(map.getCenter()).not.to.eql(L.latLng(10, 10));\n        });\n    });\n\n    describe(\"#whenReady\", function () {\n        describe(\"when the map has not yet been loaded\", function () {\n            it(\"calls the callback when the map is loaded\", function () {\n                var spy = sinon.spy();\n                map.whenReady(spy);\n                expect(spy.called).to.not.be.ok();\n\n                map.setView([0, 0], 1);\n                expect(spy.called).to.be.ok();\n            });\n        });\n\n        describe(\"when the map has already been loaded\", function () {\n            it(\"calls the callback immediately\", function () {\n                var spy = sinon.spy();\n                map.setView([0, 0], 1);\n                map.whenReady(spy);\n\n                expect(spy.called).to.be.ok();\n            });\n        });\n    });\n\n    describe(\"#setView\", function () {\n        it(\"sets the view of the map\", function () {\n            expect(map.setView([51.505, -0.09], 13)).to.be(map);\n            expect(map.getZoom()).to.be(13);\n            expect(map.getCenter().distanceTo([51.505, -0.09])).to.be.lessThan(5);\n        });\n\n        it(\"can be passed without a zoom specified\", function () {\n            map.setZoom(13);\n            expect(map.setView([51.605, -0.11])).to.be(map);\n            expect(map.getZoom()).to.be(13);\n            expect(map.getCenter().distanceTo([51.605, -0.11])).to.be.lessThan(5);\n        });\n\n        // Skip because we have custom logic for maxZoom. Function setZoom is overridden in DGMap.js\n        it.skip(\"limits initial zoom when no zoom specified\", function () {\n            map.options.maxZoom = 20;\n            map.setZoom(100);\n            expect(map.setView([51.605, -0.11])).to.be(map);\n            expect(map.getZoom()).to.be(20);\n            expect(map.getCenter().distanceTo([51.605, -0.11])).to.be.lessThan(5);\n        });\n\n        it(\"defaults to zoom passed as map option\", function () {\n            map = L.map(document.createElement('div'), {zoom: 13});\n            expect(map.setView([51.605, -0.11])).to.be(map);\n            expect(map.getZoom()).to.be(13);\n        });\n\n        it(\"passes duration option to panBy\", function () {\n            map = L.map(document.createElement('div'), {zoom: 13, center: [0, 0]});\n            map.panBy = sinon.spy();\n            map.setView([51.605, -0.11], 13, {animate: true, duration: 13});\n            expect(map.panBy.callCount).to.eql(1);\n            expect(map.panBy.args[0][1].duration).to.eql(13);\n        });\n    });\n\n    describe(\"#getBounds\", function () {\n        it(\"is safe to call from within a moveend callback during initial load (#1027)\", function () {\n            map.on(\"moveend\", function () {\n                map.getBounds();\n            });\n\n            map.setView([51.505, -0.09], 13);\n        });\n    });\n\n    describe('#setMaxBounds', function () {\n        it(\"aligns pixel-wise map view center with maxBounds center if it cannot move view bounds inside maxBounds (#1908)\", function () {\n            var container = map.getContainer();\n            // large view, cannot fit within maxBounds\n            container.style.width = container.style.height = \"1000px\";\n            document.body.appendChild(container);\n            // maxBounds\n            var bounds = L.latLngBounds([51.5, -0.05], [51.55, 0.05]);\n            map.setMaxBounds(bounds, {animate: false});\n            // set view outside\n            map.setView(L.latLng([53.0, 0.15]), 12, {animate: false});\n            // get center of bounds in pixels\n            var boundsCenter = map.project(bounds.getCenter()).round();\n            expect(map.project(map.getCenter()).round()).to.eql(boundsCenter);\n            document.body.removeChild(container);\n        });\n        it(\"moves map view within maxBounds by changing one coordinate\", function () {\n            var container = map.getContainer();\n            // small view, can fit within maxBounds\n            container.style.width = container.style.height = \"200px\";\n            document.body.appendChild(container);\n            // maxBounds\n            var bounds = L.latLngBounds([51, -0.2], [52, 0.2]);\n            map.setMaxBounds(bounds, {animate: false});\n            // set view outside maxBounds on one direction only\n            // leaves untouched the other coordinate (that is not already centered)\n            var initCenter = [53.0, 0.1];\n            map.setView(L.latLng(initCenter), 16, {animate: false});\n            // one pixel coordinate hasn't changed, the other has\n            var pixelCenter = map.project(map.getCenter()).round();\n            var pixelInit = map.project(initCenter).round();\n            expect(pixelCenter.x).to.eql(pixelInit.x);\n            expect(pixelCenter.y).not.to.eql(pixelInit.y);\n            // the view is inside the bounds\n            expect(bounds.contains(map.getBounds())).to.be(true);\n            document.body.removeChild(container);\n        });\n    });\n\n    describe(\"#getMinZoom and #getMaxZoom\", function () {\n        describe('#getMinZoom', function () {\n            it('returns 0 if not set by Map options or TileLayer options', function () {\n                var map = L.map(document.createElement('div'));\n                expect(map.getMinZoom()).to.be(0);\n            });\n        });\n\n        it(\"minZoom and maxZoom options overrides any minZoom and maxZoom set on layers\", function () {\n\n            var map = L.map(document.createElement('div'), {minZoom: 2, maxZoom: 20});\n\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 4, maxZoom: 10}).addTo(map);\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 6, maxZoom: 17}).addTo(map);\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 22}).addTo(map);\n\n            expect(map.getMinZoom()).to.be(2);\n            expect(map.getMaxZoom()).to.be(20);\n        });\n    });\n\n    describe(\"#getMinZoom and #getMaxZoom\", function () {\n        describe('#getMinZoom', function () {\n            it('returns 0 if not set by Map options or TileLayer options', function () {\n                var map = L.map(document.createElement('div'));\n                expect(map.getMinZoom()).to.be(0);\n            });\n        });\n\n        it(\"minZoom and maxZoom options overrides any minZoom and maxZoom set on layers\", function () {\n\n            var map = L.map(document.createElement('div'), {minZoom: 2, maxZoom: 20});\n\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 4, maxZoom: 10}).addTo(map);\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 6, maxZoom: 17}).addTo(map);\n            L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 22}).addTo(map);\n\n            expect(map.getMinZoom()).to.be(2);\n            expect(map.getMaxZoom()).to.be(20);\n        });\n    });\n\n    describe(\"#hasLayer\", function () {\n        it(\"returns false when passed undefined, null, or false\", function () {\n            var map = L.map(document.createElement('div'));\n            expect(map.hasLayer(undefined)).to.equal(false);\n            expect(map.hasLayer(null)).to.equal(false);\n            expect(map.hasLayer(false)).to.equal(false);\n        });\n    });\n\n    function layerSpy() {\n        var layer = new L.Layer();\n        layer.onAdd = sinon.spy();\n        layer.onRemove = sinon.spy();\n        return layer;\n    }\n\n    describe(\"#addLayer\", function () {\n\n        it(\"calls layer.onAdd immediately if the map is ready\", function () {\n            var layer = layerSpy();\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n            expect(layer.onAdd.called).to.be.ok();\n        });\n\n        it(\"calls layer.onAdd when the map becomes ready\", function () {\n            var layer = layerSpy();\n            map.addLayer(layer);\n            expect(layer.onAdd.called).not.to.be.ok();\n            map.setView([0, 0], 0);\n            expect(layer.onAdd.called).to.be.ok();\n        });\n\n        it(\"does not call layer.onAdd if the layer is removed before the map becomes ready\", function () {\n            var layer = layerSpy();\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            map.setView([0, 0], 0);\n            expect(layer.onAdd.called).not.to.be.ok();\n        });\n\n        it(\"fires a layeradd event immediately if the map is ready\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layeradd', spy);\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"fires a layeradd event when the map becomes ready\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layeradd', spy);\n            map.addLayer(layer);\n            expect(spy.called).not.to.be.ok();\n            map.setView([0, 0], 0);\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"does not fire a layeradd event if the layer is removed before the map becomes ready\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layeradd', spy);\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            map.setView([0, 0], 0);\n            expect(spy.called).not.to.be.ok();\n        });\n\n        it(\"adds the layer before firing layeradd\", function (done) {\n            var layer = layerSpy();\n            map.on('layeradd', function () {\n                expect(map.hasLayer(layer)).to.be.ok();\n                done();\n            });\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n        });\n\n        // Skip because we have base layer with greater zooms.\n        describe.skip(\"When the first layer is added to a map\", function () {\n            it(\"fires a zoomlevelschange event\", function () {\n                var spy = sinon.spy();\n                map.on(\"zoomlevelschange\", spy);\n                expect(spy.called).not.to.be.ok();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map);\n                expect(spy.called).to.be.ok();\n            });\n        });\n\n        // Skip because we have base layer with greater zooms.\n        describe.skip(\"when a new layer with greater zoomlevel coverage than the current layer is added to a map\", function () {\n            it(\"fires a zoomlevelschange event\", function () {\n                var spy = sinon.spy();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map);\n                map.on(\"zoomlevelschange\", spy);\n                expect(spy.called).not.to.be.ok();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 15}).addTo(map);\n                expect(spy.called).to.be.ok();\n            });\n        });\n\n        describe(\"when a new layer with the same or lower zoomlevel coverage as the current layer is added to a map\", function () {\n            it(\"fires no zoomlevelschange event\", function () {\n                var spy = sinon.spy();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map);\n                map.on(\"zoomlevelschange\", spy);\n                expect(spy.called).not.to.be.ok();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map);\n                expect(spy.called).not.to.be.ok();\n                L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 5}).addTo(map);\n                expect(spy.called).not.to.be.ok();\n            });\n        });\n    });\n\n    describe(\"#removeLayer\", function () {\n        it(\"calls layer.onRemove if the map is ready\", function () {\n            var layer = layerSpy();\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            expect(layer.onRemove.called).to.be.ok();\n        });\n\n        it(\"does not call layer.onRemove if the layer was not added\", function () {\n            var layer = layerSpy();\n            map.setView([0, 0], 0);\n            map.removeLayer(layer);\n            expect(layer.onRemove.called).not.to.be.ok();\n        });\n\n        it(\"does not call layer.onRemove if the map is not ready\", function () {\n            var layer = layerSpy();\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            expect(layer.onRemove.called).not.to.be.ok();\n        });\n\n        it(\"fires a layerremove event if the map is ready\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layerremove', spy);\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"does not fire a layerremove if the layer was not added\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layerremove', spy);\n            map.setView([0, 0], 0);\n            map.removeLayer(layer);\n            expect(spy.called).not.to.be.ok();\n        });\n\n        it(\"does not fire a layerremove if the map is not ready\", function () {\n            var layer = layerSpy(),\n                spy = sinon.spy();\n            map.on('layerremove', spy);\n            map.addLayer(layer);\n            map.removeLayer(layer);\n            expect(spy.called).not.to.be.ok();\n        });\n\n        it(\"removes the layer before firing layerremove\", function (done) {\n            var layer = layerSpy();\n            map.on('layerremove', function () {\n                expect(map.hasLayer(layer)).not.to.be.ok();\n                done();\n            });\n            map.setView([0, 0], 0);\n            map.addLayer(layer);\n            map.removeLayer(layer);\n        });\n\n        it(\"supports adding and removing a tile layer without initializing the map\", function () {\n            var layer = L.tileLayer(\"{z}{x}{y}\");\n            map.addLayer(layer);\n            map.removeLayer(layer);\n        });\n\n        it(\"supports adding and removing a tile layer without initializing the map\", function () {\n            map.setView([0, 0], 18);\n            var layer = L.gridLayer();\n            map.addLayer(layer);\n            map.removeLayer(layer);\n        });\n\n        describe(\"when the last tile layer on a map is removed\", function () {\n            it(\"fires a zoomlevelschange event\", function () {\n                map.whenReady(function () {\n                    var spy = sinon.spy();\n                    var tl = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map);\n\n                    map.on(\"zoomlevelschange\", spy);\n                    expect(spy.called).not.to.be.ok();\n                    map.removeLayer(tl);\n                    expect(spy.called).to.be.ok();\n                });\n            });\n        });\n\n        describe(\"when a tile layer is removed from a map and it had greater zoom level coverage than the remainding layer\", function () {\n            it(\"fires a zoomlevelschange event\", function () {\n                map.whenReady(function () {\n                    var spy = sinon.spy(),\n                        tl = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map),\n                        t2 = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 15}).addTo(map);\n\n                    map.on(\"zoomlevelschange\", spy);\n                    expect(spy.called).to.not.be.ok();\n                    map.removeLayer(t2);\n                    expect(spy.called).to.be.ok();\n                });\n            });\n        });\n\n        describe(\"when a tile layer is removed from a map it and it had lesser or the sa,e zoom level coverage as the remainding layer(s)\", function () {\n            it(\"fires no zoomlevelschange event\", function () {\n                map.whenReady(function () {\n                    var tl = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map),\n                        t2 = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 10}).addTo(map),\n                        t3 = L.tileLayer(\"{z}{x}{y}\", {minZoom: 0, maxZoom: 5}).addTo(map);\n\n                    map.on(\"zoomlevelschange\", spy);\n                    expect(spy).not.toHaveBeenCalled();\n                    map.removeLayer(t2);\n                    expect(spy).not.toHaveBeenCalled();\n                    map.removeLayer(t3);\n                    expect(spy).not.toHaveBeenCalled();\n                });\n            });\n        });\n    });\n\n    describe(\"#eachLayer\", function () {\n        it(\"returns self\", function () {\n            expect(map.eachLayer(function () {})).to.be(map);\n        });\n\n        it(\"calls the provided function for each layer\", function () {\n            var t1 = L.tileLayer(\"{z}{x}{y}\").addTo(map),\n                t2 = L.tileLayer(\"{z}{x}{y}\").addTo(map),\n                spy = sinon.spy();\n\n            map.eachLayer(spy);\n\n            expect(spy.callCount).to.eql(2);\n            expect(spy.firstCall.args).to.eql([t1]);\n            expect(spy.secondCall.args).to.eql([t2]);\n        });\n\n        it(\"calls the provided function with the provided context\", function () {\n            var t1 = L.tileLayer(\"{z}{x}{y}\").addTo(map),\n                spy = sinon.spy();\n\n            map.eachLayer(spy, map);\n\n            expect(spy.thisValues[0]).to.eql(map);\n        });\n    });\n\n    describe(\"#invalidateSize\", function () {\n        var container,\n            origWidth = 100,\n            clock;\n\n        beforeEach(function () {\n            container = map.getContainer();\n            container.style.width = origWidth + \"px\";\n            document.body.appendChild(container);\n            map.setView([0, 0], 0);\n            map.invalidateSize({pan: false});\n            clock = sinon.useFakeTimers();\n        });\n\n        afterEach(function () {\n            document.body.removeChild(container);\n            clock.restore();\n        });\n\n        it(\"pans by the right amount when growing in 1px increments\", function () {\n            container.style.width = (origWidth + 1) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(1);\n\n            container.style.width = (origWidth + 2) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(1);\n\n            container.style.width = (origWidth + 3) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(2);\n        });\n\n        it(\"pans by the right amount when shrinking in 1px increments\", function () {\n            container.style.width = (origWidth - 1) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(0);\n\n            container.style.width = (origWidth - 2) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(-1);\n\n            container.style.width = (origWidth - 3) + \"px\";\n            map.invalidateSize();\n            expect(map._getMapPanePos().x).to.be(-1);\n        });\n\n        it(\"pans back to the original position after growing by an odd size and back\", function () {\n            container.style.width = (origWidth + 5) + \"px\";\n            map.invalidateSize();\n\n            container.style.width = origWidth + \"px\";\n            map.invalidateSize();\n\n            expect(map._getMapPanePos().x).to.be(0);\n        });\n\n        it(\"emits no move event if the size has not changed\", function () {\n            var spy = sinon.spy();\n            map.on(\"move\", spy);\n\n            map.invalidateSize();\n\n            expect(spy.called).not.to.be.ok();\n        });\n\n        it(\"emits a move event if the size has changed\", function () {\n            var spy = sinon.spy();\n            map.on(\"move\", spy);\n\n            container.style.width = (origWidth + 5) + \"px\";\n            map.invalidateSize();\n\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"emits a moveend event if the size has changed\", function () {\n            var spy = sinon.spy();\n            map.on(\"moveend\", spy);\n\n            container.style.width = (origWidth + 5) + \"px\";\n            map.invalidateSize();\n\n            expect(spy.called).to.be.ok();\n        });\n\n        it(\"debounces the moveend event if the debounceMoveend option is given\", function () {\n            var spy = sinon.spy();\n            map.on(\"moveend\", spy);\n\n            container.style.width = (origWidth + 5) + \"px\";\n            map.invalidateSize({debounceMoveend: true});\n\n            expect(spy.called).not.to.be.ok();\n\n            clock.tick(200);\n\n            expect(spy.called).to.be.ok();\n        });\n    });\n\n    describe('#flyTo', function () {\n\n        it('move to requested center and zoom, and call zoomend once', function (done) {\n            var spy = sinon.spy(),\n                newCenter = new L.LatLng(10, 11),\n                newZoom = 12;\n            var callback = function () {\n                expect(map.getCenter()).to.eql(newCenter);\n                expect(map.getZoom()).to.eql(newZoom);\n                spy();\n                expect(spy.calledOnce).to.be.ok();\n                done();\n            };\n            map.setView([0, 0], 0);\n            map.once('zoomend', callback).flyTo(newCenter, newZoom);\n        });\n\n    });\n\n    describe('#zoomIn and #zoomOut', function () {\n        var center = L.latLng(22, 33);\n        beforeEach(function () {\n            map.setView(center, 10);\n        });\n\n        it('zoomIn zooms by 1 zoom level by default', function (done) {\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(11);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            map.zoomIn(null, {animate: false});\n        });\n\n        it('zoomOut zooms by 1 zoom level by default', function (done) {\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(9);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            map.zoomOut(null, {animate: false});\n        });\n\n        it('zoomIn ignores the zoomDelta option on non-any3d browsers', function (done) {\n            L.Browser.any3d = false;\n            map.options.zoomSnap = 0.25;\n            map.options.zoomDelta = 0.25;\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(11);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            map.zoomIn(null, {animate: false});\n        });\n\n        it('zoomIn respects the zoomDelta option on any3d browsers', function (done) {\n            L.Browser.any3d = true;\n            map.options.zoomSnap = 0.25;\n            map.options.zoomDelta = 0.25;\n            map.setView(center, 10);\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(10.25);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            map.zoomIn(null, {animate: false});\n        });\n\n        it('zoomOut respects the zoomDelta option on any3d browsers', function (done) {\n            L.Browser.any3d = true;\n            map.options.zoomSnap = 0.25;\n            map.options.zoomDelta = 0.25;\n            map.setView(center, 10);\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(9.75);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            map.zoomOut(null, {animate: false});\n        });\n\n        it('zoomIn snaps to zoomSnap on any3d browsers', function (done) {\n            map.options.zoomSnap = 0.25;\n            map.setView(center, 10);\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(10.25);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            L.Browser.any3d = true;\n            map.zoomIn(0.22, {animate: false});\n        });\n\n        it('zoomOut snaps to zoomSnap on any3d browsers', function (done) {\n            map.options.zoomSnap = 0.25;\n            map.setView(center, 10);\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(9.75);\n                expect(map.getCenter()).to.eql(center);\n                done();\n            });\n            L.Browser.any3d = true;\n            map.zoomOut(0.22, {animate: false});\n        });\n    });\n\n    describe('#fitBounds', function () {\n        var center = L.latLng(50.5, 30.51),\n            bounds = L.latLngBounds(L.latLng(1, 102), L.latLng(11, 122)),\n            boundsCenter = bounds.getCenter();\n\n        beforeEach(function () {\n            // fitBounds needs a map container with non-null area\n            var container = map.getContainer();\n            container.style.width = container.style.height = \"100px\";\n            document.body.appendChild(container);\n            map.setView(center, 15);\n        });\n\n        afterEach(function () {\n            document.body.removeChild(map.getContainer());\n        });\n\n        it('Snaps zoom level to integer by default', function (done) {\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(2);\n                expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                done();\n            });\n            map.fitBounds(bounds, {animate: false});\n        });\n\n        it('Snaps zoom to zoomSnap on any3d browsers', function (done) {\n            map.options.zoomSnap = 0.25;\n            L.Browser.any3d = true;\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(2.75);\n                expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                done();\n            });\n            map.fitBounds(bounds, {animate: false});\n        });\n\n        it('Ignores zoomSnap on non-any3d browsers', function (done) {\n            map.options.zoomSnap = 0.25;\n            L.Browser.any3d = false;\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(2);\n                expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                done();\n            });\n            map.fitBounds(bounds, {animate: false});\n        });\n\n        it('can be called with an array', function (done) {\n            map.once('zoomend', function () {\n                expect(map.getZoom()).to.eql(2);\n                expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                done();\n            });\n            var bounds = [[1, 102], [11, 122]];\n            map.fitBounds(bounds, {animate: false});\n        });\n\n        it('throws an error with invalid bounds', function () {\n            expect(function () {\n                map.fitBounds(NaN);\n            }).to.throwError();\n        });\n\n        it('Fits to same scale and zoom', function (done) {\n            var bounds = map.getBounds(),\n                zoom = map.getZoom();\n            map.once('moveend zoomend', function () {\n                var newBounds = map.getBounds();\n                expect(newBounds.getSouthWest()).to.nearLatLng(bounds.getSouthWest());\n                expect(newBounds.getNorthEast()).to.nearLatLng(bounds.getNorthEast());\n                expect(map.getZoom()).to.eql(zoom);\n                done();\n            });\n            map.fitBounds(bounds, {animate: false});\n        });\n\n        it('Fits to small bounds from small zoom', function (done) {\n            map.once('zoomend', function () {\n                map.once('zoomend', function () {\n                    expect(map.getZoom()).to.eql(11);\n                    expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                    done();\n                });\n                map.fitBounds(bounds);\n            });\n\n            bounds = L.latLngBounds([57.73, 11.93], [57.75, 11.95]);\n            boundsCenter = bounds.getCenter();\n            map.setZoom(0);\n        });\n\n        it('Fits to large bounds from large zoom', function (done) {\n            map.once('zoomend', function () {\n                map.once('zoomend', function () {\n                    expect(map.getZoom()).to.eql(0);\n                    expect(map.getCenter().equals(boundsCenter, 0.05)).to.eql(true);\n                    done();\n                });\n                map.fitBounds(bounds);\n            });\n\n            bounds = L.latLngBounds([90, -180], [-90, 180]);\n            boundsCenter = bounds.getCenter();\n            map.setZoom(22);\n        });\n    });\n\n    describe('#fitBounds after layers set', function () {\n        var center = L.latLng(22, 33),\n            bounds = L.latLngBounds(L.latLng(1, 102), L.latLng(11, 122)),\n            boundsCenter = bounds.getCenter();\n\n        beforeEach(function () {\n            // fitBounds needs a map container with non-null area\n            var container = map.getContainer();\n            container.style.width = container.style.height = \"100px\";\n            document.body.appendChild(container);\n        });\n\n        afterEach(function () {\n            document.body.removeChild(map.getContainer());\n        });\n\n        it('Snaps to a number after adding tile layer', function (done) {\n            L.Browser.any3d = true;\n            map.addLayer(L.tileLayer('file:///dev/null'));\n            expect(map.getZoom()).to.be(undefined);\n            map.fitBounds(bounds);\n            expect(map.getZoom()).to.be(2);\n            done();\n        });\n\n        it('Snaps to a number after adding marker', function (done) {\n            L.Browser.any3d = true;\n            map.addLayer(L.marker(center));\n            expect(map.getZoom()).to.be(undefined);\n            map.fitBounds(bounds);\n            expect(map.getZoom()).to.be(2);\n            done();\n        });\n\n    });\n\n    describe('#DOM events', function () {\n\n        var c, map;\n\n        beforeEach(function () {\n            c = document.createElement('div');\n            c.style.width = '400px';\n            c.style.height = '400px';\n            map = new L.Map(c);\n            map.setView(new L.LatLng(0, 0), 0);\n            document.body.appendChild(c);\n        });\n\n        afterEach(function () {\n            document.body.removeChild(c);\n        });\n\n        it(\"DOM events propagate from polygon to map\", function () {\n            var spy = sinon.spy();\n            map.on(\"mousemove\", spy);\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            happen.mousemove(layer._path);\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        it(\"DOM events propagate from marker to map\", function () {\n            var spy = sinon.spy();\n            map.on(\"mousemove\", spy);\n            var layer = new L.Marker([1, 2]).addTo(map);\n            happen.mousemove(layer._icon);\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        it(\"DOM events fired on marker can be cancelled before being caught by the map\", function () {\n            var mapSpy = sinon.spy();\n            var layerSpy = sinon.spy();\n            map.on(\"mousemove\", mapSpy);\n            var layer = new L.Marker([1, 2]).addTo(map);\n            layer.on(\"mousemove\", L.DomEvent.stopPropagation).on(\"mousemove\", layerSpy);\n            happen.mousemove(layer._icon);\n            expect(layerSpy.calledOnce).to.be.ok();\n            expect(mapSpy.called).not.to.be.ok();\n        });\n\n        it(\"DOM events fired on polygon can be cancelled before being caught by the map\", function () {\n            var mapSpy = sinon.spy();\n            var layerSpy = sinon.spy();\n            map.on(\"mousemove\", mapSpy);\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            layer.on(\"mousemove\", L.DomEvent.stopPropagation).on(\"mousemove\", layerSpy);\n            happen.mousemove(layer._path);\n            expect(layerSpy.calledOnce).to.be.ok();\n            expect(mapSpy.called).not.to.be.ok();\n        });\n\n        it(\"mouseout is forwarded if fired on the original target\", function () {\n            var mapSpy = sinon.spy(),\n                layerSpy = sinon.spy(),\n                otherSpy = sinon.spy();\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            var other = new L.Polygon([[10, 20], [30, 40], [50, 60]]).addTo(map);\n            map.on(\"mouseout\", mapSpy);\n            layer.on(\"mouseout\", layerSpy);\n            other.on(\"mouseout\", otherSpy);\n            happen.mouseout(layer._path, {relatedTarget: map._container});\n            expect(mapSpy.called).not.to.be.ok();\n            expect(otherSpy.called).not.to.be.ok();\n            expect(layerSpy.calledOnce).to.be.ok();\n        });\n\n        it(\"mouseout is forwarded when using a DivIcon\", function () {\n            var icon = L.divIcon({\n                html: \"<p>this is text in a child element</p>\",\n                iconSize: [100, 100]\n            });\n            var mapSpy = sinon.spy(),\n                layerSpy = sinon.spy(),\n                layer = L.marker([1, 2], {icon: icon}).addTo(map);\n            map.on(\"mouseout\", mapSpy);\n            layer.on(\"mouseout\", layerSpy);\n            happen.mouseout(layer._icon, {relatedTarget: map._container});\n            expect(mapSpy.called).not.to.be.ok();\n            expect(layerSpy.calledOnce).to.be.ok();\n        });\n\n        it(\"mouseout is not forwarded if relatedTarget is a target's child\", function () {\n            var icon = L.divIcon({\n                html: \"<p>this is text in a child element</p>\",\n                iconSize: [100, 100]\n            });\n            var mapSpy = sinon.spy(),\n                layerSpy = sinon.spy(),\n                layer = L.marker([1, 2], {icon: icon}).addTo(map),\n                child = layer._icon.querySelector('p');\n            map.on(\"mouseout\", mapSpy);\n            layer.on(\"mouseout\", layerSpy);\n            happen.mouseout(layer._icon, {relatedTarget: child});\n            expect(mapSpy.called).not.to.be.ok();\n            expect(layerSpy.calledOnce).not.to.be.ok();\n        });\n\n        it(\"mouseout is not forwarded if fired on target's child\", function () {\n            var icon = L.divIcon({\n                html: \"<p>this is text in a child element</p>\",\n                iconSize: [100, 100]\n            });\n            var mapSpy = sinon.spy(),\n                layerSpy = sinon.spy(),\n                layer = L.marker([1, 2], {icon: icon}).addTo(map),\n                child = layer._icon.querySelector('p');\n            map.on(\"mouseout\", mapSpy);\n            layer.on(\"mouseout\", layerSpy);\n            happen.mouseout(child, {relatedTarget: layer._icon});\n            expect(mapSpy.called).not.to.be.ok();\n            expect(layerSpy.calledOnce).not.to.be.ok();\n        });\n\n        it(\"mouseout is not forwarded to layers if fired on the map\", function () {\n            var mapSpy = sinon.spy(),\n                layerSpy = sinon.spy(),\n                otherSpy = sinon.spy();\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            var other = new L.Polygon([[10, 20], [30, 40], [50, 60]]).addTo(map);\n            map.on(\"mouseout\", mapSpy);\n            layer.on(\"mouseout\", layerSpy);\n            other.on(\"mouseout\", otherSpy);\n            happen.mouseout(map._container);\n            expect(otherSpy.called).not.to.be.ok();\n            expect(layerSpy.called).not.to.be.ok();\n            expect(mapSpy.calledOnce).to.be.ok();\n        });\n\n        it(\"preclick is fired before click on marker and map\", function () {\n            var called = 0;\n            var layer = new L.Marker([1, 2]).addTo(map);\n            layer.on(\"preclick\", function (e) {\n                expect(called++).to.eql(0);\n                expect(e.latlng).to.ok();\n            });\n            layer.on(\"click\", function (e) {\n                expect(called++).to.eql(2);\n                expect(e.latlng).to.ok();\n            });\n            map.on(\"preclick\", function (e) {\n                expect(called++).to.eql(1);\n                expect(e.latlng).to.ok();\n            });\n            map.on(\"click\", function (e) {\n                expect(called++).to.eql(3);\n                expect(e.latlng).to.ok();\n            });\n            happen.click(layer._icon);\n        });\n\n    });\n\n    describe('#getScaleZoom && #getZoomScale', function () {\n        it(\"convert zoom to scale and viceversa and return the same values\", function () {\n            var toZoom = 6.25;\n            var fromZoom = 8.5;\n            var scale = map.getScaleZoom(toZoom, fromZoom);\n            expect(Math.round(map.getZoomScale(scale, fromZoom) * 100) / 100).to.eql(toZoom);\n        });\n    });\n\n    describe('#getZoom', function () {\n        it(\"returns undefined if map not initialized\", function () {\n            expect(map.getZoom()).to.be(undefined);\n        });\n\n        it(\"returns undefined if map not initialized but layers added\", function () {\n            map.addLayer(L.tileLayer('file:///dev/null'));\n            expect(map.getZoom()).to.be(undefined);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/PathSpec.js",
    "content": "describe('Path', function () {\n    describe('#bringToBack', function () {\n        it('is a no-op for layers not on a map', function () {\n            var path = new L.Path();\n            expect(path.bringToBack()).to.equal(path);\n        });\n    });\n\n    describe('#bringToFront', function () {\n        it('is a no-op for layers not on a map', function () {\n            var path = new L.Path();\n            expect(path.bringToFront()).to.equal(path);\n        });\n    });\n\n    describe('#events', function () {\n\n        var c, map;\n\n        beforeEach(function () {\n            c = document.createElement('div');\n            c.style.width = '400px';\n            c.style.height = '400px';\n            map = new L.Map(c);\n            map.setView(new L.LatLng(0, 0), 0);\n            document.body.appendChild(c);\n        });\n\n        afterEach(function () {\n            document.body.removeChild(c);\n        });\n\n        it('fires click event', function () {\n            var spy = sinon.spy();\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            layer.on('click', spy);\n            happen.click(layer._path);\n            expect(spy.called).to.be.ok();\n        });\n\n        it('propagates click event by default', function () {\n            var spy = sinon.spy();\n            var spy2 = sinon.spy();\n            var mapSpy = sinon.spy();\n            var layer = new L.Polygon([[1, 2], [3, 4], [5, 6]]).addTo(map);\n            layer.on('click', spy);\n            layer.on('click', spy2);\n            map.on('click', mapSpy);\n            happen.click(layer._path);\n            expect(spy.called).to.be.ok();\n            expect(spy2.called).to.be.ok();\n            expect(mapSpy.called).to.be.ok();\n        });\n\n        it('can add a layer while being inside a moveend handler', function (done) {\n            var zoneLayer = L.layerGroup();\n            var polygon;\n            map.addLayer(zoneLayer);\n\n            map.on('moveend', function () {\n                zoneLayer.clearLayers();\n                polygon = new L.Polygon([[1, 2], [3, 4], [5, 6]]);\n                zoneLayer.addLayer(polygon);\n            });\n\n            map.invalidateSize();\n            map.setView([1, 2], 12, {animate: false});\n\n            map.panBy([-260, 0]);\n            setTimeout(function () {\n                expect(polygon._parts.length).to.be(0);\n                map.panBy([260, 0]);\n                setTimeout(function () {\n                    expect(polygon._parts.length).to.be(1);\n                    done();\n                }, 300);\n            }, 300);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/PopupSpec.js",
    "content": "describe('Popup', function () {\n\n    var c, map;\n\n    beforeEach(function () {\n        c = document.createElement('div');\n        c.style.width = '400px';\n        c.style.height = '400px';\n        document.body.appendChild(c);\n        map = new L.Map(c);\n        map.setView(new L.LatLng(55.8, 37.6), 6);\n    });\n\n    afterEach(function () {\n        document.body.removeChild(c);\n    });\n\n    it(\"closes on map click when map has closePopupOnClick option\", function () {\n        map.options.closePopupOnClick = true;\n\n        var popup = new L.Popup()\n            .setLatLng(new L.LatLng(55.8, 37.6))\n            .openOn(map);\n\n        happen.click(c);\n\n        expect(map.hasLayer(popup)).to.be(false);\n    });\n\n    it(\"closes on map click when popup has closeOnClick option\", function () {\n        map.options.closePopupOnClick = false;\n\n        var popup = new L.Popup({closeOnClick: true})\n            .setLatLng(new L.LatLng(55.8, 37.6))\n            .openOn(map);\n\n        happen.click(c);\n\n        expect(map.hasLayer(popup)).to.be(false);\n    });\n\n    it(\"does not close on map click when popup has closeOnClick: false option\", function () {\n        map.options.closePopupOnClick = true;\n\n        var popup = new L.Popup({closeOnClick: false})\n            .setLatLng(new L.LatLng(55.8, 37.6))\n            .openOn(map);\n\n        happen.click(c);\n\n        expect(map.hasLayer(popup)).to.be(true);\n    });\n\n    it(\"toggles its visibility when marker is clicked\", function () {\n        var marker = new L.Marker(new L.LatLng(55.8, 37.6));\n        map.addLayer(marker);\n\n        marker.bindPopup('Popup1');\n        expect(map.hasLayer(marker._popup)).to.be(false);\n\n        // toggle open popup\n        happen.click(marker._icon);\n        expect(map.hasLayer(marker._popup)).to.be(true);\n\n        // toggle close popup\n        happen.click(marker._icon);\n        expect(map.hasLayer(marker._popup)).to.be(false);\n    });\n\n    it.skip(\"it should use a popup with a function as content with a FeatureGroup\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(54.6, 38.2));\n        var group = new L.FeatureGroup([marker1, marker2]).addTo(map);\n\n        marker1.description = \"I'm marker 1.\";\n        marker2.description = \"I'm marker 2.\";\n        group.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        map.options.closePopupOnClick = true;\n\n        // toggle popup on marker1\n        group.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6),\n            layer: marker1\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.innerHTML).to.be(\"I'm marker 1.\");\n\n        // toggle popup on marker2\n        group.fire('click', {\n            latlng: new L.LatLng(54.6, 38.2),\n            layer: marker2\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.innerHTML).to.be(\"I'm marker 2.\");\n    });\n\n    it.skip(\"it should function for popup content after bindPopup is called\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(54.6, 38.2));\n        var group = new L.FeatureGroup([marker1]).addTo(map);\n\n        marker1.description = \"I'm marker 1.\";\n        marker2.description = \"I'm marker 2.\";\n        group.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        group.addLayer(marker2);\n\n        map.options.closePopupOnClick = true;\n\n        // toggle popup on marker1\n        group.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6),\n            layer: marker1\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.innerHTML).to.be(\"I'm marker 1.\");\n\n        // toggle popup on marker2\n        group.fire('click', {\n            latlng: new L.LatLng(54.6, 38.2),\n            layer: marker2\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.innerHTML).to.be(\"I'm marker 2.\");\n    });\n\n    it.skip(\"should use a function for popup content when a source is passed to Popup\", function () {\n        var marker = new L.Marker(new L.LatLng(55.8, 37.6)).addTo(map);\n        var popup = L.popup({}, marker);\n\n        marker.description = \"I am a marker.\";\n\n        marker.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        marker.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6)\n        });\n\n        expect(map.hasLayer(marker._popup)).to.be(true);\n        expect(marker._popup._contentNode.innerHTML).to.be(\"I am a marker.\");\n    });\n\n    it(\"triggers popupopen on marker when popup opens\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(57.123076977278, 44.861962891635));\n\n        map.addLayer(marker1);\n        map.addLayer(marker2);\n\n        marker1.bindPopup('Popup1');\n        marker2.bindPopup('Popup2');\n\n        var spy = sinon.spy();\n\n        marker1.on('popupopen', spy);\n\n        expect(spy.called).to.be(false);\n        marker2.openPopup();\n        expect(spy.called).to.be(false);\n        marker1.openPopup();\n        expect(spy.called).to.be(true);\n    });\n\n    it(\"triggers popupclose on marker when popup closes\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(57.123076977278, 44.861962891635));\n\n        map.addLayer(marker1);\n        map.addLayer(marker2);\n\n        marker1.bindPopup('Popup1');\n        marker2.bindPopup('Popup2');\n\n        var spy = sinon.spy();\n\n        marker1.on('popupclose', spy);\n\n        expect(spy.called).to.be(false);\n        marker2.openPopup();\n        expect(spy.called).to.be(false);\n        marker1.openPopup();\n        expect(spy.called).to.be(false);\n        marker2.openPopup();\n        expect(spy.called).to.be(true);\n        marker1.openPopup();\n        marker1.closePopup();\n        expect(spy.callCount).to.be(2);\n    });\n\n    it(\"should take into account icon popupAnchor option\", function () {\n        var autoPanBefore = L.Popup.prototype.options.autoPan;\n        L.Popup.prototype.options.autoPan = false;\n        var popupAnchorBefore = L.Icon.Default.prototype.options.popupAnchor;\n        L.Icon.Default.prototype.options.popupAnchor = [0, 0];\n\n        var latlng = new L.LatLng(55.8, 37.6),\n            offset = new L.Point(20, 30),\n            icon = new L.DivIcon({popupAnchor: offset}),\n            marker1 = new L.Marker(latlng),\n            marker2 = new L.Marker(latlng, {icon: icon});\n\n        marker1.bindPopup('Popup').addTo(map);\n        marker1.openPopup();\n        var defaultLeft = parseInt(marker1._popup._container.style.left, 10);\n        var defaultBottom = parseInt(marker1._popup._container.style.bottom, 10);\n        marker2.bindPopup('Popup').addTo(map);\n        marker2.openPopup();\n        var offsetLeft = parseInt(marker2._popup._container.style.left, 10);\n        var offsetBottom = parseInt(marker2._popup._container.style.bottom, 10);\n        expect(offsetLeft - offset.x).to.eql(defaultLeft);\n        expect(offsetBottom + offset.y).to.eql(defaultBottom);\n\n        // Now retry passing a popup instance to bindPopup\n        marker2.bindPopup(new L.Popup());\n        marker2.openPopup();\n        offsetLeft = parseInt(marker2._popup._container.style.left, 10);\n        offsetBottom = parseInt(marker2._popup._container.style.bottom, 10);\n        expect(offsetLeft - offset.x).to.eql(defaultLeft);\n        expect(offsetBottom + offset.y).to.eql(defaultBottom);\n\n        L.Popup.prototype.options.autoPan = autoPanBefore;\n        L.Icon.Default.prototype.options.popupAnchor = popupAnchorBefore;\n    });\n\n    it(\"prevents an underlying map click for Layer\", function () {\n        var layer = new L.Polygon([[55.8, 37.6], [55.9, 37.7], [56.0, 37.8]]).addTo(map);\n        layer.bindPopup(\"layer popup\");\n\n        var mapClicked = false;\n        map.on('click', function (e) {\n            mapClicked = true;\n            new L.Popup()\n                .setLatLng(e.latlng)\n                .setContent(\"map popup\")\n                .openOn(map);\n        });\n\n        expect(map.hasLayer(layer._popup)).to.be(false);\n        happen.click(layer._path);\n        expect(mapClicked).to.be(false);\n        expect(map.hasLayer(layer._popup)).to.be(true);\n    });\n\n});\n\ndescribe(\"L.Map#openPopup\", function () {\n    var c, map;\n\n    beforeEach(function () {\n        c = document.createElement('div');\n        c.style.width = '400px';\n        c.style.height = '400px';\n        map = new L.Map(c);\n        map.setView(new L.LatLng(55.8, 37.6), 6);\n    });\n\n    it(\"adds the popup layer to the map\", function () {\n        var popup = new L.Popup()\n            .setLatLng(new L.LatLng(55.8, 37.6));\n        map.openPopup(popup);\n        expect(map.hasLayer(popup)).to.be(true);\n    });\n\n    it(\"sets popup location\", function () {\n        var popup = new L.Popup();\n        map.openPopup(popup, L.latLng(55.8, 37.6));\n        expect(popup.getLatLng()).to.eql(L.latLng(55.8, 37.6));\n    });\n\n    it(\"creates a popup from content\", function () {\n        map.openPopup(\"<h2>Hello World</h2>\", L.latLng(55.8, 37.6));\n        expect(map._popup).to.be.an(L.Popup);\n        expect(map._popup.getContent()).to.eql(\"<h2>Hello World</h2>\");\n    });\n\n    it(\"closes existing popup\", function () {\n        var p1 = new L.Popup().setLatLng(new L.LatLng(55.8, 37.6));\n        var p2 = new L.Popup().setLatLng(new L.LatLng(55.8, 37.6));\n        map.openPopup(p1);\n        map.openPopup(p2);\n        expect(map.hasLayer(p1)).to.be(false);\n    });\n\n    it(\"does not close existing popup with autoClose: false option\", function () {\n        var p1 = new L.Popup({autoClose: false}).setLatLng(new L.LatLng(55.8, 37.6));\n        var p2 = new L.Popup().setLatLng(new L.LatLng(55.8, 37.6));\n        map.openPopup(p1);\n        map.openPopup(p2);\n        expect(map.hasLayer(p1)).to.be(true);\n        expect(map.hasLayer(p2)).to.be(true);\n    });\n\n    it('should not be closed when dragging map', function (done) {\n        document.body.appendChild(c);\n        c.style.position = 'absolute';\n        c.style.left = 0;\n        c.style.top = 0;\n        c.style.zIndex = 10000;\n        var coords = map._container.getBoundingClientRect();\n        var spy = sinon.spy();\n        var p = new L.Popup().setLatLng(new L.LatLng(55.8, 37.6));\n        map.openPopup(p);\n        expect(map.hasLayer(p)).to.be(true);\n        map.on('drag', spy);\n        var hand = new Hand({\n            timing: 'fastframe',\n            onStop: function () {\n                expect(spy.called).to.be(true);\n                expect(map.hasLayer(p)).to.be(true);\n                document.body.removeChild(c);\n                done();\n            }\n        });\n        var toucher = hand.growFinger('touch');\n        toucher.moveTo(coords.left + 100, coords.top + 100, 0).down().moveBy(10, 10, 20).up();\n    });\n});\n"
  },
  {
    "path": "src/DGCustomization/test/UtilSpec.js",
    "content": "describe('Util', function () {\r\n\r\n    describe('#extend', function () {\r\n        var a;\r\n\r\n        beforeEach(function () {\r\n            a = {\r\n                foo: 5,\r\n                bar: 'asd'\r\n            };\r\n        });\r\n\r\n        it('extends the first argument with the properties of the second', function () {\r\n            L.Util.extend(a, {\r\n                bar: 7,\r\n                baz: 3\r\n            });\r\n\r\n            expect(a).to.eql({\r\n                foo: 5,\r\n                bar: 7,\r\n                baz: 3\r\n            });\r\n        });\r\n\r\n        it('accepts more than 2 arguments', function () {\r\n            L.Util.extend(a, {bar: 7}, {baz: 3});\r\n\r\n            expect(a).to.eql({\r\n                foo: 5,\r\n                bar: 7,\r\n                baz: 3\r\n            });\r\n        });\r\n    });\r\n\r\n    describe('#bind', function () {\r\n        it('returns the given function with the given context', function () {\r\n            var fn = function () {\r\n                return this;\r\n            };\r\n\r\n            var fn2 = L.Util.bind(fn, {foo: 'bar'});\r\n\r\n            expect(fn2()).to.eql({foo: 'bar'});\r\n        });\r\n\r\n        it('passes additional arguments to the bound function', function () {\r\n            var fn = sinon.spy(),\r\n                foo = {},\r\n                a = {},\r\n                b = {},\r\n                c = {};\r\n\r\n            var fn2 = L.Util.bind(fn, foo, a, b);\r\n\r\n            fn2(c);\r\n\r\n            expect(fn.calledWith(a, b, c)).to.be.ok();\r\n        });\r\n    });\r\n\r\n    describe('#stamp', function () {\r\n        it('sets a unique id on the given object and returns it', function () {\r\n            var a = {},\r\n                id = L.Util.stamp(a);\r\n\r\n            expect(typeof id).to.eql('number');\r\n            expect(L.Util.stamp(a)).to.eql(id);\r\n\r\n            var b = {},\r\n                id2 = L.Util.stamp(b);\r\n\r\n            expect(id2).not.to.eql(id);\r\n        });\r\n    });\r\n\r\n    describe('#falseFn', function () {\r\n        it('returns false', function () {\r\n            expect(L.Util.falseFn()).to.be(false);\r\n        });\r\n    });\r\n\r\n    describe('#formatNum', function () {\r\n        it('formats numbers with a given precision', function () {\r\n            expect(L.Util.formatNum(13.12325555, 3)).to.eql(13.123);\r\n            expect(L.Util.formatNum(13.12325555)).to.eql(13.12326);\r\n        });\r\n    });\r\n\r\n\r\n    describe('#getParamString', function () {\r\n        it('creates a valid query string for appending depending on url input', function () {\r\n            var a = {\r\n                url: 'http://example.com/get',\r\n                obj: {bar: 7, baz: 3},\r\n                result: '?bar=7&baz=3'\r\n            };\r\n\r\n            expect(L.Util.getParamString(a.obj, a.url)).to.eql(a.result);\r\n\r\n            var b = {\r\n                url: 'http://example.com/get?justone=qs',\r\n                obj: {bar: 7, baz: 3},\r\n                result: '&bar=7&baz=3'\r\n            };\r\n\r\n            expect(L.Util.getParamString(b.obj, b.url)).to.eql(b.result);\r\n\r\n            var c = {\r\n                url: undefined,\r\n                obj: {bar: 7, baz: 3},\r\n                result: '?bar=7&baz=3'\r\n            };\r\n\r\n            expect(L.Util.getParamString(c.obj, c.url)).to.eql(c.result);\r\n        });\r\n    });\r\n\r\n    describe('#requestAnimFrame', function () {\r\n        it('calles a function on next frame, unless canceled', function (done) {\r\n            var spy = sinon.spy(),\r\n                foo = {};\r\n\r\n            L.Util.requestAnimFrame(spy);\r\n\r\n            L.Util.requestAnimFrame(function () {\r\n                expect(this).to.eql(foo);\r\n                done();\r\n            }, foo);\r\n\r\n            L.Util.cancelAnimFrame(spy);\r\n        });\r\n    });\r\n\r\n    describe('#throttle', function () {\r\n        it('limits execution to not more often than specified time interval', function (done) {\r\n            var spy = sinon.spy();\r\n\r\n            var fn = L.Util.throttle(spy, 20);\r\n\r\n            fn();\r\n            fn();\r\n            fn();\r\n\r\n            expect(spy.callCount).to.eql(1);\r\n\r\n            setTimeout(function () {\r\n                expect(spy.callCount).to.eql(2);\r\n                done();\r\n            }, 30);\r\n        });\r\n    });\r\n\r\n    describe('#splitWords', function () {\r\n        it('splits words into an array', function () {\r\n            expect(L.Util.splitWords('foo bar baz')).to.eql(['foo', 'bar', 'baz']);\r\n        });\r\n    });\r\n\r\n    describe('#setOptions', function () {\r\n        it('sets specified options on object', function () {\r\n            var o = {};\r\n            L.Util.setOptions(o, {foo: 'bar'});\r\n            expect(o.options.foo).to.eql('bar');\r\n        });\r\n\r\n        it('returns options', function () {\r\n            var o = {};\r\n            var r = L.Util.setOptions(o, {foo: 'bar'});\r\n            expect(r).to.equal(o.options);\r\n        });\r\n\r\n        it('accepts undefined', function () {\r\n            var o = {};\r\n            L.Util.setOptions(o, undefined);\r\n            expect(o.options).to.eql({});\r\n        });\r\n\r\n        it('creates a distinct options object', function () {\r\n            var opts = {},\r\n                o = L.Util.create({options: opts});\r\n            L.Util.setOptions(o, {});\r\n            expect(o.options).not.to.equal(opts);\r\n        });\r\n\r\n        it(\"doesn't create a distinct options object if object already has own options\", function () {\r\n            var opts = {},\r\n                o = {options: opts};\r\n            L.Util.setOptions(o, {});\r\n            expect(o.options).to.equal(opts);\r\n        });\r\n\r\n        it('inherits options prototypally', function () {\r\n            var opts = {},\r\n                o = L.Util.create({options: opts});\r\n            L.Util.setOptions(o, {});\r\n            opts.foo = 'bar';\r\n            expect(o.options.foo).to.eql('bar');\r\n        });\r\n    });\r\n\r\n    describe('#template', function () {\r\n        it('evaluates templates with a given data object', function () {\r\n            var tpl = 'Hello {foo} and {bar}!';\r\n\r\n            var str = L.Util.template(tpl, {\r\n                foo: 'Vlad',\r\n                bar: 'Dave'\r\n            });\r\n\r\n            expect(str).to.eql('Hello Vlad and Dave!');\r\n        });\r\n        it('does not modify text without a token variable', function () {\r\n            expect(L.Util.template('foo', {})).to.eql('foo');\r\n        });\r\n\r\n        it('supports templates with double quotes', function () {\r\n            expect(L.Util.template('He said: \"{foo}\"!', {\r\n                foo: 'Hello'\r\n            })).to.eql('He said: \"Hello\"!');\r\n        });\r\n\r\n        it('throws when a template token is not given', function () {\r\n            expect(function () {\r\n                L.Util.template(undefined, {foo: 'bar'});\r\n            }).to.throwError();\r\n        });\r\n\r\n        it('allows underscores and dashes in placeholders', function () {\r\n            expect(L.Util.template('{nice_stuff}', {'nice_stuff': 'foo'})).to.eql('foo');\r\n            expect(L.Util.template('{-y}', {'-y': 1})).to.eql('1');\r\n        });\r\n    });\r\n\r\n    describe('#isArray', function () {\r\n        expect(L.Util.isArray([1, 2, 3])).to.be(true);\r\n        /* eslint no-array-constructor: 0 */\r\n        expect(L.Util.isArray(new Array(1, 2, 3))).to.be(true);\r\n        expect(L.Util.isArray('blabla')).to.be(false);\r\n        expect(L.Util.isArray({0: 1, 1: 2})).to.be(false);\r\n    });\r\n});\r\n"
  },
  {
    "path": "src/DGCustomization/test/ValidatorApiKeySpec.js",
    "content": "describe('DG.ApiKeyValidator', function() {\n    afterEach(function() {\n        validator = null;\n    });\n\n    describe('#validate', function() {\n        var xhr;\n        var requests = [];\n        var testApiKey = window.__karma__.config.secretKey;\n        var validator;\n        beforeEach(function() {\n            validator = new DG.ApiKeyValidator(testApiKey);\n            xhr = sinon.useFakeXMLHttpRequest();\n            requests = [];\n            xhr.onCreate = function(req) { requests.push(req); };\n        });\n\n        afterEach(function() {\n            xhr.restore();\n            validator.destroy();\n            validator = null;\n        });\n\n\n        it('should make a request to the correct endpoint', function() {\n            validator.validate(function() {});\n            expect(requests.length).to.be(1);\n            expect(requests[0].url).to.be(validator.endpoint);\n            expect(requests[0].method).to.be('GET');\n        });\n\n        it('should handle successful response', function(done) {\n            var response = {\n                meta: {code: 200},\n                result: {\n                    // eslint-disable-next-line camelcase\n                    is_active: true,\n                    service: {\n                        // eslint-disable-next-line camelcase\n                        is_active: true,\n                        status: {\n                            code: 'ok'\n                        }\n                    }\n                }\n            };\n\n            validator.validate(function(result) {\n                expect(result.result.service.is_active).to.eql(response.result.service.is_active);\n                expect(validator.isLoading).to.be(false);\n                done();\n            });\n\n            requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify(response));\n        });\n    });\n\n    describe('#invalid', function() {\n        var xhr;\n        var requests = [];\n        var invalidApiKey = window.__karma__.config.secretInvalidKey;\n        var validator;\n        beforeEach(function() {\n            validator = new DG.ApiKeyValidator(invalidApiKey);\n            xhr = sinon.useFakeXMLHttpRequest();\n            requests = [];\n            xhr.onCreate = function(req) { requests.push(req); };\n        });\n\n        afterEach(function() {\n            xhr.restore();\n            validator.destroy();\n            validator = null;\n        });\n\n        it('should handle insecure response the key service is blocked', function(done) {\n            var response = {\n                meta: {code: 200},\n                result: {\n                    // eslint-disable-next-line camelcase\n                    is_active: false,\n                    service: {\n                        // eslint-disable-next-line camelcase\n                        is_active: false,\n                        status: {\n                            code: 'blocked'\n                        }\n                    }\n                }\n            };\n\n            validator.validate(function(result) {\n                expect(result.result.service.is_active).to.eql(response.result.service.is_active);\n                expect(validator.isLoading).to.be(false);\n                done();\n            });\n\n            requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify(response));\n        });\n    });\n\n    describe('#empty', function() {\n        var xhr;\n        var requests = [];\n        var validator;\n        beforeEach(function() {\n            validator = new DG.ApiKeyValidator('');\n            xhr = sinon.useFakeXMLHttpRequest();\n            requests = [];\n            xhr.onCreate = function(req) { requests.push(req); };\n        });\n\n        afterEach(function() {\n            xhr.restore();\n            validator.destroy();\n            validator = null;\n        });\n\n        it('should handle insecure response without key', function(done) {\n            var response = {\n                meta: {code: 400},\n                result: {}\n            };\n\n            validator.validate(function(result) {\n                expect(result.meta.code).to.eql(response.meta.code);\n                expect(validator.isLoading).to.be(false);\n                done();\n            });\n            requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify(response));\n        });\n\n    });\n});\n"
  },
  {
    "path": "src/DGDust/doc/DGDust.md",
    "content": "## DG.dust\n\nИспользуется для шаблонизации в Javascript. Использует шаблонизатор [dustjs (fork Linkedin)](http://linkedin.github.io/dustjs/)\n\n### Функция-конструктор\n\n<table>\n    <tr>\n        <th>Использование</th>\n        <th>Возвращает</th>\n        <th>Описание</th>\n    </tr>\n    <tr>\n        <td>\n            <code><b>String</b><i> name of dust template</i>, <b>Object</b><i> data</i></code>\n        </td>\n        <td>\n            <code><b>String</b><i> rendered template</i></code>\n        </td>\n        <td>Функция, выполняющая рендер шаблона. Принимает имя шаблона и данные для подстановки и возвращает строку с итоговым html-кодом. Имя шаблона имеет следующий вид: имя_модуля/имя_файла_с_шаблоном; например: DGAttribution/copyright</td>\n    </tr>\n</table>\n\n\n### Подключение шаблонов\n\nДобавляем нужные шаблоны в каталог templates:\n\n* **DGTraffic/**\n    * **...**\n    * **templates/**\n        * balloon.dust\n        * firmCard.dust\n\n```js\nvar html = DG.dust('DGTraffic/balloon', {title: 'hello'}) // вернет контент шаблона balloon.dust с подставленым title'ом\n```\n"
  },
  {
    "path": "src/DGDust/src/DGDust.js",
    "content": "var dust = require('dustjs-linkedin');\nrequire('dustjs-helpers');\n\nDG.dust = function(name, data) {\n    var result;\n\n    // The callback is called synchronously, so this works\n    dust.render(name, data, function(err, html) {\n        result = html;\n    });\n\n    return result;\n};\n"
  },
  {
    "path": "src/DGDust/test/DGDustSpec.js",
    "content": "describe('DG.Dust', function() {\n    it('should be a function', function() {\n        expect(DG.dust).to.be.a('function');\n    });\n});\n"
  },
  {
    "path": "src/DGEntrance/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset='utf-8'>\n  <title>DGEntrance demo</title>\n  <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n\n</head>\n<body>\n\n  <div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в метро\" id=\"metroEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в остановку\" id=\"busEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в 2GIS\" id=\"dgEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Погулять и зайти в 2GIS\" id=\"backDgEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в Спарк-Авто\" id=\"sparkAutoEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в ГУМ\" id=\"gumEntrance\" />\n  <input class=\"btn\" type=\"button\" value=\"Найти вход в стройку\" id=\"buildingEntrance\" />\n\n  <script type=\"text/javascript\">\n    var map,\n        balloonHTML,\n        btns = [\n            document.getElementById('metroEntrance'),\n            document.getElementById('busEntrance'),\n            document.getElementById('dgEntrance'),\n            document.getElementById('backDgEntrance'),\n            document.getElementById('sparkAutoEntrance'),\n            document.getElementById('gumEntrance'),\n            document.getElementById('buildingEntrance')\n        ];\n\n    DG.then(function () {\n        for (var i = 0; i < btns.length; i++) {\n            btns[i].onclick = addEntrance;\n        };\n\n        map = new DG.Map('map', {\n            center: [54.980206086231, 82.898068362003],\n            zoom: 18,\n            key: DG.config.key || 'Your API access key'\n        });\n        balloonHTML = '<a href=\"http://www.2gis.ru/\" target=\"_blank\">\\n\\\n            <img src=\"2gis-logo.png\" alt=\"2GIS\" title=\"2GIS\" width=\"146\" height=\"70\" style=\"border: none\"></a>\\n\\\n            <p>Компания «ДубльГИС»</p>Тел.: (383) 363-05-55<br />Адрес: г. Новосибирск, Карла Маркса площадь, 7<br />\\n\\\n            (МФК «Сан Сити»), 13 этаж';\n        DG.marker([54.980206086231, 82.898068362003]).addTo(map).bindPopup(balloonHTML).openPopup();\n\n        var entrances = {\n            'metroEntrance': new DG.Entrance({\n                \"vectors\": [\"LINESTRING(82.89755344390868 54.982320605449296, 82.89714574813843 54.982566865457464, 82.89677560329437 54.9823329184856, 82.89664685726164 54.98240679662398, 82.89677023887634 54.98247451813142)\"]\n            }),\n            'busEntrance': new DG.Entrance({\n                \"vectors\": [\"LINESTRING(82.89929687976837 54.98181268941162, 82.89916276931763 54.98173265357113, 82.89852440357208 54.98208665704234)\"]\n            }),\n            'dgEntrance': new DG.Entrance({\n                \"vectors\": [\"LINESTRING(82.89850294589996 54.97985176538553, 82.89841711521149 54.97989794209166)\"]\n            }),\n\n            'backDgEntrance': new DG.Entrance({\n                \"vectors\": [\"LINESTRING(82.8998601436615 54.98056903755945, 82.8987979888916 54.98116931987221, 82.89790213108063 54.980658310881815, 82.89726376533508 54.980996932024134, 82.89698481559753 54.98087379739374, 82.89712429046631 54.98043050959726, 82.89719939231873 54.98039664713382, 82.89721012115477 54.98036278464179, 82.89705991744995 54.98028274591077, 82.89718866348267 54.97991333431523, 82.8970867395401 54.97967629341785, 82.89766073226929 54.97944540808143, 82.89810597896576 54.97967013649277, 82.8980040550232 54.97970399956898, 82.89811134338379 54.979771725635736)\"]\n            }),\n\n            'sparkAutoEntrance': new DG.Entrance({\n                \"vectors\": [\n                    \"LINESTRING(82.8987067937851 54.97971323494846, 82.89879262447357 54.979667058029875)\",\n                    \"LINESTRING(82.89904475212097 54.97952237000778, 82.89896428585052 54.97956854709275)\"\n                ]\n            }),\n\n            'gumEntrance': new DG.Entrance({\n                \"vectors\": [\n                    \"LINESTRING(82.8974461555481 54.9816433826377, 82.89768755435944 54.98177574981275, 82.89783239364624 54.9816957138986, 82.89774119853973 54.98164030432612)\"\n                ]\n            }),\n\n            'buildingEntrance': new DG.Entrance({\n                \"vectors\": [\n                    \"LINESTRING(82.89892673492432 54.98161567782492, 82.89850294589996 54.98136633364934, 82.89860486984253 54.98131400195911)\"\n                ]\n            })\n\n        }\n\n        function addEntrance() {\n            var entrance = entrances[this.id];\n            entrance.addTo(map).show(true);\n        }\n    });\n\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGEntrance/src/DGAnimation.js",
    "content": "/*\n * DG.Animation provides tick (step) logic returning progression values\n * calculated over provided or custom Bézier curves\n * Original input can be array object btw...\n */\n\nDG.Animation = DG.Evented.extend({\n    options: {\n        // animation: {    //  Or array of objects\n        //     function: DG.Animation.EASE,\n        //     duration: 2000,\n        //     frames: null\n        // }\n\n        //offset: 0\n        //repeat: 0\n    },\n\n    initialize: function(options) {\n        DG.setOptions(this, options);\n\n        this._animID = -1;\n        this._startTime = 0;\n        this._running = false;\n        this._animation = null;\n        this._durations = null;\n    },\n\n    start: function() {\n        this.stop();\n        this._prepare();\n\n        this._running = true;\n\n        this.fire('start');\n\n        //  Date.now(), but... IE9+\n        this._startTime = new Date().getTime();\n\n        this._animate();\n    },\n\n    stop: function() {\n        if (this._running) {\n            this._run(this._durations.getLength());\n        }\n    },\n\n    _prepare: function() {\n        this._animation = DG.Util.isArray(this.options.animation) ? this.options.animation : [this.options.animation];\n\n        this._durations = new DG.Metric.Segments();\n        this._animation.forEach(function(animation) {\n            this.push(animation.duration);\n        }, this._durations);\n    },\n\n    _animate: function() {\n        this._animID = DG.Util.requestAnimFrame(this._animate, this);\n        this._run();\n    },\n\n    _run: function(elapsed) {\n        var el, index, progress;\n        //  Possible skip zero delta time but who cares?!\n        elapsed = elapsed ? elapsed : new Date().getTime() - this._startTime;\n\n        if (elapsed < this._durations.getLength()) {\n            index = this._durations.getIndex(elapsed);\n            el = this._durations.getSegRatio(elapsed);\n            progress = this._animation[index]['function'].getYbyX(el);\n            this._step(this._getFrameValues(index, progress));\n        } else {\n            index = this._durations.length - 1;\n            this._step(this._getFrameValues(index, 1));\n            this._complete();\n        }\n    },\n\n    _step: function(obj) {\n        this.fire('step', obj);\n    },\n\n    _complete: function() {\n        DG.Util.cancelAnimFrame(this._animID);\n\n        this._durations = null;\n        this._animation = null;\n        this._running = false;\n        this.fire('end');\n    },\n\n    _getFrameValues: function(index, progress) {\n        var frames = this._animation[index].frames;\n        var obj = {progress: progress};\n        var fr, to;\n\n        if (frames) {\n            for (var key in frames) {\n                if (frames[key].progress) {\n                    obj[key] = frames[key].progress(progress);\n                } else {\n                    fr = frames[key].from;\n                    to = frames[key].to;\n                    obj[key] = fr + (to - fr) * progress;\n                }\n            }\n        }\n        return obj;\n    }\n});\n\nDG.animation = function(options) {\n    return new DG.Animation(options);\n};\n\nDG.Animation.LINEAR         = new DG.TimeBezier(DG.point(0.00, 0.0), DG.point(1.00, 1.0));\nDG.Animation.EASE           = new DG.TimeBezier(DG.point(0.25, 0.1), DG.point(0.25, 1.0));\nDG.Animation.EASE_IN        = new DG.TimeBezier(DG.point(0.42, 0.0), DG.point(1.00, 1.0));\nDG.Animation.EASE_IN_OUT    = new DG.TimeBezier(DG.point(0.42, 0.0), DG.point(0.58, 1.0));\nDG.Animation.EASE_OUT       = new DG.TimeBezier(DG.point(0.00, 0.0), DG.point(0.58, 1.0));\n"
  },
  {
    "path": "src/DGEntrance/src/DGArrowPathTransform.js",
    "content": "/*\n * DG.ArrowPathTransform class is a core of arrow's body calculations\n *\n * General ideas are:\n *      We construct arrow body with stroke points making arcs on outer path turns\n *      Processing is done segment by segment around {0, 0} virtual point\n *          and resulting 'path' finally rotated to it's original map's angle (.fullAngle)\n *      Subset of this vertices lately used in .subPath() calculations which can be used\n *          in animations for ex.\n *\n *  Final translation (see DG.Entrance.Arrow) moves arrow objects to their original positions\n */\n\nDG.ArrowPathTransform = DG.VertexTransform.extend({\n    initialize: function(path) {\n        //  'path.offset' is initial points offset (-x / +x) to compensate arrow tip length\n\n        //  Skip super initialization as we need only subset of DG.VertexTransform power\n        this._lengths = new DG.Metric.Segments();\n        this._vertices = [[], []];\n        this._drawings = [[], []];\n        //  this._arcs = [];    //  initialized in _setPath()\n\n        this._setPath(path);\n        this.subPath(1);\n    },\n\n    load: function() {\n        return this.subPath(1);\n    },\n\n    save: function() {\n        return this;    //  NoOp\n    },\n\n    //  Method constructs new path points with some displacement from original 'path'\n    //  Outer corners will be smoothed by arcs (cubic Bézier curves)\n    _setPath: function(path) {\n        var transform = DG.ArrowPathTransform.transform;\n        var vertices = this._vertices;\n        var drawings = this._drawings;\n        var Point = DG.Point;\n        var width = path.width;\n        var arcs = [[], [], []];\n        var lengths = [];\n\n        var i, x,\n            ax, bx, cx,\n            angles, angle;\n\n        vertices.push(path.vertices);   //  expect .pop() in final transform\n        vertices[0].push(new DG.Point(path.offset, +width));\n        vertices[1].push(new DG.Point(path.offset, -width));\n        angles = DG.ArrowPathTransform.getAngles(path);\n\n        cx = -path.offset;\n        for (i = 0; i < angles.length; i++) {\n            x = path.vertices[i + 1].x;\n            ax = width * angles[i].cot;\n\n            //  http://pomax.github.io/bezierinfo/#circles_cubic\n            //  actual equation is (4/3 * tan(α/4) * radius)\n            bx = angles[i].tan * width * 8 / 3;\n\n            //  Next code can be combined by -/+ inversion but for simplicity it is left as is\n            if (ax > 0) {\n                vertices[0].push(new Point(x + ax,      +width));\n                drawings[0].push('L');\n\n                arcs[2].push(1);\n                arcs[1].push(vertices[1].length);\n                vertices[1].push(new Point(x + ax,      -width));\n                vertices[1].push(new Point(x + ax - bx, -width));\n\n                transform(vertices, angles[i], {x: x, y: 0});\n\n                vertices[1].push(new Point(0 - ax + bx, -width));\n                vertices[1].push(new Point(0 - ax,      -width));\n                drawings[1].push('L', 'C');\n\n                lengths.push(Math.abs(x + ax) - cx); cx = +ax;\n            } else {\n                vertices[1].push(new Point(x - ax,      -width));\n                drawings[1].push('L');\n\n                arcs[2].push(0);\n                arcs[0].push(vertices[0].length);\n                vertices[0].push(new Point(x - ax,      +width));\n                vertices[0].push(new Point(x - ax + bx, +width));\n\n                transform(vertices, angles[i], {x: x, y: 0});\n\n                vertices[0].push(new Point(0 + ax - bx, +width));\n                vertices[0].push(new Point(0 + ax,      +width));\n                drawings[0].push('L', 'C');\n\n                lengths.push(Math.abs(x - ax) - cx); cx = -ax;\n            }\n        }\n\n        //  Final segments and tail arc\n        ax = path.vertices[i + 1].x;\n        bx = width * 4 / 3; // tan(PI/4) = 1\n\n        vertices[0].push(new Point(ax, +width));\n        vertices[1].push(new Point(ax, -width));\n\n        vertices[0].push(new Point(ax - bx, +width));\n        vertices[1].push(new Point(ax - bx, -width));\n\n        drawings[0].push('L');\n        drawings[1].push('L');\n\n        lengths.push(Math.abs(ax) - cx);\n\n        //  Reverse right path\n        vertices[1].reverse();\n        drawings[1].reverse();\n\n        //  Move vertices into original position (before last translation)\n        angle = DG.VertexTransform.getAnglesSum(angles.fullAngle, path.getAngle());\n        transform(vertices, angle, vertices.pop()[0]);  //  path.vertices[0]\n\n        //  We need to reconstruct arc's indexes but too many variables already touched, reuse some of them\n        ax = vertices[0].length;\n        bx = vertices[1].length;\n        this._arcs = arcs[2].map(function(i) {\n            cx = arcs[i].shift();\n            if (i > 0) {\n                return new DG.ArcBezier(vertices[1].slice(bx - cx - 4, bx - cx));\n            } else {\n                return new DG.ArcBezier(vertices[0].slice(cx, cx + 4).reverse());\n            }\n        }).reverse();\n\n        this._lengths.push(lengths.pop());\n        lengths.reverse().forEach(function(l, i) {\n            this._lengths.push(this._arcs[i].getLength()).push(l);\n        }, this);\n\n        //  Shortcut border cases (0%-length sub-path and full-path)\n        this[0] = {\n            vertices: [vertices[0][ax - 2], vertices[0][ax - 1], vertices[1][0], vertices[1][1]],\n            drawings: ['M', 'C']\n        };\n        this[1] = {\n            vertices: vertices[0].concat(vertices[1]),\n            drawings: ['M'].concat(drawings[0], 'C', drawings[1])\n        };\n    },\n\n    _setAngleAndDisplacement: function(vL, vR) { // Used in DG.ArrowTipTransform.subShape()\n        this.angle = DG.VertexTransform.getAngle({x: vL.x - vR.x, y: vL.y - vR.y}, {x: 0, y: 1});\n        this.displ = vR.clone();\n    },\n\n    subPath: function(pathRatio) {\n        pathRatio = pathRatio > 1 ? 1 : pathRatio;\n\n        //  Shortcut border cases (0%-length sub-path and full-path)\n        if (pathRatio === 0 || pathRatio === 1) {\n            this.vertices = this[pathRatio].vertices.map(function(vertex) { return vertex.clone(); });\n            this.drawings = this[pathRatio].drawings;\n            this._setAngleAndDisplacement(this.vertices[0], this.vertices[this.vertices.length - 1]);\n            return this;\n        }\n\n        var getScaled = DG.VertexTransform.getScaled;\n        var vertices = this._vertices;\n        var drawings = this._drawings;\n        var lengths = this._lengths;\n        var len = lengths.getLength() * pathRatio;\n        var segIndex = lengths.getIndex(len);\n        var segRatio = lengths.getSegRatio(len);\n        var vertexIndexLeft = vertices[0].length - 2;\n        var vertexIndexRight = 1;\n        var drawingIndexLeft = drawings[0].length - 1;\n        var drawingIndexRight = 0;\n        var vertexLeft, vertexRight;\n        var arc = 0, aed = 0;\n\n        while (aed++ < segIndex) {\n            if (aed % 2 == 1) {\n                vertexIndexLeft--;\n                drawingIndexLeft--;\n                vertexIndexRight++;\n                drawingIndexRight++;\n            } else {\n                if (drawings[0][drawingIndexLeft] === 'C') {\n                    vertexIndexLeft -= 3;\n                    drawingIndexLeft -= 1;\n                } else {\n                    vertexIndexRight += 3;\n                    drawingIndexRight += 1;\n                }\n                arc++;\n            }\n        }\n\n        if (segIndex % 2 == 1) {\n            //  One path ends with an arc\n            arc = this._arcs[arc];\n            if (drawings[0][drawingIndexLeft] === 'C') {\n                arc = arc.getCurveBefore(arc.getTbyL(lengths.getSegLength(len)));\n                vertexLeft = arc.points[3];\n                vertexRight = vertices[1][vertexIndexRight];\n                this.vertices = arc.points.slice(1).reverse()\n                    .concat(vertices[0].slice(vertexIndexLeft), vertices[1].slice(0, vertexIndexRight + 1))\n                    .map(function(vertex) { return vertex.clone(); });\n                this.drawings = ['M'].concat(drawings[0].slice(drawingIndexLeft), 'C', drawings[1].slice(0, drawingIndexRight));\n            } else {\n                arc = arc.getCurveBefore(arc.getTbyL(lengths.getSegLength(len)));\n                vertexLeft = vertices[0][vertexIndexLeft];\n                vertexRight = arc.points[3];\n                this.vertices = vertices[0].slice(vertexIndexLeft)\n                    .concat(vertices[1].slice(0, vertexIndexRight + 1), arc.points.slice(1))\n                    .map(function(vertex) { return vertex.clone(); });\n                this.drawings = ['M'].concat(drawings[0].slice(drawingIndexLeft + 1), 'C', drawings[1].slice(0, drawingIndexRight + 1));\n            }\n        } else {\n            //  Both paths end with lines\n            vertexLeft = getScaled(vertices[0][vertexIndexLeft], vertices[0][vertexIndexLeft - 1], segRatio);\n            vertexRight = getScaled(vertices[1][vertexIndexRight], vertices[1][vertexIndexRight + 1], segRatio);\n            this.vertices = [vertexLeft]\n                .concat(vertices[0].slice(vertexIndexLeft), vertices[1].slice(0, vertexIndexRight + 1), vertexRight)\n                .map(function(vertex) { return vertex.clone(); });\n            this.drawings = ['M'].concat(drawings[0].slice(drawingIndexLeft), 'C', drawings[1].slice(0, drawingIndexRight + 1));\n        }\n\n        this._setAngleAndDisplacement(vertexLeft, vertexRight);\n        return this;\n    },\n\n    statics: {\n        getAngles: function(path) {\n            var getAngle = DG.VertexTransform.getAngle;\n            var fullAngle = {cos: 1, sin: 0};\n            var vertices = path.vertices;\n            var angles = [];\n\n            var absSin, angle,\n                cos, sin, cot, temp, sign;\n\n            for (var i = 1, len = vertices.length - 1; i < len; i++) {\n                angle = getAngle(vertices[i - 1], vertices[i + 1], vertices[i]);\n\n                absSin = Math.abs(angle.sin);\n                if (absSin < 0.000001) {\n                    //  Exclude 180° angle from vertices array\n                    vertices.splice(vertices.length - i - 1, 1);\n                    len--;\n                    i--;\n                } else {\n                    //  This is half ∢α cotangent, sign describes angle direction and used to shortcut stroke calculations\n                    //  '-1' - right angle is inner angle, '1' - left angle is inner angle (if seen from [0, 0] to [-1, 0])\n                    angle.cot = (1 + angle.cos) / angle.sin;\n\n                    //  We need to rotate next segment to [-1, 0] axis, so we need complementary angle actually\n                    angle.cos = -angle.cos;\n\n                    //  Complimentary angle also used to calculate it's quaternary ∢β tangent\n                    //  ∢β tangent used in approximation of outer arc segment by Bézier curve\n                    cot = (1 + angle.cos) / angle.sin;\n                    sign = cot < 0 ? -1 : 1;\n                    temp = sign * Math.sqrt(4 * cot * cot + 4);\n                    angle.tan = -0.5 * (cot + cot - temp);\n\n                    angles.push(angle);\n\n                    cos = fullAngle.cos * angle.cos - fullAngle.sin * angle.sin;\n                    sin = fullAngle.sin * angle.cos + fullAngle.cos * angle.sin;\n\n                    fullAngle = {cos: cos, sin: sin};\n                }\n            }\n\n            //  Used in final stroke points translation\n            angles.fullAngle =  {cos: fullAngle.cos, sin: -fullAngle.sin};\n            return angles;\n        },\n\n        //  TODO - if length of 'latlngs' array is less than 2 or it is undefined next function produces exception\n        //  check this condition in outer routines?!\n        getTranslatedPath: function(map, latlngs) {\n            var path = new DG.VertexTransform([]);\n            var i = latlngs.length - 1;\n            var v = map.project(latlngs[i]);\n            var dx = v.x, dy = v.y;\n\n            path.vertices.push(new DG.Point(0, 0));\n            while (i--) {\n                v = map.project(latlngs[i]);\n                path.vertices.push(new DG.Point(v.x - dx, v.y - dy));\n            }\n            return path\n                .setAngle(DG.VertexTransform.getAngle(-path.vertices[1].x, -path.vertices[1].y))\n                .unRotate();\n        },\n\n        transform: function(rings, angle, vector) {\n            var i = rings.length;\n            var cos = angle.cos;\n            var sin = angle.sin;\n            var dx = vector.x;\n            var dy = vector.y;\n            var ring, x, y, j;\n\n            while (i--) {\n                ring = rings[i];\n                j = ring.length;\n                while (j--) {\n                    x = ring[j].x - dx;\n                    y = ring[j].y - dy;\n                    ring[j].x = x * cos - y * sin;\n                    ring[j].y = x * sin + y * cos;\n                }\n            }\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/src/DGArrowTipTransform.js",
    "content": "/*\n * DG.ArrowTipTransform class is a core of arrow's tip calculations\n *\n * .subShape() routine 'bound' arrow's tip to the ending points of .subPath()\n * calculated separately in DG.ArrowPathTransform\n *\n *  Final translation (see DG.Entrance.Arrow) moves arrow objects to their original positions\n */\n\nDG.ArrowTipTransform = DG.VertexTransform.extend({\n    initialize: function(path, shape) {\n        this.drawings = shape.drawings; //  static mapping\n        this._vertices = shape.vertices;\n\n        this._setShape(path, shape);\n    },\n\n    _setShape: function(path, shape) {\n        var sp = shape.vertices[0];\n        var width = Math.abs(sp.y);\n        var pl = path.vertices[1].x;    //  negative value\n        var length = sp.x;              //  negative value\n        var offset = pl - length + width + width;\n\n        path.width = width;\n        path.offset = length + (offset > 0 ? offset : 0);\n        if (path.vertices.length < 3 && length > -10) {\n            path.offset += 2.5;\n        }\n\n        this._vertices = this.load().unTranslate(sp).vertices;\n    },\n\n    subShape: function(transform) {\n        this.load().unRotate(transform.angle).translate(transform.displ);\n        return this;\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/src/DGBezierCurves.js",
    "content": "/*\n * DGBezierCurves is a collection of three classes:\n * Original DG.Bezier class provides basic math for Cubic and Quadratic Bézier curves\n * DG.TimeBezier used in animation effects it can return 'Distance' (Y) by Time (X) value\n * DG.ArcBezier can return 't' value by curve's segment length\n * Actual calculations can be very hard (in math terms) so we use LUT's to optimize them\n *\n * Original ideas come from this source:   https://pomax.github.io/bezierinfo/\n */\n\nDG.Bezier = DG.Class.extend({\n    /**\n     * Initialize curve object by provided control points\n     * @param {Array<DG.Point>} coords Curve's control points in DG.Point format (up to four control points supported)\n     * @param {boolean} [clone] Clone original points or not (Default)\n     */\n    initialize: function(coords, clone) {\n        if (clone) {\n            this.points = coords.map(function(coord) { return coord.clone(); });\n        } else {\n            this.points = coords;\n        }\n        this.dpoints = this._getDerivatives();\n        this.order = this.points.length - 1;\n        this._lut = [];\n    },\n\n    getPoint: function(t) {\n        var p = this.points;\n        var mt, mt2, t2;\n        var a, b, c, d;\n\n        if (t === 0) { return p[0]; }\n        if (t === 1) { return p[this.order]; }\n\n        mt = 1 - t;\n        mt2 = mt * mt;\n        t2 = t * t;\n\n        if (this.order > 2) {\n            a = mt2 * mt;\n            b = mt2 * t * 3;\n            c = mt * t2 * 3;\n            d = t * t2;\n        } else {\n            p = [p[0], p[1], p[2], {x: 0, y: 0}];\n            a = mt2;\n            b = mt * t * 2;\n            c = t2;\n            d = 0;\n        }\n\n        return new DG.Point(\n            a * p[0].x + b * p[1].x + c * p[2].x + d * p[3].x,\n            a * p[0].y + b * p[1].y + c * p[2].y + d * p[3].y\n        );\n    },\n\n    derivative: function(t) {\n        var p = this.dpoints[0];\n        var mt = 1 - t;\n        var a, b, c;\n\n        if (this.order > 2) {\n            a = mt * mt;\n            b = mt * t * 2;\n            c = t * t;\n        } else {\n            p = [p[0], p[1], {x: 0, y: 0}];\n            a = mt; b = t; c = 0;\n        }\n\n        return new DG.Point(\n            a * p[0].x + b * p[1].x + c * p[2].x,\n            a * p[0].y + b * p[1].y + c * p[2].y\n        );\n    },\n\n    getLength: function() {\n        /* eslint-disable camelcase */\n        var w_i = DG.Bezier.WEIGHT;\n        var x_i = DG.Bezier.ABSCISSA;\n        var z = 0.5;\n        var sum = 0;\n        var d, l, t;\n\n        for (var i = 0; i < x_i.length; i++) {\n            t = z * x_i[i] + z;\n            d = this.derivative(t);\n            l = d.x * d.x + d.y * d.y;\n            sum += w_i[i] * Math.sqrt(l);\n        }\n        /* eslint-enable camelcase */\n\n        return z * sum;\n    },\n\n    getCurveBefore: function(z) {\n        var p = this.points;\n        var z2, z3, mz, mz2, mz3;\n        var b$3, b$4, c$4;\n        var curve;\n\n        if (z === 1) { return this.clone(); }\n\n        curve = [];\n        z2 = z * z;\n        mz = z - 1;\n        mz2 = mz * mz;\n\n        curve[0] = new DG.Point(\n            p[0].x,\n            p[0].y\n        );\n\n        curve[1] = new DG.Point(\n            z * p[1].x - mz * p[0].x,\n            z * p[1].y - mz * p[0].y\n        );\n\n        b$3 = z * mz * 2;\n        curve[2] = new DG.Point(\n            z2 * p[2].x - b$3 * p[1].x + mz2 * p[0].x,\n            z2 * p[2].y - b$3 * p[1].y + mz2 * p[0].y\n        );\n\n        if (this.order > 2) {\n            z3 = z2 * z;\n            mz3 = mz2 * mz;\n            b$4 = z2 * mz * 3;\n            c$4 = z * mz2 * 3;\n            curve[3] = new DG.Point(\n                z3 * p[3].x - b$4 * p[2].x + c$4 * p[1].x - mz3 * p[0].x,\n                z3 * p[3].y - b$4 * p[2].y + c$4 * p[1].y - mz3 * p[0].y\n            );\n        }\n\n        return new DG.Bezier(curve);\n    },\n\n    getCurveAfter: function(z) {\n        var p = this.points;\n        var n = this.order;\n        var z2, z3, mz, mz2, mz3;\n        var b$3, b$4, c$4;\n        var curve;\n\n        if (z === 1) { return this.clone(); }\n\n        curve = [];\n        z2 = z * z;\n        mz = z - 1;\n        mz2 = mz * mz;\n\n        curve[n] = new DG.Point(\n            p[n].x,\n            p[n].y\n        );\n\n        curve[--n] = new DG.Point(\n            z * p[n + 1].x - mz * p[n].x,\n            z * p[n + 1].y - mz * p[n].y\n        );\n\n        b$3 = z * mz * 2;\n        curve[--n] = new DG.Point(\n            z2 * p[n + 2].x - b$3 * p[n + 1].x + mz2 * p[n].x,\n            z2 * p[n + 2].y - b$3 * p[n + 1].y + mz2 * p[n].y\n        );\n\n        if (this.order > 2) {\n            z3 = z2 * z;\n            mz3 = mz2 * mz;\n            b$4 = z2 * mz * 3;\n            c$4 = z * mz2 * 3;\n            curve[--n] = new DG.Point(\n                z3 * p[n + 3].x - b$4 * p[n + 2].x + c$4 * p[n + 1].x - mz3 * p[n].x,\n                z3 * p[n + 3].y - b$4 * p[n + 2].y + c$4 * p[n + 1].y - mz3 * p[n].y\n            );\n        }\n\n        return new DG.Bezier(curve);\n    },\n\n    _getDerivatives: function() {\n        var p = this.points;\n        var d, c, j, list;\n        var result = [];\n\n        for (d = p.length, c = d - 1; d > 1; d--, c--) {\n            list = [];\n            for (j = 0; j < c; j++) {\n                list.push(new DG.Point(\n                    c * (p[j + 1].x - p[j].x),\n                    c * (p[j + 1].y - p[j].y)\n                ));\n            }\n            result.push(list);\n            p = list;\n        }\n\n        return result;\n    },\n\n    getLUT: function(steps) {\n        steps = steps || 125;\n\n        if (this._lut.length !== steps + 1) {\n            if (this.order > 2) {\n                this._setLUT3(steps);\n            } else {\n                this._setLUT2(steps);\n            }\n        }\n\n        return this._lut;\n    },\n\n    _setLUT2: function(steps) {\n        var lut = this._lut = [];\n        var p = this.points;\n        var t, mt;\n        var a, b, c;\n\n        lut.push({x: p[0].x, y: p[0].y, l: 0});\n        for (var s = 1; s < steps; s++) {\n            t = s / steps;\n            mt = 1 - t;\n            a = mt * mt;\n            b = mt * t * 2;\n            c = t * t;\n            lut.push({\n                x: a * p[0].x + b * p[1].x + c * p[2].x,\n                y: a * p[0].y + b * p[1].y + c * p[2].y\n            });\n        }\n        lut.push({x: p[2].x, y: p[2].y, l: 0});\n    },\n\n    _setLUT3: function(steps) {\n        var lut = this._lut = [];\n        var p = this.points;\n        var t, t2, mt, mt2;\n        var a, b, c, d;\n\n        lut.push({x: p[0].x, y: p[0].y, l: 0});\n        for (var s = 1; s < steps; s++) {\n            t = s / steps;\n            mt = 1 - t;\n            mt2 = mt * mt;\n            t2 = t * t;\n            a = mt2 * mt;\n            b = mt2 * t * 3;\n            c = mt * t2 * 3;\n            d = t * t2;\n            lut.push({\n                x: a * p[0].x + b * p[1].x + c * p[2].x + d * p[3].x,\n                y: a * p[0].y + b * p[1].y + c * p[2].y + d * p[3].y\n            });\n        }\n        lut.push({x: p[3].x, y: p[3].y, l: 0});\n    },\n\n    clone: function() {\n        return new DG.Bezier(this.points, true);\n    }\n});\n\nDG.bezier = function(coords) {\n    if (typeof coords === 'number' || coords instanceof DG.Point) {\n        coords = Array.prototype.slice.call(arguments);\n    }\n\n    if (typeof coords[0] === 'number') {\n        if (coords.length < 7) {\n            coords = [\n                new DG.Point(coords[0], coords[1]),\n                new DG.Point(coords[2], coords[3]),\n                new DG.Point(coords[4], coords[5])\n            ];\n        } else {\n            coords = [\n                new DG.Point(coords[0], coords[1]),\n                new DG.Point(coords[2], coords[3]),\n                new DG.Point(coords[4], coords[5]),\n                new DG.Point(coords[6], coords[7])\n            ];\n        }\n        return new DG.Bezier(coords);\n    } else {\n        return new DG.Bezier(coords, true);\n    }\n};\n\n/* eslint-disable indent */\nDG.Bezier.WEIGHT = [\n    0.3626837833783620,\n    0.3626837833783620,\n    0.3137066458778873,\n    0.3137066458778873,\n    0.2223810344533745,\n    0.2223810344533745,\n    0.1012285362903763,\n    0.1012285362903763\n];\nDG.Bezier.ABSCISSA = [\n   -0.1834346424956498,\n    0.1834346424956498,\n   -0.5255324099163290,\n    0.5255324099163290,\n   -0.7966664774136267,\n    0.7966664774136267,\n   -0.9602898564975363,\n    0.9602898564975363\n];\n/* eslint-enable indent */\n\n\n//  This curve is monotonically ordered by 'X' coordinate and has P[0] = {0, 0} and P[3] = {1, 1}\n//  We can utilize this facts to shortcut calculations\nDG.TimeBezier = DG.Bezier.extend({\n    initialize: function(controlPoint1, controlPoint2, clone) {\n        DG.Bezier.prototype.initialize.call(\n            this,\n            [DG.TimeBezier.START, controlPoint1, controlPoint2, DG.TimeBezier.END],\n            clone\n        );\n    },\n\n    getYbyX: function(x) {\n        var lut = this.getLUT();\n        var max = lut.length - 1;\n        var min = 0;\n        var mid;\n\n        if (x <= 0) { return 0; }\n        if (x >= 1) { return 1; }\n\n        //  'X' is monotonically increasing so we can do a simple binary search (LUT)\n        //  and then fine-tune the result by linear interpolation assuming 'Y' is not changed so radically\n        while (true) {\n            mid = min + (max - min >> 1);\n            if (x < lut[mid].x) {\n                max = mid;\n            } else {\n                min = mid;\n            }\n            if (max - min < 2) { break; }\n        }\n        x = (x - lut[min].x) / (lut[max].x - lut[min].x);\n\n        return (lut[min].y + (lut[max].y - lut[min].y) * x);\n    },\n\n    getLUT: function(steps) {\n        var p = this.points;\n        var t, t2, mt;\n        var b, c, d;\n        var lut;\n\n        steps = steps || 240;\n        if (this._lut.length === steps + 1) {\n            return this._lut;\n        } else {\n            this._lut = lut = [];\n        }\n\n        lut.push({x: 0, y: 0});\n        for (var s = 1; s < steps; s++) {\n            t = s / steps;\n            mt = 1 - t;\n            t2 = t * t;\n            //  We don't need 'a' coefficient because p[0] is {0, 0}\n            b = mt * mt * t * 3;\n            c = mt * t2 * 3;\n            d = t * t2;\n            lut.push({\n                x: b * p[1].x + c * p[2].x + d,\n                y: b * p[1].y + c * p[2].y + d\n            });\n        }\n        lut.push({x: 1, y: 1});\n\n        return lut;\n    },\n\n    clone: function() {\n        return new DG.TimeBezier(this.points, true);\n    }\n});\n\nDG.TimeBezier.START = DG.point(0, 0);\nDG.TimeBezier.END = DG.point(1, 1);\n\n\n//  This is cubic Bezier describing circular arc\nDG.ArcBezier = DG.Bezier.extend({\n    initialize: function(coords, clone) {\n        DG.Bezier.prototype.initialize.call(this, coords, clone);\n        this.getLUT();\n        this._setLutLengths();\n    },\n\n    getTbyL: function(l) {\n        var lut = this.getLUT();\n        var max = lut.length - 1;\n        var min = 0;\n        var mid;\n        var x, y;\n\n        if (l <= 0) { return 0; }\n        if (l >= lut[max].l) { return 1; }\n\n        //  'L' is monotonically increasing so we can do a binary search (LUT)\n        //  and then fine-tune the result by linear interpolation\n        while (true) {\n            mid = min + (max - min >> 1);\n            if (l < lut[mid].l) {\n                max = mid;\n            } else {\n                min = mid;\n            }\n            if (max - min < 2) { break; }\n        }\n        l = (l - lut[min].l) / (lut[max].l - lut[min].l);\n\n        x = (lut[min].x + (lut[max].x - lut[min].x) * l);\n        y = (lut[min].y + (lut[max].y - lut[min].y) * l);\n\n        //  BUT this is a part of story, we need a projection of this point to the actual curve and it's reverse 't' val\n        var p, dx, dy, t;\n        var et = max / lut.length;\n        var dt = min / lut.length;\n        var s = 1 / lut.length / 10;    //  TODO\n        var d = Math.pow(2, 53) - 1;\n\n        for (t = dt; dt < et; dt += s) {\n            p = this.getPoint(dt);\n            dx = p.x - x; dy = p.y - y;\n            l = Math.sqrt(dx * dx + dy * dy);\n            if (l < d) {\n                d = l;\n                t = dt;\n            }\n        }\n\n        return t;\n    },\n\n    _setLutLengths: function() {\n        var lut = this._lut;\n        var dx, dy;\n\n        lut[0].l = 0;\n        for (var i = 1; i < lut.length; i++) {\n            dx = lut[i].x - lut[i - 1].x;\n            dy = lut[i].y - lut[i - 1].y;\n            lut[i].l = lut[i - 1].l + Math.sqrt(dx * dx + dy * dy);\n        }\n    },\n\n    getLength: function() {\n        return this._lut[this._lut.length - 1].l;\n    },\n\n    clone: function() {\n        return new DG.ArcBezier(this.points, true);\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/src/DGComplexPath.js",
    "content": "/*\n * DG.ComplexPath is a simple vector layer class with empty .getEvents() object(!)\n * It's drawing logic is maintained in DG.Entrance.Arrow class\n *\n * _pxBounds is a pixel bounds of this drawings and they are used in L.Canvas\n */\n\nDG.ComplexPath = DG.Path.extend({\n    options: {\n        fill: true,\n        fillOpacity: 1,\n        interactive: false\n    },\n\n    initialize: function(options) {\n        DG.setOptions(this, options);\n\n        this._empty = [];\n\n        this._pxEmpty = DG.bounds(\n            DG.point(0, 0), DG.point(0, 0)\n        );\n        this._pxBounds = this._pxEmpty;\n\n        this._vertices = [this._empty];\n        this._drawings = [this._empty];\n    },\n\n    getEvents: function() {\n        return {};\n    },\n\n    _project: function() {\n        var opts = this.options,\n            zoom, weight;\n\n        if (this._map) {\n            zoom = this._map.getZoom();\n        } else {\n            return;\n        }\n\n        if (opts.visibility.isShown && opts.transform[zoom]) {\n            //  Next numbers was empirically selected in order to provide visual compliance\n            //  to the original arrow's implementation\n            weight = 2.2 - ((19 - zoom) * 0.2);\n            if (opts.weight !== weight) {\n                this.setStyle({weight: +weight.toFixed(2)});\n            }\n\n            this._vertices[0] = opts.transform[zoom].vertices;\n            this._drawings[0] = opts.transform[zoom].drawings;\n\n            this._pxBounds = opts.transform[zoom]._pxBounds;\n        } else {\n            this._vertices[0] = this._empty;\n            this._drawings[0] = this._empty;\n\n            this._pxBounds = this._pxEmpty;\n        }\n    },\n\n    _update: function() {\n        if (this._map) {\n            this._updatePath();\n        }\n    },\n\n    _updatePath: function() {  //  used in Canvas renderer\n        this._renderer._updateComplexPath(this);\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/src/DGEntrance.js",
    "content": "/*\n * DG.Entrance is a main class that hosts actual arrow layers\n * It orchestrates animation and provides user space methods like .show() and .hide()\n */\n\nDG.Entrance = DG.FeatureGroup.extend({\n\n    options: {\n        vectors: [],\n\n        fillColor: '#0085a0',\n        strokeColor: '#fff',\n\n        enableAnimation: true,\n        interactive: false,\n\n        autoClose: true\n    },\n\n    initialize: function(options) {\n        DG.LayerGroup.prototype.initialize.call(this);\n\n        DG.setOptions(this, options);\n\n        this._bounds =\n            new DG.LatLngBounds();\n        this._animations = {\n            bounce: DG.animation(DG.Entrance.BOUNCE_ANIMATION),\n            path: DG.animation(DG.Entrance.PATH_ANIMATION)\n        };\n\n        this._initArrows();\n\n        this._isShown = false;\n    },\n\n    onAdd: function(map) {\n        DG.LayerGroup.prototype.onAdd.call(this, map);\n        this.show();\n    },\n\n    onRemove: function(map) {\n        this.hide();\n        DG.LayerGroup.prototype.onRemove.call(this, map);\n    },\n\n    getEvents: function() {\n        var events = {};\n\n        if (this.options.autoClose) {\n            events['layeradd'] = this._removeEntrance;  //  eslint-disable-line dot-notation\n        }\n        if (this.options.enableAnimation) {\n            events['zoomend'] = this._animate;          //  eslint-disable-line dot-notation\n        }\n\n        return events;\n    },\n\n    show: function(fitBounds) {\n        if (this._layers) {\n            if (fitBounds) {\n                this.fitBounds();\n            }\n            if (!this._isShown) {\n                this._isShown = true;\n                this.eachLayer(function(arrow) {\n                    arrow.setVisibility(true);\n                });\n                if (this.options.enableAnimation) {\n                    this._animate();\n                }\n                this._map.fire('entranceshow');\n            }\n        }\n\n        return this;\n    },\n\n    hide: function() {\n        if (this._layers && this._isShown) {\n            this._isShown = false;\n            this.eachLayer(function(arrow) {\n                arrow.setVisibility(false);\n            });\n            this._map.fire('entrancehide');\n        }\n\n        return this;\n    },\n\n    isShown: function() {\n        return this._isShown;\n    },\n\n    getBounds: function() {\n        return this._bounds;\n    },\n\n    setFillColor: function(color) {\n        this.eachLayer(function(arrow) {\n            arrow.setStyle({fillColor: color});\n        });\n    },\n\n    setStrokeColor: function(color) {\n        this.eachLayer(function(arrow) {\n            arrow.setStyle({color: color});\n        });\n    },\n\n    _initArrows: function() {\n        var base = {\n            color: this.options.strokeColor,\n            fillColor: this.options.fillColor,\n            interactive: this.options.interactive\n        };\n\n        this.options.vectors\n            .map(function(vector) {\n                return DG.Wkt.toLatLngs(vector);\n            })\n            .forEach(function(latlngs) {\n                var options = DG.Util.create(base),\n                    bounds = DG.latLngBounds(latlngs);\n\n                this._bounds.extend(bounds);\n\n                options.latlngs = latlngs;\n                options.bounds = bounds;\n                if (this.options.enableAnimation) {\n                    if (latlngs.length > 2) {\n                        options.animation = this._animations.path;\n                    } else {\n                        options.animation = this._animations.bounce;\n                        options.distance = true;\n                    }\n                }\n\n                this.addLayer(DG.entrance.arrow(options));\n            }, this);\n    },\n\n\n    _animate: function() {\n        if (this._isShown) {\n            this._animations.bounce.start();\n            this._animations.path.start();\n        }\n    },\n\n    //  Current logic of next four methods extracted from original arrow's implementation\n    fitBounds: function() {\n        var map = this._map, fitZoom,\n            bounds = this.getBounds();\n\n        if (!map.getBounds().contains(bounds) || !this._isAllowedZoom()) {\n            fitZoom = this._getFitZoom();\n            if (!map.projectDetector.getProject()) {\n                map.once('moveend', function() {\n                    map.setZoom(this._getFitZoom());\n                }, this);\n            }\n            map.setView(bounds.getCenter(), fitZoom, {animate: true});\n        }\n\n        return this;\n    },\n\n    _getFitZoom: function() {\n        var project = this._map.projectDetector.getProject();\n        return project ? project.maxZoom : DG.Entrance.SHOW_FROM_ZOOM;\n    },\n\n    _isAllowedZoom: function() {\n        return this._map.getZoom() >= DG.Entrance.SHOW_FROM_ZOOM;\n    },\n\n    _removeEntrance: function(e) {\n        if (e.layer instanceof DG.Popup ||\n            (e.layer instanceof DG.Entrance && e.layer !== this)) {\n\n            this.remove();\n        }\n    }\n});\n\nDG.entrance = function(options) {\n    return new DG.Entrance(options);\n};\n\nDG.Entrance.SHOW_FROM_ZOOM = 16;\nDG.Entrance.PATH_ANIMATION = {\n    animation: {\n        'function': DG.Animation.EASE_IN_OUT,\n        'duration': 750\n    }\n};\nDG.Entrance.BOUNCE_ANIMATION = {\n    animation: [\n        {'function': DG.Animation.EASE_IN_OUT, 'duration': 250, 'frames': {'distance': {'from': 0, 'to': 0.6}}},\n        {'function': DG.Animation.EASE_IN, 'duration': 135, 'frames': {'distance': {'from': 0.6, 'to': 0}}},\n        {'function': DG.Animation.EASE_OUT, 'duration': 135, 'frames': {'distance': {'from': 0, 'to': 0.16}}},\n        {'function': DG.Animation.EASE_IN, 'duration': 90, 'frames': {'distance': {'from': 0.16, 'to': 0}}},\n        {'function': DG.Animation.EASE_OUT, 'duration': 90, 'frames': {'distance': {'from': 0, 'to': 0.06}}},\n        {'function': DG.Animation.EASE_IN, 'duration': 50, 'frames': {'distance': {'from': 0.06, 'to': 0}}}\n    ]\n};\n"
  },
  {
    "path": "src/DGEntrance/src/DGEntranceArrow.js",
    "content": "/*\n * DG.Entrance.Arrow class hosts two layers, one for arrow body (path) and one for arrow tip\n * It overrides projection events from hosted layers to minimize total overhead\n * Actual calculations produced in DG.ArrowPathTransform and DG.ArrowTipTransform classes\n */\n\nDG.Entrance.Arrow = DG.FeatureGroup.extend({\n    initialize: function(options) {\n        DG.LayerGroup.prototype.initialize.call(this);\n\n        DG.setOptions(this, options);\n\n        this._progress = 1;\n        this._distance = 0;\n        this._visibility = {\n            isShown: false\n        };\n        this._position =\n            options.latlngs[options.latlngs.length - 1];\n        this._shape =\n            this.options.shape ||\n            DG.Entrance.Arrow.SHAPE;\n\n        this._apt = {}; // DG.ArrowPathTransform objects by zoom levels\n        this._att = {}; // DG.ArrowTipTransform objects by zoom levels\n    },\n\n    beforeAdd: function(map) {\n        //  this._map is not initialized yet, so we can freely addLayer(s)\n        var opts = this.options;\n\n        //  TODO: Check Canvas processing order\n        //  Additional logic to DISABLE animation on Canvas for now!\n        if (opts.animation && !map.options.preferCanvas && !DG.Browser.ielt9) {\n            opts.animation.on('step', this._animation, this);\n        } else {\n            opts.animation = null;\n        }\n\n        this.projection();\n\n        this.addLayer(new DG.ComplexPath({\n            lineCap: 'butt',\n            color: opts.color,\n            fillColor: opts.fillColor,\n            interactive: opts.interactive,\n            visibility: this._visibility,\n            transform: this._apt\n        }));\n\n        this.addLayer(new DG.ComplexPath({\n            lineJoin: 'miter',\n            color: opts.color,\n            fillColor: opts.fillColor,\n            interactive: opts.interactive,\n            visibility: this._visibility,\n            transform: this._att\n        }));\n    },\n\n    getEvents: function() {\n        return {\n            zoomend: this._project,\n            moveend: this._update,\n            viewreset: this._reset\n        };\n    },\n\n    setVisibility: function(isShown) {\n        if (this._visibility.isShown !== isShown) {\n            this._visibility.isShown = isShown;\n            if (isShown) {\n                if (!this.options.animation) {\n                    this._reset();\n                }\n            } else {\n                this._reset();\n            }\n        }\n    },\n\n    getBounds: function() {\n        return this.options.bounds;\n    },\n\n    projection: function() {\n        var map = this._map || this._mapToAdd;\n        var zoom = map ? map.getZoom() : 0;\n        var vertices = this._shape.vertices[zoom];\n        var drawings = this._shape.drawings[zoom];\n        var latlngs = this.options.latlngs;\n        var shape, path, lastPoint, prevPoint;\n\n        if (zoom && vertices && drawings) {\n            if (!this._att[zoom]) {\n                path = DG.ArrowPathTransform.getTranslatedPath(map, latlngs);\n                shape = {vertices: vertices, drawings: drawings};\n                this._att[zoom] = new DG.ArrowTipTransform(path, shape);\n                this._apt[zoom] = new DG.ArrowPathTransform(path);\n            }\n\n            lastPoint = map.latLngToLayerPoint(this._position);\n            prevPoint = map.latLngToLayerPoint(latlngs[latlngs.length - 2]);\n            if (!this._apt[zoom]._pxBounds) {\n                //  One-time action per 'viewreset' event\n                //  Caching _pxBounds for using with Canvas renderer\n                this._setBounds(lastPoint, prevPoint, this._apt[zoom], this._att[zoom]);\n            }\n            if (this.options.distance) {\n                //  Arrow position recalculated for Bounce animation effect\n                lastPoint = DG.VertexTransform.getScaled(lastPoint, prevPoint, this._distance);\n            }\n\n            //  Main calculations\n            //  Get part of the arrow path and move (bound) arrow tip to it\n            this._apt[zoom].subPath(this._progress).translate(lastPoint);\n            this._att[zoom].subShape(this._apt[zoom]).translate(lastPoint);\n        }\n\n        return this;\n    },\n\n    _animation: function(e) {\n        if (e.distance != undefined) {\n            this._distance = e.distance;    //  bounce animation effect\n        } else {\n            this._progress = e.progress;    //  path animation effect\n        }\n        if (this._visibility.isShown) {\n            //  TODO: Additional logic for animation on Canvas\n            // this.projection().invoke('redraw');\n\n            this._project();\n            this._update();\n        }\n    },\n\n    _project: function() {\n        this.projection().invoke('_project');\n    },\n\n    _update: function() {\n        this.invoke('_update');\n    },\n\n    _reset: function() {\n        this._resetBounds();\n\n        this._project();\n        this._update();\n    },\n\n    _resetBounds: function() {\n        //  Canvas renderer specific\n        var z;\n\n        for (z in this._apt) {\n            this._apt[z]._pxBounds = null;\n        }\n\n        for (z in this._att) {\n            this._att[z]._pxBounds = null;\n        }\n    },\n\n    _setBounds: function(pl, pp, apt, att) {\n        var _apt = apt.subPath(1).translate(pl).vertices,\n            _att = att.subShape(apt).translate(pl).vertices;\n\n        //  TODO: Additional logic for animation on Canvas\n        // if (this.options.distance) {\n        //     pl = DG.VertexTransform.getScaled(pl, pp, 1);\n        //     _apt = _apt.concat(apt.subPath(1).translate(pl).vertices);\n        //     _att = _att.concat(att.subShape(apt).translate(pl).vertices);\n        // }\n\n        apt._pxBounds = new DG.Bounds(_apt);\n        att._pxBounds = new DG.Bounds(_att);\n    }\n});\n\nDG.entrance.arrow = function(options) {\n    return new DG.Entrance.Arrow(options);\n};\n"
  },
  {
    "path": "src/DGEntrance/src/DGEntranceArrowShape.js",
    "content": "/*\n * Predefined arrow tips\n */\n\n/* eslint-disable array-bracket-spacing */\nDG.Entrance.Arrow.SHAPE = {\n    vertices: {\n        16: [\n            [ -6.5000,  -1.8000],\n            [ -6.0522,  -1.8000],\n            [ -7.0975,  -5.2537],\n            [ -6.6619,  -6.2565], [ -6.5980,  -6.3550], [ -6.1757,  -6.1470],\n            [  0.8371,  -0.3552],\n            [  0.9275,  -0.1764], [  0.9275,   0.1764], [  0.8371,   0.3552],\n            [ -6.1757,   6.1470],\n            [ -6.5980,   6.3550], [ -6.6619,   6.2565], [ -7.0975,   5.2537],\n            [ -6.0522,   1.8000],\n            [ -6.5000,   1.8000]\n        ],\n        17: [\n            [ -9.0000,  -2.4000],\n            [ -7.8890,  -2.4000],\n            [ -9.9245,  -7.2548],\n            [ -9.3363,  -8.6404], [ -9.3448,  -8.6448], [ -8.8717,  -8.3508],\n            [  1.0285,  -0.3552],\n            [  1.1190,  -0.1764], [  1.1190,   0.1764], [  1.0285,   0.3552],\n            [ -8.8717,   8.3508],\n            [ -9.3448,   8.6448], [ -9.3363,   8.6404], [ -9.9245,   7.2548],\n            [ -7.8890,   2.4000],\n            [ -9.0000,   2.4000]\n        ],\n        18: [\n            [-11.5000,  -3.0000],\n            [-10.0795,  -3.0000],\n            [-12.4909,  -9.3173],\n            [-11.8402, -10.7654], [-11.5986, -10.7073], [-10.9380, -10.2258],\n            [  1.1497,  -0.3552],\n            [  1.2402,  -0.1764], [  1.2402,   0.1764], [  1.1497,   0.3552],\n            [-10.9380,  10.2258],\n            [-11.5986,  10.7073], [-11.8402,  10.7654], [-12.4909,   9.3173],\n            [-10.0795,   3.0000],\n            [-11.5000,   3.0000]\n        ],\n        19: [\n            [-13.0000,  -3.6000],\n            [-11.6600,  -3.6000],\n            [-14.1696, -10.8351],\n            [-13.5189, -12.2832], [-13.2773, -12.2251], [-12.6167, -11.7436],\n            [  1.3061,  -0.3552],\n            [  1.3966,  -0.1764], [  1.3966,   0.1764], [  1.3061,   0.3552],\n            [-12.6167,  11.7436],\n            [-13.2773,  12.2251], [-13.5189,  12.2832], [-14.1696,  10.8351],\n            [-11.6600,   3.6000],\n            [-13.0000,   3.6000]\n        ]\n    },\n    drawings: {\n        16: ['M', 'L', 'L', 'C', 'L', 'C', 'L', 'C', 'L', 'L'],\n        17: ['M', 'L', 'L', 'C', 'L', 'C', 'L', 'C', 'L', 'L'],\n        18: ['M', 'L', 'L', 'C', 'L', 'C', 'L', 'C', 'L', 'L'],\n        19: ['M', 'L', 'L', 'C', 'L', 'C', 'L', 'C', 'L', 'L']\n    }\n};\n/* eslint-enable array-bracket-spacing */\n\n\n(function(vertices) {\n    for (var i in vertices) {\n        vertices[i] = vertices[i].map(function(vertex) { return DG.point(vertex); });\n    }\n})(DG.Entrance.Arrow.SHAPE.vertices);\n"
  },
  {
    "path": "src/DGEntrance/src/DGMetric.js",
    "content": "/*\n * Utility functions\n */\n\nDG.Metric = function() {};\n\n/*\n * DG.Metric.Segments class can calculate total pushed segments length and used to shortcut\n * 'get Something by provided Length' calculations (segment's Index, segment's Length, etc...)\n */\nDG.Metric.Segments = function() {\n    this.length = 0;\n};\n\nDG.Metric.Segments.prototype = {\n    push: function(len) {\n        this[this.length] = this.length > 0 ? this[this.length - 1] + len : len;\n        this.length += 1;\n\n        return this;\n    },\n\n    getLength: function() {\n        return this[this.length - 1];\n    },\n\n    getReverse: function() {\n        var segments = new DG.Metric.Segments();\n        var i = this.length - 1;\n\n        if (i < 0) { return segments; }\n\n        while (i--) {\n            segments.push(this[i + 1] - this[i]);\n        }\n\n        return segments.push(this[0]);\n    },\n\n    getIndex: function(len) {\n        var i = this.length - 1;\n\n        if (i < 0) { return i; }\n\n        while (i--) {\n            if (this[i] <= len) { break; }\n        }\n\n        return i + 1;\n    },\n\n    getSegRatio: function(len) {\n        var i = this.getIndex(len);\n        var sub = i > 0 ? this[i - 1] : 0;\n\n        return (len - sub) / (this[i] - sub);\n    },\n\n    getSegLength: function(len) {\n        var i = this.getIndex(len);\n        var sub = i > 0 ? this[i - 1] : 0;\n\n        return len - sub;\n    }\n};\n"
  },
  {
    "path": "src/DGEntrance/src/DGRenderer.js",
    "content": "/*\n * Actual painting methods that can draw complex objects with curves\n *\n * Point coordinates must be provided in layer._vertices object\n * And types of line must be provided in layer._drawings object\n */\n\nDG.extend(L.Canvas.prototype, {\n    _updateComplexPath: function(layer, closed) {\n        var i, j, k, d, x, y, _x, _y, $x, $y, points;\n        var drawings = layer._drawings;\n        var vertices = layer._vertices;\n        var ctx = this._ctx;\n\n        this._drawnLayers[layer._leaflet_id] = layer;\n\n        //  TODO: Do we need to do a 'beginPath()' and possible 'closePath()' per ring?!\n        ctx.beginPath();\n\n        for (i = 0; i < vertices.length; i++) {\n            points = vertices[i];\n            x = y = 0;\n            j = k = 0;\n            while (j < points.length) {\n                d = drawings[i][k++];\n                switch (d) {\n                    case 'M':\n                        x = points[j].x;\n                        y = points[j].y;\n                        j += 1;\n                        ctx.moveTo(x, y);\n                        break;\n\n                    case 'm':\n                        x += points[j].x;\n                        y += points[j].y;\n                        j += 1;\n                        ctx.moveTo(x, y);\n                        break;\n\n                    case 'L':\n                        x = points[j].x;\n                        y = points[j].y;\n                        j += 1;\n                        ctx.lineTo(x, y);\n                        break;\n\n                    case 'l':\n                        x += points[j].x;\n                        y += points[j].y;\n                        j += 1;\n                        ctx.lineTo(x, y);\n                        break;\n\n                    case 'C':\n                        _x = points[j].x;\n                        _y = points[j].y;\n                        j += 1;\n                        $x = points[j].x;\n                        $y = points[j].y;\n                        j += 1;\n                        x = points[j].x;\n                        y = points[j].y;\n                        j += 1;\n                        ctx.bezierCurveTo(_x, _y, $x, $y, x, y);\n                        break;\n\n                    case 'c':\n                        _x = x + points[j].x;\n                        _y = y + points[j].y;\n                        j += 1;\n                        $x = x + points[j].x;\n                        $y = y + points[j].y;\n                        j += 1;\n                        x = x + points[j].x;\n                        y = y + points[j].y;\n                        j += 1;\n                        ctx.bezierCurveTo(_x, _y, $x, $y, x, y);\n                        break;\n\n                    case 'Q':\n                        _x = points[j].x;\n                        _y = points[j].y;\n                        j += 1;\n                        x = points[j].x;\n                        y = points[j].y;\n                        j += 1;\n                        ctx.quadraticCurveTo(_x, _y, x, y);\n                        break;\n\n                    case 'q':\n                        _x = x + points[j].x;\n                        _y = y + points[j].y;\n                        j += 1;\n                        x = x + points[j].x;\n                        y = y + points[j].y;\n                        j += 1;\n                        ctx.quadraticCurveTo(_x, _y, x, y);\n                        break;\n                }\n            }\n            if (closed) {\n                ctx.closePath();\n            }\n        }\n\n        this._fillStroke(ctx, layer);\n    }\n});\n\n\nDG.extend(L.SVG.prototype, {\n    _updateComplexPath: function(layer, closed) {\n        this._setPath(layer, L.SVG.complexPointsToPath(layer._vertices, layer._drawings, closed));\n    }\n});\n\n\nDG.extend(L.SVG, {\n    complexPointsToPath: function(vertices, drawings, closed) {\n        var str = '';\n        var svg = DG.Browser.svg;\n        var i, j, k, n, d, points;\n\n        for (i = 0; i < vertices.length; i++) {\n            points = vertices[i];\n\n            //  Speedup hot path by removing if/ternary condition checks but duplicating loops\n            if (svg) {\n                j = k = 0;\n                while (j < points.length) {\n                    d = drawings[i][k++];\n                    switch (d) {\n                        case 'C':\n                        case 'c':   n = 3; break;\n                        case 'Q':\n                        case 'q':   n = 2; break;\n\n                        default:    n = 1;  //  'M', 'm', 'L', 'l', ...\n                    }\n                    str += d;\n                    while (n--) {\n                        str += points[j].x.toFixed(4) + ',' + points[j].y.toFixed(4) + ' ';\n                        j += 1;\n                    }\n                }\n            } else {\n                //  vml in IE8 can support only integer values in 'path', sorry about loss of precision\n                j = k = 0;\n                while (j < points.length) {\n                    d = drawings[i][k++];\n                    switch (d) {\n                        case 'M':   d = 'm'; n = 1; break;\n                        case 'm':   d = 't'; n = 1; break;\n                        case 'L':   d = 'l'; n = 1; break;\n                        case 'l':   d = 'r'; n = 1; break;\n                        case 'C':   d = 'c'; n = 3; break;\n                        case 'c':   d = 'v'; n = 3; break;\n                        case 'Q':\n                            //  VML spec has 'qb' command in 'v' attribute string but no 'relativeTo' compliment\n                            //  So we'll emulate Cubic Bézier curve by applying Quadratic variant in both cases\n                            //  TODO: Both control points will use the same value but this is not true solution\n                            str += 'C' +\n                                points[j].x.toFixed(0) + ',' + points[j].y.toFixed(0) + ' ' +\n                                points[j].x.toFixed(0) + ',' + points[j].y.toFixed(0) + ' ' +\n                                points[j + 1].x.toFixed(0) + ',' + points[j + 1].y.toFixed(0) + ' ';\n                            j += 2;\n                            d = '';\n                            n = 0;\n                            break;\n                        case 'q':\n                            str += 'c' +\n                                points[j].x.toFixed(0) + ',' + points[j].y.toFixed(0) + ' ' +\n                                points[j].x.toFixed(0) + ',' + points[j].y.toFixed(0) + ' ' +\n                                points[j + 1].x.toFixed(0) + ',' + points[j + 1].y.toFixed(0) + ' ';\n                            j += 2;\n                            d = '';\n                            n = 0;\n                            break;\n\n                        default:    n = 1;\n                    }\n                    str += d;\n                    while (n--) {\n                        str += points[j].x.toFixed(0) + ',' + points[j].y.toFixed(0) + ' ';\n                        j += 1;\n                    }\n                }\n            }\n\n            str += closed ? (svg ? 'z' : 'x') : '';\n        }\n\n        // SVG complains about empty path strings\n        return str || 'm0,0';\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/src/DGVertexTransform.js",
    "content": "/*\n * DG.VertexTransform is a classic 2D matrix transformation class\n *\n * Prototype methods can scale/rotate/translate vertices\n *\n * Static methods do the same but return simple array instances with attached\n * .clone() method which can reconstruct full DG.VertexTransform object\n */\n\nDG.VertexTransform = DG.Class.extend({\n    initialize: function(vertices) {\n        this._vertices = vertices;\n\n        this._scale = null;\n        this._angle = null;\n        this._trans = null;\n        this._matrix = null;\n\n        this.load();\n    },\n\n    load: function() {\n        this.vertices = this._vertices.map(function(vertex) { return vertex.clone(); });\n        this.vertices.clone = DG.VertexTransform.clone;\n\n        return this;\n    },\n\n    save: function() {\n        this._vertices = this.vertices.map(function(vertex) { return vertex.clone(); });\n\n        return this;\n    },\n\n    setScale: function(scale) {\n        this._scale = scale;\n        return this;\n    },\n\n    getScale: function() {\n        return this._scale;\n    },\n\n    setAngle: function(angle) {\n        this._angle = angle;\n        return this;\n    },\n\n    getAngle: function() {\n        return this._angle;\n    },\n\n    setTranslation: function(trans) {\n        this._trans = trans;\n        return this;\n    },\n\n    getTranslation: function() {\n        return this._trans;\n    },\n\n    setMatrix: function(matrix) {\n        this._matrix = matrix;\n        return this;\n    },\n\n    getMatrix: function() {\n        return this._matrix;\n    },\n\n    scale: function(scale) {\n        var v = this.vertices;\n        var i = v.length;\n\n        scale = scale || this._scale || 1;\n        while (i--) {\n            v[i].x *= scale;\n            v[i].y *= scale;\n        }\n\n        return this;\n    },\n\n    unScale: function(scale) {\n        scale = scale || this._scale || 1;      //  Also safeguard against zero scale\n        return this.scale(1 / scale);\n    },\n\n    rotate: function(angle) {\n        var cos = angle ? angle.cos : (this._angle ? this._angle.cos : 1);\n        var sin = angle ? angle.sin : (this._angle ? this._angle.sin : 0);\n        var v = this.vertices;\n        var i = v.length;\n        var x, y;\n\n        while (i--) {\n            x = v[i].x;\n            y = v[i].y;\n            v[i].x = x * cos - y * sin;\n            v[i].y = x * sin + y * cos;\n        }\n\n        return this;\n    },\n\n    unRotate: function(angle) {\n        var cos = angle ? angle.cos : (this._angle ? this._angle.cos : 1);\n        var sin = angle ? angle.sin : (this._angle ? this._angle.sin : 0);\n\n        return this.rotate({cos: cos, sin: -sin});\n    },\n\n    translate: function(trans) {\n        var dx = trans ? trans.x : (this._trans ? this._trans.x : 0);\n        var dy = trans ? trans.y : (this._trans ? this._trans.y : 0);\n        var v = this.vertices;\n        var i = v.length;\n\n        while (i--) {\n            v[i].x += dx;\n            v[i].y += dy;\n        }\n\n        return this;\n    },\n\n    unTranslate: function(trans) {\n        var dx = trans ? trans.x : (this._trans ? this._trans.x : 0);\n        var dy = trans ? trans.y : (this._trans ? this._trans.y : 0);\n\n        return this.translate({x: -dx, y: -dy});\n    },\n\n    transform: function(matrix) {\n        var a, b, c, d, dx, dy;\n        var v = this.vertices;\n        var i = v.length;\n        var x, y;\n\n        if (matrix) {\n            a = matrix[0]; b = matrix[1]; dx = matrix[2];\n            c = matrix[3]; d = matrix[4]; dy = matrix[5];\n        } else if (this._matrix) {\n            a = this._matrix[0]; b = this._matrix[1]; dx = this._matrix[2];\n            c = this._matrix[3]; d = this._matrix[4]; dy = this._matrix[5];\n        } else {\n            a = 1; b = 0; dx = 0;\n            c = 0; d = 1; dy = 0;\n        }\n\n        while (i--) {\n            x = v[i].x;\n            y = v[i].y;\n            v[i].x = x * a + y * b + dx;\n            v[i].y = x * c + y * d + dy;\n        }\n\n        return this;\n    },\n\n    statics: {\n        scale: function(vt, scale) {\n            var v = vt.vertices;\n            var result = [];\n            var x, y;\n\n            scale = scale || 1;\n            for (var i = 0; i < v.length; i++) {\n                x = v[i].x * scale;\n                y = v[i].y * scale;\n                result.push(new DG.Point(x, y));\n            }\n            result.clone = DG.VertexTransform.clone;\n\n            return result;\n        },\n\n        unScale: function(vt, scale) {\n            scale = scale || 1;         //  Also safeguard against zero scale\n            return DG.VertexTransform.scale(vt, 1 / scale);\n        },\n\n        rotate: function(vt, angle) {\n            var cos = angle ? angle.cos : 1;\n            var sin = angle ? angle.sin : 0;\n            var v = vt.vertices;\n            var x, y, rx, ry;\n            var result = [];\n\n            for (var i = 0; i < v.length; i++) {\n                rx = v[i].x;\n                ry = v[i].y;\n                x = rx * cos - ry * sin;\n                y = rx * sin + ry * cos;\n                result.push(new DG.Point(x, y));\n            }\n            result.clone = DG.VertexTransform.clone;\n\n            return result;\n        },\n\n        unRotate: function(vt, angle) {\n            var cos = angle ? angle.cos : 1;\n            var sin = angle ? angle.sin : 0;\n\n            return DG.VertexTransform.rotate(vt, {cos: cos, sin: -sin});\n        },\n\n        translate: function(vt, trans) {\n            var dx = trans ? trans.x : 0;\n            var dy = trans ? trans.y : 0;\n            var v = vt.vertices;\n            var result = [];\n            var x, y;\n\n            for (var i = 0; i < v.length; i++) {\n                x = v[i].x + dx;\n                y = v[i].y + dy;\n                result.push(new DG.Point(x, y));\n            }\n            result.clone = DG.VertexTransform.clone;\n\n            return result;\n        },\n\n        unTranslate: function(vt, trans) {\n            var dx = trans ? trans.x : 0;\n            var dy = trans ? trans.y : 0;\n\n            return DG.VertexTransform.translate(vt, {x: -dx, y: -dy});\n        },\n\n        clone: function() {\n            //  'this' is an array\n            return new DG.VertexTransform(this).save();\n        },\n\n        getLength: function(vec1, vec2) {\n            var dx, dy;\n\n            if (typeof vec1 === 'number') {\n                //  'vec1' and 'vec2' are absolute coordinates of vector\n                return Math.sqrt(vec1 * vec1 + vec2 * vec2);\n            } else {\n                //  'vec1' and 'vec2' are vector objects\n                dx = vec2.x - vec1.x;\n                dy = vec2.y - vec1.y;\n                return Math.sqrt(dx * dx + dy * dy);\n            }\n        },\n\n        getScaled: function(vec1, vec2, scale) {\n            var dx, dy;\n\n            if (typeof vec1 === 'number') {\n                //  'vec1' and 'vec2' are absolute coordinates of vector\n                return new DG.Point(vec1 * scale, vec2 * scale);\n            } else {\n                //  'vec1' and 'vec2' are vector objects\n                dx = (vec2.x - vec1.x) * scale;\n                dy = (vec2.y - vec1.y) * scale;\n                return new DG.Point(vec1.x + dx, vec1.y + dy);\n            }\n        },\n\n        getAngle: function(vec1, vec2, origin) {\n            var l, sp, x1, y1, x2, y2;\n\n            if (typeof vec1 === 'number') {\n                //  'vec1' and 'vec2' are absolute coordinates of vector\n                l = Math.sqrt(vec1 * vec1 + vec2 * vec2);\n                if (l > 0) {\n                    return {cos: vec1 / l, sin: vec2 / l};\n                } else {\n                    return {cos: 1, sin: 0};\n                }\n            } else {\n                //  'vec1' and 'vec2' are vector objects\n                x1 = vec1.x; y1 = vec1.y;\n                x2 = vec2.x; y2 = vec2.y;\n                if (origin) {\n                    x1 -= origin.x; y1 -= origin.y;\n                    x2 -= origin.x; y2 -= origin.y;\n                }\n                sp = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2);\n                return {\n                    cos: (x1 * x2 + y1 * y2) / sp,\n                    sin: (x1 * y2 - x2 * y1) / sp\n                };\n            }\n        },\n\n        getAnglesSum: function(angle1, angle2) {\n            return {\n                cos: angle1.cos * angle2.cos - angle1.sin * angle2.sin,\n                sin: angle1.sin * angle2.cos + angle1.cos * angle2.sin\n            };\n        },\n\n        getAnglesDif: function(angle1, angle2) {\n            return {\n                cos: angle1.cos * angle2.cos + angle1.sin * angle2.sin,\n                sin: angle1.sin * angle2.cos - angle1.cos * angle2.sin\n            };\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGEntrance/test/DGArrowShapeSpec.js",
    "content": "describe('DG.Entrance.Arrow.SHAPE', function () {\n    var dgArrowShape = DG.Entrance.Arrow.SHAPE;\n\n    after(function () {\n        dgArrowShape = null;\n    });\n\n    it('should be an object', function () {\n        expect(dgArrowShape).to.be.an('object');\n    });\n\n    it('should contain paired \\'vertices\\' and \\'drawings\\' objects', function () {\n        var v = Object.keys(dgArrowShape.vertices);\n        var d = Object.keys(dgArrowShape.drawings);\n\n        expect(v.length).to.be.equal(d.length);\n        expect(v).to.be.eql(d);\n    });\n\n    it('should contain paired \\'vertices\\' and \\'drawings\\' elements', function () {\n        var vertices = dgArrowShape.vertices;\n        var drawings = dgArrowShape.drawings;\n        var k = Object.keys(drawings);\n\n        for (var i = 0; i < k.length; i++) {\n            var d = drawings[k[i]];\n            for (var len = 0, j = 0; j < d.length; j++) {\n                switch(d[j]) {\n                    case 'C':\n                    case 'c': len += 3; break;\n                    case 'Q':\n                    case 'q': len += 2; break;\n\n                    default:  len += 1;\n                }\n            }\n            expect(len).to.be.equal(vertices[k[i]].length);\n        }\n    });\n\n    it('should contain instances of \\'DG.Point\\' objects in \\'vertices\\' arrays', function () {\n        var vertices = dgArrowShape.vertices;\n        var k = Object.keys(vertices);\n\n        for (var i = 0; i < k.length; i++) {\n            var v = vertices[k[i]];\n            for (var j = 0; j < v.length; j++) {\n                expect(v[j]).to.be.an(DG.Point);\n            }\n        }\n    });\n});\n"
  },
  {
    "path": "src/DGEntrance/test/DGBezierSpec.js",
    "content": "describe('DG.Bezier', function () {\n    var s = DG.point(1, 0), e = DG.point(7, 0),\n        cp1 = DG.point(3, 1), cp2 = DG.point(5, -1);\n\n    var bc;\n\n    beforeEach(function () {\n        bc = new DG.Bezier([s, cp1, cp2, e]);\n    });\n\n    after(function () {\n        bc = s = e = cp1 = cp2 = null;\n    });\n\n    describe('#getPoint', function () {\n        it('should return correct curve\\'s point coordinates at specific (t) value', function () {\n            expect(bc.getPoint(0.50)).to.be.eql({x: 4, y: 0});\n            expect(bc.getPoint(0.25)).to.be.eql({x: 2.5, y: 0.28125});\n            expect(bc.getPoint(0.75)).to.be.eql({x: 5.5, y: -0.28125});\n        });\n    });\n\n    describe('#getLength', function () {\n        it('should return correct (approximated) curve\\'s length', function () {\n            expect(bc.getLength()).to.be.within(6.1462605, 6.1462615);\n        });\n    });\n\n    describe('#getCurveBefore', function () {\n        it('should return new curve as a (beginning) part of original', function () {\n            expect(bc.getCurveBefore(0.25).points)\n                .to.be.eql([{x: 1, y: 0}, {x: 1.5, y: 0.25}, {x: 2, y: 0.3125}, {x: 2.5, y: 0.28125}]);\n        });\n    });\n\n    describe('#getCurveAfter', function () {\n        it('should return new curve as a (ending) part of original', function () {\n            expect(bc.getCurveAfter(0.25).points)\n                .to.be.eql([{x: 2.5, y: 0.28125}, {x: 4, y: 0.1875}, {x: 5.5, y: -0.75}, {x: 7, y: 0}]);\n        });\n    });\n});\n\n\ndescribe('DG.TimeBezier', function () {\n    var cp1 = DG.point(0.42, 0.0);\n    var cp2 = DG.point(0.58, 1.0);\n\n    it('should return correct distance (Y) by time (X) value', function () {\n        expect(new DG.TimeBezier(cp1, cp2).getYbyX(0.37)).to.be.within(0.2851635, 0.2851640);\n    });\n});\n\n\ndescribe('DG.ArcBezier', function () {\n    var s = DG.point(1, 0), e = DG.point(7, 0),\n        cp1 = DG.point(3, 1), cp2 = DG.point(5, -1);\n\n    var bc = new DG.ArcBezier([s, cp1, cp2, e]);\n\n    after(function () {\n        bc = null;\n    });\n\n    it('should return correct (t) value by curve\\'s segment length', function () {\n        expect(bc.getTbyL(3)).to.be.within(0.485, 0.490);\n    });\n\n    it('should return correct (t) value by curve\\'s segment length', function () {\n        expect(bc.getLength()).to.be.within(6.1461, 6.1463);\n    });\n});\n"
  },
  {
    "path": "src/DGEntrance/test/DGMetricSpec.js",
    "content": "describe('DG.Metric', function () {\n    var dgMetric = DG.Metric;\n\n    it('should be a function object', function () {\n        expect(dgMetric).to.be.a('function');\n    });\n\n    describe('DG.Metric.Segments', function () {\n        var dgMetricSegments;\n\n        beforeEach(function () {\n            dgMetricSegments = new dgMetric.Segments();\n        });\n        \n        after(function () {\n            dgMetricSegments = null;\n        });\n\n        describe('#push', function () {\n            it('should return \\'DG.Metric.Segments\\' instance', function () {\n                expect(dgMetricSegments.push(0)).to.be.a(DG.Metric.Segments);\n            });\n\n            it('should update .length counter', function () {\n                expect(dgMetricSegments.push(0).push(1).push(2).length).to.be.equal(3);\n            });\n        });\n\n        describe('#getLength', function () {\n            it('should return correct total segments length in case of [0]', function () {\n                expect(dgMetricSegments.push(0).getLength()).to.be.equal(0);\n            });\n\n            it('should return correct total segments length in case of [0, 1, 2]', function () {\n                expect(dgMetricSegments.push(2).push(1).push(0).getLength()).to.be.equal(3);\n            });\n        });\n\n        describe('#getReverse', function () {\n            it('should return new instance of \\'DG.Metric.Segments\\'', function () {\n                var segments = dgMetricSegments.getReverse();\n                expect(segments).to.be.a(DG.Metric.Segments);\n                expect(segments).not.equal(dgMetricSegments);\n            });\n\n            it('should return correct total segments length', function () {\n                expect(dgMetricSegments.push(2).push(3).push(5).getReverse().getLength()).to.be.equal(10);\n            });\n\n            it('should map to correct segment lengths', function () {\n                expect(dgMetricSegments.push(2).push(3).push(5).getReverse())\n                    .to.be.eql({'0': 5, '1': 8, '2': 10, length: 3});\n            });\n        });\n\n        describe('#getIndex', function () {\n            it('should return correct index value in case of []', function () {\n                expect(dgMetricSegments.getIndex(5)).to.be.equal(-1);\n            });\n\n            it('should return correct index value in case of [1, 2, 3]', function () {\n                expect(dgMetricSegments.push(1).push(2).push(3).getIndex(2)).to.be.equal(1);\n            });\n\n            it('should return correct index value in case of [3, 2, 1]', function () {\n                expect(dgMetricSegments.push(3).push(2).push(1).getIndex(2)).to.be.equal(0);\n            });\n        });\n\n        describe('#getSegRatio', function () {\n            it('should return correct intra-segment ratio value in case of [1, 2, 3]', function () {\n                expect(dgMetricSegments.push(1).push(2).push(3).getSegRatio(4.5)).to.be.equal((4.5 - 3) / (6 - 3));\n            });\n\n            it('should return correct intra-segment ratio value in case of [3, 2, 1]', function () {\n                expect(dgMetricSegments.push(3).push(2).push(1).getSegRatio(4.5)).to.be.equal((4.5 - 3) / (5 - 3));\n            });\n        });\n\n        describe('#getSegLength', function () {\n            it('should return correct segment length in case of [1, 2, 3]', function () {\n                expect(dgMetricSegments.push(1).push(2).push(3).getSegLength(5)).to.be.equal(2);\n            });\n\n            it('should return correct segment length in case of [3, 2, 1]', function () {\n                expect(dgMetricSegments.push(3).push(2).push(1).getSegLength(5)).to.be.equal(0);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGEntrance/test/DGTransformSpec.js",
    "content": "describe('DG.VertexTransform', function () {\n    var a030 = Math.PI / 6,\n        a045 = Math.PI / 4,\n        a120 = Math.PI * 2 / 3,\n        a210 = Math.PI * 7 / 6,\n\n        p1 = DG.point(0, 0),\n        p2 = DG.point(1, 0),\n        p3 = DG.point(Math.cos(a030), Math.sin(a030)),\n        p4 = DG.point(-Math.cos(a030), -Math.sin(a030)),\n        p5 = DG.point(3, -4),\n        p6 = DG.point(12.3, 45.6),\n\n        DGVT = DG.VertexTransform, vt,\n        EPSILON = 0.000000000000001;\n\n    beforeEach(function () {\n        vt = new DG.VertexTransform([p1, p2, p3, p4, p5, p6]);\n    });\n\n    after(function () {\n        vt = p1 = p2 = p3 = p4 = p5 = p6 = null;\n    });\n\n    it('should contain chaining methods', function () {\n        expect(vt.load().save().setScale(1).setAngle({cos: 1, sin: 0}).setTranslation({x: 0, y: 0}).setMatrix([1, 0, 0, 0, 1, 0])\n            .scale().unScale().rotate().unRotate().translate().unTranslate().transform().vertices).to.be.an('array');\n    });\n\n    describe('statics', function () {\n        it('should return array objects with working \\'.clone()\\' method', function () {\n            expect(DGVT.scale(vt).clone().vertices).to.be.eql(vt.vertices);\n            expect(DGVT.unScale(vt).clone().vertices).to.be.eql(vt.vertices);\n            expect(DGVT.rotate(vt).clone().vertices).to.be.eql(vt.vertices);\n            expect(DGVT.unRotate(vt).clone().vertices).to.be.eql(vt.vertices);\n            expect(DGVT.translate(vt).clone().vertices).to.be.eql(vt.vertices);\n            expect(DGVT.unTranslate(vt).clone().vertices).to.be.eql(vt.vertices);\n        });\n\n        describe('cloned objects', function () {\n            it('should be distinct from original objects', function () {\n                expect(DGVT.scale(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n                expect(DGVT.unScale(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n                expect(DGVT.rotate(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n                expect(DGVT.unRotate(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n                expect(DGVT.translate(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n                expect(DGVT.unTranslate(vt).clone().vertices[0]).not.to.be(vt._vertices[0]);\n            });\n        });\n    });\n\n    describe('#getLength', function () {\n        it('should return correct length value in (vertex) case', function () {\n            var pc = p5.clone();\n            expect(DGVT.getLength(pc.x, pc.y)).to.be.equal(5);\n        });\n\n        it('should return correct length value in (vertex, vertex) case', function () {\n            expect(DGVT.getLength(DG.point(10, -5), DG.point(13, -1))).to.be.equal(5);\n        });\n    });\n\n    describe('#getScaled', function () {\n        it('should return correct scaled vector in (vertex) case', function () {\n            expect(DGVT.getScaled(p5.x, p5.y, 2)).to.be.eql({x: 6, y: -8});\n        });\n\n        it('should return correct scaled vector in (vertex, vertex) case', function () {\n            expect(DGVT.getScaled(DG.point(10, -5), DG.point(13, -1), 0.5)).to.be.eql({x: 11.5, y: -3});\n        });\n    });\n\n    describe('#getAngle', function () {\n        it('should return correct angle in (vertex) case', function () {\n            expect(DGVT.getAngle(p3.x, p3.y)).to.be.eql({cos: p3.x, sin: p3.y});\n            expect(DGVT.getAngle(p5.x, p5.y)).to.be.eql({cos: 0.6, sin: -0.8});\n        });\n\n        it('should return correct angle in (vertex, vertex) case', function () {\n            expect(DGVT.getAngle(p3.clone(), p2.clone(), p1.clone())).to.be.eql({cos: p3.x, sin: -p3.y});\n\n            var angle = 4.048560303417995,\n                cos = Math.cos(angle),\n                sin = Math.sin(angle);\n\n            angle = DGVT.getAngle(p6.clone(), p5.clone(), p1.clone());\n            expect(Math.abs(angle.cos - cos) < EPSILON).to.be.ok();\n            expect(Math.abs(angle.sin - sin) < EPSILON).to.be.ok();\n        });\n    });\n\n    describe('#getAngles(Sum/Dif)', function () {\n        it('should return correct angle', function () {\n            var cos045 = Math.cos(a045),\n                sin045 = Math.sin(a045),\n                cos210 = Math.cos(a210),\n                sin210 = Math.sin(a210),\n                angle, cos, sin;\n\n            angle = a045 + a210;\n            cos = Math.cos(angle);\n            sin = Math.sin(angle);\n            angle = DGVT.getAnglesSum({cos: cos045, sin: sin045}, {cos: cos210, sin: sin210});\n            expect(Math.abs(angle.cos - cos) < EPSILON).to.be.ok();\n            expect(Math.abs(angle.sin - sin) < EPSILON).to.be.ok();\n\n            angle = a045 - a210;\n            cos = Math.cos(angle);\n            sin = Math.sin(angle);\n            angle = DGVT.getAnglesDif({cos: cos045, sin: sin045}, {cos: cos210, sin: sin210});\n            expect(Math.abs(angle.cos - cos) < EPSILON).to.be.ok();\n            expect(Math.abs(angle.sin - sin) < EPSILON).to.be.ok();\n        });\n    });\n\n\n    describe('prototype', function () {\n        describe('#scale', function () {\n            it('should return correctly scaled vertices', function () {\n                expect(vt.scale(2).save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: p.x * 2, y: p.y * 2};\n                    }));\n\n                expect(vt.setScale(0.25).scale().save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: p.x / 2, y: p.y / 2};\n                    }));\n\n                expect(vt.unScale(0.5).save()._vertices).to.be.eql([p1, p2, p3, p4, p5, p6]);\n            });\n        });\n\n        describe('#rotate', function () {\n            it('should return correctly rotated vertices', function () {\n                var cos = Math.cos(a120), sin = Math.sin(a120);\n\n                expect(vt.rotate({cos: cos, sin: sin}).save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: p.x * cos - p.y * sin, y: p.x * sin + p.y * cos};\n                    }));\n\n                expect(vt.setAngle({cos: 0, sin: 1}).rotate().save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: -(p.x * sin + p.y * cos), y: p.x * cos - p.y * sin};\n                    }));\n\n                cos = Math.cos(a210); sin = Math.sin(a210);\n                vt.unRotate({cos: cos, sin: sin});\n                [p1, p2, p3, p4, p5, p6].forEach(function (p, i, a) {\n                    expect(Math.abs(a[i].x - vt.vertices[i].x) < EPSILON * 10).to.be.ok();\n                    expect(Math.abs(a[i].y - vt.vertices[i].y) < EPSILON * 10).to.be.ok();\n                });\n            });\n        });\n\n        describe('#translate', function () {\n            it('should return correctly translated vertices', function () {\n                expect(vt.translate(p5.clone()).save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: p.x + p5.x, y: p.y + p5.y};\n                    }));\n\n                expect(vt.setTranslation(DG.point(9.3, 49.6)).translate().save()._vertices).to.be\n                    .eql([p1, p2, p3, p4, p5, p6].map(function (p) {\n                        return {x: p.x + p6.x, y: p.y + p6.y};\n                    }));\n\n                vt.unTranslate(p6.clone());\n                [p1, p2, p3, p4, p5, p6].forEach(function (p, i, a) {\n                    expect(Math.abs(a[i].x - vt.vertices[i].x) < EPSILON).to.be.ok();\n                    expect(Math.abs(a[i].y - vt.vertices[i].y) < EPSILON).to.be.ok();\n                });\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGEntrance/test/EntranceSpec.js",
    "content": "describe('DG.Entrance', function () {\n    var map,\n        spy,\n        entrance,\n        mapContainer = document.createElement('div'),\n        ua = navigator.userAgent.toLowerCase(),\n        ff = ua.indexOf('firefox') > -1;\n\n    after(function() {\n        entrance.remove();\n        map && map.remove();\n        map = spy = entrance = mapContainer = ua = ff = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: new DG.LatLng(69.349552990994837, 87.75222519148015),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n        entrance = new DG.Entrance({\n            'is_primary': false,\n            'name': 'ЗАГС',\n            'points': ['POINT(87.75222519148015 69.349552990994837)'],\n            'vectors': ['LINESTRING(87.752433542237128 69.349501774294012,87.75222519148015 69.349552990994837)']\n        });\n    });\n\n    afterEach(function () {\n        entrance.removeFrom(map);\n        map && map.remove();\n        map = null;\n    });\n\n    // since ff/mocha/phantom has some strange bug with svg beginElement()\n    if (!ff) {\n        describe('#addTo', function () {\n            it('should return \\'DG.Entrance\\' instance', function () {\n                expect(entrance.addTo(map)).to.be.a(DG.Entrance);\n            });\n\n            it('should fire \\'entranceshow\\' event', function () {\n                spy = sinon.spy();\n                map.on('entranceshow', spy);\n                entrance.addTo(map);\n                expect(spy.called).to.be.ok();\n            });\n\n            it('should not fire \\'entranceshow\\' event if already shown', function () {\n                entrance.addTo(map);\n                spy = sinon.spy();\n                map.on('entranceshow', spy);\n                entrance.addTo(map);\n                expect(spy.called).not.to.be.ok();\n            });\n\n            it('should adjust map center and show entrance in viewport', function () {\n                map.setView([54.980206086231, 82.898068362003], 17); // Novosibirsk\n                entrance.addTo(map);\n                entrance.fitBounds();\n                expect(map.getCenter()).to.eql(entrance.getBounds().getCenter()); // Kayerkan\n            });\n\n            it('should add layers on map and visible container', function() {\n                var layers = entrance._layers;\n\n                entrance.addTo(map);\n\n                Object.keys(layers).forEach(function(el) {\n                    expect(map.hasLayer(layers[el])).to.be.ok();\n                    expect(layers[el]._visibility.isShown).to.be(true);\n                });\n            });\n        });\n    }\n    describe('#removeFrom', function () {\n\n        it('should return \\'DG.Entrance\\' instance', function () {\n            expect(entrance.removeFrom(map)).to.be.a(DG.Entrance);\n        });\n        if (!ff) {\n            it('should fire \\'entrancehide\\' event', function () {\n                entrance.addTo(map);\n                spy = sinon.spy();\n                map.on('entrancehide', spy);\n                entrance.removeFrom(map);\n                expect(spy.called).to.be.ok();\n            });\n        }\n        it('should not fire \\'entrancehide\\' event if already hidden (hidden by default)', function () {\n            spy = sinon.spy();\n            map.on('entrancehide', spy);\n            entrance.removeFrom(map);\n            expect(spy.called).not.to.be.ok();\n        });\n\n        it('should layers not on map and not visible container', function() {\n            var layers = entrance._layers;\n\n            Object.keys(layers).forEach(function(el) {\n                expect(map.hasLayer(layers[el])).not.be.ok();\n                expect(layers[el]._visibility.isShown).not.be(true);\n            });\n        });\n\n    });\n\n    describe('#isShown', function () {\n\n        it('should return \\'false\\' by default', function () {\n            expect(entrance.isShown()).not.to.be.ok();\n        });\n        if (!ff) {\n            it('should return \\'true\\' after show and \\'false\\' after hide', function () {\n                entrance.addTo(map);\n                expect(entrance.isShown()).to.be.ok();\n                entrance.removeFrom(map);\n                expect(entrance.isShown()).not.to.be.ok();\n            });\n        }\n    });\n\n    describe('#getBounds', function () {\n\n        it('should return bounds of all arrows of the entrance', function () {\n            var entranceBounds = new DG.LatLngBounds(\n                [69.349552990994837, 87.75222519148015],\n                [69.349501774294012, 87.752433542237128]\n            );\n            expect(entrance.getBounds()).to.eql(entranceBounds);\n        });\n    });\n\n});\n"
  },
  {
    "path": "src/DGFullScreen/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset='utf-8'>\n  <title>DGFullScreen Demo</title>\n  <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n\n</head>\n<body>\n\n  <div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n\n  <script type=\"text/javascript\">\n\n  DG.then(function () {\n\n    map = new DG.Map('map', {\n        center: new DG.LatLng(54.980206086231, 82.898068362003),\n        zoom:12,\n        key: DG.config.key || 'Your API access key'\n        // возможно отключить кнопку фулскрина передав опцию\n        //fullscreenControl: false\n    });\n\n    // изменить дефолтное положение контрола\n    map.fullscreenControl.setPosition('bottomleft');\n\n  });\n  </script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/DGFullScreen/lang/ar.js",
    "content": "DG.Control.Fullscreen.Dictionary.ar = {\n    title_max : '',\n    title_min : ''\n};\n"
  },
  {
    "path": "src/DGFullScreen/lang/cs.js",
    "content": "DG.Control.Fullscreen.Dictionary.cs = {\n    title_max : 'Rozbalit',\n    title_min : 'Obnovit'\n};\n"
  },
  {
    "path": "src/DGFullScreen/lang/en.js",
    "content": "DG.Control.Fullscreen.Dictionary.en = {\n    title_max : 'Expand',\n    title_min : 'Restore'\n};\n"
  },
  {
    "path": "src/DGFullScreen/lang/es.js",
    "content": "DG.Control.Fullscreen.Dictionary.es = {\n    title_max : 'Maximizar',\n    title_min : 'Restaurar'\n};\n"
  },
  {
    "path": "src/DGFullScreen/lang/it.js",
    "content": "DG.Control.Fullscreen.Dictionary.it = {\n    title_max : 'Espandi',\n    title_min : 'Ripristina'\n};\n"
  },
  {
    "path": "src/DGFullScreen/lang/ru.js",
    "content": "DG.Control.Fullscreen.Dictionary.ru = {\n    title_max : 'Развернуть',\n    title_min : 'Восстановить'\n};\n"
  },
  {
    "path": "src/DGFullScreen/skin/basic/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_fullscreen {\n    &:after {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        margin: auto;\n        content: '';\n    }\n\n    .dg-control-round__icon_state_active&:after,\n    .no-touch .dg-control-round__icon_state_active&:hover:after,\n    .dg-control-round__icon_state_active&:active:after {\n        .notRepeatableBg('DGRoundControl__fullscreenIconEnabled');\n    }\n}\n"
  },
  {
    "path": "src/DGFullScreen/skin/basic/less/dg-fullscreen.ie.less",
    "content": ".dg-fullscreen {\n    zoom: 1;\n    .opacity(.8);\n}\n\n.dg-fullscreen:hover {\n    .opacity(1);\n}\n"
  },
  {
    "path": "src/DGFullScreen/skin/dark/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_fullscreen {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__fullscreenIcon_dark');\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__fullscreenIconHover_dark');\n    }\n}\n"
  },
  {
    "path": "src/DGFullScreen/skin/light/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_fullscreen {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__fullscreenIcon_light');\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__fullscreenIconHover_light');\n    }\n}\n"
  },
  {
    "path": "src/DGFullScreen/src/DGFullScreen.js",
    "content": "DG.Control.Fullscreen = DG.RoundControl.extend({\n\n    statics: {\n        Dictionary: {}\n    },\n\n    options: {\n        position: 'topright',\n        iconClass: 'fullscreen'\n    },\n\n    initialize: function(options) {\n        DG.Util.setOptions(this, options);\n        this._isFullscreen = false;\n        this.on('click', this._toggleFullscreen);\n    },\n\n    _toggleFullscreen: function() {\n        if (!this._isFullscreen) {\n            this._toggle(true, 'request', 'on', 'requestfullscreen');\n        } else {\n            this._toggle(false, 'exit', 'on', 'cancelfullscreen');\n        }\n\n        this._renderTranslation();\n        this._map.invalidateSize();\n    },\n\n    _renderTranslation: function() {\n        this._link.title = this.t(this._isFullscreen ? 'title_min' : 'title_max');\n    },\n\n    _toggle: function(isEnabled, method, list, event) {\n        var container = this._map._container;\n\n        this._isFullscreen = isEnabled;\n        this.setState(isEnabled ? 'active' : '');\n\n        DG.screenfull[method](container);\n        DG.DomEvent[list](document, DG.screenfull.api.fullscreenchange, this._onFullScreenStateChange, this);\n        this._map.fire(event);\n    },\n\n    _onFullScreenStateChange: function() {\n        if (!DG.screenfull.isFullscreen()) {\n            this._toggle(false, 'exit', 'on', 'cancelfullscreen');\n        }\n    }\n});\n\nDG.control.fullscreen = function(options) {\n    return new DG.Control.Fullscreen(options);\n};\n\nDG.Map.mergeOptions({\n    fullscreenControl: true\n});\n\nDG.Map.addInitHook(function() {\n    if (this.options.fullscreenControl) {\n        this.fullscreenControl = DG.control.fullscreen(this.options.fullscreenControl);\n\n        if (DG.screenfull.isAvailable()) {\n            this.addControl(this.fullscreenControl);\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGFullScreen/src/DGScreenfull.js",
    "content": "// Inspired by Sindre Sorhus screenfull\nDG.Screenfull = DG.Class.extend({\n    _apiMap: [\n        [\n            'requestFullscreen',\n            'exitFullscreen',\n            'fullscreenElement',\n            'fullscreenEnabled',\n            'fullscreenchange',\n            'fullscreenerror'\n        ],\n        [\n            'webkitRequestFullscreen',\n            'webkitExitFullscreen',\n            'webkitFullscreenElement',\n            'webkitFullscreenEnabled',\n            'webkitfullscreenchange',\n            'webkitfullscreenerror'\n\n        ],\n        [\n            'mozRequestFullScreen',\n            'mozCancelFullScreen',\n            'mozFullScreenElement',\n            'mozFullScreenEnabled',\n            'mozfullscreenchange',\n            'mozfullscreenerror'\n        ],\n        [\n            'msRequestFullscreen',\n            'msExitFullscreen',\n            'msFullscreenElement',\n            'msFullscreenEnabled',\n            'MSFullscreenChange',\n            'MSFullscreenError'\n        ]\n    ],\n\n    initialize: function() {\n        this.api = this._api();\n    },\n\n    request: function(elem) {\n        var request = this.api.requestFullscreen;\n\n        elem = elem || document.documentElement;\n        elem[request](Element.ALLOW_KEYBOARD_INPUT);\n    },\n\n    exit: function() {\n        document[this.api.exitFullscreen]();\n    },\n\n    isFullscreen: function() {\n        return !!document[this.api.fullscreenElement];\n    },\n\n    isAvailable: function() {\n        return Boolean(this.api);\n    },\n\n    _api: function() {\n        var api = {},\n            apiMap = this._apiMap;\n\n        apiMap.forEach(function(val) {\n            if (val && val[1] in document) {\n                val.forEach(function(method, i) {\n                    api[apiMap[0][i]] = method;\n                });\n            }\n        });\n\n        return api.requestFullscreen ? api : false;\n    }\n});\n\nDG.screenfull = new DG.Screenfull();\n"
  },
  {
    "path": "src/DGFullScreen/src/LegacyFullScreen.js",
    "content": "if (!DG.screenfull.api ||\n    //fallback since srange android ff bug with fullscreen mode\n    (DG.Browser.android && DG.Browser.gecko) ||\n    //fallback for safari5.1 because of error on fullscreen exit\n    DG.Browser.safari51) {\n\n    DG.Screenfull.include({\n        _fullscreenClass: 'DGFullScreen_legacy-mode',\n        _fullscreenBodyClass: this._fullscreenClass + '-body',\n        _api: function() {\n            return {fullscreenchange: 'keyup'};\n        },\n\n        _mapParams: [\n            'zIndex', 'position', 'left', 'top', 'border', 'marginTop', 'marginRight',\n            'marginBottom', 'marginLeft', 'paddingTop', 'paddingRight', 'paddingBottom',\n            'paddingLeft', 'previousSibling', 'width', 'height'\n        ],\n\n        _documentParams: [\n            'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'paddingTop',\n            'paddingRight', 'paddingBottom', 'paddingLeft', 'overflow', 'scrollTop'\n        ],\n        _initialDocumentParams: {},\n        _initialMapParams: {},\n        _initialDocumentElementParams: {},\n\n        exit: function(container) { // (HTMLDivElement)\n\n            DG.DomUtil.removeClass(container, this._fullscreenClass);\n            DG.DomUtil.removeClass(document.body, this._fullscreenBodyClass);\n\n            // restore map container params\n            this._mapParams.forEach(function(cssRule) {\n                container.style[cssRule] = this._initialMapParams[cssRule];\n            }, this);\n\n            // restore map container params\n            this._documentParams.forEach(function(cssRule) {\n                document.body.style[cssRule] = this._initialDocumentParams[cssRule];\n            }, this);\n\n            // restore document.documentElement params\n            document.documentElement.scrollTop = this._initialDocumentElementParams.scrollTop;\n        },\n\n        request: function(container) { // (HTMLDivElement)\n            this._storePosition(container);\n            // set full map mode style\n            DG.DomUtil.addClass(container, this._fullscreenClass);\n            DG.DomUtil.addClass(document.body, this._fullscreenBodyClass);\n\n            // reset document.documentElement params\n            document.documentElement.scrollTop = '0px';\n        },\n\n        _storePosition: function(container) { // (HTMLDivElement)\n\n            // store initial map container params\n            this._mapParams.forEach(function(cssRule) {\n                this._initialMapParams[cssRule] = container.style[cssRule];\n            }, this);\n\n            // store initial document.body params\n            this._documentParams.forEach(function(cssRule) {\n                this._initialDocumentParams[cssRule] = document.body.style[cssRule];\n            }, this);\n\n            // store initial document.documentElement params\n            this._initialDocumentElementParams.scrollTop = document.documentElement.scrollTop;\n        },\n\n        _onFullScreenStateChange: function(e) { // (Object)\n            if (!e) {\n                e = window.event;\n            }\n            if (e.keyCode === 27) {\n                this._exitFullScreen();\n            }\n        }\n    });\n\n    DG.screenfull = new DG.Screenfull();\n}\n"
  },
  {
    "path": "src/DGFullScreen/test/DGFullScreenSpec.js",
    "content": "/*global describe:false, it:false, expect:false, sinon:false */\ndescribe.skip('DG.FullScreen', function () {\n    var mapContainer, map, classControl, container, spy;\n\n    before(function() {\n        mapContainer = document.createElement('div');\n\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [54.98117239821992, 82.88922250270844],\n            key: window.__karma__.config.secretKey,\n            'zoom': 17,\n            'geoclicker': true,\n            'zoomAnimation': false\n        });\n\n        classControl = 'dg-control-round__icon_name_fullscreen';\n    });\n\n    after(function() {\n        map.remove();\n        document.body.removeChild(mapContainer);\n        mapContainer = map = classControl = container = spy = null;\n    });\n\n    describe('check init', function() {\n        it('should be one container on map', function() {\n            container = mapContainer.getElementsByClassName(classControl);\n            expect(container.length).to.be(1);\n            container = container[0];\n        });\n\n        it('should be DG.control.fullscreen', function() {\n            expect(DG.control.fullscreen).to.be.ok();\n        });\n    });\n\n    describe('enable fullscreen', function() {\n        before(function() {\n            spy = sinon.spy();\n            map.on('requestfullscreen', spy);\n\n            happen.click(container);\n        });\n\n        after(function() {\n            map.off('requestfullscreen', spy);\n            spy = null;\n        });\n\n        it('should fire request event', function() {\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        // phantom hasn't fullscreen\n        if (DG.screenfull.api['fullscreenElement']) {\n            it('should enable fullscreen', function () {\n                expect(document[DG.screenfull.api['fullscreenElement']]).to.be(null);\n            });\n        }\n\n        it('should container has active class', function() {\n            expect(container.className).to.contain('active');\n        });\n    });\n\n    describe('enable fullscreen', function() {\n        before(function() {\n            spy = sinon.spy();\n            map.on('cancelfullscreen', spy);\n\n            happen.click(container);\n        });\n\n        after(function() {\n            map.off('cancelfullscreen', spy);\n            spy = null;\n        });\n\n        it('should fire cancel event', function() {\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        // phantom hasn't fullscreen\n        if (DG.screenfull.api['fullscreenElement']) {\n            it('should disable fullscreen', function() {\n                expect(document[DG.screenfull.api['fullscreenElement']]).to.be(null);\n            });\n        }\n\n        it('should container hasn\\'t active class', function() {\n            expect(container.className).not.to.contain('active');\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGGeoclicker/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>geoclicker demo</title>\n    <script src=\"http://maps.api.2gis.dev/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            map = new DG.Map('map', {\n                center: new DG.LatLng(54.980206086231, 82.898068362003),\n                zoom: 18,\n                key: DG.config.key || 'Your API access key',\n                geoclicker: {\n                    showPhotos: true,\n                    showBooklet: true,\n                    showRouteSearch: true\n                }\n            });\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGGeoclicker/lang/cs.js",
    "content": "DG.Geoclicker.Handler.Default.Dictionary.cs = DG.extend({\n    apiErrorTitle: 'Chybička se&nbsp;vloudila',\n    apiErrorBody: 'Naše servery odmítají reagovat. Již nyní vynakládáme veškeré úsilí, abychom je přivedli k rozumu. Zkuste akci opakovat za několik minut.',\n    we_have_not : 'O tomto místě zatím nemáme informace',\n    noname : 'Bez názvu',\n    'adm_div.place' : 'Místo',\n    'adm_div.division' : 'Správní obvod',\n    'adm_div.settlement' : 'Obec',\n    street : 'Ulice',\n    'adm_div.district' : 'Městská část',\n    'adm_div.city' : 'Město',\n    go_to : 'Cesta sem',\n    show_organization_in_building : ['Celkem {n} organizace', 'Celkem {n} organizace', 'Celkem {n} organizací'],\n    back_button : 'Zpět',\n    show_more_about_sight : 'Více',\n    n_floors : ['{n} patro', '{n} patra', '{n} pater']\n}, DG.Dictionary.cs);\n"
  },
  {
    "path": "src/DGGeoclicker/lang/en.js",
    "content": "DG.Geoclicker.Handler.Default.Dictionary.en = DG.extend({\n    apiErrorTitle: 'Oops! Error detected.',\n    apiErrorBody: 'Our servers are not responding. We are doing our best to straighten them out. Please return to us in a few minutes.',\n    we_have_not: 'We haven\\'t collected info about this place yet',\n    noname : 'No name',\n    'adm_div.place' : 'Place',\n    'adm_div.division' : 'Area',\n    'adm_div.settlement' : 'Village',\n    street : 'Street',\n    'adm_div.district' : 'District',\n    'adm_div.city' : 'City',\n    go_to : 'Directions to here',\n    show_organization_in_building : ['{n} organization total', '{n} organizations total'],\n    back_button : 'Back',\n    show_more_about_sight : 'More information',\n    n_floors : ['{n} floor', '{n} floors']\n}, DG.Dictionary.en);\n"
  },
  {
    "path": "src/DGGeoclicker/lang/es.js",
    "content": "DG.Geoclicker.Handler.Default.Dictionary.es = DG.extend({\n    apiErrorTitle: 'Vaya, ha ocurrido un error',\n    apiErrorBody: 'Nuestros servidores se niegan a responder. Ya nos estamos esforzando por hacerlos entrar en razón. Vuelva con nosotros pasados unos minutos.',\n    we_have_not : 'Todavía no hemos recopilado la información sobre este lugar',\n    noname : 'Sin nombre',\n    'adm_div.place' : 'Lugar',\n    'adm_div.division' : 'Comuna',\n    'adm_div.settlement' : 'Población',\n    street : 'Calle',\n    'adm_div.district' : 'Comuna',\n    'adm_div.city' : 'Ciudad',\n    go_to : 'Ir para allá',\n    show_organization_in_building : ['Total {n} organización', 'Total {n} organizaciones', 'Total {n} organizaciones'],\n    show_more_about_sight : 'Read more',\n    back_button: 'Atrás',\n    n_floors : ['{n} piso', '{n} pisos']\n}, DG.Dictionary.es);\n"
  },
  {
    "path": "src/DGGeoclicker/lang/it.js",
    "content": "DG.Geoclicker.Handler.Default.Dictionary.it = DG.extend({\n    apiErrorTitle: 'Oh oh, c\\'è&nbsp;un&nbsp;errore',\n    apiErrorBody: 'I nostri server si rifiutano di rispondere. Stiamo facendo del nostro meglio per convincerli a&nbsp;comportarsi bene. Ritorna tra qualche minuto.',\n    we_have_not : 'Non disponiamo ancora di informazioni su questo posto',\n    noname : 'Nome non indicato',\n    'adm_div.place' : 'Luogo',\n    'adm_div.division' : 'Zona',\n    'adm_div.settlement' : 'Comune',\n    street : 'Via',\n    'adm_div.district' : 'Municipalità',\n    'adm_div.city' : 'Сittà',\n    go_to : 'Come arrivare',\n    show_organization_in_building : ['{n} azienda in tutto', '{n} aziende in tutto'],\n    show_more_about_sight : 'Maggiori informazioni',\n    back_button: 'Indietro',\n    n_floors : ['{n} piano', '{n} piani']\n}, DG.Dictionary.it);\n"
  },
  {
    "path": "src/DGGeoclicker/lang/ru.js",
    "content": "DG.Geoclicker.Handler.Default.Dictionary.ru = DG.extend({\n    apiErrorTitle: 'Ошибочка вышла',\n    apiErrorBody: 'Наши серверы отказываются отвечать. Мы уже прикладываем все силы, чтобы вразумить их. Возвращайтесь к&nbsp;нам через&nbsp;несколько минут.',\n    we_have_not : 'Это место мы ещё не успели изучить',\n    noname: 'Без названия',\n    'adm_div.place': 'Место',\n    'adm_div.division': 'Округ',\n    'adm_div.settlement': 'Населенный пункт',\n    street: 'Улица',\n    'adm_div.district': 'Район',\n    'adm_div.city': 'Город',\n    go_to: 'Проехать сюда',\n    show_organization_in_building: ['Всего {n} организация', 'Всего {n} организации', 'Всего {n} организаций'],\n    show_more_about_sight: 'Подробнее',\n    back_button: 'Назад',\n    n_floors: ['{n} этаж', '{n} этажа', '{n} этажей']\n}, DG.Dictionary.ru);\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-building-callout.less",
    "content": ".dg-building-callout__body {\n    position: relative;\n}\n\n.dg-building-callout__list {\n    margin-bottom: 8px;\n    padding-left: 24px;\n    color: #ffe6aa;\n    list-style: none;\n}\n\n.dg-building-callout__list-item {\n    position: relative;\n    margin-bottom: 4px;\n    font-size: 12px;\n\n    &:before {\n        position: absolute;\n        top: 5px;\n        left: -21px;\n        content: '';\n    }\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-firm-card.less",
    "content": ".dg-firm-card__icon {\n    position: relative;\n    padding-left: 24px;\n\n    &:before {\n        position: absolute;\n        top: 0;\n        left: 0;\n        margin: auto;\n        background-position: 0 50%;\n        background-repeat: no-repeat;\n        content: '';\n    }\n}\n\n.dg-firm-card__link {\n    overflow: hidden;\n    margin-bottom: 4px;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    word-wrap: normal;\n    line-height: 16px;\n}\n\n.dg-firm-card__link a {\n    background-position: center bottom;\n    background-size: 10px 1px;\n    background-repeat: repeat-x;\n    text-decoration: none;\n}\n\n.dg-firm-card__address {\n    margin-bottom: 10px;\n    font-size: 16px;\n\n    &:before {\n        position: absolute;\n        top: 5px;\n        left: 1px;\n        content: '';\n    }\n}\n\n.dg-firm-card__comment {\n    position: relative;\n    margin-left: 5px;\n    font-size: 12px;\n}\n\n.dg-firm-card__phone {\n    overflow: hidden;\n    margin-bottom: 4px;\n    text-overflow: ellipsis;\n    line-height: 16px;\n\n    &:before {\n        top: 3px;\n        left: 1px;\n    }\n}\n\n.dg-firm-card__site {\n    &:before {\n        top: 3px;\n    }\n}\n\n.dg-firm-card__email {\n    &:before {\n        top: 5px;\n        height: 7px;\n    }\n}\n\n.dg-firm-card__rubrics {\n    overflow: hidden;\n    margin-bottom: 4px;\n    font-size: 12px;\n    line-height: 16px;\n}\n\n.dg-firm-card__rubrics-list {\n    margin: 0;\n    padding: 0;\n    list-style: none;\n}\n\n.dg-firm-card__rubrics-list-item {\n    display: inline;\n    cursor: default;\n\n    &:before {\n        display: inline-block;\n        margin: 0 4px;\n        content: '•';\n    }\n\n    &:first-child:before {\n        margin: 0;\n        content: '';\n    }\n}\n\n.dg-firm-card__aa {\n    margin: 0 0 4px;\n    padding: 0 0 0 24px;\n    font-size: 12px;\n}\n\n.dg-firm-card__aa-list {\n    display: inline;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n    line-height: 16px;\n}\n\n.dg-firm-card__aa-list-item {\n    display: inline;\n    box-sizing: border-box;\n    max-width: 100%;\n    cursor: default;\n\n    &:before {\n        display: inline-block;\n        margin: 0 4px;\n        content: '•';\n    }\n\n    &:first-child:before {\n        margin: 0;\n        content: '';\n    }\n}\n\n.dg-firm-card__aa-list-additional {\n    display: inline;\n    margin: 0;\n    padding: 0;\n    list-style: none;\n    line-height: 16px;\n}\n\n.dg-firm-card__schedule {\n    margin-bottom: 10px;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-link.less",
    "content": ".dg-link,\n.dg-link:hover {\n    background-position: 0 95%;\n    background-size: 10px 1px;\n    background-repeat: repeat-x;\n}\n\n.dg-link_type_local {\n    background: linear-gradient(to right, #99ccdd, #99ccdd 50%, transparent 50%);\n\n    .no-touch &:hover {\n        background: linear-gradient(to right, #99bbcc, #99bbcc 50%, transparent 50%);\n    }\n}\n\n.dg-link.dg-link_type_local,\n.dg-link.dg-link_type_local:hover {\n    background-size: 6px 1px;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-map-geoclicker.less",
    "content": ".dg-map-geoclicker__address {\n    margin-bottom: 10px;\n    font-size: 16px;\n\n    .dg-map-geoclicker__purpose + & {\n        margin-top: -6px;\n    }\n}\n\n.dg-map-geoclicker__address-header {\n    position: relative;\n    margin-bottom: 4px;\n    padding-left: 24px;\n\n    &:first-child:before {\n        position: absolute;\n        top: 5px;\n        left: 1px;\n        content: '';\n    }\n}\n\n.dg-map-geoclicker__address-drilldown {\n    position: relative;\n    margin-bottom: 4px;\n    padding-left: 24px;\n    color: #aaa;\n    font-size: 12px;\n\n    &:first-child:before {\n        position: absolute;\n        top: 2px;\n        left: 1px;\n        content: '';\n    }\n}\n\n.dg-map-geoclicker__purpose {\n    position: relative;\n    margin-bottom: 10px;\n    padding-left: 24px;\n    font-size: 16px;\n\n    .dg-map-geoclicker__address + & {\n        margin-top: -6px;\n    }\n\n    &:before {\n        position: absolute;\n        top: 4px;\n        left: 2px;\n        content: '';\n    }\n\n    &_type_street:before {\n        top: 4px;\n    }\n}\n\n.dg-map-geoclicker__sight-description {\n    overflow: hidden;\n    padding: .5em 0 0 24px;\n    max-height: 3.6em;\n}\n\na.dg-map-geoclicker__show-more-sights-link {\n    position: relative;\n    margin-left: 24px;\n    border-bottom: 1px dotted;\n    text-decoration: none;\n\n    &:after {\n        position: absolute;\n        top: 4px;\n        margin-left: 5px;\n        width: 6px;\n        height: 10px;\n        content: '';\n        font-weight: bold;\n    }\n}\n\n.dg-map-geoclicker__clamped-line {\n    display: block;\n    white-space: nowrap;\n}\n\n.dg-map-geoclicker__clamped-line_last {\n    overflow: hidden;\n    width: 100%;\n    text-overflow: ellipsis;\n}\n\n.dg-map-geoclicker__preloader-wrapper {\n    display: table-cell;\n    vertical-align: middle;\n    text-align: center;\n}\n\n.dg-map-geoclicker__drilldown {\n    margin-bottom: 10px;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-popup.ie.less",
    "content": ".dg-popup__header-title_for_firmcard {\n    max-height: none;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-popup.less",
    "content": ".dg-popup__footer-buttons {\n    display: table;\n    margin-top: 10px;\n    width: 100%;\n}\n\n.dg-popup__footer-button-wrapper {\n    display: table-cell;\n}\n\n.dg-popup__footer-button {\n    position: relative;\n    display: inline-block;\n    box-sizing: border-box;\n    margin-left: 5%;\n    width: 95%;\n    border-radius: 2px;\n    text-align: center;\n    text-decoration: none;\n    font: 12px/24px Arial, sans-serif;\n    cursor: pointer;\n    transition: all .1s;\n\n    .dg-popup__footer-button-wrapper:first-child & {\n        margin: 0;\n        width: 100%;\n    }\n\n    .no-touch &:hover {\n        transition: all .2s; /* @TODO: all? */\n    }\n}\n\n.dg-popup__footer-icon-button:before {\n    display: inline-block;\n    margin: -2px 5px 0 0;\n    width: 12px;\n    height: 12px;\n    background-size: contain;\n    background-repeat: no-repeat;\n    content: '';\n    vertical-align: middle;\n}\n\n.dg-popup__button_name_goto:before {\n    width: 20px;\n    height: 7px;\n}\n\n.dg-popup__button_name_firm-card-back:before {\n    width: 9px;\n    height: 6px;\n}\n\n.dg-popup__button_name_firm-list-back:before {\n    width: 9px;\n    height: 6px;\n}\n\n.dg-popup__button_name_back:before {\n    width: 9px;\n    height: 6px;\n}\n\n.dg-popup__show-less-house-link {\n    position: relative;\n    top: 6px;\n    margin: 0 15px 10px;\n    color: #0070c0;\n    text-decoration: none;\n    font-size: 12px;\n    line-height: 24px;\n}\n\n.dg-popup__header-links {\n    margin: 8px 18px 0 0;\n}\n\n.dg-popup__header-title_for_firmcard {\n    position: relative;\n    overflow: hidden;\n    max-height: 3.4em;\n}\n\n.dg-popup__header-teaser {\n    display: -webkit-box;\n    height: 3.3em;\n    -webkit-line-clamp: 3;\n    -webkit-box-orient: vertical;\n}\n\n.dg-popup__header-title {\n    display: block;\n    white-space: normal;\n    font: 22px/24px 'Arial narrow', Arial, sans-serif;\n}\n\n.dg-popup__header-link {\n    display: inline-block;\n    margin-left: 2.6em;\n    vertical-align: middle;\n    white-space: nowrap;\n\n    &:first-child {\n        margin-left: 1.2em;\n    }\n}\n\n.dg-popup__rating {\n    display: inline-block;\n    margin: 0 .4em 3px 0;\n    width: 70px;\n    height: 14px;\n    vertical-align: middle;\n}\n\n.dg-popup__rating-stars {\n    .repeatableBg('DGPopup__ratingStar');\n    float: left;\n    height: 100%;\n}\n\n.dg-popup__link {\n    position: relative;\n    background-position: center bottom;\n    background-size: 10px 1px;\n    background-repeat: repeat-x;\n    text-decoration: none;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\n.dg-popup__link_type_flamp_reviews {\n    margin-left: .1em;\n}\n\n.dg-popup__link_type_photos:before {\n    position: absolute;\n    top: 2px;\n    left: -18px;\n    display: inherit;\n    content: '';\n}\n\n.dg-popup__link_type_booklet:before {\n    .notRepeatableBgWithSizes('DGPopup__bookletLinkIcon');\n    position: absolute;\n    top: 2px;\n    left: -18px;\n    display: inherit;\n    content: '';\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-preloader.less",
    "content": ".dg-preloader {\n    position: relative;\n    margin: 0 auto;\n    width: 200px;\n    height: 44px;\n    vertical-align: middle;\n}\n\n.dg-preloader_animation_false {\n    .notRepeatableBg('DGPreloader__preloader');\n    background-attachment: scroll;\n    background-position: 50% 50%;\n}\n\n.dg-preloader_animation_true {\n    &:before {\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        margin: -22px 0 0 -22px;\n        width: 44px;\n        height: 44px;\n        outline: 1px solid transparent;\n        content: '';\n        animation: dg-preloader__outer 5s linear infinite;\n        image-rendering: optimizeQuality;\n    }\n\n    &.dg-preloader_size_small:before {\n        margin: -12px 0 0 -12px;\n        width: 24px;\n        height: 24px;\n    }\n\n    &.dg-preloader_scheme_regular:before {\n        .notRepeatableBg('DGPreloader__preloaderBig', true);\n        background-size: 44px 44px;\n    }\n\n    &.dg-preloader_scheme_regular.dg-preloader_size_small:before {\n        .notRepeatableBg('DGPreloader__preloaderSmall', true);\n        background-size: 24px 24px;\n    }\n\n    &:after {\n        position: absolute;\n        top: 50%;\n        left: 50%;\n        margin: -16px 0 0 -16px;\n        width: 32px;\n        height: 32px;\n        outline: 1px solid transparent;\n        content: '';\n        animation: dg-preloader__inner 4s linear infinite;\n        image-rendering: optimizeQuality;\n    }\n\n    &.dg-preloader_size_small:after {\n        margin: -6px 0 0 -6px;\n        width: 12px;\n        height: 12px;\n    }\n\n    &.dg-preloader_scheme_regular:after {\n        .notRepeatableBg('DGPreloader__preloaderBigInner', true);\n        background-size: 32px 32px;\n    }\n\n    &.dg-preloader_scheme_regular.dg-preloader_size_small:after {\n        .notRepeatableBg('DGPreloader__preloaderSmallInner', true);\n        background-size: 12px 12px;\n    }\n}\n\n@keyframes dg-preloader__outer {\n    to {\n        transform: rotate(360deg);\n    }\n}\n\n@keyframes dg-preloader__inner {\n    to {\n        transform: rotate(-360deg);\n    }\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-schedule.ie.less",
    "content": ".dg-schedule__today_shown_true:after {\n    content: ' ';\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/basic/less/dg-schedule.less",
    "content": ".dg-schedule {\n}\n\n.dg-schedule__today {\n    position: relative;\n    display: inline-block;\n    margin-left: 24px;\n    max-width: 84%;\n    background-position: center bottom;\n    background-size: 2px 1px;\n    background-repeat: repeat-x;\n    font-size: 14px;\n    line-height: 16px;\n    cursor: pointer;\n\n    &:before {\n        position: absolute;\n        top: 3px;\n        left: -24px;\n        content: '';\n    }\n\n    &:after {\n        position: absolute;\n        right: -15px;\n        bottom: 4px;\n        content: '';\n    }\n}\n\n.dg-schedule__today-inner {\n    overflow: hidden;\n    width: 100%;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n}\n\n.dg-schedule_works-everyday_true .dg-schedule__today {\n    background-image: none;\n    cursor: default;\n\n    &:after {\n        background-image: none;\n    }\n}\n\n.dg-schedule_open_true .dg-schedule__today:before {\n    .notRepeatableBgWithSizes('DGSchedule__clockOn');\n}\n\n.dg-schedule__now {\n    margin: 2px 7px 0 36px;\n    font-size: 12px;\n}\n\n.dg-schedule__string {\n    padding: 3px 16px 3px 24px;\n    text-align: left;\n    font-size: 14px;\n}\n\n.dg-schedule__string-time {\n    white-space: nowrap;\n}\n\n.dg-schedule__table {\n    display: none;\n    text-align: center;\n    font-size: 0;\n}\n\n.dg-schedule__table-cell-group {\n    white-space: nowrap;\n}\n\n.dg-schedule__tc {\n    display: inline-block;\n    padding: 2px 0 15px;\n    width: 44px;\n    vertical-align: top;\n    white-space: normal;\n    font-size: 14px;\n}\n\n.dg-schedule__tc_pre {\n    width: 19px;\n}\n\n.dg-schedule__day-name {\n    margin: 0;\n    color: #8c8782;\n    text-transform: capitalize;\n}\n\n.dg-schedule__td {\n    margin: 10px 0 0;\n}\n\n.dg-schedule_state_expanded .dg-schedule__popup {\n    display: block;\n    visibility: visible;\n    max-height: 1000px;\n    opacity: 1;\n}\n\n.dg-schedule__table-clock {\n    margin: 13px 0 0 0;\n}\n\n.dg-schedule__table-lunch {\n    margin: 31px 0 0 0;\n}\n\n.dg-schedule_open_true {\n}\n\n.dg-schedule_state_expanded {\n}\n\n.dg-schedule_works-everyday_true {\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-building-callout.less",
    "content": ".dg-building-callout__list-item:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__bullet_dark');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-firm-card.less",
    "content": ".dg-firm-card__link a {\n    background-image: linear-gradient(to right, rgba(255, 230, 170, .3), rgba(255, 230, 170, .3) 100%);\n    color: #ffe6aa;\n\n    .no-touch &:hover {\n        background-image: linear-gradient(to right, rgba(153, 204, 221, .3), rgba(153, 204, 221, .3) 100%);\n        color: #9cd;\n    }\n}\n\n.dg-firm-card__comment {\n    color: #aaa;\n}\n\n.dg-firm-card__rubrics {\n    color: #aaa;\n}\n\n.dg-firm-card__rubrics-list-item:after {\n    color: #6e6964;\n}\n\n.dg-firm-card__aa-list-item:after {\n    color: #e6e6e6;\n}\n\n.dg-firm-card__address:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__marker_dark');\n}\n\n.dg-firm-card__phone:before {\n    .notRepeatableBgWithSizes('DGFirmCard__phoneIcon_dark');\n}\n\n.dg-firm-card__site:before {\n    .notRepeatableBgWithSizes('DGFirmCard__siteIcon_dark');\n}\n\n.dg-firm-card__email:before {\n    .notRepeatableBgWithSizes('DGFirmCard__mailIcon_dark');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-map-geoclicker.less",
    "content": ".dg-map-geoclicker__address-header:first-child:before,\n.dg-map-geoclicker__address-drilldown:first-child:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__marker_dark');\n}\n\n.dg-map-geoclicker__purpose {\n    &:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purpose_dark');\n    }\n\n    &_type_street:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeStreet_dark');\n    }\n\n    &_type_sight:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeSight_dark');\n    }\n\n    &_type_settlement:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeSettlement_dark');\n    }\n}\n\na.dg-map-geoclicker__show-more-sights-link {\n    color: #ffe6aa;\n\n    .no-touch &:hover {\n        color: #9cd;\n    }\n\n    &:after {\n        .notRepeatableBg('DGGeoclicker__arrowLeft_dark');\n    }\n}\n\n.dg-map-geoclicker__drilldown {\n    color: #aaa;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-popup.ie.less",
    "content": ".dg-popup__footer-button {\n    background-color: #373737;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-popup.less",
    "content": "a.dg-popup__link {\n    background-image: linear-gradient(to right, rgba(255, 230, 170, .3), rgba(255, 230, 170, .3) 100%);\n    color: #ffe6aa;\n\n    .no-touch &:hover {\n        background-image: linear-gradient(to right, rgba(153, 204, 221, .3), rgba(153, 204, 221, .3) 100%);\n        color: #9cd;\n    }\n}\n\n.dg-popup__header-title {\n    color: #ffc84b;\n}\n\n.dg-popup__footer-button-wrapper .dg-popup__footer-button,\n.dg-popup__footer-button-wrapper .dg-popup__footer-button:hover {\n    color: #e6e6e6;\n}\n\n.dg-popup__footer-button {\n    background: rgba(0, 0, 0, .2);\n    box-shadow: 0 1px rgba(0, 0, 0, .1);\n\n    .no-touch &:hover {\n        background: #222;\n        box-shadow: 0 1px 3px rgba(0, 0, 0, .5);\n    }\n}\n\n.dg-popup__rating {\n    .repeatableBg('DGPopup__ratingStarOff_dark');\n}\n\n.dg-popup__link_type_photos:before {\n    .notRepeatableBgWithSizes('DGPopup__photoIcon_dark');\n}\n\n.dg-popup__button_name_firm-card-back:before {\n    .notRepeatableBg('DGPopup__backIcon_dark');\n}\n\n.dg-popup__button_name_firm-list-back:before {\n    .notRepeatableBg('DGPopup__backIcon_dark');\n}\n\n.dg-popup__button_name_back:before {\n    .notRepeatableBgWithSizes('DGPopup__backIcon_dark');\n}\n\n.dg-popup__button_name_goto:before {\n    .notRepeatableBgWithSizes('DGPopup__pathIcon_dark');\n}\n\n.dg-popup__button_name_show-entrance:before {\n    .notRepeatableBg('DGPopup__entranceIcon_dark');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-schedule.ie.less",
    "content": ".dg-schedule__tc_active_true {\n    .gradient(rgba(255, 255, 255, .4), rgba(255, 255, 255, .4));\n}\n\n.dg-schedule__tc_active_true > .dg-schedule__day-name {\n    color: #e6e6e6;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/dark/less/dg-schedule.less",
    "content": ".dg-schedule__today {\n    background-image: linear-gradient(to right,\n    rgba(230, 230, 230, .55),\n    rgba(230, 230, 230, .55) 50%,\n    rgba(0, 0, 0, .0) 51%,\n    rgba(0, 0, 0, .0) 100%\n    );\n}\n\n.dg-schedule__now {\n    color: #aaa;\n}\n\n.dg-schedule__td {\n    color: #e6e6e6;\n}\n\n.dg-schedule__tc_active_true {\n    background: rgba(255, 255, 255, .1);\n}\n\n.dg-schedule__string-time {\n    color: #e6e6e6;\n}\n\n.dg-schedule__table-clock {\n    .notRepeatableBgWithSizes('DGSchedule__clockOff_dark');\n}\n\n.dg-schedule__table-lunch {\n    .notRepeatableBgWithSizes('DGSchedule__lunchIcon_dark');\n}\n\n.dg-schedule_open_false .dg-schedule__today:before {\n    .notRepeatableBgWithSizes('DGSchedule__clockOff_dark');\n}\n\n.dg-schedule__today:after {\n    .notRepeatableBgWithSizes('DGSchedule__expandIcon_dark');\n}\n\n.dg-schedule__today_shown_true:after {\n    .notRepeatableBgWithSizes('DGSchedule__collapseIcon_dark');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-building-callout.less",
    "content": ".dg-building-callout__list-item:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__bullet_light');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-firm-card.less",
    "content": ".dg-firm-card__link a {\n    background-image: linear-gradient(to right, rgba(0, 91, 143, .3), rgba(0, 91, 143, .3) 100%);\n    color: #005b8f;\n\n    .no-touch &:hover {\n        background-image: linear-gradient(to right, rgba(0, 0, 0, .3), rgba(0, 0, 0, .3) 100%);\n        color: #000;\n    }\n}\n\n.dg-firm-card__comment {\n    color: #666;\n}\n\n.dg-firm-card__rubrics {\n    color: #666;\n}\n\n.dg-firm-card__rubrics-list-item:after {\n    color: #666;\n}\n\n.dg-firm-card__address:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__marker_light');\n}\n\n.dg-firm-card__phone:before {\n    .notRepeatableBgWithSizes('DGFirmCard__phoneIcon_light');\n}\n\n.dg-firm-card__site:before {\n    .notRepeatableBgWithSizes('DGFirmCard__siteIcon_light');\n}\n\n.dg-firm-card__email:before {\n    .notRepeatableBgWithSizes('DGFirmCard__mailIcon_light');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-map-geoclicker.less",
    "content": ".dg-map-geoclicker__address-header:first-child:before,\n.dg-map-geoclicker__address-drilldown:first-child:before {\n    .notRepeatableBgWithSizes('DGBuildingCallout__marker_light');\n}\n\n.dg-map-geoclicker__purpose {\n    &:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purpose_light');\n    }\n\n    &_type_street:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeStreet_light');\n    }\n\n    &_type_sight:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeSight_light');\n    }\n\n    &_type_settlement:before {\n        .notRepeatableBgWithSizes('DGGeoclicker__purposeSettlement_light');\n    }\n}\n\na.dg-map-geoclicker__show-more-sights-link {\n    color: #005b8f;\n\n    .no-touch &:hover {\n        color: #000;\n    }\n\n    &:after {\n        .notRepeatableBg('DGGeoclicker__arrowLeft_light');\n    }\n}\n\n.dg-map-geoclicker__drilldown {\n    color: #666;\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-popup.less",
    "content": "a.dg-popup__link {\n    background-image: linear-gradient(to right, rgba(0, 91, 143, .3), rgba(0, 91, 143, .3) 100%);\n    color: #005b8f;\n\n    .no-touch &:hover {\n        background-image: linear-gradient(to right, rgba(0, 0, 0, .3), rgba(0, 0, 0, .3) 100%);\n        color: #000;\n    }\n}\n\n.dg-popup__footer-button-wrapper .dg-popup__footer-button {\n    color: #647882;\n\n    .no-touch &:hover {\n        color: #286482;\n    }\n}\n\n.dg-popup__footer-button {\n    border: 1px solid #e9edf2;\n    background: #f5faff;\n    box-shadow: 0 1px rgba(0, 0, 0, .1);\n\n    .no-touch &:hover {\n        background: #e7f3ff;\n    }\n}\n\n.dg-popup__rating {\n    .repeatableBg('DGPopup__ratingStarOff_light');\n}\n\n.dg-popup__link_type_photos:before {\n    .notRepeatableBgWithSizes('DGPopup__photoIcon_light');\n}\n\n.dg-popup__button_name_firm-card-back:before {\n    .notRepeatableBgWithSizes('DGPopup__backIcon_light');\n}\n\n.dg-popup__button_name_firm-list-back:before {\n    .notRepeatableBgWithSizes('DGPopup__backIcon_light');\n}\n\n.dg-popup__button_name_back:before {\n    .notRepeatableBgWithSizes('DGPopup__backIcon_light');\n}\n\n.dg-popup__button_name_goto:before {\n    .notRepeatableBg('DGPopup__pathIcon_light');\n}\n\n.dg-popup__button_name_show-entrance:before {\n    .notRepeatableBg('DGPopup__entranceIcon_light');\n}\n\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-schedule.ie.less",
    "content": ".dg-schedule__tc_active_true {\n    .gradient(rgba(230, 230, 230, .4), rgba(230, 230, 230, .4));\n}\n"
  },
  {
    "path": "src/DGGeoclicker/skin/light/less/dg-schedule.less",
    "content": ".dg-schedule__today {\n    background-image: linear-gradient(to right,\n    rgba(0, 0, 0, .55),\n    rgba(0, 0, 0, .55) 50%,\n    rgba(0, 0, 0, .0) 51%,\n    rgba(0, 0, 0, .0) 100%\n    );\n}\n\n.dg-schedule__now {\n    color: #666;\n}\n\n.dg-schedule__td {\n    color: #000;\n}\n\n.dg-schedule__tc_active_true {\n    background: rgba(0, 0, 0, .03);\n}\n\n.dg-schedule__string-time {\n    color: #666;\n}\n\n.dg-schedule__table-clock {\n    .notRepeatableBgWithSizes('DGSchedule__clockOff_light');\n}\n\n.dg-schedule__table-lunch {\n    .notRepeatableBgWithSizes('DGSchedule__lunchIcon_light');\n}\n\n.dg-schedule_open_false .dg-schedule__today:before {\n    .notRepeatableBgWithSizes('DGSchedule__clockOff_light');\n}\n\n.dg-schedule__today:after {\n    .notRepeatableBgWithSizes('DGSchedule__expandIcon_light');\n}\n\n.dg-schedule__today_shown_true:after {\n    .notRepeatableBgWithSizes('DGSchedule__collapseIcon_light');\n}\n"
  },
  {
    "path": "src/DGGeoclicker/src/ClampHelper.js",
    "content": "DG.Geoclicker.clampHelper = function(el, lineClamp) {\n    var measure, text, lineWidth,\n        lineStart, lineCount, wordStart,\n        line, lineText, wasNewLine,\n        ce = document.createElement.bind(document),\n        ctn = document.createTextNode.bind(document);\n\n    // measurement element is made a child of the clamped element to get it's style\n    measure = ce('span');\n\n    (function(s) {\n        s.position = 'absolute'; // prevent page reflow\n        s.whiteSpace = 'pre'; // cross-browser width results\n        s.visibility = 'hidden'; // prevent drawing\n        s.margin = '0 18px 8px 0';\n    })(measure.style);\n\n    // make sure the element belongs to the document\n    if (!el.ownerDocument || el.ownerDocument !== document) {\n        return;\n    }\n    // reset to safe starting values\n    lineStart = wordStart = 0;\n    lineCount = 1;\n    wasNewLine = false;\n    lineWidth = el.clientWidth;\n    // get all the text, remove any line changes\n    text = (el.textContent || el.innerText).replace(/\\n/g, ' ');\n    // remove all content\n    while (el.firstChild !== null) {\n        el.removeChild(el.firstChild);\n    }\n    // add measurement element within so it inherits styles\n    el.appendChild(measure);\n    // http://ejohn.org/blog/search-and-dont-replace/\n    text.replace(/ |-/g, function(m, pos) {\n        // ignore any further processing if we have total lines\n        if (lineCount === lineClamp) {\n            return;\n        }\n        // create a text node and place it in the measurement element\n        measure.appendChild(ctn(text.substr(lineStart, pos - lineStart)));\n        // have we exceeded allowed line width?\n        if (lineWidth < measure.clientWidth) {\n            if (wasNewLine) {\n                // we have a long word so it gets a line of it's own\n                lineText = text.substr(lineStart, pos + 1 - lineStart);\n                // next line start position\n                lineStart = pos + 1;\n            } else {\n                // grab the text until this word\n                lineText = text.substr(lineStart, wordStart - lineStart);\n                // next line start position\n                lineStart = wordStart;\n            }\n            // create a line element\n            line = ce('span');\n            // add text to the line element\n            line.appendChild(ctn(lineText));\n            // add the line element to the container\n            el.appendChild(line);\n            line.className = 'dg-map-geoclicker__clamped-line';\n            // yes, we created a new line\n            wasNewLine = true;\n            lineCount++;\n        } else {\n            // did not create a new line\n            wasNewLine = false;\n        }\n        // remember last word start position\n        wordStart = pos + 1;\n        // clear measurement element\n        measure.removeChild(measure.firstChild);\n    });\n    // remove the measurement element from the container\n    el.removeChild(measure);\n    // create the last line element\n    line = ce('span');\n    // give styles required for text-overflow to kick in\n    line.className = 'dg-map-geoclicker__clamped-line dg-map-geoclicker__clamped-line_last';\n    // add all remaining text to the line element\n    line.appendChild(ctn(text.substr(lineStart)));\n    // add the line element to the container\n    el.appendChild(line);\n};\n"
  },
  {
    "path": "src/DGGeoclicker/src/Controller.js",
    "content": "DG.Geoclicker.Controller = DG.Class.extend({\n\n    options: {\n        // if handler worked successfully, it should return rendering object that will be processed in View , otherwise it should return false\n        // default handler always should return rendering object\n        'handlersSequence': {\n            'poi': DG.Geoclicker.Handler.Poi,\n            'attraction': DG.Geoclicker.Handler.Sight,\n            'building': DG.Geoclicker.Handler.House,\n            'street': DG.Geoclicker.Handler.CityArea,\n            'adm_div.place': DG.Geoclicker.Handler.CityArea,\n            'adm_div.district': DG.Geoclicker.Handler.CityArea,\n            'adm_div.division': DG.Geoclicker.Handler.CityArea,\n            'adm_div.settlement': DG.Geoclicker.Handler.CityArea,\n            'adm_div.city': DG.Geoclicker.Handler.CityArea,\n\n            'default': DG.Geoclicker.Handler.Default,\n\n            'apiError': DG.Geoclicker.Handler.ApiError\n\n            // station_platform\n            // project\n            // station\n            // crossbroad\n            // metro\n        }\n    },\n\n    initialize: function(map, options) { // (Object, Object)\n        this._options = options;\n        this._handlers = {};\n        this._catalogApi = new DG.Geoclicker.Provider.CatalogApi(map);\n        this._map = map;\n        this._view = new DG.Geoclicker.View(map);\n\n        this._renderHandlerResult = DG.bind(this._renderHandlerResult, this);\n        this._lastHandleClickArguments = null;\n        this._hasCatalogKey = false;\n    },\n\n    handlePopupClose: function(popup) { // (Object)\n        if (popup === this._view.getPopup()) {\n            this._lastHandleClickArguments = null;\n            this._catalogApi.cancelLastRequest();\n        }\n    },\n\n    handleClick: function(latlng, zoom, meta) { // (Object, Number, Object)\n        var self = this,\n            args = Array.prototype.slice.call(arguments, 0);\n\n        function initShowPopup() {\n            var loader = self._view.initLoader();\n            self._view._popup.clear();\n            self._view.showPopup(latlng, loader);\n            self._lastHandleClickArguments = args;\n        }\n\n        if (meta && meta.linked && meta.linked.type != 'sight' && meta.linked.type != 'attraction') {\n            if (meta.linked.type != 'branch' && meta.linked.type != 'building') {\n                return;\n            }\n\n            initShowPopup();\n            self.handleResponse({\n                poi: {\n                    reference: meta.linked\n                }\n            });\n        } else {\n            this._catalogApi.getLocations({\n                latlng: latlng,\n                zoom: zoom,\n                beforeRequest: initShowPopup,\n                hasCatalogKey: this._hasCatalogKey,\n            }).then(function(result) {\n                if (!result['meta'] || result['meta']['code'] !== 403) {\n                    initShowPopup();\n                    self._hasCatalogKey = true;\n                }\n\n                self.handleResponse(result);\n            }, function(error) {\n                self.handleResponse(error);\n            });\n        }\n    },\n\n    handleResponse: function(result) { // (Object)\n        var type;\n\n        if (!result) {\n            this._runHandler('default');\n            return;\n        }\n\n        if (result === 'no type') {\n            return;\n        }\n\n        if (result === 'aborted') {\n            this._runHandler('apiError');\n            return;\n        }\n\n        type = this.findHandler(result);\n\n        while (type) {\n            if (this._runHandler(type, result)) {\n                return;\n            }\n            delete result[type];\n\n            type = this.findHandler(result);\n        }\n        this._runHandler('default');\n    },\n\n    findHandler: function(result) { // (Object) -> String|Null\n        for (var i in this.options.handlersSequence) {\n            if (result[i]) {\n                return i;\n            }\n        }\n\n        return null;\n    },\n\n    getCatalogApi: function() { // () -> Object\n        return this._catalogApi;\n    },\n\n    getMap: function() {\n        return this._map;\n    },\n\n    reinvokeHandler: function() {\n        if (this._lastHandleClickArguments) {\n            this.handleClick.apply(this, this._lastHandleClickArguments);\n        }\n    },\n\n    _runHandler: function(type, data) { // (String, Object) -> Boolean\n        data = data || {};\n        this._initHandlerOnce(type);\n        this._handlers[type].addClickEvent();\n\n        var handlerResult = this._handlers[type].handle(data, type);\n\n        return handlerResult && handlerResult.then ?\n            handlerResult.then(this._renderHandlerResult) :\n            handlerResult;\n    },\n\n    _renderHandlerResult: function(result) {\n        this._view.renderPopup(result);\n    },\n\n    _initHandlerOnce: function(type) { // (String)\n        if (!this._handlers[type]) {\n            this._handlers[type] = new this.options.handlersSequence[type](this, this._view, this._map, this._options);\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/DGGeoclicker.js",
    "content": "DG.Map.mergeOptions({\n    geoclicker: false\n});\n\nDG.Geoclicker = DG.Handler.extend({\n    clickCount: 0,\n    pendingClick: 0,\n    timeout: 250, // should be equal to 'delay' value in DoubleTap event\n\n    initialize: function(map, options) { // (Object)\n        this._map = map;\n        this._controller = new DG.Geoclicker.Controller(map, options);\n    },\n\n    addHooks: function() {\n        this._toggleEvents(true);\n\n        this._map\n            .on('rulerstart', this._pause, this)\n            .on('rulerend', this._unpause, this);\n    },\n\n    removeHooks: function() {\n        this._toggleEvents();\n\n        this._map\n            .off('rulerstart', this._pause, this)\n            .off('rulerend', this._unpause, this);\n    },\n\n    _checkOpenPopup: function() {\n        if (DG.Browser.mobile && this._map._popup &&\n            (this._map._popup.options.closeOnClick ||\n            this._map.options.closePopupOnClick)) {\n            this.popupWasOpen = true;\n        }\n    },\n\n    _pause: function() {\n        this._toggleEvents();\n    },\n\n    _unpause: function() {\n        // Reenable event handling only in case geoclicker is enabled\n        if (this.enabled()) {\n            this._toggleEvents(true);\n        }\n    },\n\n    _toggleEvents: function(flag) {\n        this._map[flag ? 'on' : 'off'](this._mapEventsListeners, this);\n        if (this._map.poi) {\n            this._map.poi.getMetaLayer()[flag ? 'on' : 'off']('click', this._onMetaClick, this);\n        }\n    },\n\n    getController: function() {\n        return this._controller;\n    },\n\n    _onMetaClick: function(e) {\n        this.clickCount = 0;\n        clearTimeout(this.pendingClick);\n        this.popupWasOpen = false;\n\n        this._mapEventsListeners.click.call(this, e);\n    },\n\n    _mapEventsListeners: {\n        langchange: function() {\n            this._controller.reinvokeHandler();\n        },\n\n        popupclose: function(e) { // (Object)\n            this._controller.handlePopupClose(e.popup);\n        },\n\n        click: function(e) { // (Object)\n            if (this.clickCount === 0) {\n                this.clickCount = 1;\n                this._singleClick(e);\n            } else {\n                this.clickCount = 0;\n                clearTimeout(this.pendingClick);\n                this.popupWasOpen = false;\n            }\n        },\n\n        dblclick: function() {\n            if (DG.Browser.ielt9) {\n                this.clickCount = 0;\n                this.popupWasOpen = false;\n                clearTimeout(this.pendingClick);\n            }\n        }\n    },\n\n    _singleClick: function(e) { // (Object)\n        var self = this;\n\n        clearTimeout(this.pendingClick);\n\n        this.pendingClick = setTimeout(function() {\n            if (e.meta) {\n                self._checkOpenPopup();\n                self._map.closePopup();\n            }\n\n            //  DGPopup's '_close' method is the only place where .popupWasOpen is modified\n            //  It signals geoclicker that popup was open before user do a 'click' on map\n            //  Multistage behavior is needed as this processing occurs after popup was already closed\n            if (!self.popupWasOpen) {\n                var zoom = self._map.getZoom();\n                self._controller.handleClick(e.latlng, zoom, e.meta);\n            }\n\n            self.clickCount = 0;\n            self.popupWasOpen = false;\n        }, this.timeout);\n    }\n});\n\nDG.Map.addInitHook('addHandler', 'geoclicker', DG.Geoclicker);\n"
  },
  {
    "path": "src/DGGeoclicker/src/View.js",
    "content": "DG.Geoclicker.View = DG.Class.extend({\n\n    initialize: function(map, options) { // (Object, Object)\n        this._map = map;\n        this._popup = DG.popup({\n            maxHeight: 300,\n            minHeight: 50,\n            maxWidth: 385,\n            minWidth: 310,\n            sprawling: true,\n            closeOnClick: true\n        });\n\n        if (options) {\n            DG.Util.setOptions(this, options);\n        }\n    },\n\n    initLoader: function(isSmall) {\n        var loader = document.createElement('div');\n        loader.innerHTML = DG.dust('DGGeoclicker/loader', {\n            small: isSmall,\n            anim: this._detectCssAnimation()\n        });\n\n        return loader.firstChild;\n    },\n\n    showPopup: function(latlng, content) { // (Object)\n        this._popup\n            .setContent(content)\n            .setLatLng(latlng)\n            .openOn(this._map);\n    },\n\n    render: function(options) { // (Object) -> String\n        var html,\n            data = {};\n\n        options = options || {};\n        options.tmpl = options.tmpl || '';\n\n        if (options.data) {\n            html = this.renderTemplate(options.tmpl, options.data);\n        } else {\n            html = options.tmpl;\n        }\n\n        if (options.beforeRender) {\n            options.beforeRender();\n        }\n\n        if (options.popup) {\n            if (options.header) {\n                data.header = options.header;\n            }\n            if (options.footer) {\n                data.footer = options.footer;\n            }\n            data.body = html;\n            this._popup.setContent(data);\n        }\n        if (options.afterRender) {\n            options.afterRender();\n        }\n\n        return html;\n    },\n\n    renderTemplate: function(name, data) {\n        return DG.dust('DGGeoclicker/' + name, data);\n    },\n\n    renderPopup: function(options) { // (Object) -> String\n        options.popup = true;\n        return this.render(options);\n    },\n\n    getPopup: function() { // () -> Object\n        return this._popup;\n    },\n\n    _detectCssAnimation: function() {\n        var animation = false,\n            domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),\n            elm = document.createElement('div');\n\n        if (elm.style.animationName) { animation = true; }\n\n        if (animation === false) {\n            for (var i = 0; i < domPrefixes.length; i++) {\n                if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) {\n                    animation = true;\n                    break;\n                }\n            }\n        }\n        return animation;\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/ApiError.js",
    "content": "DG.Geoclicker.Handler.ApiError = DG.Geoclicker.Handler.Default.extend({\n    handle: function() { // () -> Promise\n        var header = this._view.render({\n            tmpl: 'popupHeader',\n            data: {\n                title: this.t('apiErrorTitle')\n            }\n        });\n\n        return Promise.resolve({\n            header: header,\n            tmpl: this.t('apiErrorBody')\n        });\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/CityArea.js",
    "content": "DG.Geoclicker.Handler.CityArea = DG.Geoclicker.Handler.Default.extend({\n\n    _polylineStyleDefault : {\n        fillColor: '#ff9387',\n        color: '#ff9387',\n        noClip: true,\n        opacity: 1\n    },\n\n    _polylineStyles : {\n        11 : {\n            fillOpacity: 0.18,\n            weight: 1\n        },\n        12 : {\n            fillOpacity: 0.12,\n            weight: 1\n        },\n        13 : {\n            fillOpacity: 0.08,\n            weight: 2\n        },\n        18 : {\n            fillOpacity: 0,\n            weight: 3\n        }\n    },\n\n    handle: function(results, type) { // (Object, String) -> Promise\n        if (!results[type]) {\n            return false;\n        }\n\n        if (!this._stylesInited) {\n            this._initStyles();\n        }\n\n        // remove previous geometry see https://github.com/2gis/mapsapi/issues/213\n        if (this._geometry) {\n            this._map.removeLayer(this._geometry);\n        }\n\n        this._popup = this._view.getPopup();\n\n        this._geometryZoomStyle = this._getPolyStyleNum();\n        this._geometry = DG.Wkt.geoJsonLayer(results[type].geometry.selection, {\n            style: this._polylineStyles[this._geometryZoomStyle],\n            interactive: false\n        }).addTo(this._map);\n\n        this._map\n            .on('zoomend', this._updateGeometry, this)\n            .once('popupclose', this._clearPopup, this);\n\n        return Promise.resolve(this._fillCityAreaObject(results, type));\n    },\n\n    _fillCityAreaObject: function(results, type) {\n        var data = {\n            name: this.t('noname'),\n            drilldown: '',\n            purpose: this.t(type),\n            type: type.split('.').join('_')\n        };\n\n        data.drilldown = this._getDrilldown(results[type]);\n\n        if (results[type].name) {\n            data.name = results[type].name;\n        }\n\n        return {\n            tmpl: 'cityarea',\n            data: data,\n            header: this._view.render({\n                tmpl: 'popupHeader',\n                data: {'title': data.name}\n            })\n        };\n    },\n\n    _initStyles : function() {\n        this._stylesInited = true;\n\n        Object.keys(this._polylineStyles).forEach(function(zoom) {\n            DG.extend(this._polylineStyles[zoom], this._polylineStyleDefault);\n        }, this);\n    },\n\n    _getPolyStyleNum: function() {\n        var mapZoom = this._map.getZoom();\n\n        return Object.keys(this._polylineStyles).filter(function(zoom) {\n            return mapZoom <= zoom;\n        })[0] || false;\n    },\n\n    _updateGeometry: function() {\n        var newStyle = this._getPolyStyleNum();\n\n        if (newStyle && newStyle !== this._geometryZoomStyle) {\n            this._geometryZoomStyle = newStyle;\n            this._geometry.setStyle(this._polylineStyles[newStyle]);\n        }\n    },\n\n    _clearPopup: function() {\n        this._map\n            .removeLayer(this._geometry)\n            .off('zoomend', this._updateGeometry, this);\n    }\n\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/Default.js",
    "content": "DG.Geoclicker.Handler.Default = DG.Class.extend({\n\n    includes: DG.Locale,\n\n    statics: {\n        Dictionary: {}\n    },\n\n    _eventHandlers: {},\n\n    initialize: function(controller, view, map) { // (Object, Object, Object)\n        this._controller = controller;\n        this._view = view;\n        this._map = map;\n    },\n\n    handle: function() { // () -> Promise\n        return Promise.resolve({\n            tmpl: 'popupHeader',\n            data: {'title': this.t('we_have_not')}\n        });\n    },\n\n    addClickEvent: function() {\n        this._view._popup.on('click', this._runEventHandlers, this);\n        this._map.once('popupclose', this._removeClickEvent, this);\n    },\n\n    _removeClickEvent: function() {\n        this._view._popup.off('click', this._runEventHandlers, this);\n    },\n\n    _addEventHandler: function(el, handler) { // (String, Function)\n        this._eventHandlers[el] = handler;\n    },\n\n    _runEventHandlers: function(e) {\n        var target = e.originalEvent.target;\n\n        for (var eventClass in this._eventHandlers) {\n            if (this._eventHandlers.hasOwnProperty(eventClass) && target.className.indexOf(eventClass) > -1) {\n                DG.DomEvent.preventDefault(e.originalEvent);\n                this._eventHandlers[eventClass].call(this, target);\n                return;\n            }\n        }\n    },\n\n    _clearEventHandlers: function() {\n        this._eventHandlers = {};\n    },\n\n    _getDirectionsUrl: function(name) {\n        var project = this._map.projectDetector.getProject();\n        if (!project) {\n            return '';\n        }\n\n        return DG.Util.template(DG.config.ppnotLink, {\n            'domain': project.domain,\n            'projectCode': project.code,\n            'center': this._map.getCenter().lng + ',' + this._map.getCenter().lat,\n            'zoom': this._map.getZoom(),\n            'name': encodeURIComponent(name),\n            'rsType': project.transport ? 'bus' : 'car',\n            'point': this._popup._latlng.lng + ',' + this._popup._latlng.lat\n        });\n    },\n\n    _getDrilldown: function(object) {\n        var admDivs = [],\n            result;\n\n        if (object.adm_div) {\n            admDivs = object.adm_div\n                .reduce(function(admDivs, admDiv) {\n                    if (admDiv.name) {\n                        admDivs.push(admDiv.name);\n                    }\n\n                    return admDivs;\n                }, [])\n                .reverse();\n        }\n\n        if (admDivs.length && object.address && object.address.postcode) {\n            admDivs.push(object.address.postcode);\n        }\n\n        result = admDivs.join(', ');\n\n        return result;\n    }\n\n});\n\n\nDG.Geoclicker.Handler.HandlerExample = DG.Geoclicker.Handler.Default.extend({\n\n    handle: function(results, type) { // (Object, String) -> Promise\n        return Promise.resolve({\n            tmpl: type + ':<br/>' + results[type].id\n        });\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/Handler.js",
    "content": "DG.Geoclicker.Handler = {};\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/House.View.js",
    "content": "DG.Geoclicker.Handler.House.include({\n    _getAddressString: function(house) {\n        if (!house.address || !house.address.components) {\n            return '';\n        }\n\n        return house.address.components\n            .filter(function(component) {\n                return component.type === 'street_number';\n            })\n            .map(function(component) {\n                return component.street + ', ' + component.number;\n            })\n            .join(' / ');\n    },\n\n    _fillBody: function(house) { // // (Object) -> (DOMElement)\n        var data = {},\n            wrapper = DG.DomUtil.create('div', 'dg-building-callout__body'),\n            filials = house.links && house.links.branches;\n\n        var drilldown = this._getDrilldown(house);\n\n        if (house.building_name) {\n            data.address = {\n                header: this._getAddressString(house),\n                drilldown: drilldown\n            };\n        } else if (drilldown) {\n            data.address = {\n                drilldown: drilldown\n            };\n        }\n\n        data.purpose = house.purpose_name +\n            (house.floors ? ', ' + this.t('n_floors', house.floors.ground_count) : '');\n\n        if (filials && filials.count > 0) {\n            this._totalPages = Math.ceil(house.links.branches.count / this._firmsOnPage);\n        }\n\n        if (house.links && house.links.attractions && house.links.attractions.length) {\n            data.attractions = house.links.attractions.reduce(function(attractions, attraction) {\n                if (attraction.name) {\n                    attractions.push(attraction.name);\n                }\n\n                return attractions;\n            }, []);\n        }\n\n        wrapper.innerHTML = this._view.render({\n            tmpl: 'house',\n            data: data\n        });\n\n        if (filials && filials.items) {\n            wrapper.appendChild(this._initShortFirmList(filials.items));\n        }\n\n        return wrapper;\n    },\n\n    _fillHeader: function(house) { // (Object) -> (HTMLString)\n        var header = {};\n\n        if (house.building_name) {\n            header.title = house.building_name;\n        } else if (house.address && house.address.components) {\n            header.title = this._getAddressString(house);\n        } else {\n            header.title = house.purpose_name;\n        }\n\n        this._header = this._view.render({\n            tmpl: 'popupHeader',\n            data: header\n        });\n\n        return this._header;\n    },\n\n    _fillFooter: function(house) { // (Object) -> (HTMLString)\n        var btns = [];\n        var houseFilials = house.links && house.links.branches;\n        var filialsItemsCount = houseFilials &&\n        houseFilials.items &&\n        houseFilials.items.length || 0;\n\n        // Decide if we need to display 'more organisations' button\n        if (\n            houseFilials &&\n            houseFilials.count > filialsItemsCount\n        ) {\n            btns.push(this._getShowAllData(houseFilials.count));\n        }\n\n        if (this._isRouteSearchAllowed()) {\n            btns.push({\n                name: 'goto',\n                label: this.t('go_to'),\n                icon: true,\n                href: this._directionsUrl\n            });\n        }\n\n        return this._view.render({\n            tmpl: 'popupFooterBtns',\n            data: {'btns': btns}\n        });\n    },\n\n    _getShowAllData: function(filialsCount) {\n        return {\n            name: 'all',\n            label: this.t('show_organization_in_building', filialsCount)\n        };\n    },\n\n    _fillHouseObject: function(house) { // (Object) -> (Object)\n        var self = this;\n\n        return {\n            header: this._fillHeader(house),\n            tmpl: this._fillBody(house),\n            footer: this._fillFooter(house),\n            afterRender: function() {\n                self._initShowMore();\n                self._initPopupClose();\n            }\n        };\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/House.js",
    "content": "/*global FirmCard */\nDG.Geoclicker.Handler.House = DG.Geoclicker.Handler.Default.extend({\n\n    _firmsOnPage: 20,\n    _scrollThrottleInterval: 400,\n    _scrollHeightReserve: 60,\n\n    options: {\n        'showBooklet': true,\n        'showPhotos': true,\n        'showRouteSearch': true\n    },\n\n    handle: function(results) { // (Object) -> Promise\n        if (!results.building) {\n            return false;\n        }\n\n        // initialization setup\n        this.firmCard = null;\n        this._page = 1;\n        this._houseObject = null;\n        this._firmList = null;\n        this._firmListObject = null;\n        this._firmCardObject = null;\n        this._onScroll = false;\n        this._isFirmlistOpen = false;\n\n        this._id = results.building.id;\n        this._totalPages = 1;\n        this._api = this._controller.getCatalogApi();\n        this._popup = this._view.getPopup();\n        this._initedPopupClose = false;\n        this._directionsUrl = this._getDirectionsUrl(results.building.name);\n        this._firmListLoader = this._view.initLoader(true);\n\n        this._houseObject = this._fillHouseObject(results.building);\n\n        return Promise.resolve(this._houseObject);\n    },\n\n    _isRouteSearchAllowed: function() { //() -> Boolean\n        var project = this._controller.getMap().projectDetector.getProject();\n        return project.transport || project.roads;\n    },\n\n    _firmCardSetup: function() { //() -> Object\n        var project = this._controller.getMap().projectDetector.getProject();\n        return {\n            render: this._view.renderTemplate,\n            lang: this._map.getLang(),\n            domain: project ? project.domain : 'ru',\n            ajax: DG.bind(this._api.getFirmInfo, this._api),\n            timezoneOffset: project ? project.timeOffset : 0,\n            map: this._map,\n            popup: this._popup,\n            isMobile: DG.Browser.mobile,\n            showEntrance: DG.Entrance,\n            gotoUrl: this._directionsUrl,\n            onFirmReady: DG.bind(this._onFirmReady, this),\n            onToggle: DG.bind(this._popup.resize, this._popup),\n            showBooklet: this.options.showBooklet,\n            showPhotos: this.options.showPhotos,\n            showRouteSearch: this.options.showRouteSearch && this._isRouteSearchAllowed(),\n            t: DG.bind(this.t, this)\n        };\n    },\n\n    // init single firm card in case of poi\n    _fillFirmCardObject: function(firmId) {\n        var options = this._firmCardSetup();\n\n        this.firmCard = new FirmCard(firmId, options);\n        this._initPopupClose();\n        return this.firmCard.getContainer();\n    },\n\n    _firmListSetup: function() {\n        var options = this._firmCardSetup();\n\n        DG.extend(options, {\n            backBtn: DG.bind(this._showHousePopup, this),\n            onFirmClick: DG.bind(this._onFirmListClick, this),\n            onShowLess: DG.bind(this._showHousePopup, this),\n            pasteLoader: DG.bind(this._pasteLoader, this)\n        });\n\n        return {\n            firmCard: options,\n            firmlistItemTmpl: 'firmlistItem',\n            onListReady: DG.bind(this._renderFirmList, this)\n        };\n    },\n\n    _initShortFirmList: function(firms) { //(Object) -> DOMElement\n        var options = this._firmListSetup();\n\n        this._shortFirmList = new FirmCard.List(firms, options);\n\n        return this._shortFirmList.renderList();\n    },\n\n    _initFirmList: function(res) { //(Object) -> Promise\n        if (!res) { return false; }\n\n        var results = res.result.items,\n            options = this._firmListSetup();\n\n        options.firmCard.backBtn = DG.bind(this._showListPopup, this);\n\n        if (this._shortFirmList) {\n            this._shortFirmList._toggleEventHandlers(true);\n        }\n\n        this._firmList = new FirmCard.List(results, options);\n\n        this._firmListObject = this._fillFirmListObject(this._firmList.renderList());\n        this._clearAndRenderPopup(this._firmListObject);\n    },\n\n    _fillFirmListObject: function(firmList) { //(DOMElement) -> Object\n        var self = this;\n\n        return {\n            tmpl: firmList,\n            header: this._header,\n            footer: this._view.render({\n                tmpl: 'popupFooterBtns',\n                data: {\n                    btns: [\n                        {\n                            name: 'back',\n                            label: this.t('back_button'),\n                            icon: true\n                        }\n                    ]\n                }\n            }),\n            afterRender: function() {\n                self._initPopupClose();\n\n                if (self._totalPages > 1 && self._firmListLoader) {\n                    // \"this\" here is self._firmListObject\n                    this.tmpl.parentNode.appendChild(self._firmListLoader);\n                }\n            }\n        };\n    },\n\n    _onFirmReady: function(firmContentObject) {\n        var self = this;\n        firmContentObject.afterRender = function() {\n            var headerTitle = self._popup._popupStructure.header.firstChild;\n            if (!DG.Browser.ielt9) {\n                if (headerTitle.offsetHeight > 72) { //TODO: magic number\n                    DG.DomUtil.addClass(headerTitle, 'dg-popup__header-teaser');\n                    if (!DG.Browser.webkit) {\n                        DG.Geoclicker.clampHelper(headerTitle, 3);\n                    }\n                }\n            }\n        };\n        this._clearAndRenderPopup(firmContentObject);\n    },\n\n    _showHousePopup: function() {\n        this._popup.off('scroll', this._onScroll);\n        this._clearAndRenderPopup(this._houseObject);\n        if (this._shortFirmList) {\n            this._shortFirmList._toggleEventHandlers();\n        }\n    },\n\n    _onFirmListClick: function() {\n        this._popup.off('scroll', this._onScroll);\n    },\n\n    _pasteLoader: function() {\n        var loaderWrapper  = DG.DomUtil.create('div', 'dg-map-geoclicker__preloader-wrapper'),\n            loader = this._view.initLoader();\n\n        loaderWrapper.insertBefore(loader, loaderWrapper.firstChild);\n        loaderWrapper.style.height = this._popup._contentNode.offsetHeight - 1 + 'px'; // MAGIC\n        loaderWrapper.style.width = this._popup._contentNode.offsetWidth + 'px';\n        this._clearAndRenderPopup({tmpl: loaderWrapper});\n    },\n\n    _initPopupClose: function() {\n        if (this._initedPopupClose) { return; }\n\n        this._controller.getMap().once('popupclose', DG.bind(this._onPopupClose, this));\n        this._initedPopupClose = true;\n    },\n\n    _showListPopup: function() {\n        var firmList = this._firmListObject;\n\n        this._pasteLoader();\n\n        if (!firmList) {\n            firmList = this._api.firmsInHouse(this._id).then(DG.bind(this._initFirmList, this));\n        } else {\n            this._clearAndRenderPopup(firmList);\n            this._firmList._toggleEventHandlers();\n        }\n\n        if (!this._onScroll) {\n            this._onScroll = DG.Util.throttle(this._handlePopupScroll, this._scrollThrottleInterval, this);\n        }\n\n        this._popup.on('scroll', this._onScroll);\n    },\n\n    _renderFirmList: function() {\n        if (!this._isFirmlistOpen) {\n            this._popup.resize();\n            this._isFirmlistOpen = true;\n        }\n    },\n\n    _onPopupClose: function() {\n        this._initedPopupClose = false;\n        if (this._firmList) {\n            this._firmList.clearList();\n            this._firmList = null;\n            this._popup.off('scroll', this._onScroll);\n        }\n        this._firmId = null;\n        if (this.firmCard) {\n            this.firmCard._toggleEventHandlers(true);\n            this.firmCard = null;\n        }\n        this._firmListLoader = null;\n        this._page = 1;\n        this._clearEventHandlers();\n    },\n\n    _initShowMore: function() {\n        var link = this._popup.findElement('.dg-popup__button_name_all');\n\n        if (link) {\n            this._addEventHandler('dg-popup__button_name_all', DG.bind(this._showListPopup, this));\n        }\n    },\n\n    _clearAndRenderPopup: function(popupObject) {\n        this._clearEventHandlers();\n        this._popup.clear('header', 'footer');\n        this._view.renderPopup(popupObject);\n    },\n\n    _appendFirmList: function(res) { // (Object)\n        this._firmList.addFirms(res.result.items);\n        this._popup._updateScrollPosition();\n    },\n\n    _handlePopupScroll: function(e) {\n        var scroller = e.originalEvent.target || e.target._scroller;\n\n        DG.DomEvent.stop(e);\n\n        if (this._totalPages <= 1) { return; }\n        if (scroller && scroller.scrollHeight <= scroller.scrollTop + scroller.offsetHeight + this._scrollHeightReserve) {\n            this._handlePaging();\n        }\n    },\n\n    _handlePaging: function() {\n        this._page++;\n\n        if (this._totalPages && this._page <= this._totalPages) {\n            this._api.firmsInHouse(this._id, {page: this._page}).then(DG.bind(this._appendFirmList, this));\n        }\n\n        if (this._page === this._totalPages) {\n            var loader = this._firmListLoader;\n\n            if (loader && loader.parentNode) {\n                loader.parentNode.removeChild(loader);\n            }\n\n            this._popup.off('scroll', this._onScroll);\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/POI.js",
    "content": "DG.Geoclicker.Handler.Poi = DG.Geoclicker.Handler.House.extend({\n\n    handle: function(results) { // (Object) -> Promise\n        if (!results.poi) {\n            return false;\n        }\n\n        // initialization setup\n        this.firmCard = null;\n        this._page = 1;\n        this._houseObject = null;\n        this._firmList = null;\n        this._firmListObject = null;\n        this._firmCardObject = null;\n        this._onScroll = false;\n        this._isFirmlistOpen = false;\n\n        this._id = results.poi.reference.id;\n        this._totalPages = 1;\n        this._api = this._controller.getCatalogApi();\n        this._popup = this._view.getPopup();\n        this._initedPopupClose = false;\n        this._directionsUrl = this._getDirectionsUrl(results.poi.reference.name);\n        this._firmListLoader = this._view.initLoader(true);\n\n        // If the POI refers to a building (e.g. galleries in Santiago),\n        // show a building callout\n        if (results.poi.reference.type === 'building') {\n            var self = this;\n\n            return self._api.geoGet(results.poi.reference.id)\n                .then(function(result) {\n                    self._houseObject = self._fillHouseObject(result.result.items[0]);\n                    return Promise.resolve(self._houseObject);\n                });\n        }\n\n        // Otherwise, show a firm callout\n        if (results.poi.reference.type === 'branch') {\n            this._fillFirmCardObject(results.poi.reference.id);\n            return true;\n        }\n\n        return false;\n    }\n\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/handler/Sight.js",
    "content": "DG.Geoclicker.Handler.Sight = DG.Geoclicker.Handler.Default.extend({\n\n    handle: function(results) { // (Object, String) -> Promise\n        if (!results.attraction) {\n            return false;\n        }\n\n        this._popup = this._view.getPopup();\n        this._initedPopupClose = false;\n\n        return Promise.resolve(this._fillSightObject(results));\n    },\n\n    _fillSightObject: function(results) { // (Object) -> Object\n        var attraction = results.attraction,\n            data = {},\n            self = this,\n            footer = {\n                btns: [\n                    {\n                        name: 'goto',\n                        label: this.t('go_to'),\n                        icon: true\n                    }\n                ]\n            };\n\n        if (attraction.name) {\n            data.buildingName = attraction.name;\n            data.purpose = attraction.subtype_name;\n        } else {\n            data.buildingName = attraction.subtype_name;\n        }\n\n        data.description = attraction.description;\n\n        data.drillDown = this._getDrilldown(attraction);\n\n        if (this._checkDescFieldHeight(data.description)) {\n            data.showMoreText = this.t('show_more_about_sight');\n        }\n\n        footer.btns[0].href = this._getDirectionsUrl(data.buildingName);\n\n        return {\n            tmpl: 'sight',\n            data: data,\n            header: this._view.render({\n                tmpl: 'popupHeader',\n                data: {'title': data.buildingName}\n            }),\n            footer: this._view.render({\n                tmpl: 'popupFooterBtns',\n                data: footer\n            }),\n            afterRender: function() {\n                if (self._needShowMore) {\n                    self._initShowMore();\n                }\n                self._initPopupClose();\n            }\n        };\n    },\n\n    _initPopupClose: function() {\n        if (this._initedPopupClose) {\n            return;\n        }\n\n        this._controller.getMap().once('popupclose', DG.bind(this._clearPopup, this));\n        this._initedPopupClose = true;\n    },\n\n    _clearPopup: function() {\n        this._initedPopupClose = false;\n        this._clearEventHandlers();\n    },\n\n    _showMoreText: function() {\n        this._desc.style.maxHeight = '100%';\n        this._link.parentNode.removeChild(this._link);\n        this._popup.resize();\n    },\n\n    _initShowMore: function() {\n        this._link = this._popup.findElement('.dg-map-geoclicker__show-more-sights-link');\n        this._desc = this._popup.findElement('.dg-map-geoclicker__sight-description');\n\n        if (this._link && this._desc) {\n            this._addEventHandler('dg-map-geoclicker__show-more-sights-link', DG.bind(this._showMoreText, this));\n        }\n    },\n\n    _checkDescFieldHeight: function(desc) {\n        var el = DG.DomUtil.create('div', ''),\n            height;\n\n        el.style.visibility = 'hidden';\n        el.innerHTML = desc;\n\n        this._popup._contentNode.appendChild(el);\n        height = el.offsetHeight;\n        this._popup._contentNode.removeChild(el);\n        this._needShowMore = (height > 40);\n\n        return this._needShowMore;\n    }\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/provider/CatalogApi.js",
    "content": "DG.Geoclicker.Provider.CatalogApi = DG.Class.extend({\n    initialize: function(map) { // (Object)\n        this._map = map;\n\n        var apiUrl = DG.config.protocol +\n            DG.config.webApiServer + '/' +\n            DG.config.catalogVersion + '/';\n\n        this._urlGeoSearch = apiUrl + 'items/geocode';\n        this._urlGeoGet = apiUrl + 'items/byid';\n        this._urlDetails = apiUrl + 'items/byid';\n        this._urlFirmsInHouse = apiUrl + 'items';\n\n        this._key = this._map.options.key || DG.config.geoclickerCatalogApiKey;\n        this._geoFields = DG.config.geoAdditionalFields;\n        this._firmInfoFields = DG.config.firmInfoFields;\n    },\n\n    getLocations: function(options) { // (Object)\n        // Callback will receive array of found results or void if errors occurred or nothing was found.\n        var zoom = options.zoom,\n            latlng = options.latlng,\n            hasCatalogKey = options.hasCatalogKey,\n            beforeRequest = options.beforeRequest || function() {},\n            types = this.getTypesByZoom(zoom),\n            q = latlng.lng + ',' + latlng.lat;\n\n        if (!types) {\n            return Promise.reject('no type');\n        }\n\n        if (hasCatalogKey) {\n            beforeRequest();\n        }\n\n        return this.geoSearch(q, types, zoom).then(DG.bind(function(result) {\n            return this._filterResponse(result, types);\n        }, this));\n    },\n\n    firmsInHouse: function(houseId, parameters) { // (String, Function, Number)\n        parameters = parameters || {};\n\n        /* eslint-disable camelcase */\n        var params = {\n            building_id: houseId,\n            page: parameters.page || 1\n        };\n        /* eslint-enable camelcase */\n\n        return this._performRequest(params, this._urlFirmsInHouse);\n    },\n\n    getFirmInfo: function(firmId) {\n        return this._performRequest({\n            type: 'filial',\n            id: firmId,\n            fields: this._firmInfoFields\n        }, this._urlDetails);\n    },\n\n    geoSearch: function(q, types, zoomlevel) { // (String, String, Number)\n        /* eslint-disable camelcase */\n        var params = {\n            point: q,\n            type: types,\n            zoom_level: zoomlevel,\n            fields: this._geoFields\n        };\n        /* eslint-enable camelcase */\n\n        return this._performRequest(params, this._urlGeoSearch);\n    },\n\n    geoGet: function(id) {\n        var params = {\n            id: id,\n            fields: this._geoFields\n        };\n\n        return this._performRequest(params, this._urlGeoGet);\n    },\n\n    cancelLastRequest: function() {\n        if (this._lastRequest) {\n            this._lastRequest.abort();\n        }\n    },\n\n    getTypesByZoom: function(zoom) { // (Number) -> String|Null\n        var types = {\n                'adm_div.settlement':   8,\n                'adm_div.city':         8,\n                'adm_div.division':     11,\n                'adm_div.district':     12,\n                'street':               14,\n                'building':             14,\n                'adm_div.place':        15,\n                'attraction':           17\n            },\n            selectedTypes = [];\n\n        Object.keys(types).forEach(function(type) {\n            if (zoom >= types[type]) {\n                selectedTypes.push(type);\n            }\n        });\n\n        if (selectedTypes.length) {\n            return selectedTypes.join(',');\n        } else {\n            return null;\n        }\n    },\n\n    _performRequest: function(params, url) { // (Object, String, Function, Function)\n        var data = DG.extend({key: this._key}, params);\n        var type = 'get';\n\n        this.cancelLastRequest();\n\n        if (!DG.ajax.corsSupport) {\n            type = data.format = 'jsonp';\n        }\n\n        this._lastRequest = DG.ajax(url, {\n            type: type,\n            data: data,\n            timeout: this._timeoutMs,\n            withCredentials: true\n        });\n\n        return this._lastRequest;\n    },\n\n    _filterResponse: function(response, allowedTypes) { // (Object, Array) -> Boolean|Object\n        var result = {}, i, item, found, data, type;\n\n        if (this._isNotFound(response)) {\n            if (response && response.meta && response.meta.code === 403) {\n                console.error('The catalog service is unavailable. Please contact api@2gis.com to get the RasterJS API key');\n                return response\n            }\n\n            return false;\n        }\n\n        data = response.result.items;\n\n        for (i = data.length - 1; i >= 0; i--) {\n            item = data[i];\n\n            type = item.type;\n            if (item.subtype) {\n                type += '.' + item.subtype;\n            }\n\n            if (allowedTypes && allowedTypes.indexOf(type) === -1) {\n                continue;\n            }\n\n            result[type] = item;\n            found = true;\n        }\n\n        if (found) {\n            return result;\n        } else {\n            return false;\n        }\n    },\n\n    _isNotFound: function(response) { // (Object) -> Boolean\n        return !response ||\n               !!response.meta && !!response.meta.error ||\n               !response.result ||\n               !response.result.items ||\n               !response.result.items.length;\n    }\n\n});\n"
  },
  {
    "path": "src/DGGeoclicker/src/provider/Provider.js",
    "content": "DG.Geoclicker.Provider = {};\n"
  },
  {
    "path": "src/DGGeoclicker/templates/cityarea.dust",
    "content": "<div class=\"dg-map-geoclicker__purpose dg-map-geoclicker__purpose_type_{type}\">{purpose}</div>\n\n{#drilldown}\n<div class=\"dg-map-geoclicker__drilldown\">{drilldown}</div>\n{/drilldown}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmCardAddr.dust",
    "content": "<address class=\"dg-firm-card__address dg-firm-card__icon\">\n    {address}\n    {#comment}\n        <span class=\"dg-firm-card__comment\">&mdash; {.}</span>\n    {/comment}\n</address>\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmCardContacts.dust",
    "content": "{#groups}\n    {#contacts}\n        {@select key=type type=\"string\"}\n            {@eq value=\"phone\" type=\"string\"}\n                <div class=\"dg-firm-card__phone dg-firm-card__icon\">\n                    <span class=\"dg-firm-card__phone-num\">\n                        {text}\n                        {#comment}\n                            <span class=\"dg-firm-card__comment\" title=\"{.}\">&mdash;&nbsp;&nbsp;{.}</span>\n                        {/comment}\n                    </span>\n                </div>\n            {/eq}\n            {@eq value=\"fax\" type=\"string\"}\n                <div class=\"dg-firm-card__phone dg-firm-card__icon\">\n                    <span class=\"dg-firm-card__phone-num\">\n                        {text}\n                        {#comment}\n                            <span class=\"dg-firm-card__comment\" title=\"{.}\">&mdash;&nbsp;&nbsp;{.}</span>\n                        {/comment}\n                    </span>\n                </div>\n            {/eq}\n            {@eq value=\"website\" type=\"string\"}\n                <div class=\"dg-firm-card__link dg-firm-card__site dg-firm-card__icon\">\n                    <a href=\"{url}\" target=\"_blank\" class=\"dg-link_scheme_dark dg-firm-card__sitelink\">{text}</a>\n                </div>\n            {/eq}\n            {@eq value=\"email\" type=\"string\"}\n                <div class=\"dg-firm-card__link dg-firm-card__email dg-firm-card__icon\">\n                    <a href=\"mailto:{value}\">{value}</a>\n                </div>\n            {/eq}\n        {/select}\n    {/contacts}\n{/groups}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmCardHeader.dust",
    "content": "<div class=\"dg-popup__header-title dg-popup__header-title_for_firmcard\" title=\"{firmName}\">{firmName}</div>\n\n{?links}\n    <div class=\"dg-popup__header-links\">\n        {#links}\n            {@eq key=\"{name}\" value=\"flamp_stars\" type=\"string\"}\n                <div class=\"dg-popup__rating\">\n                    <div class=\"dg-popup__rating-stars\" style=\"width: {width}%\"></div>\n                </div>\n            {:else}\n                <a class=\"dg-popup__header-link dg-popup__link dg-popup__link_type_{name}\"\n                    {?href}\n                        href={href} target=\"_blank\"\n                    {:else}\n                        href=\"javascript:void(0)\"\n                    {/href}\n                    >{label}</a>\n            {/eq}\n        {/links}\n    </div>\n{/links}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmCardRubric.dust",
    "content": "{#rubrics}\n    <section class=\"dg-firm-card__rubrics\">\n        {?primary}\n            <ul class=\"dg-firm-card__rubrics-list dg-firm-card__rubrics-list_type_primary\">\n                {#primary}\n                    <li class=\"dg-firm-card__rubrics-list-item\">\n                        {name}\n                    </li>\n                {/primary}\n            </ul>\n        {/primary}\n        {?additional}\n            <ul class=\"dg-firm-card__rubrics-list dg-firm-card__rubrics-list_type_additional\">\n                {#additional}\n                    <li class=\"dg-firm-card__rubrics-list-item\">\n                        {name}\n                    </li>\n                {/additional}\n            </ul>\n        {/additional}\n    </section>\n{/rubrics}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmCardSchedule.dust",
    "content": "<div class=\"dg-firm-card__schedule dg-schedule dg-schedule_open_{?forecast.open}true{:else}false{/forecast.open} dg-schedule_works-everyday_{?schedule.everyday}true{:else}false{/schedule.everyday}\">\n    {?schedule}\n        {?forecast.today}\n            <div class=\"dg-schedule__today\">\n                <div class=\"dg-schedule__today-inner\">\n                    {forecast.today.text}&nbsp;\n                    {?forecast.today.from}\n                        {forecast.today.from}&ndash;{forecast.today.to}\n                    {/forecast.today.from}\n\n                    {?schedule.lunch}\n                        ,&nbsp;{forecast.today.lunchStr}&nbsp;\n                        {#schedule.lunch}\n                            {from}&ndash;{to}\n                        {/schedule.lunch}\n                    {/schedule.lunch}\n                </div>\n            </div>\n        {/forecast.today}\n\n        {#forecast.now}\n            <div class=\"dg-schedule__now\">\n                {!Вывод строки прогноза, например \"откроется завтра\" или \"закроется через 15 минут\" !}\n                <span class=\"dg-schedule__now-text\">{.}{#schedule.comment},{~s}{.}{/schedule.comment}</span>\n            </div>\n        {/forecast.now}\n\n        {^schedule.everyday}\n        {!Если ежедневно одно и то же расписание - попап не нужен !}\n            {?schedule.week}\n                {!Упрощённое расписание !}\n                {?schedule.week.evently}\n                    <div class=\"dg-schedule__table\">\n                        {#schedule.week.evently}\n                            <div class=\"dg-schedule__string\">\n                                {?alltime}\n                                    {alltimeStr}\n                                {/alltime}\n                                {?everyday}\n                                    {forecast.today.text}\n                                {:else}\n                                    {dayList}\n                                {/everyday}\n                                {?holiday}\n                                    &nbsp;&mdash;<span class=\"schedule__string-time\">&nbsp;{holidayStr}</span>\n                                {:else}\n                                    <span class=\"schedule__string-time\">&nbsp;{from}&ndash;{to}</span>\n                                    {#lunch}\n                                        <p>{lunchStr}&mdash;\n                                            <span class=\"schedule__string-time\">\n                                                {from}&ndash;{to}\n                                            </span>\n                                        </p>\n                                    {/lunch}\n                                {/holiday}\n                            </div>\n                        {/schedule.week.evently}\n                    </div>\n                {/schedule.week.evently}\n\n                {! Неупрощаемое расписание - таблица !}\n                {?schedule.week.table}\n                    <div>\n                        <div class=\"dg-schedule__table\">\n                            <div class=\"dg-schedule__tc dg-schedule__tc_pre\">\n                                <div class=\"dg-schedule__day-name\">&nbsp;</div>\n                                <div class=\"dg-schedule__table-clock dg-schedule__td\"></div>\n                                {?schedule.week.hasLunch}\n                                    <div class=\"dg-schedule__table-lunch dg-schedule__td\"></div>\n                                {/schedule.week.hasLunch}\n                            </div>\n                            {#schedule.week.table}\n                                {@if cond=\"({$idx} == {$len} - 2)\"}\n                                    <span class=\"dg-schedule__table-cell-group\">\n                                {/if}\n\n                                <div class=\"dg-schedule__tc{?active} dg-schedule__tc_active_true{/active}\">\n                                    <div class=\"dg-schedule__day-name\">{key}</div>\n                                    <div class=\"dg-schedule__td\">\n                                        {?from}\n                                            {from} {to}\n                                        {:else}\n                                            &ndash;\n                                        {/from}\n                                    </div>\n                                    {#lunch}\n                                        <div class=\"dg-schedule__td\">\n                                            {?from}\n                                                {from} {to}\n                                            {:else}\n                                                &ndash;\n                                            {/from}\n                                        </div>\n                                    {/lunch}\n                                </div> {! dg-schedule__tc !}\n\n                                {@if cond=\"({$idx} == {$len})\"}\n                                    </span>\n                                {/if}\n                            {/schedule.week.table}\n                        </div>  {! dg-schedule__table !}\n                    </div>\n                {/schedule.week.table}\n            {/schedule.week}\n        {/schedule.everyday}\n    {/schedule}\n</div>\n"
  },
  {
    "path": "src/DGGeoclicker/templates/firmlistItem.dust",
    "content": "<a id=\"{firm.id}\" class=\"dg-popup__link\" href=\"#\">{firm.name}</a>\n"
  },
  {
    "path": "src/DGGeoclicker/templates/frimCardPayments.dust",
    "content": "{?payments}\n    <section class=\"dg-firm-card__aa\">\n        <ul class=\"dg-firm-card__aa-list\">\n            {#payments}\n                <li class=\"dg-firm-card__aa-list-item\">{.}</li>\n            {/payments}\n        </ul>\n    </section>\n{/payments}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/house.dust",
    "content": "{#address}\n<address class=\"dg-map-geoclicker__address\">\n\t{#address.header}\n\t    <div class=\"dg-map-geoclicker__address-header\">{.}</div>\n\t{/address.header}\n\n\t{#address.drilldown}\n\t    <div class=\"dg-map-geoclicker__address-drilldown\">{.}</div>\n\t{/address.drilldown}\n</address>\n{/address}\n\n{#purpose}\n\t<div class=\"dg-map-geoclicker__purpose\">{.}</div>\n{/purpose}\n\n{#attractions}\n    <div class=\"dg-map-geoclicker__purpose dg-map-geoclicker__purpose_type_sight\">{.}</div>\n{/attractions}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/loader.dust",
    "content": "<div class=\"dg-preloader dg-preloader_scheme_regular dg-preloader_animation_{?anim}true{:else}false{/anim}{?small} dg-preloader_size_small{/small}\"></div>\n"
  },
  {
    "path": "src/DGGeoclicker/templates/popupFooter.dust",
    "content": "<div class=\"dg-popup__footer-title\">\n    <a class=\"dg-popup__show-less-house-link\" href=\"javascript:void(0)\">{hideFirmsText}</a>\n</div>\n"
  },
  {
    "path": "src/DGGeoclicker/templates/popupFooterBtns.dust",
    "content": "{?btns}\n    <footer class=\"dg-popup__footer-buttons\">\n        {#btns}\n            <div class=\"dg-popup__footer-button-wrapper\">\n                <a class=\"dg-popup__button_name_{name} dg-popup__footer-button{?icon} dg-popup__footer-icon-button{/icon}\"\n                    {?href}\n                        href={href} target=\"_blank\"\n                    {:else}\n                        href=\"javascript:void(0)\"\n                    {/href}\n                    >{label}</a>\n            </div>\n        {/btns}\n    </footer>\n{/btns}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/popupHeader.dust",
    "content": "{#title}\n    <div class=\"dg-popup__header-title\">{.}</div>\n{/title}\n"
  },
  {
    "path": "src/DGGeoclicker/templates/sight.dust",
    "content": "{#purpose}\n\t<div class=\"dg-map-geoclicker__purpose dg-map-geoclicker__purpose_type_sight\">{.}</div>\n{/purpose}\n\n{#address}\n<address class=\"dg-map-geoclicker__address\">\n\t{#address.header}\n\t    <div class=\"dg-map-geoclicker__address-header\">{.}</div>\n\t{/address.header}\n\n\t{#address.drilldown}\n\t    <div class=\"dg-map-geoclicker__address-drilldown\">{.}</div>\n\t{/address.drilldown}\n</address>\n{/address}\n\n{#description}\n    <div class=\"dg-map-geoclicker__sight-description\">{.}</div>\n    {#showMoreText}\n        <a class=\"dg-map-geoclicker__show-more-sights-link\" href=\"javascript:void(0)\">{.}</a>\n    {/showMoreText}\n{/description}\n"
  },
  {
    "path": "src/DGGeoclicker/test/CatalogApiSpec.js",
    "content": "describe('DG.Geoclicker.Provider.CatalogApi', function () {\n\n    var catalogApi,\n        spy,\n        map,\n        mapContainer = document.createElement(\"div\");\n\n    after(function() {\n        mapContainer = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: new DG.LatLng(54.98117239821992, 82.88922250270844),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n        catalogApi = new DG.Geoclicker.Provider.CatalogApi(map);\n        spy =  sinon.spy(catalogApi, \"getTypesByZoom\");\n    });\n\n    afterEach(function () {\n        spy = null;\n        catalogApi = null;\n        map.remove();\n        map = null;\n    });\n\n    describe(\"#getTypesByZoom\", function() {\n\n        it('should send correct types to the server corresponded to zoomlevel', function () {\n            var zoomToTypesMap = {\n                    0:  null,\n                    1:  null,\n                    2:  null,\n                    3:  null,\n                    4:  null,\n                    5:  null,\n                    6:  null,\n                    7:  null,\n                    8:  'adm_div.settlement,adm_div.city',\n                    9:  'adm_div.settlement,adm_div.city',\n                    10: 'adm_div.settlement,adm_div.city',\n                    11: 'adm_div.settlement,adm_div.city,adm_div.division',\n                    12: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district',\n                    13: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district',\n                    14: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building',\n                    15: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building,adm_div.place',\n                    16: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building,adm_div.place',\n                    17: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building,adm_div.place,attraction',\n                    18: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building,adm_div.place,attraction',\n                    19: 'adm_div.settlement,adm_div.city,adm_div.division,adm_div.district,street,building,adm_div.place,attraction'\n                },\n                zoom;\n\n            for (zoom in zoomToTypesMap) {\n                catalogApi.getTypesByZoom(zoom);\n                expect(spy.returnValues.pop()).to.be.equal(zoomToTypesMap[zoom]);\n            }\n\n        });\n\n    });\n\n});\n"
  },
  {
    "path": "src/DGGeoclicker/test/ControllerSpec.js",
    "content": "/*global describe:false, it:false, expect:false, beforeEach:false, afterEach:false, sinon:false */\n\ndescribe('DG.Geoclicker.Controller', function () {\n    var map,\n        mapContainer = document.createElement('div'),\n        spy,\n        initZoom = 17,\n        controller;\n\n    after(function() {\n        mapContainer = initZoom = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: new DG.LatLng(54.98117239821992, 82.88922250270844),\n            zoom: initZoom,\n            key: window.__karma__.config.secretKey,\n        });\n        controller = map.geoclicker.getController();\n    });\n\n    afterEach(function () {\n        map.remove();\n        map = null;\n        spy = null;\n        controller = null;\n    });\n\n    describe('#findHandler', function () {\n\n        it('should return null if handler name was not found (as a result - the default handler will be called)', function () {\n\n            spy = sinon.spy(controller, 'findHandler');\n\n            controller.findHandler({'somedummyhandler': 1});\n\n            expect(spy.returnValues.pop()).to.be.equal(null);\n\n        });\n\n\n        it('should return correct handler name if handler was found', function () {\n\n            spy = sinon.spy(controller, 'findHandler');\n\n            controller.findHandler({'building': 2});\n\n            expect(spy.returnValues.pop()).to.be.equal('building');\n        });\n\n    });\n\n    describe('#handleResponse', function () {\n        var defaultSpy,\n            houseSpy,\n            districtSpy,\n            citySpy,\n            defaultHandler,\n            cityHandler,\n            districtHandler,\n            houseHandler;\n\n        beforeEach(function () {\n\n            defaultSpy = sinon.stub().returns(Promise.resolve({}));\n            houseSpy = sinon.stub().returns(Promise.resolve({}));\n            citySpy = sinon.stub().returns(Promise.resolve({}));\n            districtSpy = sinon.stub().returns(false);\n\n            addClickEventStub = sinon.stub();\n\n            defaultHandler = DG.Class.extend({\n                handle: defaultSpy,\n                addClickEvent: addClickEventStub\n            });\n            houseHandler = DG.Class.extend({\n                handle: houseSpy,\n                addClickEvent: addClickEventStub\n            });\n            cityHandler = DG.Class.extend({\n                handle: citySpy,\n                addClickEvent: addClickEventStub\n            });\n            districtHandler = DG.Class.extend({\n                handle: districtSpy,\n                addClickEvent: addClickEventStub\n            });\n\n            DG.Geoclicker.Controller.mergeOptions({\n                handlersSequence: {\n                    default: defaultHandler,\n                    house: houseHandler,\n                    district: districtHandler,\n                    city: cityHandler\n                }\n            });\n\n        });\n\n        afterEach(function () {\n\n            defaultSpy = null;\n            districtSpy = null;\n            houseSpy = null;\n            citySpy = null;\n            defaultHandler = null;\n            houseHandler = null;\n            districtHandler = null;\n            cityHandler = null;\n\n        });\n\n\n        it('should call only default handler if no result was received from WebApi', function () {\n\n            controller.handleResponse(undefined);\n\n            expect(defaultSpy.called).to.be.ok();\n            expect(houseSpy.called).to.not.be.ok();\n\n        });\n\n        it('should call correct handler according to response of WebApi', function () {\n\n            controller.handleResponse({\n                'house' : 2\n            });\n\n            expect(defaultSpy.called).to.not.be.ok();\n            expect(houseSpy.called).to.be.ok();\n\n        });\n\n        it('should call next handler if previous returned false', function () {\n\n            controller.handleResponse({\n                'district': 1,\n                'city': 3\n            });\n\n            expect(districtSpy.called).to.be.ok();\n            expect(citySpy.called).to.be.ok();\n            expect(defaultSpy.called).to.not.be.ok();\n            expect(houseSpy.called).to.not.be.ok();\n\n        });\n\n    });\n\n});\n\n"
  },
  {
    "path": "src/DGGeoclicker/test/GeoclickerSpec.js",
    "content": "describe('DG.Geoclicker', function () {\n    var map,\n        mapContainer = document.createElement(\"div\");\n\n    after(function() {\n        mapContainer = null;\n    });\n\n    afterEach(function () {\n        DG.Map.mergeOptions({\n            geoclicker: true\n        });\n        map && map.remove();\n        map = null;\n    });\n\n    describe(\"#enabled\", function() {\n\n        it('should be inactive, if DG.Map.options.geoclicker was set to false', function () {\n\n            DG.Map.mergeOptions({\n                geoclicker: false\n            });\n\n            map = new DG.Map(mapContainer, {\n                center: new DG.LatLng(54.98117239821992, 82.88922250270844),\n                zoom: 17,\n                key: window.__karma__.config.secretKey,\n            });\n\n            expect(map.geoclicker.enabled()).to.be.equal(false);\n\n\n        });\n\n        it('should be active by default', function () {\n            map = new DG.Map(mapContainer, {\n                center: new DG.LatLng(54.98117239821992, 82.88922250270844),\n                zoom: 17,\n                key: window.__karma__.config.secretKey,\n            });\n\n            expect(map.geoclicker.enabled()).to.be.equal(true);\n        });\n\n    });\n\n});\n\ndescribe('DG.Geoclicker advance tests', function () {\n    var map, mapContainer, spy;\n\n    before(function() {\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [55.017493, 82.819576],\n            zoom: 15,\n            geoclicker: true,\n            key: window.__karma__.config.secretKey,\n        });\n    });\n\n    after(function() {\n        document.body.removeChild(mapContainer);\n        map = mapContainer = spy = null;\n    });\n\n    describe('check init', function() {\n        it('should map has geocliker field', function() {\n            expect(map.geoclicker).to.be.ok();\n        });\n\n        it('#getController should return DG.Geoclicker.Controller', function() {\n            expect(map.geoclicker.getController()).to.be.a(DG.Geoclicker.Controller);\n        });\n    });\n\n    describe('clicks', function() {\n        describe('click to Sun City', function() {\n            var xhr, requests, clock, latlng, responseData;\n\n            before(function() {\n                responseData = '{\"response\":{\"code\":200,\"method\":\"http:\\/\\/catalog.api.2gis.ru\\/doc\\/2.0\\/geo\\/geo-search\\/search-by-point\"},\"result\":{\"total\":{\"total_count\":4,\"geo_count\":4},\"data\":[{\"id\":\"141373143572328\",\"name\":\"Новосибирск, Карла Маркса площадь, 7\",\"type\":\"geo\",\"geo_type\":\"house\",\"short_name\":\"7\",\"synonym\":\"Многофункциональный комплекс Сан Сити;Многофункциональный комплекс СанСити\",\"dist\":0,\"geometry\":{\"centroid\":\"POINT(82.8977660986355 54.9800753777939)\",\"selection\":\"POINT(82.8977660986355 54.9800753777939)\"},\"adm_divs\":[{\"id\":\"141360258613345\",\"type\":\"city\",\"name\":\"г. Новосибирск\"},{\"id\":\"141347373711435\",\"type\":\"district\",\"name\":\"Ленинский район\"}],\"attributes\":{\"city\":\"Новосибирск\",\"district\":\"Ленинский район\",\"micro_district\":null,\"addresses\":[{\"street\":\"Карла Маркса площадь\",\"number\":\"7\"}],\"postal_code\":\"630048\",\"building_description\":\"Торгово-развлекательный комплекс\",\"building_name\":\"Сан Сити, многофункциональный комплекс\",\"floors_count\":23,\"filials_count\":211,\"filials\":{\"popular\":[{\"id\":\"141265770417218\",\"name\":\"Сан Сити, многофункциональный комплекс\",\"rubric_name\":\"Торгово-развлекательные центры \\/ Моллы\"},{\"id\":\"141265771060872\",\"name\":\"Здравица, центры семейной медицины\",\"rubric_name\":\"Диагностические центры\"},{\"id\":\"141265770538610\",\"name\":\"Синема Парк, кинотеатр\",\"rubric_name\":\"Кинотеатры\"}],\"servicing\":{\"total_count\":15,\"items\":[{\"id\":\"141265769370483\",\"name\":\"Orange Business Services, телекоммуникационная компания, ООО Эквант\",\"rubric_name\":\"Интернет-провайдеры\"},{\"id\":\"141265769407070\",\"name\":\"Энфорта, ООО Престиж-Интернет\",\"rubric_name\":\"Интернет-провайдеры\"},{\"id\":\"141265769349880\",\"name\":\"Билайн Бизнес, ОАО ВымпелКом\",\"rubric_name\":\"Интернет-провайдеры\"}]}},\"sight\":null}},{\"id\":\"141347373711435\",\"name\":\"Новосибирск, Ленинский\",\"type\":\"geo\",\"geo_type\":\"district\",\"short_name\":\"Ленинский\",\"synonym\":null,\"dist\":0,\"geometry\":{\"centroid\":\"POINT(82.8944577831071 54.9837576912103)\",\"selection\":\"POLYGON((82.9310537104777 55.0051498598707,82.9206144783925 55.009243785233,82.9185642534195 55.0100450677819,82.9156961123804 55.0111660637911,82.8691163089421 55.0330232906245,82.8248493978659 55.045721473722,82.8237138375152 55.0447540975008,82.8046557194365 55.0367373985273,82.7964982081729 55.0309059519357,82.7946678907815 55.0316017730696,82.7936154245947 55.030602906857,82.7931388683365 55.0299274056716,82.7914912682739 55.0283465751258,82.7914463525096 55.0282768591815,82.7914344049164 55.0282265544699,82.7914451846998 55.0281831492278,82.791486866529 55.0281458711414,82.792501783137 55.0275815981919,82.7928437717656 55.0274466946402,82.7924745641838 55.0272474793664,82.7923847326554 55.02721200257,82.7922147714037 55.0271631897421,82.7921129024505 55.0271160760385,82.7920469661086 55.0270632983267,82.7871355171242 55.0227447647132,82.7812429281865 55.0229128989067,82.778531632996 55.0226180842731,82.7777741735484 55.0227926559948,82.7775053077839 55.0224076702671,82.7772894426211 55.0208850453531,82.77970618023 55.0178489439407,82.7791320669319 55.0167147437669,82.7784043417202 55.0161830152288,82.7786256866062 55.0160915432002,82.778734113261 55.0159958475776,82.7788214295066 55.0158886146441,82.778868591059 55.0157937941215,82.7788720944886 55.0156898569738,82.7784150316721 55.0147953064994,82.7780848109736 55.0142931689784,82.7770908251118 55.0132987131325,82.7644834192568 55.0027389214354,82.7584720730385 54.9974510523445,82.7581874867565 54.9972321585879,82.7528471820555 54.9924731399271,82.7523955091306 54.9917477794525,82.7523551747744 54.9916841841683,82.7520408542565 54.9911738721697,82.7507523108129 54.9885144963879,82.7561791232758 54.9867598303463,82.762198105174 54.9829297491167,82.7673041292489 54.9796888477779,82.7674439969387 54.9796000762886,82.7734462701726 54.9758857260116,82.7765117710796 54.9738434293431,82.7863153552698 54.9680278418825,82.7865251118887 54.9678583946562,82.7906529604507 54.9653724505173,82.7938443153291 54.96361527732,82.7980247153353 54.9617050578248,82.7998279934366 54.9605926337788,82.7998960857351 54.9600686713315,82.7999811561925 54.9599004283719,82.8001579446404 54.9597479672519,82.80067043351 54.9594063202058,82.8007465208146 54.9593555680417,82.8012886540886 54.9589608955698,82.8013412055327 54.9589374275995,82.8014119029455 54.9589218510489,82.8014836783368 54.9589207679111,82.8018773200942 54.9590210869828,82.8019698465685 54.9590262963467,82.8020673137768 54.9590137629253,82.8021444790597 54.9589896244731,82.8030032684714 54.9585287732502,82.80393652822 54.958985807708,82.8061128766589 54.9575149335337,82.8102042536204 54.9547854442511,82.8168374136783 54.9502621595006,82.8170768147016 54.9501781207567,82.8176340396723 54.9499269320825,82.8191845318527 54.9489869597144,82.8198879127201 54.9486931493524,82.8205108943697 54.948537653412,82.8220605780663 54.9477813691247,82.8221968524949 54.9477395277544,82.8223289946732 54.947725339857,82.8224671555639 54.9477365353983,82.8225129696434 54.9477101716992,82.8231887722316 54.9473512934815,82.8232291065879 54.9473299340385,82.8238393321604 54.9469931343658,82.827709543899 54.9448574244386,82.8298356765134 54.9437720353976,82.8299706034691 54.943891896066,82.8300923251901 54.9440048939582,82.8317846613539 54.9432486791837,82.8318049632793 54.9433092553181,82.8322271714628 54.9437051650631,82.8326022180939 54.9440201151112,82.8329237251341 54.944128520512,82.8331461479985 54.9442195374814,82.8333151211034 54.9443300062135,82.8335338608751 54.9445768957666,82.8343897756778 54.9457509548046,82.8346470531752 54.9459487691551,82.8350521933683 54.946154063718,82.8355731264016 54.9463087949664,82.8363066008311 54.9464082684254,82.8368154964395 54.9464135310186,82.8369580590751 54.9464472219173,82.8375911018558 54.9466978648069,82.8381712338663 54.9467834586346,82.8383653597992 54.9468293252943,82.8386367408465 54.9472015707706,82.8387289079947 54.9472432063289,82.8393848578152 54.9473763675956,82.8395112507756 54.947426515777,82.8397634977074 54.9476243734748,82.8398328476473 54.9477794602098,82.8398722836883 54.9483968604508,82.8399082162997 54.9485686081926,82.8399394776716 54.948626648342,82.840078447046 54.948705737584,82.8408753425346 54.9489107085221,82.840990506554 54.9489953690048,82.8410122457839 54.9490975185271,82.8409527773121 54.9492176728602,82.8407696108256 54.9493653244514,82.8398955500542 54.9500127769816,82.8397357397651 54.9502265630007,82.8396876798974 54.9504160495135,82.8397141801983 54.9505032862655,82.8399031857341 54.9506827117043,82.8401048575154 54.9507705153505,82.8404631056507 54.9508171512867,82.8408457879617 54.9507757257841,82.8423659170855 54.9503603850411,82.8426096300221 54.9503619842995,82.8428314240657 54.9504138311903,82.8429727290599 54.9505081356122,82.8430076735245 54.950606308963,82.8429969835726 54.9528605672577,82.8430748675077 54.9530307999456,82.8432328811662 54.9531494465441,82.8434367987357 54.9532299712751,82.8436772777373 54.9532882626197,82.8450879920594 54.9534281615017,82.8453732071621 54.9534800044372,82.8455985046354 54.9535876105555,82.848091688875 54.9553223712495,82.8481352571662 54.9554146008545,82.8481128891157 54.9555114210789,82.8477452086699 54.9560011926939,82.847721762641 54.9560963608933,82.8477695530141 54.9562284096205,82.8478879509685 54.9563103724598,82.8481749627018 54.9564058494143,82.8485412956747 54.9564910615019,82.8489227203443 54.956526239805,82.8492119778658 54.9565158204281,82.8494889284679 54.9564656835867,82.8496981460976 54.9563716510498,82.8498304679389 54.9562708611308,82.8503472687219 54.9554278059708,82.8504686311167 54.9553674544274,82.8506445212494 54.9553436232802,82.8509335092763 54.9553895833371,82.8512526806967 54.9555135875384,82.8514481541025 54.9556487846945,82.8519658532008 54.9561056455836,82.8520122062694 54.9561861128098,82.8519931619854 54.9562714285261,82.851648658074 54.9567676384734,82.8516228764253 54.9569946963247,82.8515254990485 54.957228406735,82.8514802239582 54.9573838690536,82.8514470761242 54.9574524187701,82.8508701780487 54.9578200268799,82.8502836679997 54.958550229899,82.85012969676 54.9587687672775,82.8500263006708 54.9589971032686,82.8500005190222 54.9591632869035,82.8500554959176 54.9593398884984,82.8501821583726 54.9594989530555,82.8503802368928 54.9596280507075,82.8507004862916 54.9597217145853,82.8510414867734 54.959758849983,82.8532998513977 54.9596720975142,82.8535119436363 54.9596808140311,82.853637707776 54.9597102129204,82.8537347258267 54.9597537438678,82.8544591272719 54.9603126275291,82.8545833642756 54.9603704444151,82.855638974566 54.9605741696213,82.8557643793797 54.9606418886827,82.8560875033874 54.9611314946159,82.8562646511614 54.9612985977718,82.8565408831113 54.9614246983044,82.8568448730034 54.9614955619882,82.8571633257716 54.9615093840022,82.8574817785398 54.9614803990271,82.8591707011055 54.9610174102102,82.8593218875678 54.9610180806891,82.8607156237312 54.9615118595863,82.8608834290262 54.9616153698098,82.8619199950326 54.9625366867253,82.862207545755 54.9626882089464,82.8625368681382 54.9627966671491,82.862899787513 54.9628704680698,82.8632497711477 54.9629007929371,82.8652986486477 54.962940865048,82.8702157570184 54.9623793876953,82.8709533636981 54.9623302896424,82.8715441856605 54.9623664943048,82.87207841376 54.9624485993444,82.8726873816911 54.9625937268116,82.8732554762768 54.9628373582395,82.8738133300682 54.9631528804037,82.8749716177955 54.9638431216236,82.8739437654475 54.9655452086781,82.8736730132208 54.9661334575357,82.8738308472163 54.9661470201105,82.8739532875895 54.9661764142683,82.8740322495029 54.9662274156595,82.8740692600926 54.9662958471513,82.8740754584681 54.9663882578431,82.8728248239295 54.9747142486374,82.8772078838638 54.9749209945533,82.8784832220727 54.9749663650857,82.8798803718341 54.9750269965353,82.8813494766497 54.9757819947757,82.8855894349592 54.9759773412987,82.8851920202776 54.9790051682111,82.8881460402579 54.9791312647148,82.8882973165517 54.9780027745582,82.8926514507338 54.9781966667865,82.8924826572919 54.9794655267929,82.8929213944767 54.9797629269716,82.892677322214 54.9798789170838,82.8934536462826 54.9804188079829,82.8968202624728 54.9787755024658,82.8971547950847 54.9789309845146,82.9097629195919 54.9864168667424,82.9098286762706 54.9864395970629,82.9099134772335 54.9864573792775,82.909988037402 54.986468100145,82.9100563093637 54.9864734605777,82.9101295220593 54.9864750068563,82.9102907696528 54.9864741306318,82.9137278137614 54.986363159222,82.9137446122572 54.9867846221614,82.9137386833763 54.9872803521648,82.9136200159273 54.9921287821521,82.913576447636 54.9928289353984,82.9136473247119 54.9931596821832,82.913699696493 54.9932925882334,82.9137845872873 54.9934113220757,82.91408390594 54.9937025895449,82.9310537104777 55.0051498598707))\"},\"adm_divs\":[{\"id\":\"141360258613345\",\"type\":\"city\",\"name\":\"г. Новосибирск\"}],\"attributes\":{\"area\":709396967836.5,\"houses_count\":null,\"city\":\"Новосибирск\"}},{\"id\":\"141424683123064\",\"name\":\"Новосибирск, Левый берег\",\"type\":\"geo\",\"geo_type\":\"place\",\"short_name\":\"Левый берег\",\"synonym\":null,\"dist\":0,\"geometry\":{\"centroid\":\"POINT(82.8985053222828 54.9843972701992)\",\"selection\":\"POLYGON((82.9814220687952 54.8522393858022,82.981498695089 54.8522524179416,82.9815474736089 54.8522516422191,82.9815925690362 54.8522409372476,82.9816205066415 54.8522388169389,82.9816987499027 54.8522293014058,82.981768998158 54.852210166903,82.9818368209619 54.8521807411229,82.9841541150688 54.8508467843605,82.984300181134 54.8508033940825,82.9844185790885 54.8507979638299,82.9845175734328 54.8508052041665,82.9872093751816 54.8495045085516,82.9874732103806 54.849684798328,83.0053009060146 54.8607247961862,83.0122303304533 54.8681379984389,83.0459364673864 54.9230548175711,83.0468425980135 54.9309715117434,83.044455684472 54.9375593271545,83.0366992709828 54.9435779253695,83.0258656784879 54.9486642067229,82.9910798564148 54.9565149951308,82.9839848724693 54.9595493955753,82.9668105215414 54.9713456869884,82.9513421611695 54.9867598818885,82.9487155771103 54.9945845213565,82.9458017118232 54.9974843397556,82.930956692427 55.0052002965814,82.9206144783925 55.009243785233,82.9185642534195 55.0100450677819,82.9156961123804 55.0111660637911,82.8691163089421 55.0330232906245,82.8312687588862 55.0440370938023,82.8264632212738 55.0470963264953,82.8237138375152 55.0447540975008,82.8046557194365 55.0367373985273,82.7964982081729 55.0309059519357,82.7946678907815 55.0316017730696,82.7936154245947 55.030602906857,82.7931388683365 55.0299274056716,82.7914912682739 55.0283465751258,82.7914463525096 55.0282768591815,82.7914344049164 55.0282265544699,82.7914451846998 55.0281831492278,82.791486866529 55.0281458711414,82.792501783137 55.0275815981919,82.7928437717656 55.0274466946402,82.7924745641838 55.0272474793664,82.7923847326554 55.02721200257,82.7922147714037 55.0271631897421,82.7921129024505 55.0271160760385,82.7920469661086 55.0270632983267,82.7871355171242 55.0227447647132,82.7812429281865 55.0229128989067,82.778531632996 55.0226180842731,82.7777741735484 55.0227926559948,82.7775053077839 55.0224076702671,82.7772894426211 55.0208850453531,82.77970618023 55.0178489439407,82.7791320669319 55.0167147437669,82.7784043417202 55.0161830152288,82.7786256866062 55.0160915432002,82.778734113261 55.0159958475776,82.7788214295066 55.0158886146441,82.778868591059 55.0157937941215,82.7788720944886 55.0156898569738,82.7784150316721 55.0147953064994,82.7780848109736 55.0142931689784,82.7770908251118 55.0132987131325,82.7644834192568 55.0027389214354,82.7584720730385 54.9974510523445,82.7581874867565 54.9972321585879,82.760217230141 54.9931607643978,82.7604113560739 54.9924734491366,82.7607026797205 54.9914420161143,82.7519028730288 54.9909852478332,82.7507523108129 54.9885144963879,82.7561791232758 54.9867598303463,82.7621133042112 54.9829835643253,82.7651060415802 54.9810475116568,82.7672671186592 54.9796757537378,82.7734462701726 54.9758857260116,82.7765117710796 54.9738434293431,82.7863153552698 54.9680278418825,82.7865251118887 54.9678583946562,82.7906529604507 54.9653724505173,82.7938443153291 54.96361527732,82.7980247153353 54.9617050578248,82.7998279934366 54.9605926337788,82.7998960857351 54.9600686713315,82.7999811561925 54.9599004283719,82.8001579446404 54.9597479672519,82.80067043351 54.9594063202058,82.8007465208146 54.9593555680417,82.8012886540886 54.9589608955698,82.8013412055327 54.9589374275995,82.8014119029455 54.9589218510489,82.8014836783368 54.9589207679111,82.8018773200942 54.9590210869828,82.8019698465685 54.9590262963467,82.8020673137768 54.9590137629253,82.8021444790597 54.9589896244731,82.8030032684714 54.9585287732502,82.80393652822 54.958985807708,82.8061128766589 54.9575149335337,82.8102042536204 54.9547854442511,82.8168374136783 54.9502621595006,82.8170768147016 54.9501781207567,82.8176340396723 54.9499269320825,82.8191845318527 54.9489869597144,82.8198879127201 54.9486931493524,82.8205108943697 54.948537653412,82.8220605780663 54.9477813691247,82.8221968524949 54.9477395277544,82.8223289946732 54.947725339857,82.8224671555639 54.9477365353983,82.8225129696434 54.9477101716992,82.8231887722316 54.9473512934815,82.8232291065879 54.9473299340385,82.8238393321604 54.9469931343658,82.827709543899 54.9448574244386,82.8298356765134 54.9437720353976,82.8299706034691 54.943891896066,82.8300923251901 54.9440048939582,82.8316408410769 54.9433131251703,82.8317846613539 54.9432486791837,82.8317831342179 54.943161994267,82.8322556480573 54.9424118007425,82.8323687459516 54.9423220180636,82.8331306071441 54.9420463736668,82.8332677798879 54.9419616985485,82.8337668838598 54.9414808891025,82.8369469199656 54.9382194065445,82.8392156152156 54.9352519314418,82.8392872109438 54.9351882982691,82.8393905172014 54.9351444310598,82.8395243661788 54.9351236844335,82.8467673924831 54.9346042411605,82.8468290169116 54.9345452517983,82.8628864026152 54.9333883615688,82.8632036875736 54.9316974541988,82.8631942552631 54.9316944606486,82.8630677724711 54.9316260218359,82.8629986021942 54.9315615571163,82.8629387743963 54.9314806276823,82.8626071163934 54.9308765937343,82.8625398325786 54.9307542167862,82.8640624769852 54.9304684798728,82.86377241098 54.9298853865251,82.8635889749989 54.9295508666443,82.8641797969613 54.9291840838956,82.8652133086957 54.9288523970947,82.8650980548447 54.9285951908346,82.8657094482271 54.9285041901123,82.8657732286123 54.928160574071,82.8660435316813 54.9278324404652,82.8694771621918 54.9278218071779,82.8694275751881 54.9284213446927,82.8697063224207 54.9290465782148,82.8697221327697 54.9290784254807,82.8697610298215 54.9291158472764,82.8710504715804 54.9301020667962,82.8711087722423 54.9301648821783,82.8722128017265 54.9309451370499,82.8736183956515 54.9316107959907,82.8737403868671 54.9322976049074,82.873902892102 54.9335421097387,82.8739092701405 54.9335803015393,82.8743479174938 54.9337238817411,82.8744964988418 54.9337937104606,82.8745980983004 54.9338610617715,82.8746498412608 54.9339364125296,82.874683707747 54.9340357101624,82.8747020333788 54.9341282982747,82.8768777529969 54.933558212232,82.8770221122631 54.9335072725915,82.8771202981236 54.9334345531754,82.8771518289901 54.933346505218,82.8771809344053 54.9330032918208,82.877192612504 54.9329164299808,82.8772446249589 54.9328526382783,82.8773734433707 54.9328036073702,82.8775286722518 54.9327712985497,82.8776300920474 54.9327637116504,82.8854799303261 54.9322832567236,82.8857144804468 54.9322626634579,82.8878476199205 54.9322275671413,82.8922055270268 54.9318925506128,82.892478075884 54.9318252992309,82.8925565886398 54.9318119315215,82.9000263497219 54.931186018393,82.9054738234363 54.930704925249,82.907643344679 54.9305759411395,82.9089019742236 54.9304278076183,82.9139599384308 54.9299904750539,82.916042502754 54.9298271128561,82.9163467621407 54.9297964533365,82.9166041294696 54.9297621807146,82.9168548492654 54.9297075199514,82.9170642465581 54.9296503299515,82.9172518147894 54.9295772422521,82.9174705545611 54.9294613649424,82.9182846977031 54.9289857741265,82.9212906403069 54.9270461890394,82.9213396883214 54.9269407831041,82.9220249232201 54.926500057353,82.9224316803807 54.9267099421089,82.9251737877855 54.9273584305635,82.9361909959245 54.9311831796455,82.9364435123509 54.9326403598212,82.9366861473091 54.9337101533903,82.9366999813645 54.9339197424768,82.9372170516421 54.9368142413327,82.955727287229 54.9376459725456,82.9588944774262 54.9378918710457,82.97817564719 54.9385871389829,82.9867280578524 54.9389631246367,82.9907442458247 54.9389709167809,82.9928801700757 54.9392787310713,82.9958104745325 54.9394047458982,82.9974751425855 54.939502894765,82.9993123770046 54.939505320102,83.0016793479467 54.9395181176224,83.0028862345309 54.9394554200539,83.0029601658788 54.9394602707334,83.0039578348334 54.9396224069417,83.0209588109114 54.9401971028063,83.0220080431633 54.9403879266436,83.0266570942532 54.9410910463577,83.0268749357096 54.9411288697836,83.0298390168211 54.9414058104826,83.0308255466661 54.9405717833674,83.0348949149032 54.9412487383322,83.0353842272384 54.9406946980588,83.035428693845 54.9406018154551,83.0356070094289 54.940230231293,83.0356768085264 54.9401510221711,83.0357590043749 54.9400717096889,83.0365537439068 54.9394700236938,83.0366110564219 54.9393910194866,83.0367158898156 54.9390276806998,83.0368063501647 54.9388632715291,83.0370690175538 54.9384616892405,83.0371368403577 54.9383400062287,83.0376529224884 54.9368569197755,83.0377163435475 54.9366573576715,83.0378807352445 54.9350383238238,83.0379005880123 54.9349387706227,83.0379436173144 54.9348174898217,83.0387619825382 54.9332300710464,83.0387942320569 54.9331373260329,83.0388003406009 54.9330166591342,83.0388129170149 54.9322932178733,83.0388173187597 54.932130277927,83.0390547434893 54.9314740211907,83.0391362206856 54.9313804463143,83.0394041881348 54.9310782490739,83.0394594345248 54.9309568017893,83.0395003078702 54.9307929273752,83.0395322878944 54.9302040062533,83.039515399567 54.9301193578109,83.0393978100963 54.9299795326462,83.0393927795307 54.9298803798447,83.0394113746571 54.9297665164093,83.0398117537792 54.9289163499914,83.0398522677986 54.9287454990073,83.0399359009515 54.928205326394,83.0399501841645 54.9280065988583,83.0398412185206 54.9268243820076,83.039433113887 54.9255695516387,83.0389728171354 54.9249958856384,83.0388915196022 54.9248413820951,83.038589056846 54.924222484405,83.0384808098543 54.9237847746358,83.0373567479393 54.9195713874499,83.037120221525 54.9187815153893,83.0369857437269 54.9185567198921,83.0367932347615 54.918397080251,83.0365866222462 54.9182090949845,83.0364313035336 54.9180628262474,83.0363262904769 54.9179297744141,83.036269696614 54.9177818524765,83.03560413482 54.9161710428945,83.0354501635803 54.9159228429936,83.0352018692357 54.9157320579643,83.0347062686935 54.91539168903,83.0343278982958 54.9151466856412,83.0340340593664 54.9149002866298,83.0337536053347 54.9146375178744,83.0324169121919 54.9131749865801,83.0292645441969 54.9092763302598,83.0280623288521 54.9077893316619,83.0269080835436 54.9061829251705,83.0265160587536 54.905442526048,83.0251022003279 54.9033791907459,83.0246269017111 54.9023332795265,83.0239756231301 54.9005146205622,83.0218693432834 54.8946295260066,83.0215658923804 54.8938114221888,83.0212838213812 54.8932506839448,83.0185128780558 54.8877473476316,83.0182430241445 54.887255659416,83.0151277565707 54.8827628103611,83.0148636518771 54.8823158129976,83.0144395572315 54.8813245980335,83.0141580252215 54.8808659054572,83.0139777333439 54.8806872537248,83.0137996872546 54.8805105133086,83.0134551833432 54.8801550663466,83.0127734518741 54.8792480887522,83.0116542408616 54.8795704686537,83.011420050067 54.8793027147041,83.0090505638421 54.8799846801472,83.0088619176324 54.880025196676,83.0085807449485 54.8800605969262,83.0084428535524 54.8800921728895,83.0077309386897 54.8803643659695,83.0073220255724 54.8800195636407,83.0071623051149 54.8800636459974,83.00528770078 54.8807520066716,83.0051474737641 54.8808198602065,83.0050939341732 54.8808622879871,83.0037419696706 54.8799917602068,83.0009096714113 54.8775158340241,83.0008816439744 54.877497435072,82.9977230776039 54.8736495438095,82.9974977801307 54.8734730309658,82.9947218062397 54.873676214497,82.9930214750699 54.8737085707725,82.9925285694735 54.8736917207026,82.9920898322887 54.8736411187631,82.991257543178 54.8734902946279,82.9908849219982 54.8734226871902,82.9906262970278 54.8733992726612,82.9905294586402 54.8688482224148,82.9855287171166 54.8689151655099,82.9812863333558 54.8689829355879,82.9812988199382 54.8705911879443,82.9786967598863 54.8706148625608,82.9786972988754 54.8716758122723,82.9764929229997 54.8716848580085,82.9764935518204 54.8726634912956,82.9664891043327 54.8726647835121,82.9561443750154 54.8727438670824,82.9421444906385 54.872920331431,82.9418333142241 54.8729031709014,82.9416427815523 54.8728819269827,82.9415127054992 54.8728255349203,82.9414617710226 54.872780927761,82.9414277248733 54.8727209173564,82.9414197298673 54.8726054448882,82.9413660106133 54.8699781759466,82.9413545121777 54.8694179330331,82.9413440018888 54.8688946431983,82.9413438222258 54.8666001105177,82.9334712565703 54.8671581179784,82.9330277583146 54.8671756428236,82.9299694439298 54.8673594723042,82.9296148788871 54.8673944701165,82.9293040617988 54.8674460621093,82.9273274986792 54.8675627383467,82.9272987525901 54.8670594307286,82.9272552741303 54.8653474864332,82.9270509972347 54.8642666209949,82.9270620465127 54.864197860698,82.9270914214225 54.8641350457379,82.9271642747921 54.8640382639781,82.9271211556584 54.8639925613996,82.9271062436247 54.8639254550311,82.9268671120961 54.8615069662347,82.9268490559589 54.861323368586,82.9268104284017 54.8611311873301,82.9267474565002 54.8609451578974,82.9267211358624 54.860888904248,82.9256646272567 54.8586422616805,82.9256333658849 54.8585423643313,82.9256460321304 54.8584418462519,82.9256962479547 54.8583581844084,82.9257694606504 54.8582943262096,82.9264015152843 54.8580284475046,82.9264505632988 54.8579855820262,82.9264843399535 54.8579319096258,82.9265044622159 54.8564466346352,82.9265121877273 54.855876120201,82.9265209912171 54.8552336677483,82.9265145233471 54.8550401646905,82.9264492158259 54.8530514558734,82.9263209364033 54.8510303779879,82.9262783562589 54.8502744323289,82.9261242053561 54.8475495074341,82.9262257149832 54.8472325090417,82.9270495599303 54.8445484481259,82.9270514463924 54.8445204650501,82.9272551842988 54.8438348477665,82.9278202246125 54.8411529403686,82.9272697370064 54.8379609242879,82.9279052950699 54.8337614225461,82.9287545623395 54.8332353934534,82.9295479543985 54.8326664133816,82.9326102213705 54.833253812607,82.9330779741389 54.8330677580739,82.9335098841275 54.8329567768609,82.9344637152962 54.8326332998087,82.9347757001944 54.8327389527074,82.9350833731792 54.8328044552961,82.9354733318441 54.8328377756876,82.9360448400278 54.8328499345192,82.9376603702348 54.8328274794826,82.9379164799223 54.8328004713345,82.9380928192125 54.8327605282164,82.9382513718602 54.8326855571536,82.938716968672 54.8328297560306,82.9384471147606 54.8329989445838,82.9383542289602 54.833125706185,82.938318835338 54.8332625565281,82.938362852787 54.833387144263,82.9384934678292 54.833490570417,82.9406581381694 54.8341749665223,82.9409905148245 54.8342470374961,82.9413497511066 54.8342800462696,82.9423387064029 54.8342922564047,82.9425807125405 54.8343138310835,82.943094728546 54.834471941567,82.9430442432271 54.834595025183,82.9430405601344 54.8347250412221,82.9431322781249 54.8348650421076,82.9433354770422 54.8349897283706,82.9435914070666 54.8350637121538,82.944612162724 54.8351423003735,82.9449673565873 54.8351423521103,82.945222298465 54.8351061880967,82.9453870494881 54.8350297210199,82.9458661210291 54.8351960548346,82.9456724442538 54.8352772813629,82.945614502918 54.835364767842,82.9456292352887 54.8354869692181,82.9457361348075 54.8356267087802,82.9459320573709 54.8357477194356,82.9462026299345 54.8358618488619,82.9464235256629 54.8359051517375,82.947674429696 54.8359758227585,82.9478351383003 54.83597111481,82.9479765331261 54.8359477820022,82.9481177482887 54.8358897344705,82.9483946090593 54.8360114686365,82.9481935660987 54.8361955436563,82.9481738031625 54.836318311605,82.9482305766884 54.8364335775904,82.9483912852927 54.8365787977776,82.9486345490717 54.8366931835279,82.948949947568 54.8367851678536,82.9491967147765 54.8368285214733,82.9502684049104 54.8368955177271,82.9505187653801 54.8368855329643,82.9508198806633 54.8367934971326,82.9510588325289 54.8369208158975,82.9507741564154 54.8371916450103,82.9507278931783 54.8374021506625,82.9507419967282 54.8375880817509,82.950874049075 54.8378843074194,82.951115785718 54.8381197964801,82.9518046138778 54.8384986868037,82.9520241621332 54.8385955815871,82.9526878374652 54.8387710572924,82.9528606733258 54.8388510350583,82.9533304922194 54.8391476653106,82.9536035800658 54.8392880647082,82.9541747289234 54.8394561398371,82.9543864618359 54.8394940588137,82.9547709407775 54.8395056465975,82.9549624615961 54.839549876724,82.9550986461932 54.8396126782472,82.9554958812118 54.839898129079,82.9558119085287 54.8402566210114,82.9560445721873 54.8404009997631,82.9563117311528 54.8405121674289,82.9566021564842 54.8405756399421,82.9573860264011 54.8406428886246,82.9575316433087 54.8406623907216,82.9576284816963 54.8407168103164,82.9576626176771 54.8407873694536,82.9577511017326 54.8411939097625,82.9577976344643 54.841328094582,82.9579132476414 54.8414643998304,82.9581095295309 54.8415748403677,82.9586228268843 54.8417855818002,82.9601442136495 54.8420791385398,82.9603068985474 54.84212988355,82.9604175709904 54.8422083028287,82.9604649122059 54.8423041541543,82.9605641760448 54.8425182540534,82.9606914673206 54.842643589128,82.9610991227965 54.8428379792826,82.9614636591388 54.8429558647132,82.964605516845 54.8436848949122,82.9651180057146 54.8437562247458,82.9655761465095 54.8437893291942,82.9662451219016 54.8438055710543,82.9664642209994 54.8438344856871,82.9666254685929 54.8438987288581,82.9672735132388 54.8442342710361,82.9673051339368 54.8443298589246,82.9672611164879 54.8444207913486,82.9671202606514 54.8446218454176,82.9670844178715 54.844771536168,82.967125291217 54.844944709156,82.9672396467526 54.8451021055849,82.9677598611336 54.8453298456996,82.9678443027703 54.8453910865196,82.9678688267776 54.8454716201253,82.9680893631799 54.8459126124726,82.9681736251535 54.8459745765284,82.9682936400755 54.8460149203533,82.9684096125786 54.8460575916626,82.9684902812912 54.8461267449494,82.9685147154669 54.8462108459446,82.9686991395947 54.8466539508151,82.9688416123988 54.8468230814248,82.9690192093305 54.8469610232045,82.9693026278026 54.8470996368913,82.970717115049 54.8475764022721,82.9710918921855 54.8475952286479,82.9710927006693 54.8476267783241,82.9713626444121 54.8476404326025,82.9717149636666 54.8476821194997,82.9721121986852 54.8477556662529,82.972655320106 54.8478854847378,82.9733595992887 54.8481121747398,82.9737649191449 54.8482904536619,82.9814220687952 54.8522393858022))\"},\"adm_divs\":[],\"attributes\":null},{\"id\":\"141360258613345\",\"name\":\"Новосибирск\",\"type\":\"geo\",\"geo_type\":\"city\",\"short_name\":\"Новосибирск\",\"synonym\":null,\"dist\":0,\"geometry\":{\"centroid\":\"POINT(82.9204115489698 55.03011111017)\",\"selection\":\"MULTIPOLYGON(((82.8046557194365 55.0367373985273,82.8237138375152 55.0447540975008,82.8287484455251 55.0490427787456,82.827504189025 55.049930544056,82.8245913118847 55.052616208903,82.8234864739168 55.0538767985827,82.8228815484045 55.0548843978938,82.8217046655508 55.0565917325255,82.8215412620006 55.0567238109813,82.8213036576079 55.0569941922811,82.8211659458749 55.0571571405098,82.8207684413616 55.0574909070404,82.8202769730697 55.0578107275765,82.8187864883503 55.0586221526748,82.8183419121162 55.0589429417144,82.8171843430411 55.060326086702,82.8168384018251 55.0606155820985,82.814412950558 55.0623506070409,82.8142288857563 55.0625173918366,82.8137863756474 55.0631496449763,82.8134461836493 55.0636357374463,82.8128700940575 55.0643850048358,82.8113556243201 55.0663543305668,82.810340528049 55.0674976709746,82.8097775538604 55.0680024340283,82.8089299035584 55.0686366580049,82.8083000947126 55.0689593213819,82.808002303196 55.0690518043634,82.8073760876114 55.0691386805622,82.8067213056008 55.0693231311205,82.8061851012077 55.0695787166713,82.8053633223858 55.0701537653329,82.8047035098096 55.0708258622706,82.8037008102895 55.0722026819153,82.8025208731638 55.074487967299,82.8030838473524 55.0802473010254,82.8032473407341 55.0805268307736,82.8036378383881 55.0813124963649,82.8038611595677 55.0820224051525,82.8039235924799 55.0828052133307,82.8039158669685 55.0835420386124,82.8038155251513 55.0840450567563,82.803722819014 55.0844148479262,82.8036737709994 55.0848387255897,82.8038355575821 55.0860040060962,82.8042187788823 55.0871758335427,82.8042237196164 55.0875047226055,82.8041867988582 55.0877831733851,82.8039765930817 55.0882073752311,82.8038395101693 55.0888504815305,82.8040015662466 55.090549375799,82.8034807230449 55.0933766105587,82.803112683273 55.0950995233594,82.8030008430201 55.0970645618608,82.8030572572199 55.0974845532449,82.8046540126375 55.1001307932501,82.8064175852032 55.1021158850772,82.8068131134228 55.1050273529032,82.8069571133629 55.1054954641629,82.8072582286461 55.1061100799081,82.8077629021727 55.1066904103291,82.8083903753987 55.1072688823763,82.8092554530173 55.1080663553389,82.8093167181197 55.1081413279757,82.8099093367126 55.1092858379536,82.8099363760027 55.1094117818929,82.8099094265442 55.1101023854213,82.8105250420084 55.1104173151657,82.8116358986887 55.111429811091,82.8133892304602 55.1139930246889,82.816150382149 55.1174572403879,82.8176626060983 55.1204546634981,82.8178396640408 55.1204491668614,82.8178666134993 55.1204515299016,82.8221422349256 55.1208163610775,82.8257504979274 55.1212970269714,82.8280464121305 55.1216729974694,82.8284812865596 55.1217281162243,82.8317521423406 55.1221433794029,82.8367068002901 55.1227722760671,82.8452780755736 55.1237990468619,82.8624450603161 55.125853433798,82.8701110134562 55.1266101649057,82.8848736573409 55.1286985615242,82.8876733467553 55.1289289096925,82.8893403504281 55.1286712894458,82.8895145337617 55.1290411301136,82.889836400128 55.1289912601165,82.8905425657728 55.1304842514839,82.8906670722712 55.130798917842,82.8906882725119 55.1308281400367,82.8908564371331 55.1308020506266,82.8917322945351 55.1306638997264,82.8966846168649 55.1298816176563,82.8973444294411 55.1297690914468,82.8975962272153 55.1297133674876,82.8978460486958 55.1296433144,82.9000052393127 55.1290349669866,82.9001772666896 55.1289593145243,82.9002950358234 55.1288544896604,82.9003733689161 55.128750178119,82.9016974856449 55.1281809024527,82.9022130287865 55.1280577911569,82.9135346759753 55.1252679884628,82.9184852016745 55.123547557492,82.9231268865791 55.1218945507728,82.9236243735835 55.1221334139591,82.9240301425973 55.1218558188441,82.9244853189518 55.1215970742137,82.9250907834533 55.1213239958707,82.9257361331534 55.1210933983516,82.9290945746746 55.1200253584842,82.9295466069256 55.1198637450386,82.9299053042185 55.1197181588129,82.9302140551817 55.1195676403857,82.931366054702 55.1188900949541,82.9316990601778 55.1187366965384,82.9320978223324 55.1185926987622,82.9325203898421 55.1184593346791,82.9599599691847 55.111458585023,82.9648070987948 55.1100429857656,82.9655358121532 55.1104930027568,82.9679672821328 55.1121640023132,82.968470877681 55.1124554348249,82.9689127589693 55.1126450292351,82.9734356865933 55.1141117607884,82.9736502941147 55.1142085065575,82.9738048941751 55.1142983160156,82.9746840753436 55.1146694201195,82.9777189436995 55.1151073113353,82.9790678539301 55.114876883434,82.9850706661532 55.1156949093117,82.9853540846254 55.1157494197989,82.990185673381 55.1166782444633,82.9911804677266 55.1166553310775,82.9908955221185 55.1172856498975,82.9897942774117 55.1184888227698,82.9852495207263 55.1195237176661,82.9867720753013 55.1210164465999,82.9850595270437 55.1223809055341,82.9803726568803 55.1223962645498,82.981538310793 55.1253654776745,82.9826912984602 55.1285612251055,82.9846086626026 55.1296398220141,82.9877666899839 55.1325720346388,82.9877665103209 55.1325721373485,82.9877666899839 55.1325721373485,82.9910494933582 55.1337388510485,82.9987683572685 55.1339694782559,82.9998730155734 55.1339117060344,83.0009244037819 55.1337093742174,83.001855687237 55.1334164534451,83.0025711055293 55.1329551913079,83.0030855706925 55.1323566518326,83.0045562924756 55.1282714509024,83.0029178552289 55.1281012936064,83.0027535533635 55.1215107228929,83.0030384091401 55.1196414612688,83.0057470992163 55.1195755002357,83.0036976827271 55.1138530687467,83.0032543641344 55.1126163589186,83.0031255457226 55.1123069442656,83.0028905464443 55.1118561256016,83.0003320546836 55.1069460654823,83.0006031662363 55.1068079348208,83.0006789840463 55.1067312124874,83.0006945249007 55.1066289500726,83.0006800620247 55.1065932866362,82.9998980785698 55.1046707028135,82.9992587475821 55.1033160201539,82.9984907778457 55.101856909784,83.000894489883 55.101457470896,83.0034051912706 55.1010393714894,83.0166899268498 55.0937072477905,83.0172797606653 55.0934283756168,83.0200181849774 55.0917621959364,83.019314983773 55.0913768447294,83.0203779602487 55.090738765701,83.0215893384094 55.0904162265523,83.0229333079059 55.0898781242884,83.0231318355837 55.0896142885656,83.0235783881115 55.0897768983567,83.0255275526149 55.0908284736885,83.0285923348698 55.0888115633283,83.0261596072488 55.0874328474402,83.0283387404651 55.0867119293016,83.030847465559 55.0878902653678,83.0325275846349 55.0868048339732,83.0370302103335 55.0841638304331,83.0360775469747 55.083486198735,83.0354037206801 55.0828742173631,83.0336445498592 55.081826186513,83.0352695123766 55.0804784942755,83.0373640242931 55.0788105921991,83.0387455433685 55.0795369493473,83.0451810740639 55.0779485627039,83.0478235583037 55.0765113598975,83.0479194085445 55.0764594700838,83.0511401383327 55.0748599039933,83.0536304479633 55.0744842643721,83.055809311685 55.0740505566821,83.059458088706 55.0728484628757,83.059604963255 55.0728166781057,83.0602567808251 55.0725702681346,83.0606163764333 55.07240095362,83.0609411174085 55.071457675561,83.0610807156037 55.0712932425349,83.0631366897945 55.0700720862949,83.0634013334772 55.0699879381947,83.0637141268591 55.0699625805723,83.0648119579678 55.0700087694951,83.0650980713858 55.0699714788879,83.0674527354086 55.069148093425,83.0702962626089 55.0681169860127,83.0735177110493 55.0672744271573,83.075159382231 55.0667047897095,83.0753718337957 55.0666297393455,83.0862148586011 55.0637816309124,83.0838202195483 55.0589343496438,83.082265325623 55.0559626173594,83.080659317558 55.052543036057,83.0807362133463 55.0524920928574,83.0814139922282 55.0520335496862,83.0811840235155 55.0487293724604,83.0796052344036 55.0478185247381,83.0796363161125 55.0475148870721,83.0796664096745 55.0472340459138,83.07991299722 55.0449440645302,83.0797737583509 55.0449390721815,83.0790646282657 55.0410661602162,83.0786445760388 55.0381211562281,83.0776336120181 55.0235552010799,83.0759400182129 55.0235222957669,83.0725028842728 55.0090849176687,83.0725852597844 55.0089503124598,83.0729274280761 55.0076322599351,83.0729363213974 55.0074578282581,83.0721686211556 55.002467967741,83.0721953011195 55.0022932044709,83.0721689804817 55.0021296208262,83.071879183971 54.9977239464665,83.0726726658615 54.9969289619676,83.0730885858381 54.9967114566585,83.0736938706765 54.9966193218579,83.0743245778375 54.9966344715544,83.0765040703798 54.9969479247058,83.0775135970961 54.9969306624309,83.0783787645462 54.9968019938375,83.0804703120223 54.9962536146932,83.0820912321209 54.9944844456937,83.0782938737519 54.99301914863,83.0767868600312 54.9908344507998,83.0832875185848 54.9846255636165,83.083675500956 54.9846655625101,83.0862902272535 54.9846349448039,83.0868466437405 54.9846069558702,83.0873619173874 54.9850219941898,83.0876942940426 54.9851914205466,83.0881300667869 54.9852930657086,83.0944300417059 54.984949986483,83.0949313016345 54.984823598986,83.0952846988672 54.984617367962,83.0955202371347 54.984320003743,83.0955997380374 54.98398346252,83.0954314835847 54.983079235629,83.0956846288317 54.9830031522185,83.0960766536217 54.9828956248762,83.0970232084366 54.9826998996313,83.0973617834672 54.9826145884872,83.0976839193281 54.9824883998281,83.0979390408688 54.9823553033534,83.0992893884039 54.981354488268,83.099844637081 54.9808589943781,83.1002653181285 54.9801710044775,83.1004392319675 54.979699364248,83.1006895026057 54.9786866774044,83.1007890359392 54.9784198401703,83.1010080452054 54.9781669721055,83.1010566440623 54.9780802078337,83.1014640300437 54.977433259055,83.1016665103087 54.9772077602343,83.1019551390095 54.9769863329766,83.1060364548398 54.974847937577,83.1069173428074 54.9743597362055,83.1073609308947 54.9740511077966,83.1078602145296 54.9735327861561,83.1086328555055 54.9729379428609,83.109111837215 54.9725813007689,83.1096193853505 54.9720596086845,83.1097922212112 54.9721181305199,83.1102640163984 54.9723025639753,83.1112418325852 54.9727106141849,83.1125016299396 54.9720244955423,83.1107292538841 54.970527234347,83.1109823991311 54.9699760726603,83.111495606653 54.9691349035668,83.1117769589999 54.9688850709419,83.1120874167621 54.96869453707,83.1126586554513 54.9684795601493,83.1131776121909 54.9683420856985,83.1137565763916 54.9681888315552,83.114769876032 54.9679828244755,83.1165854610528 54.967726693549,83.1178908029921 54.9675915885972,83.1196603044388 54.9675101644392,83.1210226893987 54.9675190339565,83.1225468609412 54.9676043256101,83.1240793868159 54.9677608306824,83.1253708946999 54.9678981524232,83.1284041460883 54.968398240923,83.1302646468732 54.9687785886594,83.1312017693776 54.9690732834868,83.1319432388131 54.9694012352935,83.1325734968165 54.9696484864968,83.1331642289473 54.9698156573551,83.1339866365899 54.9699493626025,83.1347839812361 54.9700157252036,83.1351151002498 54.9700182518273,83.1353392299132 54.9700199018672,83.136560489542 54.9699613254105,83.137910657414 54.9697742514362,83.1386957849723 54.9695616006896,83.1392582201717 54.969346319022,83.1409397765521 54.9684084509554,83.1417746707771 54.9679427573938,83.1421154017644 54.9677989899816,83.1431760426203 54.9674040910486,83.1437794409967 54.9671256277275,83.1446205335972 54.9666502760647,83.1450840642838 54.9663329764727,83.1453898508065 54.9660324858273,83.1462634624204 54.9649477201312,83.1468481758388 54.9639889660541,83.1473283253581 54.963276241779,83.1475309852862 54.9629752125399,83.1481289937709 54.9616526066063,83.1487306853482 54.9606152755693,83.1491351967206 54.9601406205121,83.14952542488 54.9598215674656,83.1499689231358 54.9595670865464,83.1504750339669 54.9593516481564,83.151969381442 54.9587977542089,83.1524524954018 54.958618674469,83.1537512796396 54.9580637904143,83.1546388151403 54.9577690663942,83.1557237105089 54.9574718127996,83.1564233184522 54.9572800900278,83.1574270061191 54.9570458125337,83.1579092217637 54.956982626494,83.1583722134611 54.9569999059514,83.1589091365064 54.9570449356669,83.1605524246556 54.9566867597648,83.1608602773035 54.956566163531,83.1612551767024 54.9564715122556,83.1618310866311 54.9563789755889,83.1628216588949 54.9563833084141,83.1635036598586 54.9564830148476,83.1629793132272 54.9544903866833,83.1608766266417 54.9533706441368,83.1577898356624 54.9514916638925,83.1514580603823 54.9495107571271,83.1512762413688 54.9494282129274,83.1510893917897 54.9493255999327,83.1503483715118 54.9487719289174,83.149813065434 54.9483721481139,83.1489884120032 54.9475298043238,83.1489069348069 54.9473963340086,83.1465079838407 54.9440592773054,83.1466395870298 54.9437535119133,83.1470567646477 54.9430152486606,83.145950938533 54.9400280026132,83.1467371440696 54.9385822365939,83.147315209955 54.9357091274085,83.1449477898552 54.9317079832358,83.1442533921406 54.9311950507701,83.1438993660871 54.9305700054862,83.1433208510442 54.9282399616641,83.1435285415378 54.9276204452211,83.1442585125377 54.9267660006655,83.1472870926866 54.9237610796321,83.147402077043 54.9235814307843,83.1502611450977 54.9205049746514,83.1504324538224 54.9202669721186,83.1507050925111 54.9193400395095,83.1507783052068 54.9191560857123,83.1508833182635 54.919001921147,83.153023734091 54.9164856922847,83.1530509530441 54.9164314265415,83.1530698176651 54.916356301153,83.1530477191091 54.9152429316182,83.1525726899868 54.9149102004498,83.1427963247498 54.9089520707143,83.1363732806368 54.9046680258991,83.1350234720909 54.9037245679058,83.1333597023531 54.9030823096709,83.1326929727493 54.9025924614413,83.1304135875473 54.901391781244,83.1297410188941 54.9009923041227,83.1297197288219 54.9008853836623,83.1297623987979 54.9008130701465,83.140071734493 54.8870905735969,83.1401861798602 54.886938559703,83.1414627757105 54.8851970244609,83.1328019383932 54.8818856573269,83.1296264836954 54.8806711817483,83.1292417352592 54.8805031232685,83.1288453087243 54.8803057621847,83.1271646506593 54.8793786327679,83.123657448127 54.8773513284881,83.1235528842279 54.8752593156113,83.123418765756 54.8722768582615,83.1228786087757 54.8661261031165,83.1229136430717 54.8650695568049,83.1235655504734 54.8605579988391,83.1253127737011 54.8551642198042,83.1253336146156 54.8542115867165,83.1253989221368 54.8474797359345,83.1254064679852 54.8471377038503,83.1261540459646 54.8454585340719,83.126121976109 54.8449268643036,83.1260926910307 54.8444250327877,83.1260348395264 54.8434503693929,83.1246537696086 54.8286461236243,83.1189833340407 54.826667498172,83.1184080529327 54.8264442065532,83.1169246649041 54.825986752428,83.1160380277186 54.8257498988611,83.1141040447434 54.8253329048705,83.1128329286164 54.8251074323872,83.1126455400482 54.8250596157061,83.1120998135131 54.8248083702012,83.1117987880613 54.8247177040863,83.1099822148938 54.8243738230501,83.1098509710308 54.8243343373501,83.1091464223534 54.8242757556115,83.1083930053247 54.824346084738,83.1056895254771 54.8250725531254,83.1049690766192 54.8252117077454,83.1042084730682 54.8252554877907,83.0998140943613 54.8252017200925,83.0985482782945 54.8250342066025,83.0973819955611 54.8246757864643,83.0949416322602 54.8235342131647,83.0940448441121 54.8230293210048,83.0894862533713 54.8199523232893,83.0895400624568 54.818878418983,83.0976684683052 54.8222998659253,83.101776553931 54.8224418247644,83.1016114435818 54.821849817397,83.101578834737 54.8218134344599,83.1014577418367 54.8217448605562,83.1014255821495 54.8217034573882,83.101213669574 54.8206934657115,83.1010370607891 54.8207040755427,83.1006078457464 54.8183191741699,83.1005115463479 54.8172523175175,83.1028614492996 54.8176241056638,83.1029399620555 54.8172683112587,83.1029756251722 54.8169990565576,83.1029671810086 54.8168748840905,83.1002708876833 54.8164484297639,83.0999907929777 54.8159034374592,83.0998435591026 54.8156168852269,83.099743666443 54.8146453048148,83.099746541052 54.8142805290867,83.099694528597 54.8137190982789,83.0993078936987 54.8123684437225,83.0992668406902 54.8122966442878,83.0991616479704 54.8108065313243,83.0990104615081 54.8102103154436,83.0989733610869 54.8100798580736,83.09890419081 54.809949141437,83.0986018178854 54.8093914813958,83.0985525003763 54.8092365341973,83.0984938403882 54.8090411021189,83.0984651841307 54.8088880690819,83.0984200887034 54.8083126368963,83.0957140037415 54.8085126801076,83.0955372152936 54.8085547698187,83.0954207038013 54.8086007940651,83.0952768835243 54.8086822294142,83.0951031493483 54.8087385040955,83.094874438277 54.8087543976666,83.0946364745582 54.8087330681822,83.0943641951956 54.8086624530127,83.094126590803 54.8085809140821,83.0925483406803 54.8086975017596,83.0923028311131 54.8087377793071,83.0919453914616 54.8088188002162,83.0917124583084 54.8088566962023,83.0891735498209 54.8090441047911,83.0879384561368 54.8055532959358,83.0876171287597 54.8045173748394,83.0874712423575 54.8040781565739,83.0872803503596 54.8036721226638,83.0870670903112 54.8033206582399,83.0865437318267 54.8025787310361,83.0824753517364 54.8037445587496,83.0830353614845 54.8045580189855,83.0832764693068 54.80504652218,83.0834462508955 54.805617289391,83.0839363717145 54.808427465134,83.0841613098616 54.8090222577573,83.0847447656387 54.8101423948337,83.0850002465055 54.8109645785668,83.08553770854 54.8120336201785,83.0855884633535 54.8122847898627,83.0858094489134 54.8133777118182,83.0859451843528 54.8142535602949,83.085896765159 54.8149629732884,83.0855607952428 54.8162365208175,83.0851233156994 54.8174887033326,83.0828880377779 54.8213962963099,83.082434478391 54.8225984809136,83.0822168165976 54.8238314217418,83.0823327891008 54.8250512322561,83.0823316212909 54.8259321577264,83.081979212205 54.8268890291465,83.0814960982452 54.8277786596321,83.080681416114 54.8288947062671,83.0799121887362 54.8297948482603,83.0792339606967 54.830509990455,83.0783768780841 54.8311459032334,83.0774865578061 54.8317664388945,83.0767308949891 54.8321907653433,83.0758068878878 54.8326062915306,83.0746132963698 54.8330242969359,83.0741154500393 54.8331128748247,83.0736375463082 54.8331182557183,83.0732610623726 54.8330529605965,83.0728063351758 54.8327652882791,83.0726106821069 54.8327099783846,83.0724028119502 54.8327307260714,83.0712398529834 54.8331248783555,83.0709233765088 54.8331576810893,83.0706228002147 54.8331134439577,83.0702623062912 54.8328996563415,83.0700968366158 54.8328620933472,83.0699007343893 54.8328795813571,83.0693138650142 54.8330595315049,83.0687760436536 54.8331468158334,83.0685371816195 54.8331619754516,83.0683151180813 54.8331297935933,83.0678952455175 54.8329791800861,83.0677073179601 54.8329575012148,83.0675400516542 54.8329659347628,83.0666444313159 54.8331382271053,83.0663859860087 54.8331481093164,83.0653486115186 54.8330931103827,83.0651461312535 54.8330743807194,83.0649663783652 54.8330302987149,83.0646868226488 54.8329105216639,83.0645651907593 54.8328765287169,83.0644205619985 54.8328651459885,83.0636595092898 54.8328717686672,83.0633844451498 54.8328460023017,83.0631849293252 54.8327939521236,83.0629974509254 54.8326631020255,83.0629269331756 54.8325977544275,83.0627865264967 54.8325779379932,83.0619478593475 54.8325229382828,83.0617395400331 54.8324875997651,83.0608806607899 54.8322072705741,83.0607374693336 54.8321320397807,83.0606508717402 54.8320363712584,83.060581970958 54.8319309234844,83.0605092972515 54.8318094874584,83.0604837850974 54.8316538501257,83.060490342799 54.8315046281303,83.0604547695137 54.8313475925985,83.0603921569384 54.8312489729373,83.0602883116916 54.8312123397595,83.0601587746276 54.8311890042009,83.0582839007981 54.8311728090048,83.0580030874403 54.831125827377,83.0577309877408 54.8310303634383,83.0575162903879 54.8309324156503,83.0573933110255 54.8308385035227,83.0573321357546 54.8307556123062,83.0573022218556 54.830666615305,83.0573242305801 54.8305382937022,83.0573926822047 54.8304526595024,83.0574426285346 54.8303773736964,83.0574454133119 54.8303097457083,83.0573851363564 54.8302431524678,83.0572793148159 54.830215728646,83.0571273198698 54.8302146420414,83.0569992201103 54.8302461018211,83.0568750729381 54.8302956716215,83.0567616157177 54.830363403119,83.0566389956814 54.8304603174322,83.0564510681239 54.8305645272243,83.0562799390623 54.8305997639402,83.0561159066914 54.8306117164757,83.0559789136106 54.8305939170277,83.0558271881591 54.8305307910152,83.0556397097593 54.8305157338944,83.0554066867746 54.8305378797609,83.0552261254025 54.8305975907516,83.0551080867742 54.8306698750824,83.0549586969424 54.8308139776748,83.0548486533201 54.8308908149331,83.0547004312982 54.8309554409044,83.0545285835844 54.8309985420752,83.0543613172785 54.8310086317784,83.0541520996488 54.8309994216905,83.0539833960385 54.8309767586561,83.0538668845461 54.8309877797223,83.0537236930898 54.8310358480934,83.0536479651114 54.8311116500908,83.0536219139681 54.8312295180335,83.0534798004902 54.8313802415518,83.0533112765429 54.8315087157027,83.0531134675173 54.8315997287584,83.0529320078299 54.8316374998924,83.0527763297912 54.8316272551226,83.052631970525 54.8316480551071,83.0525332456753 54.8316989684568,83.0525035114394 54.8317581603193,83.0525458220893 54.8318531568682,83.0525412406813 54.8319737649096,83.0523552894175 54.8321788132753,83.0522481204041 54.8322482490491,83.0521072645676 54.8322807937931,83.0519783563243 54.8322965746214,83.0518613058428 54.8323588700276,83.0517138923047 54.8325074162436,83.0517013158907 54.8325716257067,83.0517497350845 54.8326511500974,83.051800310235 54.8327124101589,83.0518100120401 54.8327816380557,83.0517603352048 54.8328574367752,83.0514971288266 54.8331577328286,83.0513791800298 54.8332260286558,83.0512489243136 54.8332551060865,83.0511311551799 54.8333045687142,83.0510433897766 54.8333846090513,83.0510053910401 54.833507592505,83.0510424914613 54.8336165543936,83.0510282082483 54.8337063727094,83.0509740398367 54.833782738816,83.0507544017497 54.8339813107126,83.0505597368276 54.8340722147176,83.0504240013882 54.8341440271846,83.0503674075253 54.8342143391233,83.0503524954916 54.8342967575976,83.0503292291257 54.8344488148432,83.050192595371 54.834626947186,83.0497394851417 54.8349775184465,83.0490920693164 54.8353257585187,83.047571491035 54.8360322146264,83.0474145553549 54.8360844675714,83.0472363296025 54.8360840019514,83.045944731887 54.8356636483689,83.04566984741 54.8356978459132,83.0455645648588 54.8357870387667,83.0455676191307 54.8358477767108,83.0456568218384 54.8359630440399,83.0493697385708 54.8369422857025,83.0494809500029 54.8369916920777,83.0495245182942 54.8370708973553,83.049508168956 54.8371395487013,83.0492457710615 54.8375175687539,83.0492241216632 54.8375777867575,83.0492408303275 54.8376264163512,83.0493052395334 54.8376697173338,83.0496147989803 54.8377584402293,83.0497037321934 54.8377621133013,83.0498030858638 54.8377382641944,83.0499120515078 54.8377278657725,83.0501606153469 54.8377391436628,83.0503359664903 54.83773609139,83.0504736782234 54.8377046374471,83.0511607097527 54.8378346952035,83.0511707708839 54.8381831692901,83.0513348930863 54.8383822885984,83.051828696998 54.8385958919811,83.0524497023539 54.838840481727,83.0533996707668 54.8395201313226,83.0543129879162 54.8401281229706,83.0547050127062 54.8405180646348,83.0549558223335 54.8409029330525,83.0552980804568 54.8416052567249,83.0549919346079 54.8421218140114,83.053363827987 54.8432212737837,83.0530544482032 54.8433315543341,83.052654069081 54.8434389896462,83.0522816275642 54.8435000264317,83.0517677013902 54.8435415624288,83.047944651204 54.8434274029917,83.0417833761648 54.843080525983,83.0411180838654 54.8429586062307,83.0400531310961 54.8417687701161,83.0414517181619 54.8387796448221,83.0429728354325 54.8358307038737,83.0436984046875 54.8342880139005,83.0437018182856 54.8342809258133,83.043713945542 54.8341143812753,83.0435801863961 54.8340146818708,83.0433499481888 54.8339883471141,83.0431659732186 54.8340272542535,83.0430661703906 54.8341026884674,83.0403256799533 54.8397655948917,83.0398453507709 54.8406436645703,83.0397108729728 54.841025428037,83.0395476490857 54.8413722709824,83.0394100271842 54.8416251721845,83.039333490722 54.8418123252956,83.0392642306136 54.8419036772176,83.0391890416243 54.8419780621519,83.0390982219491 54.8420369803023,83.0386352302516 54.842291273984,83.0378931319954 54.8426989888657,83.0377682661709 54.8427436810356,83.0375921963753 54.8427695445372,83.0374141502859 54.842776217318,83.037251465388 54.8427645787462,83.0357838877083 54.8424883556578,83.0342966369239 54.8419810106479,83.0337406695946 54.8418543285832,83.0331741919764 54.8417899787011,83.0326597268132 54.8417764258993,83.0152388781713 54.840784576059,83.014023816918 54.8407700400581,83.0129051448947 54.840793939103,83.0117105652299 54.840813648045,83.010572759091 54.8408875694239,83.0095293658885 54.8409931489893,83.0079822873062 54.8411989792048,83.0059793137172 54.841543906702,83.0042249937989 54.8419497669253,83.0020179229773 54.8425786197777,82.9999896168973 54.8433354338039,82.9982096949933 54.8441401829529,82.9899752879415 54.8482692484934,82.989853835715 54.8482557495877,82.9897110035849 54.8482554909879,82.9895930547881 54.8483089176654,82.9895337659793 54.848376929258,82.9895685307808 54.8484459751301,82.9897543922131 54.8485923933639,82.9874732103806 54.8496849017643,82.9872012903441 54.8494990781242,82.9845175734328 54.8508052041665,82.9844185790885 54.8507979638299,82.984300181134 54.8508033940825,82.9841541150688 54.8508467843605,82.9818368209619 54.8521807411229,82.981768998158 54.852210166903,82.9816987499027 54.8522293014058,82.9816205066415 54.8522388169389,82.9815925690362 54.8522409372476,82.9815474736089 54.8522516422191,82.981498695089 54.8522524179416,82.9814220687952 54.8522393858022,82.978060393339 54.8505058668788,82.9737649191449 54.8482904536619,82.9733595992887 54.8481121747398,82.972655320106 54.8478854847378,82.9721121986852 54.8477556662529,82.9717149636666 54.8476821194997,82.9713626444121 54.8476404326025,82.9710927006693 54.8476267783241,82.9710918921855 54.8475952286479,82.970717115049 54.8475764022721,82.9693026278026 54.8470996368913,82.9690192093305 54.8469610232045,82.9688416123988 54.8468230814248,82.9686991395947 54.8466539508151,82.9685147154669 54.8462108459446,82.9684902812912 54.8461267449494,82.9684096125786 54.8460575916626,82.9682936400755 54.8460149203533,82.9681736251535 54.8459745765284,82.9680893631799 54.8459126124726,82.9678688267776 54.8454716201253,82.9678443027703 54.8453910865196,82.9677598611336 54.8453298456996,82.9672396467526 54.8451021055849,82.967125291217 54.844944709156,82.9670844178715 54.844771536168,82.9671202606514 54.8446218454176,82.9672611164879 54.8444207913486,82.9673051339368 54.8443298589246,82.9672735132388 54.8442342710361,82.9666254685929 54.8438987288581,82.9664642209994 54.8438344856871,82.9662451219016 54.8438055710543,82.9655761465095 54.8437893291942,82.9651180057146 54.8437562247458,82.964605516845 54.8436848949122,82.9614636591388 54.8429558647132,82.9610991227965 54.8428379792826,82.9606914673206 54.842643589128,82.9605641760448 54.8425182540534,82.9604649122059 54.8423041541543,82.9604175709904 54.8422083028287,82.9603068985474 54.84212988355,82.9601442136495 54.8420791385398,82.9586228268843 54.8417855818002,82.9581095295309 54.8415748403677,82.9579132476414 54.8414643998304,82.9577976344643 54.841328094582,82.9577511017326 54.8411939097625,82.9576626176771 54.8407873694536,82.9576284816963 54.8407168103164,82.9575316433087 54.8406623907216,82.9573860264011 54.8406428886246,82.9566021564842 54.8405756399421,82.9563117311528 54.8405121674289,82.9560445721873 54.8404009997631,82.9558119085287 54.8402566210114,82.9554958812118 54.839898129079,82.9550986461932 54.8396126782472,82.9549624615961 54.839549876724,82.9547709407775 54.8395056465975,82.9543864618359 54.8394940588137,82.9541747289234 54.8394561398371,82.9536035800658 54.8392880647082,82.9533304922194 54.8391476653106,82.9528606733258 54.8388510350583,82.9526878374652 54.8387710572924,82.9520241621332 54.8385955815871,82.9518046138778 54.8384986868037,82.951115785718 54.8381197964801,82.950874049075 54.8378843074194,82.9507419967282 54.8375880817509,82.9507278931783 54.8374021506625,82.9507741564154 54.8371916450103,82.9510588325289 54.8369208158975,82.9508198806633 54.8367934971326,82.9505187653801 54.8368855329643,82.9502684049104 54.8368955177271,82.9491967147765 54.8368285214733,82.948949947568 54.8367851678536,82.9486345490717 54.8366931835279,82.9483912852927 54.8365787977776,82.9482305766884 54.8364335775904,82.9481738031625 54.836318311605,82.9481935660987 54.8361955436563,82.9483946090593 54.8360114686365,82.9481177482887 54.8358897344705,82.9479765331261 54.8359477820022,82.9478351383003 54.83597111481,82.947674429696 54.8359758227585,82.9464235256629 54.8359051517375,82.9462026299345 54.8358618488619,82.9459320573709 54.8357477194356,82.9457361348075 54.8356267087802,82.9456292352887 54.8354869692181,82.945614502918 54.835364767842,82.9456724442538 54.8352772813629,82.9458661210291 54.8351960548346,82.9453870494881 54.8350297210199,82.945222298465 54.8351061880967,82.9449673565873 54.8351423521103,82.944612162724 54.8351423003735,82.9435914070666 54.8350637121538,82.9433354770422 54.8349897283706,82.9431322781249 54.8348650421076,82.9430405601344 54.8347250412221,82.9430442432271 54.834595025183,82.943094728546 54.834471941567,82.9425807125405 54.8343138310835,82.9423387064029 54.8342922564047,82.9413497511066 54.8342800462696,82.9409905148245 54.8342470374961,82.9406581381694 54.8341749665223,82.9384934678292 54.833490570417,82.938362852787 54.833387144263,82.938318835338 54.8332625565281,82.9383542289602 54.833125706185,82.9384471147606 54.8329989445838,82.938716968672 54.8328297560306,82.9382513718602 54.8326855571536,82.9380928192125 54.8327605282164,82.9379164799223 54.8328004713345,82.9376603702348 54.8328274794826,82.9360448400278 54.8328499345192,82.9354733318441 54.8328377756876,82.9350833731792 54.8328044552961,82.9347757001944 54.8327389527074,82.9344637152962 54.8326332998087,82.9335098841275 54.8329567768609,82.9330779741389 54.8330677580739,82.9326102213705 54.833253812607,82.9295479543985 54.8326664133816,82.9287545623395 54.8332353934534,82.9279052950699 54.8337614225461,82.9272697370064 54.8379609242879,82.9278202246125 54.8411529403686,82.9272551842988 54.8438348477665,82.9270514463924 54.8445204650501,82.9270495599303 54.8445484481259,82.9261242053561 54.8475495074341,82.9264492158259 54.8530514558734,82.9265209912171 54.8552336677483,82.9264843399535 54.8579319096258,82.9264505632988 54.8579855820262,82.9264015152843 54.8580284475046,82.9257694606504 54.8582943262096,82.9256962479547 54.8583581844084,82.9256460321304 54.8584418462519,82.9256333658849 54.8585423643313,82.9256646272567 54.8586422616805,82.9267474565002 54.8609451578974,82.9268104284017 54.8611311873301,82.9268490559589 54.861323368586,82.9271062436247 54.8639254550311,82.9271211556584 54.8639925613996,82.9271642747921 54.8640382639781,82.9270914214225 54.8641350457379,82.9270620465127 54.864197860698,82.9270509972347 54.8642666209949,82.9272552741303 54.8653474864332,82.9272987525901 54.8670594307286,82.9273274986792 54.8675627383467,82.9293040617988 54.8674460621093,82.9296148788871 54.8673944701165,82.9299694439298 54.8673594723042,82.9330277583146 54.8671756428236,82.9334712565703 54.8671581179784,82.9413438222258 54.8666001105177,82.9413455290248 54.8689743544859,82.9413545121777 54.8694179330331,82.9413660106133 54.8699781759466,82.9414197298673 54.8726054448882,82.9414277248733 54.8727209173564,82.9414617710226 54.872780927761,82.9415127054992 54.8728255349203,82.9416427815523 54.8728819269827,82.9418333142241 54.8729031709014,82.9421444906385 54.872920331431,82.9561443750154 54.8727438670824,82.9664891043327 54.8726647835121,82.9764935518204 54.8726634912956,82.9764929229997 54.8715961580162,82.9786972988754 54.8715871122601,82.9786967598863 54.8706148625608,82.9812988199382 54.8705911879443,82.9812863333558 54.8689829355879,82.9855287171166 54.8689151655099,82.9905294586402 54.8688482224148,82.9906262970278 54.8733992726612,82.9908849219982 54.8734226871902,82.991257543178 54.8734902946279,82.9920898322887 54.8736411187631,82.9925285694735 54.8736917207026,82.9930214750699 54.8737085707725,82.9947218062397 54.873676214497,82.9974977801307 54.8734730309658,82.9977230776039 54.8736495438095,83.0008816439744 54.877497435072,83.0009096714113 54.8775158340241,83.0037419696706 54.8799917602068,83.0050939341732 54.8808622879871,83.0051474737641 54.8808198602065,83.00528770078 54.8807520066716,83.0071623051149 54.8800636459974,83.0072725284002 54.8800331552751,83.0076773990988 54.8803847274057,83.0084428535524 54.8800921728895,83.0085170543948 54.88006845216,83.0088619176324 54.880025196676,83.0090505638421 54.8799846801472,83.011420050067 54.8793027147041,83.0116542408616 54.8795704686537,83.0127734518741 54.8792480887522,83.0134551833432 54.8801550663466,83.0137996872546 54.8805105133086,83.0139777333439 54.8806872537248,83.0141580252215 54.8808659054572,83.0144395572315 54.8813245980335,83.0148636518771 54.8823158129976,83.0151277565707 54.8827628103611,83.0182430241445 54.887255659416,83.0185128780558 54.8877473476316,83.0212838213812 54.8932506839448,83.0215658923804 54.8938114221888,83.0218693432834 54.8946295260066,83.0239756231301 54.9005146205622,83.0246269017111 54.9023332795265,83.0251022003279 54.9033791907459,83.0265160587536 54.905442526048,83.0269080835436 54.9061829251705,83.0280623288521 54.9077893316619,83.0292645441969 54.9092763302598,83.0324169121919 54.9131749865801,83.0337536053347 54.9146375178744,83.0340340593664 54.9149002866298,83.0343278982958 54.9151466856412,83.0347062686935 54.91539168903,83.0352018692357 54.9157320579643,83.0354501635803 54.9159228429936,83.03560413482 54.9161710428945,83.036269696614 54.9177818524765,83.0363262904769 54.9179297744141,83.0364313035336 54.9180628262474,83.0365866222462 54.9182090949845,83.0367932347615 54.918397080251,83.0369857437269 54.9185567198921,83.037120221525 54.9187815153893,83.0373567479393 54.9195713874499,83.0384808098543 54.9237847746358,83.038589056846 54.924222484405,83.0388915196022 54.9248413820951,83.0389728171354 54.9249958856384,83.039433113887 54.9255695516387,83.0398412185206 54.9268243820076,83.0399501841645 54.9280065988583,83.0399359009515 54.928205326394,83.0398522677986 54.9287454990073,83.0398117537792 54.9289163499914,83.0394113746571 54.9297665164093,83.0393927795307 54.9298803798447,83.0393978100963 54.9299795326462,83.039515399567 54.9301193578109,83.0395322878944 54.9302040062533,83.0395003078702 54.9307929273752,83.0394594345248 54.9309568017893,83.0394041881348 54.9310782490739,83.0391362206856 54.9313804463143,83.0390547434893 54.9314740211907,83.0388173187597 54.932130277927,83.0388129170149 54.9322932178733,83.0388003406009 54.9330166591342,83.0387942320569 54.9331373260329,83.0387619825382 54.9332300710464,83.0379436173144 54.9348174898217,83.0379005880123 54.9349387706227,83.0378807352445 54.9350383238238,83.0377163435475 54.9366573576715,83.0376529224884 54.9368569197755,83.0371368403577 54.9383400062287,83.0370690175538 54.9384616892405,83.0368063501647 54.9388632715291,83.0367158898156 54.9390276806998,83.0366110564219 54.9393910194866,83.0365537439068 54.9394700236938,83.0357590043749 54.9400717096889,83.0356768085264 54.9401510221711,83.0356070094289 54.940230231293,83.035428693845 54.9406018154551,83.0353842272384 54.9406946980588,83.0348949149032 54.9412487383322,83.0308255466661 54.9405717833674,83.0298390168211 54.9414058104826,83.0268749357096 54.9411288697836,83.0266570942532 54.9410910463577,83.0220080431633 54.9403879266436,83.0209588109114 54.9401971028063,83.0039578348334 54.9396224069417,83.0029601658788 54.9394602707334,83.0028862345309 54.9394554200539,83.0016793479467 54.9395181176224,82.9993123770046 54.939505320102,82.9975625486627 54.9395122348917,82.9958104745325 54.9394047458982,82.9928801700757 54.9392787310713,82.9907442458247 54.9389709167809,82.9867280578524 54.9389631246367,82.97817564719 54.9385871389829,82.9588944774262 54.9378918710457,82.955727287229 54.9376459725456,82.9372170516421 54.9368142413327,82.9366999813645 54.9339197424768,82.9366861473091 54.9337101533903,82.9364435123509 54.9326403598212,82.9361909959245 54.9311831796455,82.9251737877855 54.9273584305635,82.9224316803807 54.9267099421089,82.9220249232201 54.926500057353,82.9213396883214 54.9269407831041,82.9212906403069 54.9270461890394,82.9182846977031 54.9289857741265,82.9174705545611 54.9294613649424,82.9172518147894 54.9295772422521,82.9170642465581 54.9296503299515,82.9168548492654 54.9297075199514,82.9166041294696 54.9297621807146,82.9163467621407 54.9297964533365,82.916042502754 54.9298271128561,82.9139599384308 54.9299904750539,82.9089019742236 54.9304278076183,82.907643344679 54.9305759411395,82.9054738234363 54.930704925249,82.9000263497219 54.931186018393,82.8925565886398 54.9318119315215,82.892478075884 54.9318252992309,82.8922055270268 54.9318925506128,82.8878476199205 54.9322275671413,82.88627008845 54.9322534764839,82.8857144804468 54.9322626634579,82.8854799303261 54.9322832567236,82.8776300920474 54.9327637116504,82.8775286722518 54.9327712985497,82.8773734433707 54.9328036073702,82.8772446249589 54.9328526382783,82.877192612504 54.9329164299808,82.8771809344053 54.9330032918208,82.8771518289901 54.933346505218,82.8771202981236 54.9334345531754,82.8770221122631 54.9335072725915,82.8768777529969 54.933558212232,82.8747020333788 54.9341282982747,82.874683707747 54.9340357101624,82.8746498412608 54.9339364125296,82.8745980983004 54.9338610617715,82.8744964988418 54.9337937104606,82.8743479174938 54.9337238817411,82.8739092701405 54.9335803015393,82.873902892102 54.9335421097387,82.8737403868671 54.9322976049074,82.8736183956515 54.9316107959907,82.8722128017265 54.9309451370499,82.8711087722423 54.9301648821783,82.8710504715804 54.9301020667962,82.8697610298215 54.9291158472764,82.8697221327697 54.9290784254807,82.8697063224207 54.9290465782148,82.8694275751881 54.9284213446927,82.8694771621918 54.9278218071779,82.8660435316813 54.9278324404652,82.8657732286123 54.928160574071,82.8657094482271 54.9285041901123,82.8650980548447 54.9285951908346,82.8652133086957 54.9288523970947,82.8641797969613 54.9291840838956,82.8635889749989 54.9295508666443,82.86377241098 54.9298853865251,82.8640624769852 54.9304684798728,82.8625398325786 54.9307542167862,82.8626071163934 54.9308765937343,82.8629387743963 54.9314806276823,82.8629986021942 54.9315615571163,82.8630677724711 54.9316260218359,82.8631942552631 54.9316944606486,82.8632036875736 54.9316974541988,82.8628864026152 54.9333883615688,82.8468290169116 54.9345452517983,82.8467673924831 54.9346042411605,82.8395243661788 54.9351236844335,82.8393905172014 54.9351444310598,82.8392872109438 54.9351882982691,82.8392156152156 54.9352519314418,82.8369469199656 54.9382194065445,82.8337668838598 54.9414808891025,82.8332677798879 54.9419616985485,82.8331306071441 54.9420463736668,82.8323687459516 54.9423220180636,82.8322556480573 54.9424118007425,82.8317831342179 54.943161994267,82.8317846613539 54.9432486791837,82.8316408410769 54.9433131251703,82.8300923251901 54.9440048939582,82.8299706034691 54.943891896066,82.8298356765134 54.9437720353976,82.827709543899 54.9448574244386,82.8238393321604 54.9469931343658,82.8232291065879 54.9473299340385,82.8231887722316 54.9473512934815,82.8225129696434 54.9477101716992,82.8224671555639 54.9477365353983,82.8223289946732 54.947725339857,82.8221968524949 54.9477395277544,82.8220605780663 54.9477813691247,82.8205108943697 54.948537653412,82.8198879127201 54.9486931493524,82.8191845318527 54.9489869597144,82.8176340396723 54.9499269320825,82.8170768147016 54.9501781207567,82.8168374136783 54.9502621595006,82.8102042536204 54.9547854442511,82.8061128766589 54.9575149335337,82.80393652822 54.958985807708,82.8030032684714 54.9585287732502,82.8021444790597 54.9589896244731,82.8020673137768 54.9590137629253,82.8019698465685 54.9590262963467,82.8018773200942 54.9590210869828,82.8014836783368 54.9589207679111,82.8014119029455 54.9589218510489,82.8013412055327 54.9589374275995,82.8012886540886 54.9589608955698,82.8007465208146 54.9593555680417,82.80067043351 54.9594063202058,82.8001579446404 54.9597479672519,82.7999811561925 54.9599004283719,82.7998960857351 54.9600686713315,82.7998279934366 54.9605926337788,82.7980247153353 54.9617050578248,82.7938443153291 54.96361527732,82.7906529604507 54.9653724505173,82.7865251118887 54.9678583946562,82.7863153552698 54.9680278418825,82.7765117710796 54.9738434293431,82.7734462701726 54.9758857260116,82.7674439969387 54.9796000762886,82.7673041292489 54.9796888477779,82.762198105174 54.9829297491167,82.7561791232758 54.9867598303463,82.7507523108129 54.9885144963879,82.7520408542565 54.9911738721697,82.7523551747744 54.9916841841683,82.7523955091306 54.9917477794525,82.7528471820555 54.9924731399271,82.7581874867565 54.9972321585879,82.7584720730385 54.9974510523445,82.7644834192568 55.0027389214354,82.7770908251118 55.0132987131325,82.7780848109736 55.0142931689784,82.7784150316721 55.0147953064994,82.7788720944886 55.0156898569738,82.778868591059 55.0157937941215,82.7788214295066 55.0158886146441,82.778734113261 55.0159958475776,82.7786256866062 55.0160915432002,82.7784043417202 55.0161830152288,82.7791320669319 55.0167147437669,82.77970618023 55.0178489439407,82.7772894426211 55.0208850453531,82.7775053077839 55.0224076702671,82.7777741735484 55.0227926559948,82.778531632996 55.0226180842731,82.7812429281865 55.0229128989067,82.7871355171242 55.0227447647132,82.7920469661086 55.0270632983267,82.7921129024505 55.0271160760385,82.7922147714037 55.0271631897421,82.7923847326554 55.02721200257,82.7924745641838 55.0272474793664,82.7928437717656 55.0274466946402,82.792501783137 55.0275815981919,82.791486866529 55.0281458711414,82.7914451846998 55.0281831492278,82.7914344049164 55.0282265544699,82.7914463525096 55.0282768591815,82.7914912682739 55.0283465751258,82.7931388683365 55.0299274056716,82.7936154245947 55.030602906857,82.7946678907815 55.0316017730696,82.7964982081729 55.0309059519357,82.8046557194365 55.0367373985273)),((82.9787077193327 55.1550160072868,82.9703274258787 55.1529353521526,82.9584325637071 55.1500425699936,82.9553282555798 55.1491731441705,82.9529740407147 55.1492486043274,82.9527849453474 55.1492707803463,82.9526314232653 55.1493053276847,82.9494126697708 55.1501323502076,82.945238288477 55.1539059137476,82.9438570388962 55.1553182647826,82.9429668084496 55.1561056940844,82.9414717423222 55.1585900850946,82.9427303718668 55.1602326430893,82.9463741183223 55.1602132444051,82.9464709567099 55.1601980025752,82.9465589017762 55.1601686479233,82.9504019843932 55.1578425309899,82.9517266401112 55.1584354535022,82.9522687733851 55.1586979624718,82.9535170723039 55.1593976187015,82.9524655942639 55.1600146896052,82.9527464076217 55.1601716244449,82.9508559929378 55.1612808251579,82.9561203001658 55.1642213355692,82.9520667422777 55.1665895660541,82.9352430936367 55.1766579395493,82.9340355782318 55.1774758796701,82.9331104033207 55.1782912894999,82.9282269817732 55.1849454175237,82.9282044340595 55.1849760874083,82.9301216185389 55.1850407607833,82.9301374288879 55.1850726614895,82.9316851362909 55.1882852702865,82.93638997276 55.1918662631937,82.9382074442428 55.1926789685354,82.9371160810041 55.1937919823363,82.9357702250455 55.1954011978282,82.9357373467061 55.1956271103989,82.9358349037459 55.1958342043419,82.9371416829897 55.1973217727351,82.937311734073 55.1974418504541,82.9375451163838 55.1975176807314,82.9392439204176 55.1978168474558,82.95574615185 55.200084391499,82.9665696832137 55.1964225626646,82.9725474324404 55.1972859339264,82.9729573337045 55.1973882205697,82.9733691214308 55.1975328057526,82.9736219073517 55.1976744166889,82.9738568167985 55.1978267427349,82.9742496500723 55.1979883481892,82.9755838279322 55.1989201302983,82.9763523366578 55.1988062606597,82.9772434654196 55.1987777034773,82.9780761138565 55.1987642195582,82.9790609369025 55.1987626301986,82.9811575149441 55.1987720638159,82.982093200144 55.1988002108454,82.9828272135627 55.1988315878385,82.9834082438884 55.1988366122566,82.9839865792683 55.1987838045647,82.9847515845643 55.1986647562876,82.9854422093547 55.1984660853515,82.986113250872 55.1982417782647,82.9867500665769 55.1979876816706,82.9891259308403 55.197077001746,82.9896969000349 55.1968799123238,82.9990862710476 55.1910331319885,83.0043325221384 55.1862953316855,83.0045330261098 55.1859720765151,83.0045688688896 55.1855687090553,83.0037598461447 55.1834119444811,83.0037808667224 55.1829958311943,83.0039982590211 55.1826108981723,83.0076976111927 55.1792057331062,83.0079733041534 55.1787873701941,83.0080991581247 55.1783396103188,83.0080572068009 55.1778734299538,83.0070053694347 55.1761292063256,83.0068128604694 55.1752516280942,83.0068666695549 55.1744760682159,83.0070342053553 55.1741251683265,83.0074682713006 55.1739037509588,83.0087368721449 55.1734181777496,83.0089830105327 55.1732845350623,83.0090449044558 55.1730810176794,83.0087239364048 55.1715934674682,83.0086565627585 55.1708559051753,83.0087901422412 55.1701933906276,83.0105389824363 55.1671776379754,83.0130063850272 55.1586019403297,83.0092605899555 55.1562253827985,82.9968573711646 55.1573383885212,82.9967507411404 55.1565177255919,82.9963105666512 55.1529648661142,82.9927774028072 55.1531554487874,82.9920627929987 55.1533983851975,82.9912164901695 55.1536166828056,82.9903965978097 55.1537937632231,82.9903022747049 55.1538091614831,82.9898440440784 55.1538840995971,82.9887929253645 55.1540080551409,82.9874977343879 55.154094541493,82.9844060026745 55.154275931251,82.9814661760757 55.1544495185265,82.9811022685541 55.154482316274,82.9806571533308 55.1545456533189,82.9801641579029 55.1546329084024,82.9796968542921 55.1547432601464,82.9792057453263 55.1548678802605,82.9787077193327 55.1550160072868)))\"},\"adm_divs\":[],\"attributes\":{\"area\":4951911635480,\"length\":null,\"houses_count\":null,\"abbreviation\":null,\"city_description\":\"City\"}}]}}';\n                latlng = new DG.latLng(54.98017192278902, 82.89799869060518);\n                clock = sinon.useFakeTimers();\n                xhr = sinon.useFakeXMLHttpRequest();\n                requests = [];\n                xhr.onCreate = function (req) { requests.push(req); };\n\n                map.fire('click', {latlng: latlng});\n                map.geoclicker.getController()._hasCatalogKey = true;\n            });\n\n            after(function () {\n                clock.restore();\n                xhr.restore();\n                requests = xhr = clock = null;\n            });\n\n            it('should send request', function() {\n                clock.tick(300);\n                expect(requests.some(function (request) {\n                    return request.url.indexOf('items/geocode') !== -1;\n                })).to.be(true);\n            });\n\n                it('should request url contain lat and lng', function() {\n                var geoSearchRequstUrl = '';\n\n                requests.forEach(function (request) {\n                    if (request.url.indexOf('items/geocode') !== -1) {\n                        geoSearchRequstUrl = request.url;\n                    }\n                });\n\n                expect(geoSearchRequstUrl).to.contain(latlng.lat);\n                expect(geoSearchRequstUrl).to.contain(latlng.lng);\n            });\n\n            it('should open popup', function() {\n                var popup = mapContainer.getElementsByClassName('leaflet-popup');\n                expect(popup.length).to.be(1);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGLabel/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>DGLabel demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            var map = new DG.Map('map', {\n                center: new DG.LatLng(54.980206086231, 82.898068362003),\n                zoom: 12,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            var markerStatic = DG.marker([54.950206086231, 82.898068362003], {\n                                riseOnHover : true,\n                                draggable : true\n                            });\n            markerStatic.addTo(map);\n            markerStatic.bindLabel( 'Многострочная<br/>подсказка!');\n\n            var marker = DG.marker([54.950206086231, 82.938068362003], {\n                                riseOnHover : true,\n                                label : 'Подсказка'\n                            });\n            marker.addTo(map);\n\n            var standaloneLabel = DG.label('Статический тултип');\n            standaloneLabel.setPosition(new DG.LatLng(54.980206086231, 82.898068362003));\n            map.addLayer(standaloneLabel);\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGLabel/skin/basic/less/dg-label.less",
    "content": ".dg-label {\n    position: absolute;\n    top: 0;\n    left: 0;\n    max-width: none;\n    max-height: none;\n    width: 300px;\n    user-select: none;\n}\n\n.dg-label__content {\n    display: inline-block;\n    overflow: hidden;\n    padding: 3px 7px;\n    min-width: 30px;\n    max-width: 300px;\n    width: auto;\n    border-width: 1px;\n    border-style: solid;\n    border-radius: 2px;\n    vertical-align: top;\n    font-size: 12px;\n}\n\n.dg-label_name_location-error {\n    .leaflet-top & {\n        top: 5px;\n    }\n    .leaflet-right & {\n        right: 40px;\n        left: auto;\n        text-align: right;\n    }\n    .leaflet-bottom & {\n        top: 4px;\n    }\n    .leaflet-left & {\n        left: 40px;\n    }\n}\n"
  },
  {
    "path": "src/DGLabel/skin/dark/less/dg-label.less",
    "content": ".dg-label__content {\n    border-color: #323232;\n    border-color: rgba(50, 50, 50, .85);\n    background: #323232;\n    background: rgba(50, 50, 50, .85);\n    color: #ffd26e;\n}\n"
  },
  {
    "path": "src/DGLabel/skin/light/less/dg-label.less",
    "content": ".dg-label__content {\n    border-color: #bebdb5;\n    border-color: rgba(151, 151, 151, .6);\n    background: #fff;\n    background: rgba(255, 255, 255, .85);\n    color: #727170;\n}\n"
  },
  {
    "path": "src/DGLabel/src/DGLabel.Layer.js",
    "content": ""
  },
  {
    "path": "src/DGLabel/src/DGLabel.js",
    "content": "DG.Label = DG.Layer.extend({\n\n    options: {\n        offset: new DG.Point(12, 15),\n        className: 'dg-label',\n        zIndexOffset: 0,\n        textDirection: 'auto' // 'auto' | 'ltr' | 'rtl\n    },\n\n    _typeOfString : Object.prototype.toString.call('s'),\n    _defaultZIndex: 100,\n\n    initialize: function(content, options) {\n        DG.Util.setOptions(this, options);\n\n        this._animated = DG.Browser.any3d;\n        this._content = content;\n    },\n\n    onAdd: function(map) {\n        this._map = map;\n\n        if (!this._el) {\n            this._initDOM();\n        }\n\n        this._visible = true;\n\n        this\n            .setContent(this._content)\n            ._onViewReset();\n\n        map\n            .on('viewreset', this._onViewReset, this)\n            .on('zoomanim', this._onZoomAnimation, this);\n    },\n\n    onRemove: function(map) {\n        map\n            .off('viewreset', this._onViewReset, this)\n            .off('zoomanim', this._onZoomAnimation, this);\n\n        this._visible = false;\n\n        this._el.removeChild(this._container);\n        DG.Util.falseFn(this._container.offsetWidth); // we need reflow here\n        this._container = null;\n\n        map.getPanes().tooltipPane.removeChild(this._el);\n        this._el = null;\n    },\n\n    _initDOM: function() {\n        this._el = DG.DomUtil.create(\n            'div',\n            this.options.className + ' leaflet-zoom-' + (this._animated ? 'animated' : 'hide'),\n            this._map.getPanes().tooltipPane);\n        this._el.style.zIndex = this._defaultZIndex + this.options.zIndexOffset;\n\n        this._container = DG.DomUtil.create('div', this.options.className + '__content', this._el);\n        this._container.setAttribute('dir', this.options.textDirection);\n\n        DG.DomEvent\n            .disableClickPropagation(this._el)\n            .on(this._container, 'mousewheel', DG.DomEvent.stopPropagation)\n            .on(this._container, 'contextmenu', DG.DomEvent.stopPropagation);\n    },\n\n    _onViewReset: function() {\n        if (this._visible && this._latlng) {\n            DG.DomUtil.setPosition(this._el, this._map.latLngToLayerPoint(this._latlng).add(this.options.offset), DG.Browser.ie);\n        }\n    },\n\n    _onZoomAnimation: function(opt) {\n        if (this._latlng) {\n            DG.DomUtil.setPosition(this._el, this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).add(this.options.offset));\n        }\n    },\n\n    setOffset: function(point) {\n        if (point instanceof DG.Point) {\n            this.options.offset = point;\n            this._onViewReset();\n        }\n        return this;\n    },\n\n    setZIndexOffset: function(zIndex) {\n        if (!isNaN(+zIndex)) {\n            this.options.zIndexOffset = +zIndex;\n            if (this._visible) {\n                this._el.style.zIndex = this._defaultZIndex + this.options.zIndexOffset;\n            }\n        }\n        return this;\n    },\n\n    setContent: function(content) {\n        if (Object.prototype.toString.call(content) !== this._typeOfString) {\n            return this;\n        }\n        this._content = content;\n        if (this._visible) {\n            this._container.innerHTML = content;\n        }\n        return this;\n    },\n\n    setPosition: function(latlng) {\n        if (!(latlng instanceof DG.LatLng)) {\n            return this;\n        }\n\n        this._latlng = latlng;\n        this._onViewReset();\n        return this;\n    }\n});\n\nDG.label = function(content, options) {\n    return new DG.Label(content, options);\n};\n"
  },
  {
    "path": "src/DGLabel/src/Entrance.DGLabel.js",
    "content": "DG.Entrance.include({\n    bindLabel: function(content, options) {\n\n        if (!this._label) {\n            this._label = DG.label(content, options);\n            this.on(this._labelEvents, this);\n        } else {\n            this._label.setContent(content);\n\n            if (this._label.options.offset !== options.offset) {\n                this._label.setOffset(options.offset);\n            }\n        }\n        return this;\n    },\n\n    unbindLabel: function() {\n        if (this._label) {\n            this.off(this._labelEvents, this);\n            this._map.removeLayer(this._label);\n            this._label = null;\n        }\n        return this;\n    },\n\n    getLabel: function() {\n        return this._label ? this._label : null;\n    },\n\n    _labelEvents : {\n        mouseover: function(event) {\n            this._map.addLayer(this._label.setPosition(event.latlng));\n            DG.DomEvent.stop(event);\n        },\n        mousemove: function(event) {\n            this._label.setPosition(event.latlng);\n            DG.DomEvent.stop(event);\n        },\n        mouseout: function() {\n            this._label.remove();\n        },\n        remove: function() {\n            this._label.remove();\n        }\n    }\n});\n\nDG.Entrance.addInitHook(function() {\n    if (typeof this.options.label !== 'undefined') {\n        this.bindLabel(this.options.label);\n    }\n});\n"
  },
  {
    "path": "src/DGLabel/src/Marker.DGLabel.js",
    "content": "DG.Marker.include({\n\n    bindLabel: function(content, options) {\n        if (this._label) {\n            this._label.setContent(content);\n            if (options) {\n                if (this.options.offset !== options.offset) {\n                    this._label.setOffset(this.options.offset = options.offset);\n                }\n                if (this.options.static !== options.static) {\n                    this.unbindLabel().bindLabel(content, options);\n                }\n            }\n        } else {\n            options = DG.extend({\n                offset: new DG.Point(5, 5)\n            }, options);\n\n            this._label = DG.label(content, options);\n\n            this.once('remove', this._onMarkerRemove);\n\n            if (options.static) {\n                this.showLabel();\n            } else {\n                this\n                    .on('mouseover', this._mouseOverLabel)\n                    .on('mouseout', this._mouseOutLabel)\n                    .on('dragstart', this._dragStartLabel)\n                    .on('dragend', this._dragEndLabel);\n            }\n\n            if (typeof this._map !== 'undefined') {\n                this._updateLabelZIndex();\n            } else {\n                this.once('add', this._updateLabelZIndex);\n            }\n        }\n        return this;\n    },\n\n    unbindLabel: function() {\n        if (this._label) {\n            this\n                .hideLabel()\n                .off('remove', this.unbindLabel)\n                .off('mouseover', this._mouseOverLabel)\n                .off('mouseout', this._mouseOutLabel)\n                .off('dragstart', this._dragStartLabel)\n                .off('dragend', this._dragEndLabel)\n                .off('move', this._updatePosition)\n                .off('add', this._updateLabelZIndex);\n\n            this._label = null;\n        }\n        return this;\n    },\n\n    _onMarkerRemove: function() {\n        if (this._label) {\n            var content = this._label._content;\n            this.once('add', function() {\n                if (this._label) { return; } // new label added after removing marker\n                this.bindLabel(content);\n            });\n            this.unbindLabel();\n        }\n    },\n\n    getLabel: function() {\n        return this._label ? this._label : null;\n    },\n\n    _originalUpdateZIndex: DG.Marker.prototype._updateZIndex,\n    _updateZIndex: function(offset) {\n        if (!this._zIndex) {\n            this._zIndex = 0;\n        }\n        this._originalUpdateZIndex(offset);\n        this._updateLabelZIndex();\n        return this;\n    },\n\n    _updateLabelZIndex: function() {\n        if (this._label && this._icon) {\n            this._label.setZIndexOffset(this._icon.style.zIndex);\n        }\n        return this;\n    },\n\n    showLabel : function() {\n        if (this._label) {\n            this\n                .on('move', this._updatePosition)\n                ._map.addLayer(this._label.setPosition(this.getLatLng()));\n        }\n\n        return this;\n    },\n\n    hideLabel : function() {\n        if (this._label) {\n            this\n                .off('move', this._updatePosition)\n                ._map.removeLayer(this._label);\n        }\n        return this;\n    },\n\n    _updatePosition : function() {\n        this._label.setPosition(this.getLatLng());\n    },\n\n    _dragStartLabel: function() {\n        this._label.isMarkerDragging = true;\n\n        this.hideLabel();\n    },\n\n    _dragEndLabel: function() {\n        this._label.isMarkerDragging = false;\n\n        if (this._label.isMouseOverMarker) {\n            this.showLabel();\n        }\n    },\n\n    _mouseOverLabel: function() {\n        this._label.isMouseOverMarker = true;\n\n        if (!this._label.isMarkerDragging) {\n            this.showLabel();\n        }\n    },\n\n    _mouseOutLabel: function() {\n        this._label.isMouseOverMarker = false;\n\n        this.hideLabel();\n    }\n});\n\nDG.Marker.addInitHook(function() {\n    if (typeof this.options.label !== 'undefined') {\n        this.bindLabel(this.options.label);\n    }\n});\n"
  },
  {
    "path": "src/DGLabel/src/Path.DGLabel.js",
    "content": "DG.Path.include({\n    bindLabel: function(content, options) {\n\n        if (!this._label) {\n            this._label = DG.label(content, options);\n            this.on(this._labelEvents, this);\n        } else {\n            this._label.setContent(content);\n\n            if (this._label.options.offset !== options.offset) {\n                this._label.setOffset(options.offset);\n            }\n        }\n        return this;\n    },\n\n    unbindLabel: function() {\n        if (this._label) {\n            this.off(this._labelEvents, this);\n            this._map.removeLayer(this._label);\n            this._label = null;\n        }\n        return this;\n    },\n\n    getLabel: function() {\n        return this._label ? this._label : null;\n    },\n\n    _labelEvents : {\n        mouseover: function(event) {\n            this._map.addLayer(this._label.setPosition(event.latlng));\n            DG.DomEvent.stop(event);\n        },\n        mousemove: function(event) {\n            this._label.setPosition(event.latlng);\n            DG.DomEvent.stop(event);\n        },\n        mouseout: function(event) {\n            this._map.removeLayer(this._label);\n            DG.DomEvent.stop(event);\n        },\n        remove: function() {\n            this._map.removeLayer(this._label);\n        }\n    }\n});\n\nDG.Path.addInitHook(function() {\n    if (typeof this.options.label !== 'undefined') {\n        this.bindLabel(this.options.label);\n    }\n});\n"
  },
  {
    "path": "src/DGLabel/test/DGLabelSpec.js",
    "content": "describe('DG.Label', function () {\n    var map,\n        mapContainer = document.createElement(\"div\");\n\n    after(function() {\n        mapContainer = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: new DG.LatLng(69.349552990994837, 87.75222519148015),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n    });\n\n    afterEach(function () {\n        map && map.remove();\n        map = null;\n    });\n\n    describe('\"DG.Label\" class', function(){\n        var label = DG.label();\n        it('it should have \"onAdd()\" public method', function(){\n            expect(label.onAdd).to.be.a('function');\n        });\n        it('it should have \"onRemove()\" public method', function(){\n            expect(label.onRemove).to.be.a('function');\n        });\n        it('it should properly merge options object passed to constructor', function(){\n            var labelWithOptions = DG.label('', { className: \"test-class\" });\n            expect(labelWithOptions.options.className).to.eql('test-class');\n        });\n        describe('#setContent and #setPosition', function(){\n            it('should return \"DG.Label\" instance', function(){\n                expect(label.setContent('ra-ta-ta')).to.be.a(DG.Label);\n                expect(label.setPosition( new DG.LatLng(54.980206086231, 82.898068362003) )).to.be.a(DG.Label);\n\n                expect(label.setContent( null )).to.be.a(DG.Label);\n                expect(label.setPosition( null )).to.be.a(DG.Label);\n            });\n        });\n    });\n\n    describe('\"DG.label()\" factory', function(){\n        it(' should return \"DG.Label\" instance', function(){\n            var label = DG.label();\n            expect(label).to.be.a(DG.Label);\n        });\n    });\n\n    describe('mixins into \"DG.Marker\"', function(){\n        it('#bindLabel should return \"DG.Marker\" instance', function(){\n            var marker = DG.marker([54.950206086231, 82.898068362003]).addTo(map);\n\n            expect(marker.bindLabel()).to.be.a(DG.Marker);\n        });\n        it('#unbindLabel should return \"DG.Marker\" instance', function(){\n            var marker = DG.marker([54.950206086231, 82.898068362003]).addTo(map),\n                markerWithLabel = DG.marker([54.950206086231, 82.898068362003]).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(marker.unbindLabel()).to.be.a(DG.Marker);\n            expect(markerWithLabel.unbindLabel()).to.be.a(DG.Marker);\n        });\n        it('#showLabel should return \"DG.Marker\" instance', function(){\n            var marker = DG.marker([54.950206086231, 82.898068362003]).addTo(map),\n                markerWithLabel = DG.marker([54.950206086231, 82.898068362003]).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(marker.showLabel()).to.be.a(DG.Marker);\n            expect(markerWithLabel.showLabel()).to.be.a(DG.Marker);\n        });\n        it('#hideLabel should return \"DG.Marker\" instance', function(){\n            var marker = DG.marker([54.950206086231, 82.898068362003]).addTo(map),\n                markerWithLabel = DG.marker([54.950206086231, 82.898068362003]).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(marker.hideLabel()).to.be.a(DG.Marker);\n            expect(markerWithLabel.hideLabel()).to.be.a(DG.Marker);\n        });\n        it('#getLabel should return \"DG.Label\" instance after #bindLabel call', function(){\n            var markerWithLabel = DG.marker([54.950206086231, 82.898068362003])\n                                        .addTo(map)\n                                        .bindLabel('ra-ta-ta');\n\n            expect(markerWithLabel.getLabel()).to.be.a(DG.Label);\n        });\n        it('#getLabel should return null after #unbindLabel call and before #bindLabel call', function(){\n            var marker = DG.marker([54.950206086231, 82.898068362003]).addTo(map),\n                markerWithLabel = DG.marker([54.950206086231, 82.898068362003]).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(marker.getLabel()).to.be(null);\n            expect(markerWithLabel.unbindLabel().getLabel()).to.be(null);\n        });\n    });\n\n    describe('mixins into \"DG.Path\"', function(){\n        it('#bindLabel should return \"DG.Path\" instance', function(){\n            var path = DG.circle([55.0, 83.0], 900).addTo(map);\n\n            expect(path.bindLabel()).to.be.a(DG.Path);\n        });\n        it('#unbindLabel should return \"DG.Path\" instance', function(){\n            var path = DG.circle([55.0, 83.0], 900).addTo(map),\n                pathWithLabel = DG.circle([55.0, 83.0], 900).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(path.unbindLabel()).to.be.a(DG.Path);\n            expect(pathWithLabel.unbindLabel()).to.be.a(DG.Path);\n        });\n        it('#getLabel should return \"DG.Label\" instance after #bindLabel call', function(){\n            var pathWithLabel = DG.circle([55.0, 83.0], 900)\n                                        .addTo(map)\n                                        .bindLabel('ra-ta-ta');\n\n            expect(pathWithLabel.getLabel()).to.be.a(DG.Label);\n        });\n        it('#getLabel should return null after #unbindLabel call and before #bindLabel call', function(){\n            var path = DG.circle([55.0, 83.0], 900).addTo(map),\n                pathWithLabel = DG.circle([55.0, 83.0], 900).addTo(map).bindLabel('ra-ta-ta');\n\n            expect(path.getLabel()).to.be(null);\n            expect(pathWithLabel.unbindLabel().getLabel()).to.be(null);\n        });\n    });\n\n});\n"
  },
  {
    "path": "src/DGLocale/demo/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"it\">\n<head>\n    <title>DGLocale demo</title>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n</head>\n<body>\n\n<div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n\n<script type=\"text/javascript\">\n    var map;\n    DG.then(function () {\n\n       // plugin code\n       // {APP_CORE}/src/{Plugin}/{Plugin}.js\n        DG.LocaleExample = DG.Control.extend({\n\n            includes: DG.Locale,\n            options: {\n                position: 'topright'\n            },\n            statics: {\n                Dictionary: {}\n            },\n\n            _container: null,\n\n            onAdd: function (map) {\n                this._container = DG.DomUtil.create('div', 'locale-example');\n                this._renderTranslation();\n                return this._container;\n            },\n\n            //this function will be called every time when we change language\n            _renderTranslation:function () {\n                this._container.innerHTML = '<h1>' + this.t(\"{n} people\", 16700000) + ' ' + this.t(\"regularly use 2GIS\") + '</h1>';\n            }\n        });\n\n        //{APP_CORE}/src/{Plugin}/lang/it.js\n        DG.LocaleExample.Dictionary.it = DG.extend({\n            \"{n} people\" : [\"{n} utente\", \"{n} utenti\"],\n            \"regularly use 2GIS\" : \"utilizzano regolarmente 2GIS\"\n        }, DG.Dictionary.it);\n\n        //{APP_CORE}/src/{Plugin}/lang/ru.js\n        DG.LocaleExample.Dictionary.ru = DG.extend({\n            \"{n} people\" : [\"{n} пользователь\", \"{n} пользователя\", \"{n} пользователей\"],\n            \"regularly use 2GIS\" : \"регулярно используют 2GIS\"\n        }, DG.Dictionary.ru);\n\n        //{APP_CORE}/src/{Plugin}/demo/index.html\n        map = new DG.Map('map', {\n            center: new DG.LatLng(54.980206086231, 82.898068362003),\n            zoom: 13,\n            key: DG.config.key || 'Your API access key'\n        });\n        map.addControl(new DG.LocaleExample());\n        var langMenu = DG.DomUtil.get('langMenu');\n        langMenu.onchange = function() {\n            map.setLang(this.options[this.selectedIndex].value);\n        }\n    });\n</script>\n\nИзменить язык карты: <select id=\"langMenu\" size=\"1\">\n    <option value=\"ru\" selected=\"selected\">ru</option>\n    <option value=\"it\">it</option>\n</select>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/DGLocale/src/DGDictionary.js",
    "content": "DG.Dictionary = {};\n\nDG.Dictionary.ru = {\n    pluralRules: function(n) { // (Number)\n        if (n % 10 === 1 && n % 100 !== 11) { // 1, 21\n            return 0;\n        }\n        if ((n % 10 >= 2 && n % 10 <= 4 && (n % 10) % 1 === 0) && (n % 100 < 12 || n % 100 > 14)) { // 2, 3\n            return 1;\n        }\n\n        if ((n % 10 === 0) || (n % 10 >= 5 && n % 10 <= 9 && (n % 10) % 1 === 0) || (n % 100 >= 11 && (n % 100) <= 14 && (n % 100) % 1 === 0)) { // 13, 17\n            return 2;\n        }\n    }\n};\n\nDG.Dictionary.en = {\n    pluralRules: function(n) { // (Number)\n        if (n === 1) { // 1\n            return 0;\n        } else {\n            return 1; //0, 2, 3, 4 ..\n        }\n    }\n};\n\nDG.Dictionary.it = {\n    pluralRules: function(n) { // (Number)\n        if (n === 1) { // 1\n            return 0;\n        } else {\n            return 1; //0, 2, 3, 4 ..\n        }\n    }\n};\n\nDG.Dictionary.cs = {\n    pluralRules: function(n) { // (Number)\n        return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2;\n    }\n};\n\nDG.Dictionary.es = {\n    pluralRules: function(n) { // (Number)\n        return (n >= 2) ? 1 : 0;\n    }\n};\n\n// Stub for Arabic language, we don't have cases with plural form usage\n// Actually Arabic has 6 plural forms\nDG.Dictionary.ar = {\n    pluralRules: function() {\n        return 0;\n    }\n};\n"
  },
  {
    "path": "src/DGLocale/src/DGLocale.js",
    "content": "DG.Locale = {\n    t: function(msg, argument) { // (String, Number) -> String\n        var result,\n            lang = this._map.getLang(),\n            msgIsset = false,\n            dictionaryMsg,\n            exp;\n\n        if (typeof this.constructor.Dictionary[lang] === 'undefined') {\n            if (lang === 'ar') {\n                lang = 'en';\n            } else {\n                lang = DG.config.defaultLang;\n            }\n        }\n        dictionaryMsg = this.constructor.Dictionary[lang][msg];\n        msgIsset = typeof dictionaryMsg !== 'undefined';\n        if (!msgIsset) {\n            return msg;\n        }\n        result = msgIsset ? dictionaryMsg : msg;\n\n        if (argument !== undefined) {\n            argument = parseInt(argument, 10);\n            argument = isNaN(argument) ? 0 : argument;\n            exp = this.constructor.Dictionary[lang].pluralRules(argument);\n            result = dictionaryMsg[exp];\n        }\n\n        result = DG.Util.template(result, {n: argument});\n        return result;\n    }\n};\n\nDG.Map.include({\n    setLang: function(lang) { // (String)\n        if (lang && Object.prototype.toString.call(lang) === '[object String]') {\n            this.options.currentLang = lang;\n            this.fire('langchange', {'lang': lang});\n        }\n    },\n\n    getLang: function() { // () -> String\n        // If the language hasn't been set before, set it to page language or\n        // default language from config\n        if (!this.options.currentLang) {\n            var root = document.documentElement;\n            var lang = root.lang || (root.getAttributeNS && root.getAttributeNS('http://www.w3.org/XML/1998/namespace', 'lang')) || DG.config.defaultLang;\n\n            this.options.currentLang = lang;\n        }\n\n        return this.options.currentLang;\n    }\n});\n"
  },
  {
    "path": "src/DGLocale/test/DGLocaleSpec.js",
    "content": "describe('DG Locale Module', function () {\n\tvar map,\n\t\tgetLangSpy,\n\t\tsetLangSpy;\n\n\tbeforeEach(function () {\n\t\tmap = new DG.Map(document.createElement('div'), {\n            center : new DG.LatLng(54.980206086231, 82.898068362003),\n            zoom: 10,\n            fullScreenControl: false,\n            key: window.__karma__.config.secretKey,\n        });\n\t\tgetLangSpy = sinon.spy(map, 'getLang');\n\t\tsetLangSpy = sinon.spy(map, 'setLang');\n\t});\n\n\tafterEach(function () {\n\t\tmap.remove();\n\t\tmap = null;\n\t\tgetLangSpy = null;\n\t\tsetLangSpy = null;\n\t});\n\n\tdescribe('getLang / setLang test cases', function () {\n        //Skip this check because it often fails\n\t\tit.skip('should return default language: ru', function () {\n\t\t\tmap.getLang();\n\n\t\t\texpect(getLangSpy.calledOnce).to.be.ok();\n\n\t\t\texpect(getLangSpy.returnValues).to.eql(['ru']);\n\t\t});\n\n\t\tit('should return language that was set: it', function () {\n\t\t\tmap.setLang('it');\n\n\t\t\tgetLangSpy.reset();\n\n\t\t\tmap.getLang();\n\n\t\t\texpect(setLangSpy.calledOnce).to.be.ok();\n\t\t\texpect(getLangSpy.calledOnce).to.be.ok();\n\t\t\texpect(getLangSpy.returnValues).to.eql(['it']);\n\t\t});\n\n\t\tit('should return default language (ru) if setLang was called with invalid argument: undefined, null, etc', function () {\n\t\t\tgetLangSpy.reset();\n\n\t\t\tmap.setLang(null);\n\t\t\tmap.getLang();\n\n\t\t\tmap.setLang(undefined);\n\t\t\tmap.getLang();\n\n\t\t\tmap.setLang('');\n\t\t\tmap.getLang();\n\n\t\t\tmap.setLang(5);\n\t\t\tmap.getLang();\n\n\t\t\tmap.setLang(['it']);\n\t\t\tmap.getLang();\n\n\t\t\tmap.setLang({lang: 'it'});\n\t\t\tmap.getLang();\n\n\t\t\texpect(getLangSpy.returnValues).to.eql(['ru', 'ru', 'ru', 'ru', 'ru', 'ru']);\n\t\t});\n\n\t\tit('should call langchange event when setting new lang through setLang method', function () {\n\t\t\tvar callback = sinon.spy(function () {\n\t\t\t\treturn 5;\n\t\t\t});\n\t\t\tmap.on('langchange', callback);\n\t\t\tmap.setLang('it');\n\n\t\t\texpect(setLangSpy.calledOnce).to.be.ok();\n\t\t\texpect(callback.calledOnce).to.be.ok();\n\t\t\texpect(callback.returnValues).to.eql([5]);\n\t\t});\n\t});\n\n\tdescribe('t() method test cases', function () {\n\t\tvar TestPlugin,\n\t\t\tplugin,\n            tSpy;\n\n\t\tbeforeEach(function () {\n\t\t\tTestPlugin = DG.Control.extend({\n\t\t\t    includes: DG.Locale,\n\t\t\t    options: {\n\t\t\t        position: 'topright'\n\t\t\t    },\n\t\t\t    statics: {\n\t\t\t\t\tDictionary: {}\n\t\t\t    },\n\t\t\t    onAdd: function () {\n\t\t\t        return DG.DomUtil.create('div', 'locale-example');\n\t\t\t    }\n\t\t\t});\n\n\t\t\tTestPlugin.Dictionary.ru = DG.extend({\n\t\t\t\t'{n} people' : ['{n} пользователь', '{n} пользователя', '{n} пользователей'],\n\t\t\t\t'regularly use 2GIS' : 'регулярно используют 2GIS'\n\t\t\t}, DG.Dictionary.ru);\n\n\t\t\tTestPlugin.Dictionary.it = DG.extend({\n\t\t\t\t'{n} people' : ['{n} utente', '{n} utenti'],\n\t\t\t\t'regularly use 2GIS' : 'utilizzano regolarmente 2GIS'\n\t\t\t}, DG.Dictionary.it);\n\n\t\t\tplugin = new TestPlugin();\n\t\t\tmap.addControl(plugin);\n\t\t\ttSpy = sinon.spy(plugin, 't');\n\t\t});\n\n\t\tafterEach(function () {\n\t\t\tTestPlugin = null;\n\t\t\tplugin = null;\n\t\t\ttSpy = null;\n\t\t});\n\n\t\tit('should correctly get dictionary by lang', function () {\n\t\t\tplugin.t('{n} people', 123456);\n\t\t\tmap.setLang('it');\n\t\t\tplugin.t('{n} people', 1234560);\n\n\t\t\texpect(setLangSpy.calledOnce).to.be.ok();\n\t\t\texpect(tSpy.calledTwice).to.be.ok();\n\n\t\t\texpect(tSpy.returnValues).to.eql(['123456 пользователей', '1234560 utenti']);\n\t\t});\n\n\t\tit('should return source message for call with not existing lang: uk', function () {\n\t\t\tmap.setLang('uk');\n\t\t\tplugin.t('regularly use 2GIS');\n\n\t\t\texpect(TestPlugin.Dictionary).to.not.have.property('uk');\n\t\t\texpect(tSpy.calledOnce).to.be.ok();\n\t\t\texpect(tSpy.returnValues).to.eql(['регулярно используют 2GIS']);\n\t\t});\n\n\t\tit('should return source message for call with not existing message for lang: ru', function () {\n\t\t\tplugin.t('not existing message', 1);\n\n\t\t\texpect(tSpy.calledOnce).to.be.ok();\n\t\t\texpect(tSpy.returnValues).to.eql(['not existing message']);\n\t\t});\n\n\t\tit('should set second argument to 0 when it`s type is not Number', function () {\n\t\t\tplugin.t('{n} people', 'dds');\n\n\t\t\texpect(tSpy.calledOnce).to.be.ok();\n\t\t\texpect(tSpy.returnValues).to.eql(['0 пользователей']);\n\t\t});\n\n\t});\n\n});\n"
  },
  {
    "path": "src/DGLocation/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset='utf-8'>\n  <title>Leaflet.Control.Locate Demo</title>\n  <script src=\"http://maps.api.2gis.dev/2.0/loader.js\"></script>\n\n</head>\n<body>\n\n  <div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n\n  <script type=\"text/javascript\">\n\n  DG.then(function () {\n\n    map = new DG.Map('map', {\n        center: new DG.LatLng(54.980206086231, 82.898068362003),\n        zoom:15,\n        locationControl: true,\n        key: DG.config.key || 'Your API access key'\n    });\n\n    map.locationControl.setPosition('bottomleft');\n\n  });\n  </script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/DGLocation/lang/ar.js",
    "content": "DG.Control.Location.Dictionary.ar = {\n    cant_find : 'لم نستطع تحديد موقعك',\n    you_are_here : 'أنت هنا',\n    button_title : 'موقعي'\n};\n"
  },
  {
    "path": "src/DGLocation/lang/cs.js",
    "content": "DG.Control.Location.Dictionary.cs = {\n    cant_find : 'Nepodařilo se nám určit Vaši polohu',\n    you_are_here : 'Jste tady',\n    button_title : 'Určit Vaši polohu na mapě'\n};\n"
  },
  {
    "path": "src/DGLocation/lang/en.js",
    "content": "DG.Control.Location.Dictionary.en = {\n    cant_find : 'We can\\'t find you',\n    you_are_here : 'You are here',\n    button_title : 'Show your location'\n};\n"
  },
  {
    "path": "src/DGLocation/lang/es.js",
    "content": "DG.Control.Location.Dictionary.es = {\n    cant_find : 'No pudimos encontrarte',\n    you_are_here : 'Tú estás aquí',\n    button_title : 'Encontrarte en el mapa'\n};\n"
  },
  {
    "path": "src/DGLocation/lang/it.js",
    "content": "DG.Control.Location.Dictionary.it = {\n    cant_find : 'Non siamo riusciti a localizzarti',\n    you_are_here : 'Voi siete qui',\n    button_title : 'Trova la tua posizione sulla mappa'\n};\n"
  },
  {
    "path": "src/DGLocation/lang/ru.js",
    "content": "DG.Control.Location.Dictionary.ru = {\n    cant_find : 'Мы не смогли Вас найти',\n    you_are_here : 'Вы здесь',\n    button_title : 'Найти Вас на карте'\n};\n"
  },
  {
    "path": "src/DGLocation/skin/basic/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_locate {\n    &:after {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        margin: auto;\n        content: '';\n    }\n\n    .dg-control-round__icon_state_active&:after,\n    .no-touch .dg-control-round__icon_state_active&:hover:after,\n    .dg-control-round__icon_state_active&:active:after {\n        .notRepeatableBg('DGRoundControl__locateIconEnabled');\n    }\n}\n\n@keyframes DGLocation__locateIconRequestingAnim {\n    to {\n        transform: rotate(360deg);\n    }\n}\n"
  },
  {
    "path": "src/DGLocation/skin/basic/less/dg-location.less",
    "content": ".dg-location__pin {\n    .notRepeatableBgWithSizes('DGLocation__pin');\n\n    &_state_following {\n        .notRepeatableBg('DGLocation__pinFollowing');\n    }\n}\n"
  },
  {
    "path": "src/DGLocation/skin/dark/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_locate {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__locateIcon_dark');\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__locateIconHover_dark');\n    }\n\n    .dg-control-round__icon_state_requesting&:after,\n    .no-touch .dg-control-round__icon_state_requesting&:hover:after,\n    .dg-control-round__icon_state_requesting&:active:after {\n        .notRepeatableBgWithSizes('DGRoundControl__locateIconRequesting_dark');\n        animation: DGLocation__locateIconRequestingAnim 1s linear infinite;\n        image-rendering: optimizeQuality;\n    }\n}\n"
  },
  {
    "path": "src/DGLocation/skin/light/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_locate {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__locateIcon_light');\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__locateIconHover_light');\n    }\n\n    .dg-control-round__icon_state_requesting&:after,\n    .no-touch .dg-control-round__icon_state_requesting&:hover:after,\n    .dg-control-round__icon_state_requesting&:active:after {\n        .notRepeatableBgWithSizes('DGRoundControl__locateIconRequesting_light');\n        animation: DGLocation__locateIconRequestingAnim 1s linear infinite;\n        image-rendering: optimizeQuality;\n    }\n}\n"
  },
  {
    "path": "src/DGLocation/src/DGLocation.js",
    "content": "DG.Control.Location = DG.RoundControl.extend({\n\n    statics: {\n        Dictionary: {}\n    },\n\n    options: {\n        iconClass: 'locate',\n        position: DG.Browser.mobile ? 'bottomright' : 'topleft',\n        drawCircle: true,\n        follow: true,  // follow with zoom and pan the user's location\n        stopFollowingOnDrag: false, // if follow is true, stop following when map is dragged\n        metric: true,\n        onLocationError: function(/*err*/) {\n            // this event is called in case of any location error\n            // that is not a time out error.\n            // console.log(err.message);\n        },\n        onLocationOutsideMapBounds: function(/*context*/) {\n            // this event is repeatedly called when the location changes\n            // console.log(context.t('outsideMapBoundsMsg'));\n        },\n        locateOptions: {}\n    },\n\n    initialize: function(options) {\n        DG.Util.setOptions(this, options);\n\n        if (!navigator.geolocation) {\n            this._disable = true;\n            return;\n        }\n\n        this._event = undefined;\n\n        this._locateOptions = {\n            watch: true,  // if you overwrite this, visualization cannot be updated\n            setView: true,\n            maximumAge: Infinity,\n            maxZoom: Infinity\n        };\n        DG.extend(this._locateOptions, this.options.locateOptions);\n\n        this._resetVariables();\n\n        this.on({\n            'click': this._handleLocate,\n            'add': this._initLocate\n        });\n    },\n\n    _initLocate: function() {\n        this._layer = new DG.LayerGroup();\n        this._layer.addTo(this._map);\n\n        // event hooks\n        this._map.on({\n            'locationfound': this._onLocationFound,\n            'locationerror': this._onLocationError\n        }, this);\n    },\n\n    _handleLocate: function() {\n        if (this._active && (!this._event ||\n            (this._map.getBounds().contains(this._event.latlng) ||\n            this._isOutsideMapBounds()))) {\n            this._stopLocate();\n        } else {\n            this._locateOnNextLocationFound = true;\n\n            if (!this._active) {\n                this._map.locate(this._locateOptions);\n            }\n\n            this._active = true;\n\n            if (this.options.follow) {\n                this._startFollowing();\n            }\n\n            this._clearError();\n\n            if (this._event) {\n                this._visualizeLocation();\n            } else {\n                this.setState('requesting');\n            }\n        }\n    },\n\n    _onLocationFound: function(e) {\n        // no need to do anything if the location has not changed\n        if (this._event &&\n            (this._event.latlng.lat === e.latlng.lat &&\n             this._event.latlng.lng === e.latlng.lng &&\n             this._event.accuracy === e.accuracy)) {\n            return;\n        }\n\n        if (!this._active) {\n            return;\n        }\n\n        this._event = e;\n\n        if (this.options.follow && this._following) {\n            this._locateOnNextLocationFound = true;\n        }\n\n        this._visualizeLocation();\n    },\n\n    _startFollowing: function() {\n        this._following = true;\n        if (this.options.stopFollowingOnDrag) {\n            this._map.on('dragstart', this._stopFollowing, this);\n        }\n    },\n\n    _stopFollowing: function() {\n        this._following = false;\n        if (this.options.stopFollowingOnDrag) {\n            this._map.off('dragstart', this._stopFollowing, this);\n        }\n        this._visualizeLocation();\n    },\n\n    _isOutsideMapBounds: function() {\n        if (this._event === undefined) {\n            return false;\n        }\n        return this._map.options.maxBounds &&\n            !this._map.options.maxBounds.contains(this._event.latlng);\n    },\n\n    _visualizeLocation: function() {\n        if (this._event.accuracy === undefined) {\n            this._event.accuracy = 0;\n        }\n\n        var radius = this._event.accuracy;\n\n        if (this._locateOnNextLocationFound) {\n            if (this._isOutsideMapBounds()) {\n                this.options.onLocationOutsideMapBounds(this);\n            } else if (this._locateOptions.setView) {\n                var project = this._map.projectDetector.getProject();\n                var zoom = project ? project.maxZoom : DG.config.projectLeaveMaxZoom;\n                zoom = Math.min(this._locateOptions.maxZoom, zoom);\n                this._map.setView(this._event.latlng, zoom);\n            }\n            this._locateOnNextLocationFound = false;\n        }\n\n        // circle with the radius of the location's accuracy\n        var style = {\n            clickable: false,\n            color: '#FFF',\n            fillColor: '#FFF',\n            fillOpacity: 0.4,\n            weight: 0,\n            opacity: 0.3\n        };\n        if (this.options.drawCircle) {\n            if (!this._circle) {\n                this._circle = DG.circle(this._event.latlng, radius, style)\n                    .addTo(this._layer);\n            } else {\n                this._circle.setLatLng(this._event.latlng).setRadius(radius);\n            }\n        }\n\n        var markerClass = 'dg-location__pin';\n\n        markerClass += this._following ? (' ' + markerClass + 'state_following') : '';\n        // small inner marker\n        var m = {\n            icon: DG.divIcon({\n                className: markerClass,\n                iconSize: [20, 20]\n            })\n        };\n\n        if (!this._marker) {\n            this._marker = DG.marker(this._event.latlng, m)\n                .bindLabel(this.t('you_are_here'))\n                .addTo(this._layer);\n        } else {\n            this._marker.setLatLng(this._event.latlng);\n        }\n\n        DG.DomEvent.on(this._marker, 'click', function() {\n            this._map.fireEvent('dgLocateClick');\n        }, this);\n\n        if (!this._container) {\n            return;\n        }\n\n        this.setState('active');\n    },\n\n    _resetVariables: function() {\n        this._active = false;\n        this._following = false;\n    },\n\n\n    _stopLocate: function() {\n        this._map.stopLocate();\n        this._map.off('dragstart', this._stopFollowing);\n\n        this.setState();\n        this._resetVariables();\n\n        this._layer.clearLayers();\n        this._marker = undefined;\n        this._circle = undefined;\n        this._event = undefined;\n    },\n\n    _onLocationError: function(err) {\n        // ignore time out error if the location is watched\n        if (err.code === 3 && this._locateOptions.watch) {\n            return;\n        }\n\n        this._stopLocate();\n        this._error = DG.DomUtil.create('div', 'dg-label dg-label_name_location-error', this._container);\n        this._errorText = DG.DomUtil.create('div', 'dg-label__content', this._error);\n        this._errorText.innerHTML = this.t('cant_find');\n\n        var self = this;\n        setTimeout(function() {\n            self._clearError();\n        }, 3000);\n\n        //show location error\n        this.options.onLocationError(err);\n    },\n\n    _clearError: function() {\n        if (this._error) {\n            this._container.removeChild(this._error);\n            this._error = undefined;\n            this._errorText = undefined;\n        }\n    },\n\n    _renderTranslation: function() {\n        if (this._link) {\n            this._link.title = this.t('button_title');\n        }\n        if (this._marker) {\n            this._marker.bindLabel(this.t('you_are_here'));\n        }\n    }\n});\n\nDG.control.location = function(options) {\n    return new DG.Control.Location(options);\n};\n\nDG.Map.addInitHook(function() {\n    if (this.options.locationControl) {\n        this.locationControl = DG.control.location(this.options.locationControl);\n        this.addControl(this.locationControl);\n    }\n});\n"
  },
  {
    "path": "src/DGLocation/test/DGLocationSpec.js",
    "content": "describe('DG.Location', function () {\n    var mapContainer, position, map, control, classControl, classControlRequest,\n        classControlActive, container, classPin;\n    var left = 'leaflet-left', right = 'leaflet-right', top = 'leaflet-top', bottom = 'leaflet-bottom';\n\n    before(function () {\n        geolocate.use();\n\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        position = {lat: 54.910206086231, lng: 82.88806836200};\n        map = new DG.Map(mapContainer, {\n            center: [55.017493, 82.819576],\n            zoom: 15,\n            locationControl: true,\n            key: window.__karma__.config.secretKey,\n        });\n        control = DG.control.location();\n\n        classControl = 'dg-control-round__icon_name_locate';\n        classControlRequest = 'dg-control-round__icon_state_requesting';\n        classControlActive = 'dg-control-round__icon_state_active';\n        container = document.body.getElementsByClassName(classControl);\n        classPin = 'dg-location__pin';\n    });\n\n    after(function () {\n        geolocate.restore();\n        map.remove();\n        mapContainer.parentElement.removeChild(mapContainer);\n    });\n\n    function initTests() {\n        var locationControl;\n        describe('check init', function () {\n            it('should be html container on map', function () {\n                expect(container.length).to.be(1);\n\n                locationControl = container[0];\n            });\n        });\n\n        describe('check clicks', function () {\n            describe('click to enable', function () {\n                before(function () {\n                    happen.click(locationControl);\n                });\n\n                it('should change to request class', function () {\n                    expect(locationControl.className).to.contain(classControlRequest);\n                });\n\n                it('should change to active class', function () {\n                    geolocate.send(position);\n                    expect(locationControl.className).to.contain(classControlActive);\n                });\n\n                it('should change center map near coord', function () {\n                    expect(map.getCenter()).to.nearLatLng(DG.latLng(position));\n                });\n\n                it('should be location pin on map', function () {\n                    expect(document.body.getElementsByClassName(classPin).length).to.be(1);\n                });\n            });\n\n            describe('click to disable', function () {\n                before(function () {\n                    happen.click(locationControl);\n                });\n\n                it('should remove active class', function () {\n                    expect(locationControl.className).not.contain(classControlActive);\n                });\n\n                it('shouldn\\'t be location pin on map', function () {\n                    expect(document.body.getElementsByClassName(classPin).length).to.be(0);\n                });\n\n                it('should center map near coord', function () {\n                    expect(map.getCenter()).to.nearLatLng(DG.latLng(position));\n                });\n            });\n        });\n\n        describe('change position', function () {\n            before(function () {\n                geolocate.change(position);\n            });\n\n            it('should center map near coord', function () {\n                expect(map.getCenter()).to.nearLatLng(DG.latLng(position));\n            });\n        });\n    }\n\n    describe('check auto init from map options', function () {\n        initTests();\n    });\n\n    describe('check custom init', function () {\n        before(function () {\n            if (map.locationControl) {\n                map.locationControl.remove();\n            }\n\n            map.addControl(control);\n            container = document.body.getElementsByClassName(classControl);\n        });\n\n        initTests();\n\n        after(function () {\n            map.removeControl(control);\n        });\n    });\n\n    describe('#addTo', function () {\n        before(function () {\n            if (map.locationControl) {\n                map.locationControl.remove();\n            }\n            control.addTo(map);\n        });\n\n        initTests();\n\n        after(function () {\n            control.remove();\n        });\n    });\n\n    describe('#remove', function () {\n        before(function () {\n            if (map.locationControl) {\n                map.locationControl.remove();\n                control.addTo(map);\n            }\n            control.remove(map);\n        });\n\n        it('control not present',function () {\n            expect(container.length).to.be(0);\n        });\n    });\n\n    describe('position init property', function () {\n        var tmpControl, content;\n\n        before(function () {\n           if(map.locationControl){\n               map.locationControl.remove();\n           }\n           control.remove(map);\n        });\n\n        it('default', function () {\n            tmpControl = DG.control.location();\n            content = document.querySelector(classControl) == document.querySelector([top, left].join('.'));\n            expect(tmpControl.getPosition()).to.be('topleft');\n            expect(content).to.be.ok();\n\n        });\n\n        it('topleft', function () {\n            tmpControl = DG.control.location({position: 'topleft'});\n            content = document.querySelector(classControl) == document.querySelector([top, left].join('.'));\n            expect(tmpControl.getPosition()).to.be('topleft');\n            expect(content).to.be.ok();\n        });\n\n        it('topright', function () {\n            tmpControl = DG.control.location({position: 'topright'});\n            content = document.querySelector(classControl) == document.querySelector([top, right].join('.'));\n            expect(tmpControl.getPosition()).to.be('topright');\n            expect(content).to.be.ok();\n        });\n\n        it('bottomleft', function () {\n            tmpControl = DG.control.location({position: 'bottomleft'});\n            content = document.querySelector(classControl) == document.querySelector([bottom, left].join('.'));\n            expect(tmpControl.getPosition()).to.be('bottomleft');\n            expect(content).to.be.ok();\n        });\n\n        it('topleft', function () {\n            tmpControl = DG.control.location({position: 'bottomright'});\n            content = document.querySelector(classControl) == document.querySelector([bottom, right].join('.'));\n            expect(tmpControl.getPosition()).to.be('bottomright');\n            expect(content).to.be.ok()\n        });\n    });\n\n});\n"
  },
  {
    "path": "src/DGMeta/src/DGMeta.Layer.js",
    "content": "DG.Meta = {};\n\nDG.Meta.Layer = DG.Layer.extend({\n\n    options: {\n        tileSize: 256,\n\n        minZoom: 0,\n        maxZoom: 19,\n        zoomOffset: 0,\n        eventBubbling: 'transparent'\n        // maxNativeZoom: <Number>,\n        // detectRetina: <Number>,\n        // zoomReverse: <Number>\n        // attribution: <String>,\n        // zIndex: <Number>,\n        // bounds: <LatLngBounds>\n    },\n\n    initialize: function(source, options) { // (String, Object)\n        DG.TileLayer.prototype.initialize.call(this, null, options);\n        delete this._url;\n\n        this._currentTileKey = '';\n        this._currentTileData = [];\n        this._lastEntity = undefined;\n        this._dispatchMouseEvents = true;\n\n        this._origin = DG.Meta.origin(source, {\n            dataFilter: this.options.dataFilter\n        });\n    },\n\n    getOrigin: function() { // () -> Object\n        return this._origin;\n    },\n\n    onAdd: function(map) {\n        this._resetView();\n\n        map.metaLayers.push(this);\n\n        map.on('rulerstart', this._disableDispatchMouseEvents, this);\n        map.on('rulerend', this._enableDispatchMouseEvents, this);\n\n        var self = this;\n\n        if (DG.Browser.touchEnabled && this.options.isPoi) {\n            map.eachLayer(function(layer) {\n                if (layer instanceof L.TileLayer) {\n                    // On every tile will be load meta tile.\n                    layer.on('tileloadstart', self._onTileLoadStart, self);\n                    // Load metatiles for already loaded tiles.\n                    for (var tile in layer._tiles) {\n                        self._onTileLoadStart({\n                            coords: layer._tiles[tile].coords\n                        });\n                    }\n                }\n            });\n        }\n    },\n\n    onRemove: function(map) {\n        var self = this;\n\n        if (DG.Browser.touchEnabled && this.options.isPoi) {\n            map.eachLayer(function(layer) {\n                if (layer instanceof L.TileLayer) {\n                    // On every tile will be load meta tile.\n                    layer.off('tileloadstart', self._onTileLoadStart);\n                }\n            });\n        }\n\n        this._tileZoom = null;\n\n        var index = map.metaLayers.indexOf(this);\n        if (index !== -1) {\n            map.metaLayers.splice(index, 1);\n        }\n\n        map.off('rulerstart', this._disableDispatchMouseEvents, this);\n        map.off('rulerend', this._enableDispatchMouseEvents, this);\n    },\n\n    getEvents: function() {\n        return {\n            viewprereset: this._invalidateAll,\n            viewreset: this._resetView,\n            zoom: this._resetView,\n            moveend: this._onMoveEnd\n        };\n    },\n\n    setUrl: function(url) {\n        this._currentTileKey = '';\n        this._currentTileData = [];\n        this._lastEntity = undefined;\n        this._dispatchMouseEvents = true;\n        this._origin.setURL(url, true);\n    },\n\n    getHoveredObject: function(event) {\n        var tileSize = this.getTileSize(),\n            layerPoint = this._map.mouseEventToLayerPoint(event.originalEvent),\n            tileOriginPoint = this._map.getPixelOrigin().add(layerPoint),\n            tileCoord = tileOriginPoint.unscaleBy(tileSize).floor(),\n            mouseTileOffset = DG.point(tileOriginPoint.x % tileSize.x, tileOriginPoint.y % tileSize.y),\n            tileKey,\n            zoom = this._map.getZoom(),\n            self = this;\n\n        if (zoom > (this.options.maxZoom + this.options.zoomOffset) ||\n            zoom < (this.options.minZoom - this.options.zoomOffset) ||\n            !this._isValidTile(tileCoord)) {\n            return;\n        }\n\n        this._wrapCoords(tileCoord);\n\n        tileCoord.z = this._getZoomForUrl();\n        tileCoord.key = tileSize.x + 'x' + tileSize.y;\n        tileCoord.apiKey = self._map.options.key;\n        tileKey = this._origin.getTileKey(tileCoord);\n\n        if (tileKey === this._currentTileKey) {\n            self._lastEntity = self._getHoveredObject(mouseTileOffset);\n        } else {\n            this._origin.getTileData(tileCoord, function(tileData) {\n                self._currentTileKey = tileKey;\n                self._currentTileData = tileData;\n                self._lastEntity = self._getHoveredObject(mouseTileOffset);\n            });\n        }\n\n        return this._lastEntity;\n    },\n\n    _removeAllTiles: DG.GridLayer.prototype._removeAllTiles,\n    _getZoomForUrl: DG.TileLayer.prototype._getZoomForUrl,\n    getTileSize: DG.TileLayer.prototype.getTileSize,\n    _isValidTile: DG.GridLayer.prototype._isValidTile,\n    _wrapCoords: DG.GridLayer.prototype._wrapCoords,\n    _resetView: DG.GridLayer.prototype._resetView,\n    _resetGrid: DG.GridLayer.prototype._resetGrid,\n    _invalidateAll: DG.GridLayer.prototype._invalidateAll,\n    _pxBoundsToTileRange: DG.GridLayer.prototype._pxBoundsToTileRange,\n\n    // Fix for https://github.com/Leaflet/Leaflet/compare/0726f12bbf33fcb18fe8bb541d5e3212bb1f5ab2...c263f2d8b1bd962b60474376cc4816a688052513#diff-f1e6be67599c594731fff6191c710420L579\n    _onMoveEnd: function() {\n        if (!this._map || this._map._animatingZoom) { return; }\n\n        this._resetView();\n    },\n\n    _onTileLoadStart: function(e) {\n        var tileSize = this.getTileSize();\n        e.coords.key = tileSize.x + 'x' + tileSize.y;\n        this._origin.getTileData(e.coords);\n    },\n\n    _enableDispatchMouseEvents: function() {\n        this._dispatchMouseEvents = true;\n    },\n\n    _disableDispatchMouseEvents: function() {\n        this._dispatchMouseEvents = false;\n    },\n\n    mapEvents: {\n        mousemove: function(event) {\n            this._fireMetalayerEvent('mousemove', event);\n        },\n\n        mouseover: function(event) {\n            this._fireMetalayerEvent('mouseover', event);\n        },\n\n        mouseout: function(event) {\n            this._fireMetalayerEvent('mouseout', event);\n            this._currentTileKey = '';\n        },\n\n        click: function(event) {\n            var tileSize = this.getTileSize(),\n                layerPoint = this._map.mouseEventToLayerPoint(event.originalEvent),\n                tileOriginPoint = this._map.getPixelOrigin().add(layerPoint),\n                tileCoord = tileOriginPoint.unscaleBy(tileSize).floor(),\n                mouseTileOffset = DG.point(tileOriginPoint.x % tileSize.x, tileOriginPoint.y % tileSize.y);\n            tileCoord.z = this._getZoomForUrl();\n            tileCoord.key = tileSize.x + 'x' + tileSize.y;\n            var tileKey = this._origin.getTileKey(tileCoord);\n            var self = this;\n\n            // In this function the tile meta data are processed by metalayer.\n            var onTileData = function(currentTileData) {\n                self._currentTileData = currentTileData;\n                self._currentTileKey = tileKey;\n                self._lastEntity = self._getHoveredObject(mouseTileOffset);\n                self._mouseDown = false;\n\n                if (self._lastEntity) {\n                    event.entity = self._lastEntity;\n                    self._fireMetalayerEvent('click', event);\n                }\n            }\n\n            // For more information about the code below see:\n            // https://github.com/2gis/mapsapi/pull/501\n            this._origin.getTileData(tileCoord, function(tileData) {\n                if (tileData) {\n                    onTileData(tileData);\n                } else if (self._origin._requests[tileKey]) {\n                    DG.DomEvent.stop(event);\n                    self._origin._requests[tileKey].then(function() {\n                        delete event.originalEvent._stopped;\n                        onTileData(self._origin._tileStorage[tileKey]);\n                        if (!event.originalEvent._stopped) {\n                            var targets = event.eventTargets;\n                            for (var i = event.eventTargetsMapIndex; i < targets.length; i++) {\n                                targets[i].fire('click', event, true);\n                                if (\n                                    event.originalEvent._stopped ||\n                                    (targets[i].options.nonBubblingEvents &&\n                                    L.Util.indexOf(targets[i].options.nonBubblingEvents, 'click') !== -1)\n                                ) {\n                                    return;\n                                }\n                            }\n                        }\n                    });\n                }\n            });\n        },\n\n        dblclick: function(event) {\n            this._fireMetalayerEvent('dblclick', event);\n        },\n\n        mousedown: function(event) {\n            this._mouseDown = true;\n            this._fireMetalayerEvent('mousedown', event);\n        },\n\n        contextmenu: function(event) {\n            this._fireMetalayerEvent('contextmenu', event);\n        }\n    },\n\n    _fireMetalayerEvent: function(type, mouseEvent) {\n        if (!mouseEvent.entity || !this._dispatchMouseEvents) {\n            return;\n        }\n        this.fire(type, {\n            meta: mouseEvent.entity,\n            latlng: this._map.mouseEventToLatLng(mouseEvent.originalEvent)\n        });\n        var isDragging = type === 'mousedown' || (this._mouseDown && type === 'mousemove');\n        if (this.options.eventBubbling === 'layer' && !isDragging) {\n            DG.DomEvent.stop(mouseEvent);\n        }\n    },\n\n    _getHoveredObject: function(mouseTileOffset) {\n        if (!this._currentTileData) {\n            return;\n        }\n\n        for (var i = 0; i < this._currentTileData.length; i++) {\n            if (DG.PolyUtil.inside(mouseTileOffset, this._currentTileData[i].geometry, this._pointReduceHelper)) {\n                return this._currentTileData[i];\n            }\n        }\n    },\n\n    _pointReduceHelper: function(point) {\n        return [point.x, point.y];\n    },\n\n    _setView: function(center, zoom, noPrune, noUpdate) {\n        var tileZoom = Math.round(zoom),\n            tileZoomChanged = this._tileZoom !== tileZoom;\n\n        if (!noUpdate && tileZoomChanged) {\n            this._tileZoom = tileZoom;\n            this._resetGrid();\n        }\n    }\n});\n\nDG.Meta.layer = function(source, options) {\n    return new DG.Meta.Layer(source, options);\n};\n"
  },
  {
    "path": "src/DGMeta/src/DGMeta.Origin.js",
    "content": "DG.Meta.Origin = DG.Class.extend({\n\n    options: {\n        subdomains: '0123',\n        dataFilter: null\n    },\n\n    _url: false,\n\n    initialize: function(url, options) { // (String, Object)\n        this._url = url;\n        this._requests = {};\n\n        this._tileStorage = {};\n\n        options = DG.setOptions(this, options);\n\n        if (typeof options.subdomains === 'string') {\n            options.subdomains = options.subdomains.split('');\n        }\n    },\n\n    getTileData: function(coord, clb) { // (Object) -> Object\n        var tileKey = this.getTileKey(coord),\n            self = this,\n            callback = typeof clb === 'function' ? clb : function() {};\n\n        // if the tile meta data request in progress, this function returns false, it is therefore synchronous.\n        if (typeof this._tileStorage[tileKey] === 'undefined' && typeof this._requests[tileKey] === 'undefined') {\n            this._tileStorage[tileKey] = false;\n            var currentRequest = this._requests[tileKey] = this._requestData(coord).then(function(data) {\n                if (self._requests[tileKey] !== currentRequest) {\n                    callback(false);\n                    return;\n                }\n                self.setTileData(tileKey, self.options.dataFilter ? self.options.dataFilter(data, coord) : data);\n                delete self._requests[tileKey];\n                callback(self._tileStorage[tileKey]);\n            });\n        } else {\n            callback(this._tileStorage[tileKey]);\n        }\n    },\n\n    setTileData: function(key, data) { // (Object/String, Object) -> Object\n        if (typeof key !== 'string') {\n            key = this.getTileKey(key);\n        }\n\n        data.forEach(function(entity) {\n            if (entity.geometry.constructor !== Object) {\n                entity.geometry = DG.Wkt.toGeoJSON(entity.geometry);\n            }\n            if (!this._tileStorage[key]) {\n                this._tileStorage[key] = [];\n            }\n            this._tileStorage[key].push(entity);\n        }, this);\n\n        return this;\n    },\n\n    flush: function() { // () -> Object\n        this._tileStorage = {};\n        Object.keys(this._requests).forEach(function(tileKey) {\n            if (this[tileKey].abort) {\n                this[tileKey].abort();\n            }\n        }, this._requests);\n        this._requests = {};\n\n        return this;\n    },\n\n    setURL: function(url, flush) { // (String, Boolean) -> Object\n        this._url = url;\n        if (flush) {\n            this.flush();\n        }\n\n        return this;\n    },\n\n    getTileKey: function(coord) { // (Object)-> String\n        return [coord.x, coord.y, coord.z, coord.key].join(':');\n    },\n\n    _requestData: function(key) { // (String)\n        if (this._url) {\n            return this._performRequest(key);\n        } else {\n            return Promise.resolve([]);\n        }\n    },\n\n    _performRequest: function(coords) { // (Object) -> Promise\n        return DG.ajax(this._prepareURL(coords), {\n            type: 'get',\n            dataType: 'json'\n        });\n    },\n\n    _prepareURL: function(coords) { // (Object) -> String\n        return DG.Util.template(this._url, {\n            x: coords.x,\n            y: coords.y,\n            z: coords.z,\n            s: this._getSubdomain(coords),\n            key: coords.apiKey\n        });\n    },\n\n    _getSubdomain: DG.TileLayer.prototype._getSubdomain\n\n});\n\nDG.Meta.origin = function(source, options) {\n    return new DG.Meta.Origin(source, options);\n};\n"
  },
  {
    "path": "src/DGMeta/test/DGMetaSpec.js",
    "content": "describe.skip('DGMeta', function () {\n    var map, meta, ajaxSpy, ajaxStub, demoData, origin, poiCord, spy, div;\n\n    beforeEach(function () {\n        div = document.createElement('div');\n\n        document.body.appendChild(div);\n\n        map = new DG.Map(div, {\n            center : new DG.LatLng(54.980206086231, 82.898068362003),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n\n        demoData = [{\n            geometry: {\n                type: 'Polygon',\n                coordinates: [\n                    DG.point(20, 85),\n                    DG.point(40, 85),\n                    DG.point(40, 105),\n                    DG.point(20, 105),\n                    DG.point(20, 85)\n                ]\n            },\n            hint: 'Суши Терра, сеть ресторанов японской кухни',\n            id: '141806935215016',\n            linked: {\n                id: '141265769904776',\n                name: 'Суши Терра, сеть ресторанов японской кухни',\n                type: 'filial'\n            }\n        }];\n\n        poiCord = DG.latLng(51.73106181684307, 36.19431853294373); // администрация курской области\n\n        meta = DG.Meta.layer(null);\n        origin = meta.getOrigin();\n\n        ajaxSpy = sinon.spy();\n        ajaxStub = sinon.stub(DG, 'ajax', function () {\n            ajaxSpy();\n            return {then: function () {} };\n        });\n\n    });\n\n    afterEach(function () {\n        document.body.removeChild(div);\n        map && map.remove();\n        map = meta = origin = demoData = ajaxSpy = null;\n        ajaxStub.restore();\n    });\n\n    describe('#DG.Meta.Layer', function () {\n        it('should create and return origin instance', function () {\n            expect(origin).to.be.an('object');\n        });\n\n        it('should click on map', function () {\n            origin.setTileData('78713:43453:17:256x256', demoData);\n            spy = sinon.spy();\n            meta.addTo(map);\n\n            map.on('click', spy);\n\n            happen.click(map.getPane('tilePane'), {latlng: poiCord});\n\n            expect(spy.called).to.be.ok();\n        });\n    });\n\n    describe('#DG.Meta.Origin', function () {\n        it('getTileData should NOT call ajax and return false', function () {\n            origin.getTileData('124:12:42:256x256', function (tileData) {\n                expect(tileData).to.not.be.ok();\n                // ajax should not be called since empty url provided\n                expect(ajaxSpy.callCount).to.be.eql(0);\n            });\n        });\n\n        it('flush should clear cache', function () {\n            var chain;\n\n            origin.setTileData({x: 124, y: 12, z: 42, key: '256x256'}, demoData);\n            chain = origin.flush();\n            origin.getTileData({x: 124, y: 12, z: 42, key: '256x256'}, function (tileData) {\n                expect(tileData).to.not.be.ok();\n                // check for returning this\n                expect(chain.flush).to.be.a('function');\n            });\n        });\n\n        it('setURL flush option call flush method', function () {\n            var flushSpy = sinon.spy();\n                flushStub = sinon.stub(DG.Meta.Origin.prototype, 'flush', function () {\n                    flushSpy();\n                });\n\n            origin.setURL('http://demo/data', true);\n\n            expect(flushSpy.callCount).to.be.eql(1);\n\n            flushStub.restore();\n        });\n\n        it('getTileData should cache tileData', function () {\n            origin.setURL('http://demo/data');\n            origin.getTileData({x: 124, y: 12, z: 42, key: '256x256'}, function (tileData) {\n                expect(tileData).to.not.be.ok();\n                expect(ajaxSpy.callCount).to.be.eql(1);\n            });\n        });\n\n        it('setTileData by object key should write and cache tileData', function () {\n            var chain;\n\n            chain = origin.setTileData({x: 124, y: 12, z: 42, key: '256x256'}, demoData);\n\n            origin.getTileData({x: 124, y: 12, z: 42, key: '256x256'}, function (tileData) {\n                expect(tileData).to.be.a('object');\n                expect(ajaxSpy.callCount).to.be.eql(0);\n                // check for returning this\n                expect(chain.setTileData).to.be.a('function');\n            });\n        });\n\n        it('setTileData by string key should write and cache tileData', function () {\n            var chain;\n\n            chain = origin.setTileData('124:12:42:256x256', demoData);\n\n            origin.getTileData({x: 124, y: 12, z: 42, key: '256x256'}, function (tileData) {\n                expect(tileData).to.be.a('object');\n                expect(ajaxSpy.callCount).to.be.eql(0);\n                // check for returning this\n                expect(chain.setTileData).to.be.a('function');\n            });\n        });\n\n        it('getTileKey should string tileKey representation', function () {\n            var tileKey;\n\n            tileKey = origin.getTileKey({x: 124, y: 12, z: 42, key: '256x256'});\n\n            expect(tileKey).to.be.eql('124:12:42:256x256');\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGMeta/test/PolyUtilContainsSpec.js",
    "content": "/*global describe:false, it:false, expect:false */\n\ndescribe('Polygon', function () {\n\n    var polygonPointSet = [\n        [54.97952237000778, 82.89766073226929],\n        [54.98081530831201, 82.89707064628601],\n        [54.980944599852364, 82.89730668067932],\n        [54.98121549506299, 82.89891600608826],\n        [54.98071372180964, 82.89812743663788],\n        [54.98069832989291, 82.89967775344849],\n        [54.97954084084813, 82.8976821899414]\n    ],\n    innerPoints = [\n        [54.98067985958506, 82.89960801601408],\n        [54.98059366470269, 82.89906620979309],\n        [54.98043974480962, 82.89858877658844],\n        [54.98023041280807, 82.89815425872803],\n        [54.98044590161669, 82.89755344390868],\n        [54.9806459973319, 82.8972852230072],\n        [54.98087379739374, 82.89828300476074],\n        [54.98009804053787, 82.89771437644957],\n        [54.97958393944262, 82.89766609668732],\n        [54.980141138534236, 82.8980898857116],\n        [54.98067370281387, 82.89959192276001],\n        [54.98089226761238, 82.89737641811371]\n    ],\n    outerPoints = [\n        [54.98049823443851, 82.89948463439941],\n        [54.981049264127705, 82.89756953716278],\n        [54.98056903755945, 82.89710283279419],\n        [54.980950756582004, 82.89888918399811],\n        [54.980113432684746, 82.89712429046631],\n        [54.98108004768617, 82.89791285991669],\n        [54.979744019531346, 82.90242433547974],\n        [54.980113432684746, 82.89015054702759],\n        [54.98220670968463, 82.89379835128784],\n        [54.981049264127705, 82.90077209472656]\n    ];\n\n    describe('#inside', function () {\n        it('should return true if points are inside', function () {\n            for (var i = 0; i < innerPoints.length; i++) {\n                expect(DG.PolyUtil.inside(innerPoints[i], {\n                    type: 'Polygon',\n                    coordinates: [polygonPointSet]\n                })).to.be.equal(true);\n            }\n        });\n\n        it('should return false if points are outside', function () {\n            for (var i = 0; i < outerPoints.length; i++) {\n                expect(DG.PolyUtil.inside(outerPoints[i], {\n                    type: 'Polygon',\n                    coordinates: [polygonPointSet]\n                })).to.be.equal(false);\n            }\n        });\n\n    });\n\n});\n"
  },
  {
    "path": "src/DGMuseum/skin/basic/less/dg-museum.less",
    "content": ".dg-museum {\n    position: absolute;\n    top: 0;\n    left: 0;\n    right: 0;\n    z-index: 1500;\n    padding: 4px 5px 8px;\n    background: #333;\n    color: #fff;\n    opacity: .97;\n    text-align: center;\n}\n\n.dg-museum-browser {\n    position: relative;\n    top: 4px;\n    display: inline-block;\n    width: 16px;\n    height: 16px;\n    margin: 0 4px;\n    background: url('@{baseURL}/img/DGMuseum.jpg') left top no-repeat;\n}\n.dg-museum__chrome {\n    background-position: 0 0;\n\n    &:hover {\n        background-position: 0 -16px;\n        }\n    }\n.dg-museum__firefox {\n    background-position: -16px 0;\n\n    &:hover {\n        background-position: -16px -16px;\n        }\n    }\n.dg-museum__safari {\n    background-position: -32px 0;\n\n    &:hover {\n        background-position: -32px -16px;\n        }\n    }\n.dg-museum__opera {\n    width: 15px;\n    background-position: -48px 0;\n\n    &:hover {\n        background-position: -48px -16px;\n        }\n    }\n.dg-museum__ie {\n    width: 17px;\n    background-position: -63px 0;\n\n    &:hover {\n        background-position: -63px -16px;\n        }\n\n    }\n.dg-museum__close {\n    display: inline-block;\n    margin: 0 4px;\n    width: 9px;\n    height: 9px;\n    background: url('@{baseURL}/img/DGMuseum_close.gif') top left no-repeat;\n    cursor: pointer;\n\n    &:hover {\n        opacity: .6;\n        }\n    }\n"
  },
  {
    "path": "src/DGMuseum/src/DGMuseum.js",
    "content": "var ie9 = (function() {\n    var div = document.createElement('div');\n    var all = div.getElementsByTagName('i');\n    div.innerHTML = '<!--[if IE 9]><i></i><![endif]-->';\n    return Boolean(all[0]);\n})();\n\nvar safari51 = DG.Browser.safari && navigator.userAgent.indexOf('Version/5.1') !== -1;\n\nvar wasPreviouslyDisabled = false;\n\n// Old Safari throws error when localStorage.getItem is called in private mode\ntry {\n    wasPreviouslyDisabled = localStorage.getItem('DGMuseum') === 'false';\n} catch (err) {\n    // do nothing\n}\n\nDG.Map.mergeOptions({\n    museum: !wasPreviouslyDisabled && (DG.Browser.ielt9 || ie9 || DG.Browser.opera12 || safari51)\n});\n\nDG.Map.Museum = DG.Handler.extend({\n    statics: {\n        Dictionary: {\n            ar: {\n                wearesorry: 'لا نضمن لك تشغيل ثابت للتطبيق على متصفحك. حاول التحديث:'\n            },\n            cs: {\n                wearesorry: 'Nezaručujeme stabilní fungování aplikace ve Vašem prohlížeči. Zkuste provést aktualizaci:'\n            },\n            en: {\n                wearesorry: 'We do not guarantee stable operation of the application in your browser. Try updating:'\n            },\n            es: {\n                wearesorry: 'No garantizamos un funcionamiento estable de la aplicación en su buscador. Intente actualizarlo:'\n            },\n            it: {\n                wearesorry: 'Non garantiamo il funzionamento stabile dell\\'applicazione nel tuo browser. Prova ad aggiornare:'\n            },\n            ru: {\n                wearesorry: 'Мы не гарантируем стабильную работу приложения в вашем браузере. Попробуйте обновиться:'\n            }\n        }\n    },\n\n    includes: [DG.Locale],\n\n    initialize: function(map) {\n        this._map = map;\n\n        this._element = document.createElement('div');\n        this._element.className = 'dg-museum';\n        this._element.innerHTML = '<span></span>' +\n            '<a class=\"dg-museum-browser dg-museum__chrome\" target=\"_blank\" href=\"https://www.google.com/chrome/\"></a>' +\n            '<a class=\"dg-museum-browser dg-museum__firefox\" target=\"_blank\" href=\"https://www.mozilla.org/firefox/new/\"></a>' +\n            '<a class=\"dg-museum-browser dg-museum__safari\" target=\"_blank\" href=\"https://support.apple.com/downloads/safari\"></a>' +\n            '<a class=\"dg-museum-browser dg-museum__opera\" target=\"_blank\" href=\"https://www.opera.com/\"></a>' +\n            '<a class=\"dg-museum-browser dg-museum__ie\" target=\"_blank\" href=\"https://windows.microsoft.com/internet-explorer/download-ie\"></a>';\n\n        this._text = this._element.children[0];\n\n        this._closeButton = document.createElement('span');\n        this._closeButton.className = 'dg-museum__close';\n        this._element.appendChild(this._closeButton);\n\n        this._renderTranslation();\n    },\n\n    addHooks: function() {\n        this._map.getContainer().appendChild(this._element);\n        this._map.on('langchange', this._renderTranslation, this);\n        DG.DomEvent.on(this._closeButton, 'click', this._onCloseButtonClick, this);\n    },\n\n    removeHooks: function() {\n        this._map.getContainer().removeChild(this._element);\n        this._map.off('langchange', this._renderTranslation, this);\n        DG.DomEvent.off(this._closeButton, 'click', this._onCloseButtonClick, this);\n    },\n\n    _onCloseButtonClick: function(e) {\n        DG.DomEvent.stop(e);\n\n        // Old Safari throws error when localStorage.getItem is called in private mode\n        try {\n            localStorage.setItem('DGMuseum', 'false');\n        } catch (err) {\n            // do nothing\n        }\n\n        this.disable();\n    },\n\n    _renderTranslation: function() {\n        var lang = this._map.getLang();\n        this._text.innerHTML = this.t('wearesorry');\n        this._element.setAttribute('dir', lang === 'ar' ? 'rtl': 'ltr');\n    }\n});\n\nDG.Map.addInitHook('addHandler', 'museum', DG.Map.Museum);\n"
  },
  {
    "path": "src/DGPoi/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n\n    <title>poi demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            var map = new DG.Map('map', {\n                center: new DG.LatLng(51.7302800, 36.1938900),\n                zoom: 17,\n                geoclicker: true,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            var marker = DG.marker(map.getCenter()).addTo(map);\n\n            map.poi.getMetaLayer().on('click', function(e) {\n                console.log('poi click!', e)\n            })\n\n            map.poi.getMetaLayer().on('mouseover', function(e) {\n                console.log('poi hover!', e)\n            })\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGPoi/src/DGPoi.js",
    "content": "DG.Map.mergeOptions({\n    poi: true\n});\n\nDG.Poi = DG.Handler.extend({\n\n    options: {\n        disableLabel: false\n    },\n\n    initialize: function(map, options) { // (Object)\n        this._map = map;\n        DG.Util.setOptions(this, options);\n\n        var url = DG.config.protocol + (DG.Browser.retina ? DG.config.retinaPoiMetaServer : DG.config.poiMetaServer);\n\n        this._metaLayer = DG.Meta.layer(url, {\n            minZoom: DG.config.poiLayerMinZoom,\n            maxNativeZoom: 19,\n            detectRetina: DG.config.detectRetina,\n            eventBubbling: 'layer',\n            dataFilter: DG.bind(this._processData, this),\n            isPoi: true\n        });\n\n        this._currentTilesLang = ''; // 'ar' | ''\n    },\n\n    addHooks: function() {\n        this._map.addLayer(this._metaLayer);\n        if (!this.options.disableLabel) {\n            this._labelHelper = DG.label();\n        }\n        this._metaLayer.on(this._layerEventsListeners, this);\n        this._map.on('langchange', this._updateUrl, this);\n        this._map.on('projectchange', this._updateUrl, this);\n        this._map.on('projectleave', this._updateUrl, this);\n    },\n\n    removeHooks: function() {\n        this._map.removeLayer(this._metaLayer);\n        if (!this.options.disableLabel) {\n            this._map.removeLayer(this._labelHelper);\n            this._labelHelper = null;\n        }\n        this._metaLayer.off(this._layerEventsListeners, this);\n        this._map.off('langchange', this._updateUrl, this);\n        this._map.off('projectchange', this._updateUrl, this);\n        this._map.off('projectleave', this._updateUrl, this);\n    },\n\n    getMetaLayer: function() {\n        return this._metaLayer;\n    },\n\n    _updateUrl: function() {\n        var url = DG.config.protocol + (DG.Browser.retina ? DG.config.retinaPoiMetaServer : DG.config.poiMetaServer);\n        var arabicUrl = DG.config.protocol +\n            (DG.Browser.retina ? DG.config.arabicRetinaPoiMetaServer : DG.config.arabicPoiMetaServer);\n        var lang = this._map.getLang();\n        var project = this._map.projectDetector && this._map.projectDetector.getProject();\n\n        // Change POI for Arabic language in Dubai project\n        if (this._currentTilesLang === '' && lang === 'ar' && project && project.country_code === 'ae') {\n            this._currentTilesLang = 'ar';\n            this._metaLayer.setUrl(arabicUrl);\n\n        } else if (this._currentTilesLang === 'ar' && (lang !== 'ar' || (!project || project.country_code !== 'ae'))) {\n            this._currentTilesLang = '';\n            this._metaLayer.setUrl(url);\n        }\n    },\n\n    _processData: function(data, coord) {\n        var tileOriginPoint = coord.scaleBy(this._metaLayer.getTileSize());\n        var polygonLngLatToPoints = DG.bind(this._polygonLngLatToPoints, this, tileOriginPoint, coord.z);\n\n        if (data.responseText === '') {\n            return [];\n        }\n\n        return data.result.poi\n            .map(function(item) {\n                var hovers = item.hovers !== undefined\n                    ? item.hovers\n                    : [item.hover];\n\n                return {\n                    id: item.id,\n                    hint: item.links[0].name,\n                    linked: item.links[0],\n                    geometry: hovers.map(DG.Wkt.toGeoJSON),\n                };\n            })\n            .map(function(item) {\n                var coordinates = item.geometry.reduce(function(result, item) {\n                    if (item.type === 'Polygon') {\n                        result.push(polygonLngLatToPoints(item.coordinates));\n                    } else if (item.type === 'MultiPolygon') {\n                        result = result.concat(item.coordinates.map(polygonLngLatToPoints));\n                    }\n\n                    return result;\n                }, []);\n\n                item.geometry = {\n                    type: 'MultiPolygon',\n                    coordinates: coordinates,\n                };\n\n                return item;\n            });\n    },\n\n    _polygonLngLatToPoints: function(originPoint, zoom, polygon) {\n        var map = this._map;\n\n        return polygon.map(function(contour) {\n            return contour.map(function(lngLat) {\n                return map\n                    .project([lngLat[1], lngLat[0]], zoom).round()\n                    .subtract(originPoint);\n            });\n        });\n    },\n\n    _layerEventsListeners : {\n        mouseover: function(e) { // (Object)\n            this._setCursor('pointer');\n            if (e.meta.hint && e.meta.hint.length && !this.options.disableLabel) {\n                this._labelHelper\n                    .setPosition(e.latlng)\n                    .setContent(e.meta.hint)\n                    .setZIndexOffset(300);\n                this._map.addLayer(this._labelHelper);\n            }\n            this._map.fire('poihover', {\n                latlng: e.latlng,\n                meta: e.meta\n            });\n        },\n\n        mouseout: function(e) {\n            this._setCursor('');\n            if (!this.options.disableLabel) {\n                this._map.removeLayer(this._labelHelper);\n            }\n            this._map.fire('poileave', {\n                latlng: e.latlng,\n                meta: e.meta\n            });\n        },\n\n        mousemove: function(e) { // (Object)\n            if (!this.options.disableLabel) {\n                this._labelHelper.setPosition(e.latlng);\n            }\n        }\n    },\n\n    _setCursor: function(cursor) { // (String)\n        this._map.getContainer().style.cursor = cursor;\n    }\n\n});\n\nDG.Map.addInitHook('addHandler', 'poi', DG.Poi);\n"
  },
  {
    "path": "src/DGPoi/test/DGPoiSpec.js",
    "content": "describe('DG.Poi', function() {\n    var map, mapContainer, ajaxSpy, ajaxStub, tileData, tileKey;\n\n    before(function() {\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [55.017493, 82.819576],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n\n        tileKey = '23929:10367:15:256';\n        tileData = JSON.parse('[{\"id\":\"141806935212060\",\"hint\":\"Сан Сити, многофункциональный комплекс\",\"linked\":{\"id\":\"141265770417218\",\"type\":\"branch\",\"name\":\"Сан Сити, многофункциональный комплекс\"},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[{\"x\":142,\"y\":132},{\"x\":162,\"y\":132},{\"x\":162,\"y\":152},{\"x\":142,\"y\":152},{\"x\":142,\"y\":132}]]}}]');\n        tileData[0].geometry.coordinates[0].forEach(function(el, i) {\n            tileData[0].geometry.coordinates[0][i] = DG.point(el.x, el.y);\n        });\n    });\n\n    after(function() {\n        map.remove();\n        mapContainer.parentElement.removeChild(mapContainer);\n        map = mapContainer = ajaxSpy = ajaxStub = tileData = tileKey = null;\n    });\n\n    describe('check init', function() {\n        it('should object map has .poi', function() {\n            expect(map.poi).to.be.a('object');\n        });\n\n        it('should map has poi meta layer', function() {\n            expect(map.hasLayer(map.poi.getMetaLayer())).to.be.ok();\n        });\n    });\n\n    describe('#removeHooks', function() {\n        before(function() {\n            map.poi.removeHooks();\n        });\n\n        it('should map hasn\\'t meta layer', function() {\n            expect(map.hasLayer(map.poi.getMetaLayer())).not.be.ok();\n        });\n    });\n\n    describe('#addHooks', function() {\n        before(function() {\n            map.poi.addHooks();\n        });\n\n        it('should map has meta layer', function() {\n            expect(map.hasLayer(map.poi.getMetaLayer())).to.be.ok();\n        });\n    });\n\n    describe('mouse events', function() {\n        var labelContent, metaLayer;\n\n        before(function() {\n            metaLayer = map.poi.getMetaLayer();\n            metaLayer.getOrigin().setTileData(tileKey, tileData);\n        });\n\n        after(function() {\n            labelContent = metaLayer = null;\n        });\n\n        describe('#mouseover', function() {\n            before(function() {\n                metaLayer.fire('mouseover', {\n                    meta: tileData[0],\n                    latlng: DG.latLng(54.98042127438281, 82.89879798889162)\n                });\n            });\n\n            it('should view label on map', function() {\n                labelContent = document.body.getElementsByClassName('dg-label__content');\n                expect(labelContent.length).to.be(1);\n            });\n\n            it('should equel label text', function() {\n                expect(labelContent[0].innerHTML).to.be(tileData[0].hint);\n            });\n        });\n\n        describe('#mouseout', function() {\n            before(function() {\n                metaLayer.fire('mouseout', {\n                    meta: tileData[0],\n                    latlng: DG.latLng(54.98042127438281, 82.89879798889162)\n                });\n            });\n\n            it('shouldn\\'t view label on map', function() {\n                labelContent = document.body.getElementsByClassName('dg-label__content');\n                expect(labelContent.length).to.be(0);\n            });\n\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGPopup/skin/basic/less/dg-popup.less",
    "content": ".dg-popup {\n}\n\n.dg-popup__container {\n    margin: 0;\n}\n\n.leaflet-popup-scrolled .dg-popup__container { /* @TODO: .leaflet-popup-scrolled → dg-popup_scrolled_true */\n    padding: 8px 14px 8px 0;\n}\n\n.dg-popup__header {\n    position: relative;\n    padding-bottom: 12px; // не margin, чтобы правильно работал offsetHeight\n\n    .leaflet-popup-scrolled &:after {\n        position: relative;\n        top: 12px;\n        display: block;\n        width: 100%;\n        height: 1px;\n        content: '';\n    }\n}\n\n.dg-popup__footer {\n    position: relative;\n    bottom: 0;\n    overflow: hidden;\n\n    .leaflet-popup-scrolled &:before {\n        display: block;\n        width: 100%;\n        height: 1px;\n        content: '';\n    }\n}\n\n.dg-popup__footer-buttons {\n}\n\n.dg-popup_hidden_true {\n    display: none;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/basic/less/leaflet.ie.less",
    "content": ".leaflet-map-pane .leaflet-popup-tip-container {\n    bottom: -47px;\n    transform: translateY(0);\n}\n"
  },
  {
    "path": "src/DGPopup/skin/basic/less/leaflet.less",
    "content": ".leaflet-popup {\r\n    margin-bottom: 0;\r\n}\r\n\r\n.leaflet-popup-tip-container {\r\n    height: 0;\r\n}\r\n\r\n.leaflet-popup-tip {\r\n    display: none;\r\n}\r\n\r\n.leaflet-popup-content-wrapper {\r\n    overflow: hidden;\r\n    padding: 0;\r\n    min-width: 60px;\r\n    min-height: 50px;\r\n    border: 0;\r\n    border-radius: 3px;\r\n    background: none;\r\n    box-shadow: none;\r\n    color: #e6e6e6;\r\n    font-size: 14px;\r\n    transition: opacity ease-out .2s, max-height ease-out .2s, height ease-out .2s;\r\n    transform-origin: 50% 100%;\r\n\r\n    // Чтобы текст не заезжал под кнопку закрытия. Для не инлайновых боксов\r\n    // можно получить нужное поведение применяя к ним overflow:hidden или display:(inline-block|table) .\r\n    &:before {\r\n        float: right;\r\n        width: 30px;\r\n        // popupPadding + 1 , первая строчка текста уже среагирует на кнопку,\r\n        // но минимум проблем с не инлайновыми боксами\r\n        height: 17px;\r\n        content: '';\r\n    }\r\n}\r\n\r\n.leaflet-popup-content {\r\n    position: relative;\r\n    margin: 16px;\r\n    width: auto;\r\n    line-height: 1.4;\r\n}\r\n\r\n.leaflet-popup a {\r\n    outline: none;\r\n}\r\n\r\n.leaflet-popup-content p {\r\n    margin: 0;\r\n}\r\n\r\n.leaflet-popup-scrolled {\r\n    overflow: visible;\r\n    border: 0;\r\n}\r\n\r\n.leaflet-popup-inner {\r\n    position: relative;\r\n    z-index: 0;\r\n}\r\n\r\n.leaflet-popup_show_true {\r\n    transition: transform ease-in-out .2s, opacity ease-in-out .2s, height ease-out .2s;\r\n    transform: scale(1);\r\n}\r\n\r\n.leaflet-popup_show_false {\r\n    opacity: 0 !important;\r\n    transition: all ease-in-out .1s;\r\n    transform: scale(.2);\r\n}\r\n\r\n/* Коллаут показался, но контент ещё не загрузился */\r\n.leaflet-popup_preloader_true {\r\n    width: 384px;\r\n    height: 52px;\r\n}\r\n\r\n/* В коллауте ошибка вместо контента */\r\n.leaflet-popup_error_true {\r\n}\r\n\r\n.leaflet-map-pane .leaflet-popup-tip-container {\r\n    position: absolute;\r\n    top: auto;\r\n    bottom: 0;\r\n    left: 50%;\r\n    margin-left: -29px;\r\n    width: 58px;\r\n    height: 47px;\r\n    background-repeat: no-repeat;\r\n    transform: translateY(47px);\r\n    pointer-events: none;\r\n}\r\n\r\n.leaflet-popup-tip {\r\n    display: none;\r\n}\r\n\r\n.leaflet-popup-tip-container_svg {\r\n    .notRepeatableBg('DGPopup__popupShadow', true);\r\n    background-position: 50% 95%;\r\n    background-size: 36px 12px;\r\n}\r\n\r\n.leaflet-container a.leaflet-popup-close-button {\r\n    position: absolute;\r\n    top: 3px;\r\n    right: 3px;\r\n    z-index: 1;\r\n    overflow: hidden;\r\n    padding: 0;\r\n    width: 30px;\r\n    height: 30px;\r\n    text-align: center;\r\n    font-weight: normal;\r\n    font-size: 18px;\r\n    line-height: 30px;\r\n    cursor: pointer;\r\n\r\n    .no-touch &:hover {\r\n        border-radius: 2px;\r\n        transition: all .2s;\r\n    }\r\n\r\n    &:active {\r\n        color: #777777;\r\n    }\r\n\r\n    &:after {\r\n        position: absolute;\r\n        top: -3px;\r\n        right: -5px;\r\n        z-index: 2;\r\n        width: 40px;\r\n        height: 40px;\r\n        content: '';\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGPopup/skin/basic/less/scroller.less",
    "content": ".dg-scroller {\n}\n\n.dg-scroller_hidden_true {\n    overflow: auto;\n}\n\n.dg-scroller::-webkit-scrollbar {\n    width: 0;\n}\n\n.dg-scroller__wrapper {\n    position: relative;\n    overflow: hidden;\n}\n\n.dg-scroller__bar-wrapper {\n    position: absolute;\n    top: 18px;\n    right: 3px;\n    bottom: 4px;\n    width: 7px;\n    border-radius: 5px;\n}\n\n.dg-scroller_hidden_true .dg-scroller__bar-wrapper {\n    visibility: hidden;\n}\n\n.dg-popup__header + .dg-popup__container-wrapper .dg-scroller__bar-wrapper {\n    top: 4px;\n}\n\n.dg-scroller__bar {\n    position: absolute;\n    min-height: 20px;\n    width: 7px;\n    border-radius: 3px;\n    pointer-events: auto;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/basic/skin.config.js",
    "content": "DG.configTheme = DG.configTheme || {};\n\nDG.configTheme.balloonOptions = {\n    offset: {\n        x: 1,\n        y: -43\n    }\n};\n"
  },
  {
    "path": "src/DGPopup/skin/dark/less/dg-popup.less",
    "content": ".leaflet-popup-scrolled .dg-popup__header:after,\n.leaflet-popup-scrolled .dg-popup__footer:before {\n    border-bottom: 1px solid #636363;\n    background-color: #494949;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/dark/less/leaflet.ie.less",
    "content": ".leaflet-popup-content-wrapper {\n    .opacity(.85);\n    background-color: #323232;\n}\n\n.leaflet-oldie .leaflet-popup-content-wrapper {\n    border: 0;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/dark/less/leaflet.less",
    "content": ".leaflet-popup-content-wrapper {\r\n    background-color: rgba(50, 50, 50, .9);\r\n}\r\n\r\n.leaflet-popup-tip-container_image {\r\n    .notRepeatableBg('DGPopup__popupShadow_dark', true);\r\n}\r\n\r\n.leaflet-map-pane .leaflet-popup-tip-container_svg {\r\n    fill: rgba(50, 50, 50, .9);\r\n}\r\n\r\n.leaflet-container a.leaflet-popup-close-button {\r\n    .no-touch &:hover {\r\n        background-color: #222;\r\n        box-shadow: 0 1px 3px rgba(0, 0, 0, .5);\r\n    }\r\n\r\n    &:after {\r\n        top: -3px;\r\n        right: -5px;\r\n        width: 40px;\r\n        height: 40px;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGPopup/skin/dark/less/scroller.less",
    "content": ".scroller__bar-wrapper .scroller__bar {\n    background-color: #665b4f;\n}\n\n.scroller__bar-wrapper:hover .scroller__bar {\n    background-color: #897a6b;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/light/less/dg-popup.less",
    "content": ".leaflet-popup-scrolled .dg-popup__header:after,\n.leaflet-popup-scrolled .dg-popup__footer:before {\n    background-color: #eee;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/light/less/leaflet.ie.less",
    "content": ".leaflet-popup-content-wrapper {\n    .opacity(.95);\n    background-color: #fff;\n}\n\n.leaflet-oldie .leaflet-popup-content-wrapper {\n    border-color: #bebdb5;\n}\n\n.leaflet-map-pane .leaflet-popup-tip-container {\n    bottom: -46px;\n}\n"
  },
  {
    "path": "src/DGPopup/skin/light/less/leaflet.less",
    "content": ".leaflet-popup-content-wrapper {\r\n    border: 1px solid #bebdb5;\r\n    border-color: rgba(151, 151, 151, .6);\r\n    background-color: rgba(255, 255, 255, .95);\r\n    color: #000;\r\n}\r\n\r\n.leaflet-popup-tip-container_image {\r\n    .notRepeatableBg('DGPopup__popupShadow_light', true);\r\n}\r\n\r\n.leaflet-map-pane .leaflet-popup-tip-container {\r\n    transform: translateY(46px);\r\n}\r\n\r\n.leaflet-map-pane .leaflet-popup-tip-container_svg {\r\n    margin-top: -2px;\r\n    fill: rgba(255, 255, 255, .95);\r\n    stroke: #bebdb5;\r\n    stroke-dasharray: 0, 10, 100, 60;\r\n}\r\n\r\n.leaflet-container a.leaflet-popup-close-button {\r\n    .no-touch &:hover {\r\n        background-color: #f5faff;\r\n        color: #6fa4d9;\r\n    }\r\n\r\n    &:after {\r\n        top: -3px;\r\n        right: -5px;\r\n        width: 40px;\r\n        height: 40px;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGPopup/skin/light/less/scroller.less",
    "content": ".scroller__bar-wrapper .scroller__bar {\n    background-color: #eee;\n}\n\n.scroller__bar-wrapper:hover .scroller__bar {\n    background-color: #c6c6c6;\n}\n"
  },
  {
    "path": "src/DGPopup/src/DGPopup.js",
    "content": "require('../../../vendors/baron');\n\n// 2GIS-related popup content wrapper and offset\n(function() {\n    var offsetX = DG.configTheme.balloonOptions.offset.x,\n        offsetY = DG.configTheme.balloonOptions.offset.y,\n        originalInitialize = DG.Popup.prototype.initialize,\n        originalInitLayout = DG.Popup.prototype._initLayout,\n        originalOnAdd = DG.Popup.prototype.onAdd,\n        graf = baron.noConflict();\n\n    var BaronDomHelper = function(element) {\n        this[0] = element;\n        this.length = 1;\n    };\n    BaronDomHelper.prototype = {\n        setAttribute: function(name, value) {\n            this[0].setAttribute(name, value);\n            return this;\n        },\n        getAttribute: function(name) {\n            return this[0].getAttribute(name);\n        },\n        removeAttribute: function(name) {\n            this[0].removeAttribute(name);\n            return this;\n        },\n        css: function(style, value) {\n            if (value) {\n                this[0].style[style] = value;\n                return this;\n            } else {\n                return DG.DomUtil.getStyle(this[0], style);\n            }\n        }\n    };\n\n    DG.Popup.prototype.options.offset = DG.point(offsetX, offsetY);\n\n    DG.Popup.mergeOptions({\n        border: 16,\n        mapControlsWidth: 60,\n        textDirection: 'auto' // 'auto' | 'ltr' | 'rtl\n    });\n\n    DG.Popup.include({\n        _headerContent: null,\n        _footerContent: null,\n\n        //baron elements references\n        _scroller: null,\n        _scrollerBar: null,\n        _barWrapper: null,\n        _baron: null,\n        _isBaronExist: false,\n\n        _popupShowClass: 'leaflet-popup_show_true',\n        _popupHideClass: 'leaflet-popup_show_false',\n\n        _popupTipClass: 'leaflet-popup-tip-container',\n        _tipSVGPath: 'M0 0c12.643 0 28 7.115 28 44h2c0-36.885 15.358-44 28-44h-58z',\n\n        _isAutoPanPaddingUserDefined: false,\n\n        initialize: function(options, source) { // (Object, Object)\n            this._popupStructure = {};\n            this._isAutoPanPaddingUserDefined = options && options.hasOwnProperty('autoPanPadding');\n            originalInitialize.call(this, options, source);\n        },\n\n        onAdd: function(map) { // (Map)\n            map.on({\n                entranceshow: this._closePopup,\n                resize: this.resize\n            }, this);\n            originalOnAdd.call(this, map);\n            this._animateOpening();\n        },\n\n        onRemove: function(map) { // (Map)\n            this._animateClosing();\n            map.off({\n                entranceshow: this._closePopup,\n                resize: this.resize\n            }, this);\n\n            if (DG.DomUtil.TRANSITION) {\n                this._removeTimeout = setTimeout(L.bind(L.DomUtil.remove, L.DomUtil, this._container), 200);\n            } else {\n                L.DomUtil.remove(this._container);\n            }\n\n            map.fire('popupclose', {popup: this});\n\n            if (this._source) {\n                this._source.fire('popupclose', {popup: this}, true);\n            }\n        },\n\n        setContent: function(content) { // (DOMElement | Object | HTML) -> Popup\n            if (!this._isNode(content) && typeof content === 'object') {\n                Object.keys(content).forEach(function(item) {\n                    this['_' + item + 'Content'] = content[item];\n                }, this);\n            } else {\n                this._bodyContent = content;\n            }\n\n            this.update();\n\n            return this;\n        },\n\n        setHeaderContent: function(content) { // (HTML) -> Popup\n            this._headerContent = content;\n            this.update();\n\n            return this;\n        },\n\n        setFooterContent: function(content) { // (HTML) -> Popup\n            this._footerContent = content;\n            this.update();\n\n            return this;\n        },\n\n        getContent: function() { // () -> HTML\n            return this._bodyContent;\n        },\n\n        getHeaderContent: function() { // () -> HTML\n            return this._headerContent;\n        },\n\n        getFooterContent: function() { // () -> HTML\n            return this._footerContent;\n        },\n\n        clear: function() { // () -> Popup\n            Object.keys(this._popupStructure).forEach(this._clearElement, this);\n\n            // think about move this set to another public method\n            this._isBaronExist = false;\n            return this;\n        },\n\n        clearHeader: function() { // () -> Popup\n            return this._clearElement('header');\n        },\n\n        clearFooter: function() { // () -> Popup\n            return this._clearElement('footer');\n        },\n\n        findElement: function(element) { // (String) -> DOMElement\n            return this._contentNode.querySelector(element);\n        },\n\n        _animateOpening: function() {\n            DG.DomUtil.addClass(this._innerContainer, this._popupShowClass);\n            DG.DomUtil.removeClass(this._innerContainer, this._popupHideClass);\n        },\n\n        _animateClosing: function() {\n            DG.DomUtil.addClass(this._innerContainer, this._popupHideClass);\n            DG.DomUtil.removeClass(this._innerContainer, this._popupShowClass);\n        },\n\n        _closePopup: function() {\n            this._map.closePopup(this);\n        },\n\n        _isNode: function(o) { // (Object) -> Boolean\n            return (o.nodeName ? true : false);\n        },\n\n        _onCloseButtonClick: function(e) {\n            if (this._map) {\n                this._map.closePopup(this);\n            }\n            L.DomEvent.stop(e);\n        },\n\n        _close: function() {\n            if (this._map) {\n                if (DG.Browser.mobile && this._map.geoclicker &&\n                    (this.options.closeOnClick || this._map.options.closePopupOnClick)) {\n                    //  We need to signal geoclicker that popup was open before 'click' event\n                    //  But by time it will get it's event the popup will be already closed\n                    //  See 'DGGeoclicker' for '_mapEventsListeners' and '_singleClick' method\n                    this._map.geoclicker.popupWasOpen = true;\n                }\n\n                this._map.closePopup(this);\n            }\n        },\n\n        _initLayout: function() {\n            originalInitLayout.call(this);\n\n            // Prevents scroll events for div.leaflet-popup-content (this._contentNode) from web page scrolling when popup is opened\n            DG.DomEvent.on(this._contentNode, 'wheel', function(e) {\n                var eventPath;\n\n                if (e.composedPath) {\n                    eventPath = e.composedPath();\n                } else {\n                    var elem = e.target;\n                    eventPath = [];\n                    while (elem.parentNode) {\n                        eventPath.push(elem);\n                        elem = elem.parentNode;\n                    }\n                }\n\n                if (eventPath.indexOf(this._scroller) === -1 || eventPath.indexOf(this._barWrapper) !== -1) {\n                    e.preventDefault();\n                }\n            }, this);\n\n            this._innerContainer = DG.DomUtil.create('div', 'leaflet-popup-inner ' + this._popupHideClass, this._container);\n\n            // Prevents mouse events from leaking through close button\n            // See https://github.com/2gis/mapsapi/pull/153/\n            DG.DomEvent.disableClickPropagation(this._innerContainer);\n\n            if (this.options.closeButton) {\n                this._innerContainer.appendChild(this._detachEl(this._closeButton));\n            }\n\n            this._innerContainer.appendChild(this._detachEl(this._wrapper));\n\n            var tip = this._detachEl(this._tipContainer);\n\n            if (DG.Browser.svg) {\n                var path = DG.SVG.create('path');\n                var svgClass = this._popupTipClass + ' ' + this._popupTipClass + '_svg';\n\n                path.setAttribute('d', this._tipSVGPath);\n\n                tip = DG.SVG.create('svg');\n                tip.setAttribute('class', svgClass);\n\n                tip.appendChild(path);\n                DG.DomEvent.disableClickPropagation(path);\n            } else {\n                DG.DomUtil.addClass(tip, this._popupTipClass + '_image');\n                DG.DomEvent.disableClickPropagation(tip);\n            }\n\n            this._innerContainer.appendChild(tip);\n        },\n\n        _clearElement: function(elem) { // (DOMElement) -> Popup\n            this['_' + elem + 'Content'] = null;\n            this._detachEl(this._popupStructure[elem]);\n            delete this._popupStructure[elem];\n            return this;\n        },\n\n        _updateScrollPosition: function() {\n            if (this._baron) {\n                this._baron.update();\n            }\n        },\n\n        resize: function() {\n            var scrolled = this._updateLayout();\n            this._updatePosition();\n\n            if (!scrolled) {\n                if (this._isBaronExist) {\n                    this._scrollerWrapper.style.height = '';\n                    DG.DomUtil.removeClass(this._scroller, 'dg-scroller');\n\n                    DG.DomUtil.addClass(this._scroller, 'dg-scroller_hidden_true');\n                    DG.DomUtil.removeClass(this._scroller, 'dg-scroller');\n                    DG.DomEvent.off(this._scroller, 'scroll', this._onScroll);\n                }\n            } else if (this._isBaronExist) {\n                DG.DomUtil.removeClass(this._scroller, 'dg-scroller_hidden_true');\n                DG.DomUtil.addClass(this._scroller, 'dg-scroller');\n\n                var scrollTop = this._isBaronExist ? this._scroller.scrollTop : false;\n\n                if (scrollTop) {\n                    this._scroller.scrollTop = scrollTop;\n                }\n\n                var innerHeight = this.options.maxHeight - this.options.border * 2 - this._getDelta();\n                this._scrollerWrapper.style.height = innerHeight + 'px';\n\n                this._updateScrollPosition();\n            } else if (!this._isContentHeightEnough()) {\n                this._initBaronScroller();\n                this._initBaron();\n            }\n\n            this._adjustPan();\n            this._bindAdjustPanOnTransitionEnd();\n        },\n\n        _adjustPan: function(e) {\n            if (!this._map) { return; }\n\n            if (e) { // animated popup is opening (height from 0 to max)\n                if (e.propertyName === 'max-height') {\n                    // when it's finished we are here\n                    DG.DomEvent.off(this._wrapper, DG.DomUtil.TRANSITION_END, this._adjustPan);\n                } else {\n                    // here's intermediate steps - we don't need to process them\n                    return;\n                }\n            }\n\n            var options = this.options;\n\n            if (!options.autoPan) { return; }\n\n            var map = this._map,\n                containerHeight = this._container.offsetHeight,\n                containerWidth = this._containerWidth,\n                layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);\n\n            if (this._zoomAnimated) {\n                layerPos._add(L.DomUtil.getPosition(this._container));\n            }\n\n            var autoPanPadding = [options.autoPanPadding[0], options.autoPanPadding[1]];\n\n            // if width of map is more then width of popup and controls\n            // set default autoPanPadding to width controls\n            if (\n                !this._isAutoPanPaddingUserDefined &&\n                    this._map._container.offsetWidth >= options.maxWidth + options.mapControlsWidth * 2\n            ) {\n                autoPanPadding[0] = options.mapControlsWidth;\n            }\n\n            var containerPos = map.layerPointToContainerPoint(layerPos),\n                padding = L.point(autoPanPadding),\n                paddingTL = L.point(options.autoPanPaddingTopLeft || padding),\n                paddingBR = L.point(options.autoPanPaddingBottomRight || padding),\n                size = map.getSize(),\n                dx = 0,\n                dy = 0;\n\n            if (size.x === 0 || size.y === 0) {\n                // map isn't visible\n                return;\n            }\n\n            if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right\n                dx = containerPos.x + containerWidth - size.x + paddingBR.x;\n            }\n            if (containerPos.x - dx - paddingTL.x < 0) { // left\n                dx = containerPos.x - paddingTL.x;\n            }\n            if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom\n                dy = containerPos.y + containerHeight - size.y + paddingBR.y;\n            }\n            if (containerPos.y - dy - paddingTL.y < 0) { // top\n                dy = containerPos.y - paddingTL.y;\n            }\n\n            if (dx || dy) {\n                map\n                    .fire('autopanstart')\n                    .panBy([dx, dy]);\n            }\n        },\n\n        _bindAdjustPanOnTransitionEnd: function() {\n            if (DG.DomUtil.TRANSITION) {\n                DG.DomEvent.on(this._wrapper, DG.DomUtil.TRANSITION_END, this._adjustPan, this);\n            } else {\n                this._adjustPan();\n            }\n        },\n\n        _isContentHeightEnough: function() { // () -> Boolean\n            var options = this.options;\n\n            if (!options.maxHeight) {\n                return true;\n            }\n\n            var popupHeight = this._popupStructure.body ?\n                this._popupStructure.body.offsetHeight + this._getDelta() :\n                this._contentNode.offsetHeight;\n\n            popupHeight += options.border * 2;\n\n            return popupHeight <= options.maxHeight;\n        },\n\n        _initBaronScroller: function() {\n            var contentNode = this._popupStructure.body.parentNode,\n                scrollerWrapper = this._scrollerWrapper = DG.DomUtil.create('div', 'dg-scroller__wrapper', contentNode),\n                scroller = this._scroller = DG.DomUtil.create('div', 'dg-scroller', scrollerWrapper),\n                barWrapper = this._barWrapper = DG.DomUtil.create('div', 'dg-scroller__bar-wrapper', scroller),\n                innerHeight = this.options.maxHeight - this.options.border * 2;\n\n            this._scrollerBar = DG.DomUtil.create('div', 'dg-scroller__bar', barWrapper);\n            scroller.appendChild(this._detachEl(this._popupStructure.body));\n\n            innerHeight -= this._getDelta();\n            scrollerWrapper.style.height = Math.max(18, innerHeight) + 'px';\n            scrollerWrapper.style.width = contentNode.offsetWidth + 5 + 'px'; //TODO\n\n            this._isBaronExist = true;\n\n            this._switchEvents();\n        },\n\n        _onScroll: function(e) {\n            this.fire('scroll', {originalEvent: e});\n        },\n\n        _onClick: function(e) {\n            e.target = e.target || e.srcElement;\n\n            if (!this._moving) {\n                this.fire('click', {originalEvent: e});\n            }\n        },\n\n        _onStart: function(e) {\n            this._moved = false;\n\n            if (this._moving) { return; }\n\n            var first = e.touches ? e.touches[0] : e;\n\n            this._startPoint = new DG.Point(first.clientX, first.clientY);\n\n            this._toggleTouchEvents();\n        },\n\n        _onEnd: function(e) {\n            this._toggleTouchEvents(true);\n\n            this._onClick(e);\n\n            this._moving = false;\n        },\n\n        _onMove: function(e) {\n\n            if (e.touches && e.touches.length > 1) {\n                this._moved = true;\n                return;\n            }\n\n            var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\n                newPoint = DG.point(first.clientX, first.clientY),\n                offset = Math.abs(newPoint.subtract(this._startPoint).y);\n\n            if (!offset || offset < 10) { return; }\n\n            this._moving = this._moved = true;\n\n        },\n\n        _initBaron: function() {\n            var context = this._scrollerWrapper;\n            this._baron = graf({\n                scroller: '.dg-scroller',\n                bar: '.dg-scroller__bar',\n                track: '.dg-scroller__bar-wrapper',\n                $: function(selector) {\n                    var node = {}.toString.call(selector) === '[object String]' ?\n                        context.querySelector(selector) : selector;\n\n                    return new BaronDomHelper(node);\n                },\n                event: function(elem, event, func, mode) {\n                    event.split(' ').forEach(function(type) {\n                        DG.DomEvent[mode || 'on'](elem, type, func);\n                    });\n                }\n            });\n        },\n\n        _initHeader: function() {\n            this._popupStructure.header = DG.DomUtil.create('header', 'dg-popup__header', this._contentNode);\n            this._popupStructure.header.setAttribute('dir', this.options.textDirection);\n        },\n\n        _initFooter: function() {\n            this._popupStructure.footer = DG.DomUtil.create('footer', 'dg-popup__footer', this._contentNode);\n            this._popupStructure.footer.setAttribute('dir', this.options.textDirection);\n        },\n\n        _initBodyContainer: function() {\n            this._popupStructure.wrapper = DG.DomUtil.create('div', 'dg-popup__container-wrapper', this._contentNode);\n            this._popupStructure.body = DG.DomUtil.create('div', 'dg-popup__container', this._popupStructure.wrapper);\n            this._popupStructure.body.setAttribute('dir', this.options.textDirection);\n        },\n\n        update: function() {\n            if (!this._map) { return; }\n\n            if (!DG.Browser.ielt9) {\n                this._container.style.visibility = 'hidden';\n            }\n            this._switchEvents(true);\n\n            this._clearNode(this._contentNode);\n            this._isBaronExist = false;\n\n            // init popup content dom structure\n            if (this._headerContent) { this._initHeader(); }\n            if (this._bodyContent) { this._initBodyContainer(); }\n            if (this._footerContent) { this._initFooter(); }\n\n            this._updatePopupStructure();\n            this.resize();\n\n            DG.DomEvent.on(this._wrapper, 'click', DG.DomEvent.stopPropagation);\n            this._switchEvents();\n\n            if (DG.Browser.ielt9) {\n                var elem = this._popupStructure.footer;\n                if (elem) {\n                    elem.className += ' ie8';\n                }\n            }\n\n            if (!DG.Browser.ielt9) {\n                this._container.style.visibility = '';\n            }\n        },\n\n        _getDelta: function() { // () -> Number\n            var delta = 0,\n                popup = this._popupStructure;\n\n            if (popup.header) {\n                delta += popup.header.offsetHeight;\n            }\n            if (popup.footer) {\n                delta += popup.footer.offsetHeight;\n            }\n\n            return delta;\n        },\n\n        _updateLayout: function() {\n            var opts = this.options,\n                content = this._contentNode, // leaflet-popup-content\n                wrapper = this._wrapper, // leaflet-popup-content-wrapper\n                style = content.style,\n                wrapperStyle = wrapper.style,\n                width,\n                scrolledClass = 'leaflet-popup-scrolled',\n                result = false;\n\n            style.margin = opts.border + 'px';\n\n            DG.DomUtil.removeClass(content, scrolledClass);\n\n            if (this._isContentHeightEnough()) {\n                wrapperStyle.maxHeight = content.offsetHeight + opts.border * 2 + 'px';\n            } else {\n                wrapperStyle.maxHeight = opts.maxHeight + 'px';\n                DG.DomUtil.addClass(content, scrolledClass);\n                result = true;\n            }\n\n            var availableWidth = opts.autoPanPadding[0] * 2;\n\n            if (opts.sprawling) {\n                width = opts.maxWidth;\n\n                width = Math.min(width, this._map._container.offsetWidth - availableWidth);\n                width = Math.max(width, opts.minWidth);\n            } else {\n                wrapperStyle.width = '';\n\n                style.whiteSpace = 'nowrap';\n                width = wrapper.offsetWidth;\n                style.whiteSpace = '';\n\n                width = Math.min(width, this._map._container.offsetWidth - availableWidth);\n                width = Math.min(Math.max(width, opts.minWidth), opts.maxWidth);\n            }\n\n            wrapperStyle.width = width + 'px';\n\n            this._containerWidth = this._container.offsetWidth;\n\n            return result;\n        },\n\n        _updatePopupStructure: function() {\n            Object.keys(this._popupStructure).forEach(function(item) {\n                this._insertContent(this['_' + item + 'Content'], this._popupStructure[item]);\n            }, this);\n\n            this.fire('contentupdate');\n        },\n\n        _insertContent: function(content, node) { // (String | DOMElement, DOMElement)\n            if (!content || !node) { return; }\n\n            content = (typeof content === 'function') ? content(this._source || this) : content;\n\n            if (typeof content === 'string') {\n                node.innerHTML = content;\n            } else {\n                this._clearNode(node);\n                node.appendChild(content);\n            }\n        },\n\n        _clearNode: function(node) { // (DOMElement)\n            while (node.hasChildNodes()) {\n                node.removeChild(node.firstChild);\n            }\n        },\n\n        _detachEl: function(elem) { // (DOMElement) -> DOMElement\n            if (elem.parentNode) {\n                elem.parentNode.removeChild(elem);\n            }\n            return elem;\n        },\n\n        _switchEvents: function(on) { // (Boolean)\n            var switcher = on ? 'off' : 'on';\n\n            if (!DG.Browser.touch) {\n                DG.DomEvent[switcher](this._contentNode, 'click', this._onClick, this);\n            } else {\n                DG.DomEvent[switcher](this._contentNode, 'touchstart mousedown mousemove', this._onStart, this);\n            }\n\n            if (this._isBaronExist) {\n                DG.DomEvent[switcher](this._scroller, 'scroll', this._onScroll, this);\n            }\n        },\n\n        _toggleTouchEvents: function(on) {\n            var switcher = on ? 'off' : 'on';\n\n            DG.DomEvent[switcher](this._contentNode, 'touchmove', this._onMove, this);\n            DG.DomEvent[switcher](this._contentNode, 'touchend', this._onEnd, this);\n        }\n\n    });\n}());\n\n\nDG.Map.include({\n    _markerClass: 'dg-customization__marker_type_mushroom',\n    _markerShowClass: 'dg-customization__marker_appear',\n    _markerHideClass: 'dg-customization__marker_disappear',\n    _dgHideClass: 'dg-popup_hidden_true',\n    openPopup: function(popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object])\n        if (!(popup instanceof L.Popup)) {\n            var content = popup;\n\n            popup = new L.Popup(options).setContent(content);\n        }\n\n        if (latlng) {\n            popup.setLatLng(latlng);\n        }\n\n        if (this.hasLayer(popup)) {\n            return this;\n        }\n\n        if (this._popup && this._popup.options.autoClose) {\n            this.closePopup();\n        }\n\n        this._popup = popup;\n\n        if (popup._source && popup._source._icon) {\n            if (popup._source._icon.className.indexOf(this._markerClass) !== -1) {\n                DG.DomUtil.removeClass(popup._source._icon, this._markerShowClass);\n                DG.DomUtil.addClass(popup._source._icon, this._markerHideClass);\n            } else {\n                DG.DomUtil.addClass(popup._source._icon, this._dgHideClass);\n                if (popup._source._shadow) {\n                    DG.DomUtil.addClass(popup._source._shadow, this._dgHideClass);\n                }\n            }\n        }\n\n        return this.addLayer(popup);\n    },\n\n    closePopup: function(popup) {  // (Popup) -> Popup\n        if (!popup || popup === this._popup) {\n            popup = this._popup;\n            this._popup = null;\n        }\n        if (popup) {\n            if (popup._source && popup._source._icon) {\n                if (popup._source._icon.className.indexOf(this._markerClass) !== -1) {\n                    DG.DomUtil.removeClass(popup._source._icon, this._markerHideClass);\n                    DG.DomUtil.addClass(popup._source._icon, this._markerShowClass);\n                } else {\n                    DG.DomUtil.removeClass(popup._source._icon, this._dgHideClass);\n                    if (popup._source._shadow) {\n                        DG.DomUtil.removeClass(popup._source._shadow, this._dgHideClass);\n                    }\n                }\n            }\n            this.removeLayer(popup);\n        }\n\n        return this;\n    }\n});\n"
  },
  {
    "path": "src/DGPopup/test/DGPopupSpec.js",
    "content": "describe('DG.Popup', function() {\n    var map,\n        mapContainer,\n        shortString = 'qwerty',\n        longString = (new Array(15)).join('1<br>'),\n\n        classPopupBodyContainer = 'dg-popup__container',\n        classPopupHeaderContainer = 'dg-popup__header',\n        classPopupFooterContainer = 'dg-popup__footer',\n        classScrollBar = 'dg-scroller__bar';\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [54.980206086231, 82.898068362003],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n    });\n\n    after(function() {\n        map.remove();\n        mapContainer.parentElement.removeChild(mapContainer);\n        mapContainer = map = shortString = longString = classPopupBodyContainer = classPopupHeaderContainer = classPopupFooterContainer = classScrollBar = null;\n    });\n\n    describe('check contents', function() {\n        var popup;\n\n        beforeEach(function() {\n            popup = DG.popup({maxHeight: 100})\n                .setLatLng([54.980206086231, 82.898068362003])\n                .addTo(map);\n        });\n\n        afterEach(function() {\n            popup.clear();\n            popup.remove();\n        });\n\n        describe('#setContent', function() {\n            it('should change popup content without scroll', function() {\n                popup.setContent(shortString);\n                expect(mapContainer.getElementsByClassName(classPopupBodyContainer)[0].innerHTML).to.be(shortString);\n                expect(mapContainer.getElementsByClassName(classScrollBar).length).to.be(0);\n            });\n\n            it('should change popup content with scroll', function() {\n                popup.setContent(longString);\n                expect(mapContainer.getElementsByClassName(classPopupBodyContainer)[0].innerHTML).to.be(longString);\n                expect(mapContainer.getElementsByClassName(classScrollBar).length).to.be(1);\n            });\n        });\n\n        describe('#getContent', function() {\n            it('should get eql content', function() {\n                popup.setContent(shortString);\n\n                expect(popup.getContent()).to.be(shortString);\n            });\n        });\n\n        describe('#setHeaderContent', function() {\n            it('should change popup header content', function() {\n                popup.setContent(shortString);\n                popup.setHeaderContent(shortString);\n                expect(mapContainer.getElementsByClassName(classPopupHeaderContainer)[0].innerHTML).to.be(shortString);\n            });\n\n            it('should be scroll in popup', function() {\n                popup.setContent(shortString);\n                popup.setHeaderContent(longString);\n                expect(mapContainer.getElementsByClassName(classScrollBar).length).to.be(1);\n            });\n        });\n\n        describe('#getHeaderContent', function() {\n            it('should get eql header content', function() {\n                popup.setHeaderContent(shortString);\n\n                expect(popup.getHeaderContent()).to.be(shortString);\n            });\n        });\n\n        describe('#setFooterContent', function() {\n            it('should change popup footer content', function() {\n                popup.setContent(shortString);\n                popup.setFooterContent(shortString);\n                expect(mapContainer.getElementsByClassName(classPopupFooterContainer)[0].innerHTML).to.be(shortString);\n            });\n\n            it('should be scroll in popup', function() {\n                popup.setContent(shortString);\n                popup.setFooterContent(longString);\n                expect(mapContainer.getElementsByClassName(classScrollBar).length).to.be(1);\n            });\n        });\n\n        describe('#getFooterContent', function() {\n            it('should get eql footer content', function() {\n                popup.setFooterContent(shortString);\n\n                expect(popup.getFooterContent()).to.be(shortString);\n            });\n        });\n    });\n\n    describe('check events', function() {\n        var popup;\n\n        before(function() {\n            popup = DG.popup({maxHeight: 100})\n                .setLatLng([54.980206086231, 82.898068362003])\n                .setContent(longString)\n                .addTo(map);\n        });\n\n        after(function() {\n            popup.remove();\n        });\n\n        it.skip('should call click event', function() {\n            var spy = sinon.spy();\n\n            popup.on('click', spy);\n\n            happen.click(popup._contentNode);\n\n            expect(spy.called).to.be.ok();\n        });\n\n        it('should call scroll event', function() {\n            var spy = sinon.spy();\n\n            popup.on('scroll', spy);\n\n            happen.once(mapContainer.getElementsByClassName(classPopupBodyContainer)[0], {\n                type: 'scroll'\n            });\n\n            expect(spy.called).to.be.ok();\n        });\n    });\n\n    // TODO: дописать остальные тесты после фикса https://github.com/2gis/mapsapi/issues/44\n});\n\n//  Modified tests from PopupSpec.js\ndescribe('L.Popup', function () {\n\n    var c, map;\n\n    beforeEach(function () {\n        c = document.createElement('div');\n        c.style.width = '400px';\n        c.style.height = '400px';\n        document.body.appendChild(c);\n        map = new L.Map(c);\n        map.setView(new L.LatLng(55.8, 37.6), 6);\n    });\n\n    afterEach(function () {\n        document.body.removeChild(c);\n    });\n\n    it(\"it should use a popup with a function as content with a FeatureGroup\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(54.6, 38.2));\n        var group = new L.FeatureGroup([marker1, marker2]).addTo(map);\n\n        marker1.description = \"I'm marker 1.\";\n        marker2.description = \"I'm marker 2.\";\n        group.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        map.options.closePopupOnClick = true;\n\n        // toggle popup on marker1\n        group.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6),\n            layer: marker1\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.firstElementChild.firstElementChild.innerHTML).to.be(\"I'm marker 1.\");\n\n        // toggle popup on marker2\n        group.fire('click', {\n            latlng: new L.LatLng(54.6, 38.2),\n            layer: marker2\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.firstElementChild.firstElementChild.innerHTML).to.be(\"I'm marker 2.\");\n    });\n\n    it(\"it should function for popup content after bindPopup is called\", function () {\n        var marker1 = new L.Marker(new L.LatLng(55.8, 37.6));\n        var marker2 = new L.Marker(new L.LatLng(54.6, 38.2));\n        var group = new L.FeatureGroup([marker1]).addTo(map);\n\n        marker1.description = \"I'm marker 1.\";\n        marker2.description = \"I'm marker 2.\";\n        group.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        group.addLayer(marker2);\n\n        map.options.closePopupOnClick = true;\n\n        // toggle popup on marker1\n        group.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6),\n            layer: marker1\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.firstElementChild.firstElementChild.innerHTML).to.be(\"I'm marker 1.\");\n\n        // toggle popup on marker2\n        group.fire('click', {\n            latlng: new L.LatLng(54.6, 38.2),\n            layer: marker2\n        });\n        expect(map.hasLayer(group._popup)).to.be(true);\n        expect(group._popup._contentNode.firstElementChild.firstElementChild.innerHTML).to.be(\"I'm marker 2.\");\n    });\n\n    it(\"should use a function for popup content when a source is passed to Popup\", function () {\n        var marker = new L.Marker(new L.LatLng(55.8, 37.6)).addTo(map);\n        var popup = L.popup({}, marker);\n\n        marker.description = \"I am a marker.\";\n\n        marker.bindPopup(function (layer) {\n            return layer.description;\n        });\n\n        marker.fire('click', {\n            latlng: new L.LatLng(55.8, 37.6)\n        });\n\n        expect(map.hasLayer(marker._popup)).to.be(true);\n        expect(marker._popup._contentNode.firstElementChild.firstElementChild.innerHTML).to.be(\"I am a marker.\");\n    });\n});\n"
  },
  {
    "path": "src/DGProjectDetector/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>projectDetector demo</title>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n</head>\n<body>\n\n<div id=\"map\" style=\"width: 100%; height: 600px; border: 1px solid #ccc;\"></div>\n\n<script type=\"text/javascript\">\n    DG.then(function () {\n\n        var currentProjectBound,\n            map = new DG.Map('map', {\n                center:new DG.LatLng(54.980206086231, 82.898068362003),\n                zoom:10,\n                key: DG.config.key || 'Your API access key'\n            });\n\n        map.on('projectchange', function (e) {\n            // projectchange event\n            var bounds = e.getProject().latLngBounds;\n            currentProjectBound = DG.rectangle(bounds, {color:\"#f03\", weight:1}).addTo(map);\n        });\n\n        map.on('projectleave', function (e) {\n            // projectleave event\n            if (currentProjectBound) {\n                currentProjectBound.onRemove(map);\n            }\n        });\n\n    });\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/DGProjectDetector/src/DGProjectDetector.js",
    "content": "DG.ProjectDetector = DG.Handler.extend({\n    initialize: function(map) { // (Object)\n        this._map = map;\n        this._project = undefined;\n        this._loadProjectList();\n    },\n\n    addHooks: function() {\n        this._projectWatch();\n        this._map.on('move', this._projectWatch, this);\n    },\n\n    removeHooks: function() {\n        this._map.off('move', this._projectWatch, this);\n    },\n\n    getProject: function() {\n        if (!this._project) { return false; }\n\n        return DG.Util.extend({}, this._project);\n    },\n\n    getProjectsList: function() {\n        return this._projectList.slice(0);\n    },\n\n    isProjectHere: function(coords, project, checkMethod) {\n        if (!coords) { return null; }\n\n        if (!(coords instanceof DG.LatLng) && !(coords instanceof DG.LatLngBounds)) {\n            coords = DG.latLng(coords);\n        }\n\n        coords = (coords instanceof DG.LatLngBounds) ?\n            DG.latLngBounds(coords.getSouthWest().wrap(), coords.getNorthEast().wrap()) : coords.wrap();\n\n        checkMethod = checkMethod || ((coords instanceof DG.LatLngBounds) ?  'intersects' : 'contains');\n\n        var method = checkMethod == 'intersects' ? this._testProjectIntersects : this._testProjectContains;\n        method = method.bind(this, coords);\n\n        if (project) {\n            return method(project);\n        } else {\n            return this._projectList.filter(method)[0];\n        }\n    },\n\n    _projectWatch: function() {\n        if (!this._map._loaded) {\n            return;\n        }\n\n        if (this._project && this._zoomInProject(this._project) && this._centerInProject(this._project)) {\n            return;\n        }\n\n        this._searchProject();\n\n        if (this._project) {\n            this._map.attributionControl._update(null, this._project.country_code);\n        }\n    },\n\n    _checkProjectData: function(project) {\n        function check(value) {\n            return value !== undefined && value !== null;\n        }\n\n        return project &&\n                project.bounds &&\n                check(project.code) &&\n                check(project.domain) &&\n                check(project.country_code) &&\n                check(project.flags) &&\n                project.zoom_level &&\n                    check(project.zoom_level.min) &&\n                    check(project.zoom_level.max) &&\n                project.time_zone &&\n                    check(project.time_zone.offset);\n    },\n\n    _loadProjectList: function() {\n        DG.fallbackProjectsList = DG.fallbackProjectsList || [];\n\n        if (!DG.projectsList) {\n            DG.projectsList = DG.fallbackProjectsList;\n        }\n        delete DG.fallbackProjectsList;\n\n        this._projectList = DG.projectsList\n            .filter(this._checkProjectData)\n            .map(function(project) {\n                var bound = DG.Wkt.toGeoJSON(project.bounds);\n                var latLngBounds = DG.geoJSON(bound).getBounds();\n                var defaultPos = project.default_pos ? DG.latLng(project.default_pos.lat, project.default_pos.lon) : null;\n\n\n                /* eslint-disable camelcase */\n                return {\n                    id: project.id,\n                    code: project.code,\n                    minZoom: project.zoom_level.min,\n                    maxZoom: project.zoom_level.max,\n                    timeOffset: project.time_zone.offset,\n                    bound: bound,\n                    latLngBounds: latLngBounds,\n                    traffic: !!project.flags.traffic,\n                    transport: !!project.flags.public_transport,\n                    roads: !!project.flags.road_network,\n                    country_code: project.country_code,\n                    domain: project.domain,\n                    defaultPos: defaultPos\n                };\n                /* eslint-enable camelcase */\n            });\n    },\n\n    _searchProject: function() {\n        // Вначале отсеиваем регионы по зуму\n        var filteredByZoom = this._projectList.filter(this._zoomInProject, this);\n\n        // Находим проект в границы которого попадает центр карты\n        var foundProjects = filteredByZoom.filter(this._centerInProject, this);\n\n        // Если такой проект не найден, то ищем проекты баунд боксы которых пересекаются с экраном\n        if (foundProjects.length === 0) {\n            var mapBounds = this._map.getBounds();\n            foundProjects = filteredByZoom.filter(DG.bind(this._testProjectIntersects, this, mapBounds));\n\n            if (foundProjects.length > 1) {\n                var mapCenter = this._map.getCenter();\n                var neareastProject = foundProjects[0];\n                for (var i = 1; i < foundProjects.length; i++) {\n                    var currentProject = foundProjects[i];\n                    if (currentProject.defaultPos &&\n                        mapCenter.distanceTo(neareastProject.defaultPos) >\n                        mapCenter.distanceTo(currentProject.defaultPos)\n                    ) {\n                        neareastProject = currentProject;\n                    }\n                }\n                foundProjects = [neareastProject];\n            }\n        }\n\n        var newProject = foundProjects[0] || null;\n\n        if (this._project === newProject) {\n            return;\n        }\n\n        var self = this;\n\n        if (this._project !== null) {\n            this._project = null;\n            setTimeout(function() {\n                self._map.fire('projectleave');\n            }, 1);\n        }\n\n        if (newProject) {\n            this._project = newProject;\n            setTimeout(function() {\n                self._map.fire('projectchange', {getProject: self.getProject.bind(self)});\n            }, 1);\n        }\n    },\n\n    _testProjectIntersects: function(bounds, project) {\n        return project.latLngBounds.intersects(bounds);\n    },\n\n    _testProjectContains: function(latlng, project) {\n        return DG.PolyUtil.inside([latlng.lng, latlng.lat], project.bound);\n    },\n\n    _centerInProject: function(project, checkMethod) {\n        return this.isProjectHere(this._map.getCenter(), project, checkMethod);\n    },\n\n    _zoomInProject: function(project) {\n        return (this._map.getZoom() >= project.minZoom);\n    }\n});\n\nDG.Map.mergeOptions({\n    projectDetector: true\n});\n\nDG.Map.addInitHook('addHandler', 'projectDetector', DG.ProjectDetector);\n"
  },
  {
    "path": "src/DGProjectDetector/test/ProjectDetectorInSpec.js",
    "content": "describe('DG.ProjectDetectorIn', function () {\n    var map,\n        mapContainer,\n        initZoom = 17,\n        maxZoom = 18,\n        maxDesertZoom = 16,\n        start,\n        project1,\n        project2,\n        desert1,\n        desert2;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n\n        start =        new DG.LatLng(54.98117239821992, 82.88922250270844);\n\n        // Где-то где есть проект\n        project1 =     new DG.LatLng(54.97902673261798, 82.819265127182);\n        project2 =     new DG.LatLng(54.98620210307464, 73.41429233551025);\n\n        // Где-то в лесу, там где нет проекта\n        desert1 =      new DG.LatLng(59.56, 86.32);\n        desert2 =      new DG.LatLng(65.38, 87.39);\n\n        document.body.appendChild(mapContainer);\n        mapContainer.style.width = 1900 + 'px';\n        mapContainer.style.height = 600 + 'px';\n    });\n\n    after(function() {\n        document.body.removeChild(mapContainer);\n        mapContainer = initZoom = maxZoom = maxDesertZoom = start = project1 = null;\n        project2 = desert1 = desert2 = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: start,\n            key: window.__karma__.config.secretKey,\n            'zoom': initZoom,\n            'geoclicker': true,\n            'zoomAnimation': false\n        });\n    });\n\n    afterEach(function () {\n        map.remove();\n        map = null;\n    });\n\n    describe('#setView', function () {\n\n        it('go to from project to project', function () {\n            expect(map.setView(project1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from desert to project', function () {\n            map.setView(desert1, maxZoom, {animate: false});\n            expect(map.setView(project1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from project1 to project2', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.setView(project2, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('go to from project to desert', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to from desert1 to desert2', function () {\n            map.setView(desert1, maxDesertZoom, {animate: false});\n\n            expect(map.setView(desert2, maxDesertZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert2);\n        });\n\n    });\n\n    describe('#setZoom', function () {\n\n        it('go to 18 zoom level in desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to 18 zoom level from 0', function () {\n            map.setView(project1, 0);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to 0 zoom level from 18', function () {\n            map.setView(project1, maxZoom);\n\n            map.setZoom(0);\n            expect(map.getZoom()).to.be(0);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to max zoom level + 1', function () {\n            map.setZoom(map.getMaxZoom() + 1);\n            expect(map.getZoom()).to.be(map.getMaxZoom());\n        });\n\n        it('go to min zoom level - 1', function () {\n            map.setZoom(map.getMinZoom() - 1);\n            expect(map.getZoom()).to.be(map.getMinZoom());\n        });\n    });\n\n    describe('#zoomIn', function () {\n\n        it('call on maxZoom', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(11);\n        });\n\n    });\n\n    describe('#zoomOut', function () {\n\n        it('call on minZoom', function () {\n            map.setView(desert1, 0);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(0);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(9);\n        });\n\n    });\n\n    describe('#setZoomAround', function () {\n\n        it('zoom to other project', function () {\n            map.setView(project1, 17);\n\n            expect(map.setZoomAround(project2, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n\n        it('zoom in the project', function () {\n            map.setView(start, 13);\n\n            expect(map.setZoomAround(project1, maxZoom)).to.be(map);\n            expect(map.getBounds().contains(project1)).to.be.ok();\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n    });\n\n    describe('#fitBounds', function () {\n\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from project2 small zoom', function () {\n            map.setView(project2, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on small square from project1 zero zoom', function () {\n            map.setZoomAround(L.latLng(56.68037378950137, 89.4287109375), 4);\n\n            expect(map.fitBounds([[54.98116931987221, 82.8987979888916], [54.97977172563573, 82.8981113433837]])).to.be(map);\n            expect(map.getZoom()).to.be(18);\n        });\n    });\n\n    describe('#fitWorld', function () {\n\n        it('fire from max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire from min zoom', function () {\n            map.setView(project1, 0);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire after min zoom 15', function () {\n            map.setZoom(15);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n    });\n\n    describe('#panTo', function () {\n\n        it('fire on project2 from project1', function () {\n            map.setView(project1, 16);\n\n            expect(map.panTo(project2)).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('fire on desert from project1 max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panTo(desert1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('fire on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panTo(project1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('fire on project1 from project1', function () {\n            map.setView(start, 15);\n\n            expect(map.panTo(project1, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(15);\n            expect(map.getCenter().distanceTo(project1)).to.be.below(15);\n        });\n    });\n\n    describe('#panInsideBounds', function () {\n\n        it('bound on project1 from project2', function () {\n            map.setView(project2, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n    });\n\n    describe('#panBy', function () {\n\n        it('call with viewport size', function () {\n            map.setView(project1, 16);\n\n            expect(map.panBy([1901, 601], {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.971628386497684, 82.86006689071657));\n        });\n\n        it('call on project viewport', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panBy([100, -200]), {animate: false}).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.97964243031826, 82.819801568985), 10e-4);\n        });\n\n    });\n\n    describe('#MaxZoom in options', function () {\n\n        it('set less max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(16);\n        });\n\n        it('set less max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set more max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(19);\n        });\n\n        it('set more max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set max zoom, go to from project to desert and back to the project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n            map.setView(project1, maxZoom, {animate: false});\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n\n            expect(map.setView(project1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n    });\n\n    describe('#multiLayers', function () {\n        var cloudmade2;\n        beforeEach(function () {\n            function getCloudMadeUrl(styleId) {\n                return 'http://{s}.tile.cloudmade.com/d4fc77ea4a63471cab2423e66626cbb6/' + styleId + '/256/{z}/{x}/{y}.png';\n            }\n            cloudmade2 = DG.tileLayer(getCloudMadeUrl(998), {attribution: 'Hello world', minZoom: 5, maxZoom: 18}).addTo(map);\n        });\n\n        afterEach(function () {\n            map.removeLayer(cloudmade2);\n        });\n\n        it('zoom to 18 in desert with added layer', function () {\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n\n        it('zoom to 18 in desert with remove layer', function () {\n            map.removeLayer(cloudmade2);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('zoom to 18 in desert with remove 2gis tilelayer', function () {\n            map.removeLayer(map.baseLayer);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n    });\n\n    describe('#isProjectHere', function () {\n\n        it('without params', function () {\n            expect(map.projectDetector.isProjectHere()).to.not.be.ok();\n        });\n\n        it('in desert', function () {\n            expect(map.projectDetector.isProjectHere(desert1)).to.not.be.ok();\n        });\n\n        it('in project', function () {\n            expect(map.projectDetector.isProjectHere(project1)).to.have.property('latLngBounds');\n            expect(map.projectDetector.isProjectHere(project1).code).to.be.eql('novosibirsk');\n        });\n    });\n\n    describe('#should fire', function () {\n        it('\\'projectchange\\' event', function (done) {\n            var onProjectChange = function () {\n                map.off('projectchange', onProjectChange);\n                done();\n            };\n            map.on('projectchange', onProjectChange);\n            map.setView(project2, maxZoom);\n        });\n\n        it('\\'projectleave\\' event', function (done) {\n            var onProjectLeave = function () {\n                map.off('projectleave', onProjectLeave);\n                done();\n            };\n            map.on('projectleave', onProjectLeave);\n            map.setView(desert1, maxZoom);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGProjectDetector/test/ProjectDetectorInitSpec.js",
    "content": "describe('DG.ProjectDetectorInit', function () {\n    var map,\n        mapContainer,\n        maxZoom = 18,\n        maxDesertZoom = 16,\n        project1,\n        desert1;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n\n        // Где-то где есть проект\n        project1 = new DG.LatLng(54.97902673261798, 82.819265127182);\n\n        // Где-то в лесу, там где нет проекта\n        desert1 = new DG.LatLng(59.56, 86.32);\n\n        document.body.appendChild(mapContainer);\n        mapContainer.style.width = 1900 + 'px';\n        mapContainer.style.height = 600 + 'px';\n    });\n\n    after(function() {\n        document.body.removeChild(mapContainer);\n        map = mapContainer = maxZoom = maxDesertZoom = project1 = desert1 = null;\n    });\n\n    describe('#initMap', function () {\n\n        afterEach(function () {\n            map.remove();\n            map = null;\n        });\n\n        it('in project', function () {\n            map = new DG.Map(mapContainer, {\n                center: project1,\n                key: window.__karma__.config.secretKey,\n                'zoom': 19,\n                'geoclicker': true,\n                'zoomAnimation': false\n            });\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n\n        it('in desert', function () {\n            map = new DG.Map(mapContainer, {\n                center: desert1,\n                key: window.__karma__.config.secretKey,\n                'zoom': 19,\n                'geoclicker': true,\n                'zoomAnimation': false\n            });\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('in project with max zoom', function () {\n            map = new DG.Map(mapContainer, {\n                center: project1,\n                key: window.__karma__.config.secretKey,\n                'zoom': 19,\n                'maxZoom': 15,\n                'geoclicker': true,\n                'zoomAnimation': false\n            });\n            expect(map.getZoom()).to.be.equal(15);\n        });\n\n        it('in desert with max zoom', function () {\n            map = new DG.Map(mapContainer, {\n                center: desert1,\n                key: window.__karma__.config.secretKey,\n                'zoom': 19,\n                'maxZoom': 15,\n                'geoclicker': true,\n                'zoomAnimation': false\n            });\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('without options', function () {\n            map = new DG.Map(mapContainer).setView([0, 0], 0);\n            expect(map.getCenter()).to.be.eql({lat: 0, lng: 0});\n        });\n\n    });\n});\n"
  },
  {
    "path": "src/DGProjectDetector/test/ProjectDetectorOutOfWorldSpec.js",
    "content": "describe('DG.ProjectDetectorOut', function () {\n    var map,\n        mapContainer,\n        initZoom = 17,\n        maxZoom = 18,\n        maxDesertZoom = 16,\n        start,\n        project1,\n        project2,\n        desert1,\n        desert2;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n\n        start =        new DG.LatLng(54.98117239821992, 360 + 82.88922250270844);\n\n        // Где-то где есть проект\n        project1 =     new DG.LatLng(54.97902673261798, 360 + 82.819265127182);\n        project2 =     new DG.LatLng(54.98620210307464, 360 + 73.41429233551025);\n\n        // Где-то в лесу, там где нет проекта\n        desert1 =      new DG.LatLng(59.56, 360 + 86.32);\n        desert2 =      new DG.LatLng(65.38, 360 + 87.39);\n\n        document.body.appendChild(mapContainer);\n        mapContainer.style.width = 1900 + 'px';\n        mapContainer.style.height = 600 + 'px';\n    });\n\n    after(function() {\n        document.body.removeChild(mapContainer);\n        mapContainer = initZoom = maxZoom = maxDesertZoom = start = project1 = null;\n        project2 = desert1 = desert2 = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: start,\n            key: window.__karma__.config.secretKey,\n            'zoom': initZoom,\n            'geoclicker': true,\n            'zoomAnimation': false\n        });\n    });\n\n    afterEach(function () {\n        map.remove();\n        map = null;\n    });\n\n    describe('#setView', function () {\n\n        it('go to from project to project', function () {\n            expect(map.setView(project1, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from desert to project', function () {\n            map.setView(desert1, maxZoom);\n            expect(map.setView(project1, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from project1 to project2', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.setView(project2)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('go to from project to desert', function () {\n            map.setView(project1, maxZoom, {animate: false});\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to from desert1 to desert2', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.setView(desert2)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert2);\n        });\n\n    });\n\n    describe('#setZoom', function () {\n\n        it('go to 18 zoom level in desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to 18 zoom level from 0', function () {\n            map.setView(project1, 0);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to 0 zoom level from 18', function () {\n            map.setView(project1, maxZoom);\n\n            map.setZoom(0);\n            expect(map.getZoom()).to.be(0);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to max zoom level + 1', function () {\n            map.setZoom(map.getMaxZoom() + 1);\n            expect(map.getZoom()).to.be(map.getMaxZoom());\n        });\n\n        it('go to min zoom level - 1', function () {\n            map.setZoom(map.getMinZoom() - 1);\n            expect(map.getZoom()).to.be(map.getMinZoom());\n        });\n    });\n\n    describe('#zoomIn', function () {\n\n        it('call on maxZoom', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(11);\n        });\n\n    });\n\n    describe('#zoomOut', function () {\n\n        it('call on minZoom', function () {\n            map.setView(desert1, 0);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(0);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(9);\n        });\n\n    });\n\n    describe('#setZoomAround', function () {\n\n        it('zoom to other project', function () {\n            map.setView(project1, 17);\n\n            expect(map.setZoomAround(project2, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n\n        it('zoom in the project', function () {\n            map.setView(start, 13);\n\n            expect(map.setZoomAround(project1, maxZoom)).to.be(map);\n            expect(map.getBounds().contains(project1)).to.be.ok();\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n    });\n\n    describe('#fitBounds', function () {\n\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from project2 small zoom', function () {\n            map.setView(project2, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on small square from project1 zero zoom', function () {\n            map.setZoomAround(L.latLng(56.68037378950137, 89.4287109375), 4);\n\n            expect(map.fitBounds([[54.98116931987221, 82.8987979888916], [54.97977172563573, 82.8981113433837]])).to.be(map);\n            expect(map.getZoom()).to.be(18);\n        });\n    });\n\n    describe('#fitWorld', function () {\n\n        it('fire from max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire from min zoom', function () {\n            map.setView(project1, 0);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire after min zoom 15', function () {\n            map.setZoom(15);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n    });\n\n    describe('#panTo', function () {\n\n        it('fire on project2 from project1', function () {\n            map.setView(project1, 16);\n\n            expect(map.panTo(project2)).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('fire on desert from project1 max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panTo(desert1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('fire on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panTo(project1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('fire on project1 from project1', function () {\n            map.setView(start, 15);\n\n            expect(map.panTo(project1, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(15);\n            expect(map.getCenter().distanceTo(project1)).to.be.below(15);\n        });\n    });\n\n    describe('#panInsideBounds', function () {\n\n        it('bound on project1 from project2', function () {\n            map.setView(project2, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n    });\n\n    describe('#panBy', function () {\n\n        it('call with viewport size', function () {\n            map.setView(project1, 16);\n\n            expect(map.panBy([1901, 601]), {animate: false}).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.971628386497684, 442.8600454330445));\n        });\n\n        it('call on project viewport', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panBy([100, -200], {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.97964243031826, 442.8198015689851));\n        });\n\n    });\n\n    describe('#MaxZoom in options', function () {\n\n        it('set less max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(16);\n        });\n\n        it('set less max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set more max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(19);\n        });\n\n        it('set more max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set max zoom, go to from project to desert and back to the project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n            map.setView(project1, maxZoom, {animate: false});\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n\n            expect(map.setView(project1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n    });\n\n    describe('#multiLayers', function () {\n        var cloudmade2;\n        beforeEach(function () {\n            function getCloudMadeUrl(styleId) {\n                return 'http://{s}.tile.cloudmade.com/d4fc77ea4a63471cab2423e66626cbb6/' + styleId + '/256/{z}/{x}/{y}.png';\n            }\n            cloudmade2 = DG.tileLayer(getCloudMadeUrl(998), {attribution: 'Hello world', minZoom: 5, maxZoom: 18}).addTo(map);\n        });\n\n        afterEach(function () {\n            map.removeLayer(cloudmade2);\n        });\n\n        it('zoom to 18 in desert with added layer', function () {\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n\n        it('zoom to 18 in desert with remove layer', function () {\n            map.removeLayer(cloudmade2);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('zoom to 18 in desert with remove 2gis tilelayer', function () {\n            map.removeLayer(map.baseLayer);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n    });\n\n    describe('#isProjectHere', function () {\n\n        it('without params', function () {\n            expect(map.projectDetector.isProjectHere()).to.not.be.ok();\n        });\n\n        it('in desert', function () {\n            expect(map.projectDetector.isProjectHere(desert1)).to.not.be.ok();\n        });\n\n        it('in project', function () {\n            expect(map.projectDetector.isProjectHere(project1)).to.have.property('latLngBounds');\n            expect(map.projectDetector.isProjectHere(project1).code).to.be.eql('novosibirsk');\n        });\n    });\n\n    describe('#should fire', function () {\n        it('\\'projectchange\\' event', function (done) {\n            var onProjectChange = function () {\n                map.off('projectchange', onProjectChange);\n                done();\n            };\n            map.on('projectchange', onProjectChange);\n            map.setView(project2, maxZoom);\n        });\n\n        it('\\'projectleave\\' event', function (done) {\n            var onProjectLeave = function () {\n                map.off('projectleave', onProjectLeave);\n                done();\n            };\n            map.on('projectleave', onProjectLeave);\n            map.setView(desert1, maxZoom);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGProjectDetector/test/ProjectDetectorUnderSpec.js",
    "content": "describe('DG.ProjectDetectorUnder', function () {\n    var map,\n        mapContainer,\n        initZoom = 1,\n        maxZoom = 18,\n        maxDesertZoom = 16,\n        start,\n        project1,\n        project2,\n        desert1,\n        desert2;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n\n        start =        new DG.LatLng(54.98117239821992, 82.88922250270844);\n\n        // Где-то где есть проект\n        project1 =     new DG.LatLng(54.97902673261798, 82.819265127182);\n        project2 =     new DG.LatLng(54.98620210307464, 73.41429233551025);\n\n        // Где-то в лесу, там где нет проекта\n        desert1 =      new DG.LatLng(59.56, 86.32);\n        desert2 =      new DG.LatLng(65.38, 87.39);\n\n        document.body.appendChild(mapContainer);\n        mapContainer.style.width = 1900 + 'px';\n        mapContainer.style.height = 600 + 'px';\n    });\n\n    after(function () {\n        document.body.removeChild(mapContainer);\n        mapContainer = initZoom = maxZoom = maxDesertZoom = start = project1 = null;\n        project2 = desert1 = desert2 = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(mapContainer, {\n            center: start,\n            key: window.__karma__.config.secretKey,\n            'zoom': initZoom,\n            'geoclicker': true,\n            'zoomAnimation': false\n        });\n    });\n\n    afterEach(function () {\n        map.remove();\n        map = null;\n    });\n\n    describe('#setView', function () {\n\n        it('go to from project to project', function () {\n            expect(map.setView(project1, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from desert to project', function () {\n            map.setView(desert1, maxZoom);\n            expect(map.setView(project1, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to from project1 to project2', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.setView(project2)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('go to from project to desert', function () {\n            map.setView(project1, maxZoom, {animate: false});\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to from desert1 to desert2', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.setView(desert2)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert2);\n        });\n\n    });\n\n    describe('#setZoom', function () {\n\n        it('go to 18 zoom level in desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('go to 18 zoom level from 0', function () {\n            map.setView(project1, 0);\n\n            map.setZoom(maxZoom);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to 0 zoom level from 18', function () {\n            map.setView(project1, maxZoom);\n\n            map.setZoom(0);\n            expect(map.getZoom()).to.be(0);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('go to max zoom level + 1', function () {\n            map.setZoom(map.getMaxZoom() + 1);\n            expect(map.getZoom()).to.be(map.getMaxZoom());\n        });\n\n        it('go to min zoom level - 1', function () {\n            map.setZoom(map.getMinZoom() - 1);\n            expect(map.getZoom()).to.be(map.getMinZoom());\n        });\n    });\n\n    describe('#zoomIn', function () {\n\n        it('call on maxZoom', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomIn()).to.be(map);\n            expect(map.getZoom()).to.be(11);\n        });\n\n    });\n\n    describe('#zoomOut', function () {\n\n        it('call on minZoom', function () {\n            map.setView(desert1, 0);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(0);\n        });\n\n        it('call on 16 level', function () {\n            map.setView(desert1, 10);\n\n            expect(map.zoomOut()).to.be(map);\n            expect(map.getZoom()).to.be(9);\n        });\n\n    });\n\n    describe('#setZoomAround', function () {\n\n        it('zoom to other project', function () {\n            map.setView(project1, 17);\n\n            expect(map.setZoomAround(project2, maxZoom)).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n\n        it('zoom in the project', function () {\n            map.setView(start, 13);\n\n            expect(map.setZoomAround(project1, maxZoom)).to.be(map);\n            expect(map.getBounds().contains(project1)).to.be.ok();\n            expect(map.getZoom()).to.be(maxZoom);\n        });\n    });\n\n    describe('#fitBounds', function () {\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from project2 small zoom', function () {\n            map.setView(project2, 8);\n\n            expect(map.fitBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on small square from project1 zero zoom', function () {\n            map.setZoomAround(L.latLng(56.68037378950137, 89.4287109375), 4);\n\n            expect(map.fitBounds([[54.98116931987221, 82.8987979888916], [54.97977172563573, 82.8981113433837]])).to.be(map);\n            expect(map.getZoom()).to.be(18);\n        });\n    });\n\n    describe('#fitWorld', function () {\n\n        it('fire from max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire from min zoom', function () {\n            map.setView(project1, 0);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n\n        it('fire after min zoom 15', function () {\n            map.setZoom(15);\n\n            expect(map.fitWorld()).to.be(map);\n            expect(map.getZoom()).to.be(1);\n        });\n    });\n\n    describe('#panTo', function () {\n\n        it('fire on project2 from project1', function () {\n            map.setView(project1, 16);\n\n            expect(map.panTo(project2)).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project2);\n        });\n\n        it('fire on desert from project1 max zoom', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panTo(desert1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n        });\n\n        it('fire on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panTo(project1)).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n        it('fire on project1 from project1', function () {\n            map.setView(start, 15);\n\n            expect(map.panTo(project1, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(15);\n            expect(map.getCenter().distanceTo(project1)).to.be.below(15);\n        });\n    });\n\n    describe('#panInsideBounds', function () {\n\n        it('bound on project1 from project2', function () {\n            map.setView(project2, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n        it('bound on project1 from desert', function () {\n            map.setView(desert1, maxDesertZoom);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n        });\n\n        it('bound on project1 from project1 small zoom', function () {\n            map.setView(project1, 15);\n\n            expect(map.panInsideBounds(new DG.LatLngBounds(project1, start))).to.be(map);\n            expect(map.getZoom()).to.be(15);\n        });\n\n    });\n\n    describe('#panBy', function () {\n\n        it('call with viewport size', function () {\n            map.setView(project1, 16);\n\n            expect(map.panBy([1901, 601], {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.971628386497684, 82.86006689071657));\n        });\n\n        it('call on project viewport', function () {\n            map.setView(project1, maxZoom);\n\n            expect(map.panBy([100, -200], {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxZoom);\n            expect(map.getCenter()).to.nearLatLng(DG.latLng(54.97964243031826, 82.819801568985));\n        });\n\n    });\n\n    describe('#MaxZoom in options', function () {\n\n        it('set less max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(16);\n        });\n\n        it('set less max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set more max project zoom and zoom to 20 in project', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(project1, 20);\n\n            expect(map.getZoom()).to.be.equal(19);\n        });\n\n        it('set more max project zoom and zoom to 20 in desert', function () {\n            map.options.maxZoom = 19;\n            expect(map.getMaxZoom()).to.be.equal(19);\n\n            map.setView(desert1, 20);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('set max zoom, go to from project to desert and back to the project', function () {\n            map.options.maxZoom = 16;\n            expect(map.getMaxZoom()).to.be.equal(16);\n            map.setView(project1, maxZoom, {animate: false});\n\n            expect(map.setView(desert1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(maxDesertZoom);\n            expect(map.getCenter()).to.be.equal(desert1);\n\n            expect(map.setView(project1, maxZoom, {animate: false})).to.be(map);\n            expect(map.getZoom()).to.be(16);\n            expect(map.getCenter()).to.be.equal(project1);\n        });\n\n    });\n\n    describe('#multiLayers', function () {\n        var cloudmade2;\n        beforeEach(function () {\n            function getCloudMadeUrl(styleId) {\n                return 'http://{s}.tile.cloudmade.com/d4fc77ea4a63471cab2423e66626cbb6/' + styleId + '/256/{z}/{x}/{y}.png';\n            }\n            cloudmade2 = DG.tileLayer(getCloudMadeUrl(998), {attribution: 'Hello world', minZoom: 5, maxZoom: 18}).addTo(map);\n        });\n\n        afterEach(function () {\n            map.removeLayer(cloudmade2);\n        });\n\n        it('zoom to 18 in desert with added layer', function () {\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n\n        it('zoom to 18 in desert with remove layer', function () {\n            map.removeLayer(cloudmade2);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxDesertZoom);\n        });\n\n        it('zoom to 18 in desert with remove 2gis tilelayer', function () {\n            map.removeLayer(map.baseLayer);\n            map.setView(desert1, maxZoom);\n\n            expect(map.getZoom()).to.be.equal(maxZoom);\n        });\n    });\n\n    describe('#isProjectHere', function () {\n        it('without params', function () {\n            expect(map.projectDetector.isProjectHere()).to.not.be.ok();\n        });\n\n        it('in desert', function () {\n            expect(map.projectDetector.isProjectHere(desert1)).to.not.be.ok();\n        });\n\n        it('in project', function () {\n            expect(map.projectDetector.isProjectHere(project1)).to.have.property('latLngBounds');\n            expect(map.projectDetector.isProjectHere(project1).code).to.be.eql('novosibirsk');\n        });\n    });\n\n    describe('#should fire', function () {\n        it('\\'projectchange\\' event', function (done) {\n            var onProjectChange = function () {\n                map.off('projectchange', onProjectChange);\n                done();\n            };\n            map.on('projectchange', onProjectChange);\n            map.setView(project2, maxZoom);\n        });\n\n        it('\\'projectleave\\' event', function (done) {\n            var onProjectLeave = function () {\n                map.off('projectleave', onProjectLeave);\n                done();\n            };\n            map.on('projectleave', onProjectLeave);\n            map.setView(desert1, maxZoom);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGRoundControl/skin/basic/less/dg-control-round.less",
    "content": ".dg-control-round {\n    position: relative;\n    padding: 5px;\n    width: 30px;\n    height: 30px;\n    border-radius: 50%;\n    cursor: default;\n}\n\n.dg-control-round__icon {\n    position: relative;\n    display: block;\n    width: 30px;\n    height: 30px;\n    border-radius: 50%;\n    background-color: #f0f0f0; // 94%, fallback\n    background-image: linear-gradient(to bottom, #fff 0, hsl(0, 0%, 88%) 100%);\n    color: #2b2a29;\n    text-align: center;\n    text-decoration: none;\n    text-shadow: 0 1px 0 #fff;\n    font-size: 22px;\n    line-height: 30px;\n    cursor: pointer;\n\n    .no-touch &:hover {\n        background-color: #f5f5f5; // 96%, fallback\n        background-image: linear-gradient(to bottom, hsl(0, 0%, 92%) 0, #fff 100%);\n    }\n\n    &:active,\n    .no-touch &:active,\n    &_state_active {\n        background-color: #ebebeb; // 92%, fallback\n        background-image: linear-gradient(to bottom, hsl(0, 0%, 84%) 0, #fff 100%);\n    }\n\n    .leaflet-disabled &,\n    .no-touch .leaflet-disabled &:hover,\n    .leaflet-disabled &:active {\n        background-image: none;\n        cursor: default;\n    }\n\n    .leaflet-touch &:before {\n        position: absolute;\n        top: -10px;\n        right: -15px;\n        bottom: -10px;\n        left: -15px;\n        content: '';\n    }\n}\n\n.dg-control-round_is-hidden_true {\n    display: none;\n}\n"
  },
  {
    "path": "src/DGRoundControl/skin/dark/less/dg-control-round.less",
    "content": ".dg-control-round {\n    background-color: #3d3d3d; // 24%\n    box-shadow: 0 3px 5px 0 rgba(0, 0, 0, .3);\n}\n\n.dg-control-round__icon {\n    box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .4);\n\n    .no-touch &:hover {\n        box-shadow: inset 0 1px #fff, 0 0 0 1px rgba(0, 0, 0, .3), 0 1px 0 1px rgba(0, 0, 0, .4);\n    }\n\n    &:active,\n    .no-touch &:active,\n    &_state_active {\n        box-shadow: inset 0 1px 1px 1px rgba(0, 0, 0, .2), 0 0 0 1px rgba(0, 0, 0, .3), 0 -1px 1px 0 #000;\n    }\n\n    .leaflet-disabled &,\n    .no-touch .leaflet-disabled &:hover,\n    .leaflet-disabled &:active {\n        background-color: #b8b8b8; // 72%\n        box-shadow: none;\n    }\n}\n"
  },
  {
    "path": "src/DGRoundControl/skin/light/less/dg-control-round.less",
    "content": ".dg-control-round {\n    background-color: #f0f0f0; // 94%\n    box-shadow: 0 0 0 1px #fff, 0 2px 5px 0 rgba(0, 0, 0, .3);\n}\n\n.dg-control-round__icon {\n    box-shadow: 0 0 1px 0 rgba(0, 0, 0, .4);\n\n    .leaflet-disabled &,\n    .no-touch .leaflet-disabled &:hover,\n    .leaflet-disabled &:active {\n        background-color: #e0e0e0; // 88%\n    }\n\n    .leaflet-disabled & {\n        box-shadow: none;\n    }\n}\n"
  },
  {
    "path": "src/DGRoundControl/src/DGRoundControl.js",
    "content": "DG.RoundControl = DG.Control.extend({\n    includes: DG.Mixin.Events,\n\n    options: {\n        position: 'topright',\n        iconClass: 'default'\n    },\n\n    onAdd: function(map) {\n        var controlClass = this._controlCLass = 'dg-control-round',\n            controlIconClass = this._controlIconCLass = this._controlCLass + '__icon',\n            container = DG.DomUtil.create('div', '');\n\n        if (this._disable) {\n            return container;\n        }\n        DG.DomUtil.addClass(container, controlClass);\n\n        var link = this._link = DG.DomUtil.create(\n            'a',\n            controlIconClass + ' ' + controlIconClass + '_name_' + this.options.iconClass,\n            container\n        );\n\n        link.href = '#';\n\n        this._renderTranslation();\n\n        this._map = map;\n\n        DG.DomEvent\n            .on(container, 'click', this._toggleControl, this)\n            .on(container, 'dblclick', DG.DomEvent.stopPropagation)\n            .on(link, 'mousedown', DG.DomEvent.stopPropagation);\n\n        this.fireEvent('add');\n\n        return container;\n    },\n\n    onRemove: function() {\n        this.fireEvent('remove');\n        DG.DomEvent.off(this._link, 'click', this._toggleControl);\n    },\n\n    setState: function(state) {\n        if (!this._link || !this._container) {\n            return this;\n        }\n\n        if (this._state) {\n            DG.DomUtil.removeClass(this._container, this._controlCLass + '_state_' + this._state);\n            DG.DomUtil.removeClass(this._link, this._controlIconCLass + '_state_' + this._state);\n\n            this._state = null;\n        }\n\n        if (state) {\n            this._state = state;\n\n            DG.DomUtil.addClass(this._container, this._controlCLass + '_state_' + this._state);\n            DG.DomUtil.addClass(this._link, this._controlIconCLass + '_state_' + this._state);\n        }\n\n        return this;\n    },\n\n    _toggleControl: function(e) {\n        DG.DomEvent.stop(e);\n        this.fireEvent('click');\n    }\n});\n\nDG.RoundControl.include(DG.Locale);\n\nDG.roundControl = function(options) {\n    return new DG.RoundControl(options);\n};\n"
  },
  {
    "path": "src/DGRoundControl/test/DGRoundControlSpec.js",
    "content": "describe('DG.RoundControl', function() {\n    var map, mapContainer, control, classIconControl, classActive, containerControl, spy;\n\n    before(function() {\n        classIconControl = 'dg-control-round__icon_name_default';\n        classActive = 'dg-control-round__icon_state_active';\n\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [55.017493, 82.819576],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n\n        control = DG.roundControl();\n    });\n\n    after(function() {\n        mapContainer.parentElement.removeChild(mapContainer);\n        map.remove();\n        map = mapContainer = control = classIconControl = classActive = containerControl = spy = null;\n    });\n\n    describe('#addTo', function() {\n        before(function() {\n            spy = sinon.spy();\n            control.on('add', spy);\n            control.addTo(map);\n        });\n\n        after(function() {\n            spy = null;\n        });\n\n        it('should container control on map', function() {\n            containerControl = document.body.getElementsByClassName(classIconControl);\n            expect(containerControl.length).to.be(1);\n            containerControl = containerControl[0];\n        });\n\n        it('should emit add event', function() {\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        // TODO: включить после фикса leaflet'а с добавлением нескольких контейнеров для одного контрола\n        it.skip('should only one container for one control', function() {\n            control.addTo(map);\n            expect(document.body.getElementsByClassName(classIconControl).length).to.be(1);\n        });\n\n        it('should emit click event', function() {\n            var spy = sinon.spy();\n            control.on('click', spy);\n            happen.click(containerControl);\n            expect(spy.callCount).to.be(1);\n        });\n    });\n\n    describe('#setState', function() {\n        it('should container have active class', function() {\n            control.setState('active');\n            expect(containerControl.className).to.contain(classActive);\n        });\n\n        it('should container haven\\'t active class and have \\'someclass\\'', function() {\n            control.setState('someclass');\n            expect(containerControl.className).not.contain(classActive);\n            expect(containerControl.className).to.contain('someclass');\n        });\n\n        it('should container haven\\' someclass', function() {\n            control.setState();\n            expect(containerControl.className).not.contain('someclass');\n        });\n    });\n\n    describe('#remove', function() {\n        before(function() {\n            spy = sinon.spy();\n            control.on('remove', spy);\n            control.remove();\n        });\n\n        after(function() {\n            spy = null;\n        });\n\n        it('should remove container on map', function() {\n            expect(document.body.getElementsByClassName(classIconControl).length).to.be(0);\n        });\n\n        it('should emit remove event', function() {\n            expect(spy.calledOnce).to.be.ok();\n        });\n\n        it('shouldn\\'t emit click event', function() {\n            var spy = sinon.spy();\n            control.on('click', spy);\n            happen.click(containerControl);\n            expect(spy.called).not.be.ok();\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGRuler/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>DGRuler demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            map = new DG.Map('map', {\n                'center': new DG.LatLng(51.73028, 36.19389),\n                'zoom': 17,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            var latLngs = [\n                [51.7314, 36.1938],\n                [51.7307, 36.1894],\n                [51.7297, 36.1926],\n                [51.7299, 36.1968],\n                [51.7307, 36.1968]]\n            DG.ruler(latLngs).addTo(map);\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGRuler/lang/ar.js",
    "content": "DG.Ruler.Dictionary.ar = {\n    km : 'كم',\n    m : 'م',\n    delimiter : '.'\n};\n"
  },
  {
    "path": "src/DGRuler/lang/cs.js",
    "content": "DG.Ruler.Dictionary.cs = {\n    km: 'km',\n    m: 'm',\n    delimiter: ','\n};\n"
  },
  {
    "path": "src/DGRuler/lang/en.js",
    "content": "DG.Ruler.Dictionary.en = {\n    km : 'km',\n    m : 'm',\n    delimiter : '.'\n};\n"
  },
  {
    "path": "src/DGRuler/lang/es.js",
    "content": "DG.Ruler.Dictionary.es = {\n    km : 'km',\n    m : 'm',\n    delimiter : ','\n};\n"
  },
  {
    "path": "src/DGRuler/lang/it.js",
    "content": "DG.Ruler.Dictionary.it = {\n    km : 'km',\n    m : 'm',\n    delimiter : ','\n};\n"
  },
  {
    "path": "src/DGRuler/lang/ru.js",
    "content": "DG.Ruler.Dictionary.ru = {\n    km : 'км',\n    m : 'м',\n    delimiter : ','\n};\n"
  },
  {
    "path": "src/DGRuler/skin/basic/less/dg-ruler.ie.less",
    "content": ".dg-ruler__point {\n    .repeatableBg('DGRuler__point');\n}\n\n.dg-ruler__label-container {\n    background: #0da5d5;\n}\n"
  },
  {
    "path": "src/DGRuler/skin/basic/less/dg-ruler.less",
    "content": ".leaflet-rulerMarker-pane {\n    z-index: 600;\n}\n\n.dg-ruler__label {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 200;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\n.dg-ruler__label-spacer {\n    display: block;\n}\n\n.dg-ruler__label-container {\n    display: none;\n    padding: 2px 4px;\n    border: 4px solid #fff;\n    border-radius: 13px;\n    background: #0da5d5;\n    background-clip: padding-box;\n    color: #fff;\n    white-space: nowrap;\n    font-size: 12px;\n}\n\n.dg-ruler__point {\n    display: inline-block;\n    margin: 2px 4px 0 0;\n    width: 10px;\n    height: 10px;\n    border-radius: 5px;\n    background: white;\n}\n\n.dg-ruler__label-remove-link {\n    .notRepeatableBgWithSizes('DGRuler__removeIcon');\n    display: none;\n    margin: 1px 0 0 4px;\n    vertical-align: top;\n    transition: all .2s ease;\n\n    .no-touch &:hover {\n        transform: rotate(90deg);\n    }\n}\n\n.dg-ruler__remove-link-overlay {\n    position: absolute;\n    top: -7px;\n    right: -7px;\n    bottom: -7px;\n    width: 40px;\n\n    .no-touch & {\n        display: none;\n    }\n}\n"
  },
  {
    "path": "src/DGRuler/src/GeometryStyles.js",
    "content": "var rulerRenderer = DG.svg({pane: 'rulerPane'});\nvar hoverRenderer = DG.svg({pane: 'rulerPane'});\n\nDG.Ruler.mergeOptions({\n    pathStyles: {\n        back: {\n            color: '#fff',\n            opacity: 1,\n            weight: 12,\n            pointerEvents: 'none',\n            noClip: true,\n            renderer: rulerRenderer,\n            smoothFactor: 0\n        },\n        middle: {\n            color: '#0da5d5',\n            opacity: 1,\n            weight: 4,\n            pointerEvents: 'none',\n            noClip: true,\n            renderer: rulerRenderer,\n            smoothFactor: 0\n        },\n        mouse: {\n            color: '#fff',\n            opacity: DG.Browser.vml ? 0.1 : 0,\n            weight: DG.Browser.touch ? 40 : 20,\n            pointerEvents: 'painted',\n            noClip: true,\n            renderer: hoverRenderer,\n            smoothFactor: 0\n        }\n    },\n    iconStyles: {\n        large: {\n            back: {\n                color: '#fff',\n                opacity: 1,\n                fillColor: '#fff',\n                fillOpacity: 1,\n                weight: 1,\n                radius: 13,\n                renderer: rulerRenderer\n            },\n            middle: {\n                color: '#0da5d5',\n                opacity: 1,\n                fillColor: '#0da5d5',\n                fillOpacity: 1,\n                weight: 1,\n                radius: 9,\n                renderer: rulerRenderer\n            },\n            front: {\n                color: '#fff',\n                opacity: 1,\n                fillColor: '#0da5d5',\n                fillOpacity: 1,\n                weight: 4,\n                radius: 5,\n                renderer: rulerRenderer\n            }\n        },\n        small: {\n            back: {\n                color: '#fff',\n                opacity: 1,\n                fillColor: '#fff',\n                fillOpacity: 1,\n                weight: 1,\n                radius: 9,\n                renderer: rulerRenderer\n            },\n            middle: {\n                color: '#0da5d5',\n                opacity: 1,\n                fillColor: '#0da5d5',\n                fillOpacity: 1,\n                weight: 1,\n                radius: 5,\n                renderer: rulerRenderer\n            },\n            front: {\n                color: '#fff',\n                opacity: 1,\n                fillColor: '#0da5d5',\n                fillOpacity: 1,\n                weight: 4,\n                radius: 2,\n                renderer: rulerRenderer\n            }\n        }\n    }\n});\n"
  },
  {
    "path": "src/DGRuler/src/LayeredMarker.js",
    "content": "DG.Ruler.LayeredMarker = DG.Marker.extend({\n    options: {\n        draggable: false,\n        keyboard: false,\n        riseOnHover: true,\n        pane: 'rulerMarkerPane',\n        textDirection: 'auto', // 'auto' | 'ltr' | 'rtl'\n        iconHTML: [\n            '<img class=\"dg-ruler__label-spacer\" src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\" width=\"26\" height=\"26\" />',\n            '<div class=\"dg-ruler__label-container\">',\n            '    <div class=\"dg-ruler__point\"></div>',\n            '    <span class=\"dg-ruler__label-distance\">0 км</span>',\n            '    <span class=\"dg-ruler__label-remove-link\"></span>',\n            '    <div class=\"dg-ruler__remove-link-overlay\"></div>',\n            '</div>'\n        ].join('\\n')\n    },\n\n    statics: {\n        domClass : 'dg-ruler__label'\n    },\n\n    addTo : function(map, layers) {\n        Object.keys(this._layers).forEach(function(name) {\n            layers[name].addLayer(this._layers[name]);\n        }, this);\n\n        this._viewport = layers;\n        return DG.Marker.prototype.addTo.call(this.on('move', this._onMove), map);\n    },\n\n    onRemove : function(map) {\n        Object.keys(this._layers).forEach(function(name) {\n            this._viewport[name].removeLayer(this._layers[name]);\n        }, this);\n        this.off('move', this._onMove);\n        this._viewport = null;\n        this._style = null;\n        return DG.Marker.prototype.onRemove.call(this, map);\n    },\n\n    setText : function(text) {\n        if (this._iconCollapsed) {\n            this.expand();\n        }\n        this._iconNodes.label.innerHTML = text;\n        this._iconNodes.label.setAttribute('dir', this.options.textDirection);\n        return this;\n    },\n\n    setPointStyle : function(style) {\n        if (this._style !== style) {\n            Object.keys(this._style = style).forEach(function(name) {\n                this._layers[name].setStyle(style[name]);\n            }, this);\n        }\n        return this;\n    },\n\n    expand : function() {\n        this._iconCollapsed = false;\n        this._iconNodes.container.style.display = 'block';\n        this._iconNodes.spacer.style.display = 'none';\n        return this;\n    },\n\n    collapse : function() {\n        this._iconCollapsed = true;\n        this._iconNodes.container.style.display = 'none';\n        this._iconNodes.spacer.style.display = 'block';\n        return this;\n    },\n\n    querySelector : function(selector) {\n        return this._icon.querySelector('.' + DG.Ruler.LayeredMarker.domClass + '-' + selector);\n    },\n\n    _onMove : function(event) {\n        var latlng = event.latlng;\n        Object.keys(this._layers).forEach(function(name) {\n            this._layers[name].setLatLng(latlng);\n        }, this);\n    },\n\n    _initIcon : function() {\n        DG.Marker.prototype._initIcon.call(this);\n        this._iconCollapsed = true;\n        this._icon.style.width = '';\n        this._iconNodes = {\n            label : this.querySelector('distance'),\n            spacer : this.querySelector('spacer'),\n            container : this.querySelector('container')\n        };\n    },\n\n    // don't change icon zIndex\n    _setPos: function(pos) {\n        L.DomUtil.setPosition(this._icon, pos);\n\n        if (this._shadow) {\n            L.DomUtil.setPosition(this._shadow, pos);\n        }\n    },\n\n    _afterInit : function() {\n        this._layers = this.options.layers || null;\n        this.options.icon = DG.divIcon({\n            className: DG.Ruler.LayeredMarker.domClass,\n            iconSize: [26, 26],\n            iconAnchor: [13, 13],\n            html: this.options.iconHTML\n        });\n    }\n\n});\n\nDG.Ruler.LayeredMarker.addInitHook('_afterInit');\n\nDG.Ruler.layeredMarker = function(latlng, options) {\n    return new DG.Ruler.LayeredMarker(latlng, options);\n};\n"
  },
  {
    "path": "src/DGRuler/src/Ruler.js",
    "content": "DG.Ruler = DG.Layer.extend({\n\n    options: {\n        editable: true\n    },\n\n    includes: [DG.Locale],\n\n    statics: {\n        Dictionary: {}\n    },\n\n    initialize: function(latlngs, options) { // (Array, Object)\n        DG.Util.setOptions(this, options);\n\n        this._layers = {\n            back : null,\n            middle : null,\n            front : null,\n            mouse : null\n        };\n        this._points = [];\n\n        this._layersContainer = DG.featureGroup();\n        Object.keys(this._layers).forEach(function(name) {\n            this._layersContainer.addLayer(this._layers[name] = DG.featureGroup());\n        }, this);\n\n        this._reset();\n\n        if (DG.Browser.mobile) {\n            delete this._lineMouseEvents.mouseover;\n            delete this._lineMouseEvents.mouseout;\n            delete this._lineMouseEvents.mousemove;\n        } else {\n            delete this._lineMouseEvents.click;\n        }\n\n        if (latlngs && latlngs.length) {\n            this.setLatLngs(latlngs);\n        }\n    },\n\n    onAdd: function(map) { // (Map)\n        this._map = map.on('langchange', this._updateDistance, this);\n\n        //  Pane for ruler Markers\n        if (!this._map.getPane('rulerMarkerPane')) {\n            this._map.createPane('rulerMarkerPane');\n        }\n\n        //  Main ruler pane (svg objects and runner)\n        if (!this._map.getPane('rulerPane')) {\n            this._map.createPane('rulerPane');\n        }\n\n        this._layersContainer.addTo(this._map);\n\n        if (this._points.length) {\n            this._layers.mouse.fire('layeradd');\n            this._updateDistance();\n        }\n\n        this._layers.mouse.on(this._lineMouseEvents, this);\n    },\n\n    onRemove: function(map) { // (Map)\n        map\n            .off('langchange', this._updateDistance, this)\n            .removeLayer(this._layersContainer);\n\n        this._layers.mouse.off(this._lineMouseEvents, this);\n        this._reset();\n    },\n\n    getTotalDistance: function() { // () -> Number\n        return this._calcDistance();\n    },\n\n    spliceLatLngs: function(index) { // (Number, Number, args ...) -> Array\n        var oldLength = this._points.length,\n            mutationStart = index >= 0 ? Math.min(index, oldLength) : oldLength - index,\n            removed = Array.prototype.splice.apply(this._points, arguments).map(function(point) {\n                this._layers.mouse.removeLayer(point);\n                return point.off().getLatLng();\n            }, this),\n            length = this._points.length;\n\n        if (length) {\n            for (var i = mutationStart; i < length; i++) {\n                if (!(this._points[i] instanceof DG.Ruler.LayeredMarker)) {\n                    this._points[i] = this._createPoint(this._points[i], this.options.iconStyles.large)\n                        .on(this._pointEvents, this)\n                        .once('add', this._addCloseHandler, this)\n                        .addTo(this._layers.mouse, this._layers);\n                }\n                if (i && !this._points[i - 1]._legs) {\n                    this._addLegs(this._points[i - 1]);\n                }\n                this._points[i].setPointStyle(this.options.iconStyles[i && i < length - 1 ? 'small' : 'large']);\n                this._points[i]._pos = i;\n            }\n            this._removeLegs(this._points[length - 1]);\n            if (oldLength > 0 && oldLength < length) {\n                this._points[oldLength - 1].collapse();\n            }\n            if (this._points[mutationStart]) {\n                this._updateLegs(this._points[mutationStart]);\n            }\n            if (mutationStart > 1) {\n                this._points[mutationStart - 1].setPointStyle(this.options.iconStyles.small);\n            }\n            this._updateDistance();\n            this._normalizeRulerPoints();\n        }\n        if (DG.Browser.touch && this._lineMarkerHelper) {\n            this._lineMarkerHelper.collapse();\n        }\n        this._fireChangeEvent();\n        return removed;\n    },\n\n    addLatLng: function(latlng) { // (LatLng) -> Ruler\n        var lastPoint = this._points[this._points.length - 1] || null;\n        latlng = DG.latLng(latlng);\n\n        if (lastPoint) {\n            latlng = this._normalizeLatLng(latlng, lastPoint.getLatLng());\n        }\n\n        this.spliceLatLngs(this._points.length, 0, latlng);\n        return this;\n    },\n\n    getLatLngs: function() { // () -> Array\n        return this._points.map(function(point) {\n            return point.getLatLng();\n        });\n    },\n\n    setLatLngs: function(latlngs) { // (Array) -> Ruler\n        var args = latlngs.slice();\n        args.unshift(0, this._points.length);\n        this.spliceLatLngs.apply(this, args);\n        return this;\n    },\n\n    _reset: function() { // ()\n        DG.extend(this, {\n            _lineMarkerHelper: null,\n            _morphingNow: false\n        });\n    },\n\n    _lineMouseEvents: {\n        click: function(event) {\n            var target = event.layer;\n            if (target instanceof DG.Marker && target._pos !== this._points.length - 1) {\n                if (this._lineMarkerHelper) {\n                    this._lineMarkerHelper.collapse();\n                }\n                target.setText(this._getFormatedDistance(target));\n                this._lineMarkerHelper = target;\n            } else if (target instanceof DG.Path && this.options.editable) {\n                var latlng = event.latlng,\n                    insertPos = target._point._pos + 1;\n                this.spliceLatLngs(insertPos, 0, latlng);\n            }\n        },\n        mouseover: function(event) { // (MouseEvent)\n            var target = event.layer;\n\n            target._hovered = true;\n            if (this._morphingNow) {\n                return;\n            }\n            if (target instanceof DG.Marker && target._pos !== this._points.length - 1) {\n                target.setText(this._getFormatedDistance(target));\n            } else if (target instanceof DG.Path && !this._lineMarkerHelper) {\n                var point = target._point;\n\n                this._lineMarkerHelper = this._addRunningLabel(\n                    this._nearestPoint(point._legs.middle, event.latlng),\n                    point\n                );\n            }\n        },\n        mouseout: function(event) { // (MouseEvent)\n            var target = event.layer,\n                originalEv = event.originalEvent;\n\n            target._hovered = false;\n            if (this._morphingNow || target._pos === this._points.length - 1) {\n                return;\n            }\n            if (target instanceof DG.Marker) {\n                // collapse only when we move out from label container (if browser support relatedTarget)\n                if (!originalEv.relatedTarget ||\n                    (originalEv.relatedTarget !== target.querySelector('container') &&\n                    originalEv.relatedTarget.parentNode !== target.querySelector('container'))) {\n                    target.collapse();\n                }\n            } else {\n                this._removeRunningLabel();\n            }\n        },\n        mousemove: function(event) { // (MouseEvent)\n            if (this._morphingNow || !this._lineMarkerHelper) {\n                return;\n            }\n\n            var point = event.layer._point,\n                latlng = this._nearestPoint(point._legs.middle, event.latlng);\n\n            this._lineMarkerHelper\n                .setLatLng(latlng)\n                .setText(this._getFormatedDistance(point, point.getLatLng().distanceTo(latlng)));\n        },\n        layeradd: function() { // ()\n            Object.keys(this._layers).forEach(function(name) {\n                this._layers[name].bringToFront();\n            }, this);\n        }\n    },\n\n    _fireChangeEvent: function() {\n        this.fire('changed', {latlngs : this.getLatLngs()});\n    },\n\n    _addRunningLabel: function(latlng, previousPoint) { // (LatLng, Ruler.LayeredMarker)\n        var point = this._createPoint(latlng).addTo(this._layers.mouse, this._layers);\n        var pane = this._map.getPane('rulerPane');\n        pane.insertBefore(point._icon, pane.lastElementChild);\n        return point.setText(this._getFormatedDistance(previousPoint, previousPoint.getLatLng().distanceTo(latlng)));\n    },\n\n    _removeRunningLabel: function() { // ()\n        if (this._lineMarkerHelper) {\n            this._layers.mouse.removeLayer(this._lineMarkerHelper);\n            this._lineMarkerHelper = null;\n        }\n    },\n\n    _insertPointInLine: function(event) { // (MouseEvent)\n        var latlng = this._lineMarkerHelper.getLatLng(),\n            insertPos = event.target._point._pos + 1,\n            point;\n\n        if (L.Browser.ie) {\n            var path = event.originalEvent.target || event.originalEvent.srcElement,\n                parent = path.parentNode;\n            parent.appendChild(path); // IE click event leaking problem solution: we reappend mousedown event target element\n        }\n\n        L.DomEvent.stopPropagation(event.originalEvent);\n\n        this.spliceLatLngs(insertPos, 0, latlng);\n        point = this._points[insertPos];\n        point.setText(this._getFormatedDistance(point));\n\n        setTimeout(function() {\n            if (document.createEvent) {\n                var e = document.createEvent('MouseEvents');\n                e.initMouseEvent('mouseup', false, false, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 1, point._icon);\n                document.dispatchEvent(e);\n\n                e = document.createEvent('MouseEvents');\n                e.initMouseEvent('mousedown', false, false, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 1, point._icon);\n                point._icon.dispatchEvent(e);\n            } else {\n                point._icon.fireEvent('onMouseUp', DG.extend(document.createEventObject(), {\n                    button: 1,\n                    bubbles: false,\n                    cancelable: false\n                }));\n                point._icon.fireEvent('onMouseDown', DG.extend(document.createEventObject(), {\n                    button: 1,\n                    bubbles: false,\n                    cancelable: false\n                }));\n            }\n        }, 0);\n\n        this._removeRunningLabel();\n\n        this._updateLegs(point);\n    },\n\n    // Find the point on given polyline which is closest to given latlng\n    _nearestPoint: function(polyline, latlng) { // (Polyline, LatLng) -> LatLng\n        var self = this;\n\n        // Convert everything to pixel coordinates\n        var point = this._project(latlng);\n        var linePoints = polyline.getLatLngs().map(function(latlng) {\n            return self._project(latlng);\n        });\n\n        // First look for closest polyline segment\n        var minDistance;\n        var closestSegmentIndex;\n        for (var i = 0; i < linePoints.length - 1; i++) {\n            var distance = DG.LineUtil.pointToSegmentDistance(\n                point,\n                linePoints[i],\n                linePoints[i + 1]\n            );\n\n            if (minDistance === undefined || distance < minDistance) {\n                minDistance = distance;\n                closestSegmentIndex = i;\n            }\n        }\n\n        // Then look for closest point on that segment\n        var closestPoint = DG.LineUtil.closestPointOnSegment(\n            point,\n            linePoints[closestSegmentIndex],\n            linePoints[closestSegmentIndex + 1]\n        );\n\n        // Convert back to LatLng\n        return this._unproject(closestPoint);\n    },\n\n    _addCloseHandler: function(event) { // (Event)\n        event.target\n            .on('click', this._deletePoint, this)\n            .querySelector('remove-link').style.display = 'inline-block';\n    },\n\n    _createPoint: function(latlng, style) { // (LatLng, Object) -> Ruler.LayeredMarker\n        var pointStyle = style ? style : this.options.iconStyles.large,\n            layers = {};\n        Object.keys(pointStyle).forEach(function(layer) {\n            layers[layer] = DG.circleMarker(latlng, pointStyle[layer]);\n        });\n\n        return DG.Ruler.layeredMarker(latlng, {\n            layers : layers,\n            draggable : this.options.editable,\n            textDirection: this._map.getLang() !== 'ar' ? 'auto' : 'rtl'\n        });\n    },\n\n    // Moves curr LatLng to correct world if necessary so that ruler section\n    // between curr and base can be plotted correctly. Returns a new LatLng\n    // object.\n    _normalizeLatLng: function(curr, base) { // (LatLng, LatLng) -> LatLng\n        var diff = (curr.lng < base.lng) ? 360 : -360;\n\n        var newLng = curr.lng;\n        while (Math.abs(newLng - base.lng) > 180) {\n            newLng += diff;\n        }\n\n        return DG.latLng(curr.lat, newLng);\n    },\n\n    // Rearranges ruler points between worlds based on point param so that all\n    // ruler sections can be plotted correctly.\n    _normalizeRulerPoints: function(point) { // (Ruler.LayeredMarker)\n        point = point || this._points[0];\n\n        var self = this;\n        var position = point._pos;\n        var changedPoints = [];\n        var i, currPoint, prevPoint, latlng, normalized;\n\n        // Check points to the right\n        for (i = position + 1; i < this._points.length; i++) {\n            currPoint = this._points[i];\n            prevPoint = this._points[i - 1];\n\n            latlng = currPoint.getLatLng();\n            normalized = this._normalizeLatLng(latlng, prevPoint.getLatLng());\n\n            if (!normalized.equals(latlng)) {\n                currPoint.setLatLng(normalized);\n                changedPoints.push(i);\n            }\n        }\n\n        // Check points to the left\n        for (i = position - 1; i >= 0; i--) {\n            currPoint = this._points[i];\n            prevPoint = this._points[i + 1];\n\n            latlng = currPoint.getLatLng();\n            normalized = this._normalizeLatLng(latlng, prevPoint.getLatLng());\n\n            if (!normalized.equals(latlng)) {\n                currPoint.setLatLng(normalized);\n                changedPoints.push(i);\n            }\n        }\n\n        // Update legs of all points that changed position\n        changedPoints.sort().reduce(function(previous, current) {\n            var skipPrevious = previous && previous === current - 1;\n\n            self._updateLegs(self._points[current], skipPrevious);\n\n            return current;\n        }, null);\n    },\n\n    _pointEvents: {\n        drag: function(event) { // (Event)\n            var point = event.target;\n\n            this._normalizeRulerPoints(point);\n\n            if (!DG.Browser.touch && point !== this._points[this._points.length - 1]) {\n                point.setText(this._getFormatedDistance(point));\n            }\n\n            this._updateLegs(point);\n            this._updateDistance();\n        },\n        dragend: function(event) { // (Event)\n            var point = event.target;\n            this._morphingNow = false;\n            if (!point._hovered && point !== this._points[this._points.length - 1]) {\n                point.collapse();\n            }\n            this._fireChangeEvent();\n        },\n        dragstart: function() { // ()\n            if (DG.Browser.touch && this._lineMarkerHelper) {\n                this._lineMarkerHelper.collapse();\n            }\n            this._morphingNow = true;\n        }\n    },\n\n    _deletePoint: function(event) { // (MouseEvent)\n        var originalEvent = event.originalEvent,\n            target = originalEvent.target  || originalEvent.srcElement;\n\n        if (target.className !== 'dg-ruler__label-remove-link' &&\n            target.className !== 'dg-ruler__remove-link-overlay') {\n            return;\n        }\n        DG.DomEvent.stop(event.originalEvent);\n        this.spliceLatLngs(event.target._pos, 1);\n    },\n\n    _degToRad: function(deg) {\n        return (Math.PI / 180) * deg;\n    },\n\n    _radToDeg: function(rad) {\n        return (180 / Math.PI) * rad;\n    },\n\n    // Map-independent project method\n    _project: function(latlng) {\n        if (this._map) {\n            return this._map.project(latlng);\n        }\n\n        return DG.CRS.EPSG3857.latLngToPoint(latlng, 1);\n    },\n\n    // Map-independent unproject method\n    _unproject: function(point) {\n        if (this._map) {\n            return this._map.unproject(point);\n        }\n\n        return DG.CRS.EPSG3857.pointToLatLng(point, 1);\n    },\n\n    // Calculates the size of angle point1-point-point2\n    _calcAngle: function(point, point1, point2) { // (LatLng, LatLng, LatLng) -> Number\n        point1 = this._normalizeLatLng(point1, point);\n        point2 = this._normalizeLatLng(point2, point);\n\n        point = this._project(point);\n        point1 = this._project(point1);\n        point2 = this._project(point2);\n\n        var x1 = point1.x - point.x;\n        var x2 = point2.x - point.x;\n        var y1 = point1.y - point.y;\n        var y2 = point2.y - point.y;\n\n        var dotProduct = x1 * x2 + y1 * y2;\n        var mag1 = Math.sqrt(x1 * x1 + y1 * y1);\n        var mag2 = Math.sqrt(x2 * x2 + y2 * y2);\n\n        return Math.acos(dotProduct / (mag1 * mag2));\n    },\n\n    // Calculates the midpoint on the great circle between two LatLngs\n    _calcMidPoint: function(latlng1, latlng2) { // (LatLng, LatLng) -> LatLng\n        var lon1 = this._degToRad(latlng1.lng);\n        var lat1 = this._degToRad(latlng1.lat);\n\n        var lon2 = this._degToRad(latlng2.lng);\n        var lat2 = this._degToRad(latlng2.lat);\n\n        // Based on formulae from\n        // http://williams.best.vwh.net/avform.htm#Intermediate\n        var d = Math.acos(Math.sin(lat1) * Math.sin(lat2) +\n            Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));\n\n        // Split the arc in half\n        var f = 0.5;\n\n        var A = Math.sin((1 - f) * d) / Math.sin(d);\n        var B = Math.sin(f * d) / Math.sin(d);\n\n        var x = A * Math.cos(lat1) * Math.cos(lon1) +\n            B * Math.cos(lat2) * Math.cos(lon2);\n\n        var y = A * Math.cos(lat1) * Math.sin(lon1) +\n            B * Math.cos(lat2) * Math.sin(lon2);\n\n        var z = A * Math.sin(lat1) + B * Math.sin(lat2);\n\n        var lat = Math.atan2(z, Math.sqrt(x * x + y * y));\n        var lon = Math.atan2(y, x);\n\n        return DG.latLng(this._radToDeg(lat), this._radToDeg(lon));\n    },\n\n    // Adaptive sampling algorithm based on\n    // http://ariel.chronotext.org/dd/defigueiredo93adaptive.pdf\n    _adaptiveSample: function(left, right, depth, middle) { // (LatLng, LatLng, Number[, LatLng]) -> LatLng[]\n        if (depth > 9) {\n            // Max recursion depth reached\n            return [];\n        }\n\n        middle = middle || this._calcMidPoint(left, right);\n\n        var leftMiddle = this._calcMidPoint(left, middle);\n        var rightMiddle = this._calcMidPoint(middle, right);\n\n        var angle1 = this._calcAngle(leftMiddle, middle, left);\n        var angle2 = this._calcAngle(middle, left, right);\n        var angle3 = this._calcAngle(rightMiddle, middle, right);\n\n        // left --- leftMiddle --- middle --- rightMiddle --- right\n        //            angle1       angle2       angle3\n\n        var minAngle = 3.1;\n        if (angle1 > minAngle && angle2 > minAngle && angle3 > minAngle) {\n            // This section is straight enough, no intermediate points needed.\n            return [];\n        } else {\n            // Angles are too small. Recursively sample halves of this section.\n            var result = [];\n            result = result.concat(this._adaptiveSample(left, middle, depth + 1, leftMiddle));\n            result.push(middle);\n            result = result.concat(this._adaptiveSample(middle, right, depth + 1, rightMiddle));\n\n            return result;\n        }\n    },\n\n    // Calculates the great circle arc between two LatLngs.\n    _calcGreatCircle: function(latlng1, latlng2) { // (LatLng, LatLng) -> LatLng[]\n        latlng2 = this._normalizeLatLng(latlng2, latlng1);\n\n        // Special case: points are close to each other (within 1 degree)\n        if (latlng1.equals(latlng2, 1)) {\n            return [latlng1, latlng2];\n        }\n\n        // Special case: the great circle crosses a pole\n        if (Math.abs(latlng2.lng - latlng1.lng) == 180) {\n            // North or south pole?\n            var latitude = (latlng1.lat + latlng2.lat > 0) ? 90 : -90;\n\n            return [\n                latlng1,\n                DG.latLng(latitude, latlng1.lng),\n                DG.latLng(latitude, latlng2.lng),\n                latlng2\n            ];\n        }\n\n        var result = [];\n\n        result.push(latlng1);\n        result = result.concat(this._adaptiveSample(latlng1, latlng2, 0));\n        result.push(latlng2);\n\n        // Make sure the arc doesn't jump between worlds\n        for (var i = 1; i < result.length; i++) {\n            result[i] = this._normalizeLatLng(result[i], result[i - 1]);\n        }\n\n        return result;\n    },\n\n    _addLegs: function(point) {\n        var pathStyles = this.options.pathStyles;\n\n        var greatCirclePoints = this._calcGreatCircle(\n            point.getLatLng(),\n            this._points[point._pos + 1].getLatLng()\n        );\n\n        point._legs = {};\n        Object.keys(pathStyles).forEach(function(layer) {\n            point._legs[layer] = DG.polyline(greatCirclePoints, pathStyles[layer]).addTo(this._layers[layer]);\n        }, this);\n\n        point._legs.mouse._point = point.once('remove', this._clearRemovingPointLegs, this);\n\n        if (this.options.editable && !DG.Browser.mobile) {\n            point._legs.mouse.on('mousedown', this._insertPointInLine, this);\n        }\n\n        if (this._map) {\n            this._layers.mouse.addLayer(point._legs.mouse);\n        }\n    },\n\n    _clearRemovingPointLegs: function(event) { // (Event)\n        this._removeLegs(event.target);\n    },\n\n    _removeLegs: function(point) { // (Ruler.LayeredMarker)\n        if (point._legs) {\n            Object.keys(point._legs).forEach(function(layer) {\n                this._layers[layer].removeLayer(point._legs[layer]);\n            }, this);\n            point._legs = null;\n        }\n    },\n\n    _updateLegs: function(point, skipPrevious) { // (Ruler.LayeredMarker, Boolean)\n        var latlng = point.getLatLng(),\n            previousPoint = this._points[point._pos - 1],\n            nextPoint = this._points[point._pos + 1],\n            self = this,\n            newPoints;\n\n        if (previousPoint && !skipPrevious) {\n            newPoints = self._calcGreatCircle(previousPoint.getLatLng(), latlng);\n\n            Object.keys(previousPoint._legs).forEach(function(layer) {\n                previousPoint._legs[layer].setLatLngs(newPoints);\n            });\n        }\n\n        if (nextPoint) {\n            newPoints = self._calcGreatCircle(latlng, nextPoint.getLatLng());\n\n            Object.keys(point._legs).forEach(function(layer) {\n                point._legs[layer].setLatLngs(newPoints);\n            });\n        }\n    },\n\n    _calcDistance: function(finishPoint, tail) { // (Ruler.LayeredMarker, Number) -> Number\n        var distance = tail ? tail : 0,\n            calcTo = finishPoint ? finishPoint._pos : this._points.length - 1;\n\n        for (var i = 0; i < calcTo; i++) {\n            distance += this._points[i].getLatLng().distanceTo(this._points[i + 1].getLatLng());\n        }\n\n        return distance;\n    },\n\n    _getFormatedDistance: function() { // () -> String\n        var distance = this._calcDistance.apply(this, arguments),\n            units = 'm';\n\n        if (distance > 1000) {\n            distance /= 1000;\n            units = 'km';\n            if (distance > 1000) {\n                distance = distance.toFixed();\n                distance = distance.slice(0, -3) + ' ' + distance.slice(-3);\n            } else {\n                distance = distance.toFixed(2).split('.').join(this.t('delimiter'));\n            }\n        } else {\n            distance = Math.round(distance);\n        }\n\n        return [distance || 0, ' ', this.t(units)].join('');\n    },\n\n    _updateDistance: function() { // ()\n        if (this._map && this._points.length) {\n            this._points[this._points.length - 1].setText(this._getFormatedDistance());\n        }\n    }\n});\n\nDG.ruler = function(latlngs, options) { // (Array, Object)\n    return new DG.Ruler(latlngs, options);\n};\n"
  },
  {
    "path": "src/DGRuler/test/RulerSpec.js",
    "content": "describe('DG.Ruler', function () {\n\n    var map,\n        ruler,\n        mRuler = [[54.98876904122557, 82.901930809021], [54.988842907519285, 82.89030075073241]],\n        kmRuler = [[54.9798794714156, 82.89888381958008], [54.9788204717771, 82.89695262908936],\n                   [54.98273616833678, 82.88879871368408], [54.98194813431667, 82.87236213684082]],\n        originalLatLngs = [\n            [1, 2],\n            [3, 4],\n            [5, 6]\n        ];\n\n    after(function() {\n        mRuler = kmRuler = originalLatLngs = null;\n    });\n\n    beforeEach(function () {\n        map = new DG.Map(document.createElement('div'), {\n            center: new DG.LatLng(51.7302800, 36.1938900),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n        ruler = DG.ruler();\n        map.addLayer(ruler);\n    });\n\n    afterEach(function () {\n        map && map.remove();\n        ruler = map = null;\n    });\n\n    describe(\"#setLatLngs\", function () {\n        it(\"doesn't overwrite the given latlng array\", function () {\n            var sourceLatLngs = originalLatLngs.slice();\n\n            ruler.setLatLngs(originalLatLngs);\n            expect(sourceLatLngs).to.eql(originalLatLngs);\n            expect(ruler._points).to.not.eql(sourceLatLngs);\n        });\n        it(\"chains ruler instance\", function () {\n            expect(ruler.setLatLngs(originalLatLngs)).to.be.a(DG.Ruler);\n        });\n    });\n\n    describe(\"#getLatLngs\", function () {\n        it(\"should return empty array\", function () {\n            expect(ruler.getLatLngs()).to.eql([]);\n        });\n        it(\"should return latLngs array\", function () {\n            ruler.setLatLngs(originalLatLngs);\n            expect(ruler.getLatLngs()).to.eql([DG.latLng([1, 2]), DG.latLng([3, 4]), DG.latLng([5, 6])]);\n        });\n    });\n\n    describe(\"#addLatLng\", function () {\n        it(\"doesn't overwrite the given latlng\", function () {\n            var a = [5, 6],\n                b = [5, 6];\n\n            ruler.setLatLngs(originalLatLngs);\n            ruler.addLatLng(a);\n            expect(a).to.eql(b);\n        });\n        it(\"adds the given latlng to ruler\", function () {\n            ruler.setLatLngs(originalLatLngs);\n            ruler.addLatLng([7, 8]);\n            expect(ruler.getLatLngs()).to.eql([DG.latLng([1, 2]), DG.latLng([3, 4]), DG.latLng([5, 6]), DG.latLng([7, 8])]);\n        });\n        it(\"chains ruler instance\", function () {\n            expect(ruler.addLatLng(originalLatLngs[0])).to.be.a(DG.Ruler);\n        });\n    });\n\n    describe(\"#spliceLatLngs\", function () {\n        it(\"returns removed latLngs\", function () {\n            ruler.setLatLngs(originalLatLngs);\n            expect(ruler.spliceLatLngs(1, 1, [7, 8])).to.eql([DG.latLng([3, 4])]);\n        });\n        it(\"inserts the latLngs\", function () {\n            ruler.setLatLngs(originalLatLngs);\n            ruler.spliceLatLngs(1, 1, [7, 8]);\n            expect(ruler.getLatLngs()).to.eql([DG.latLng([1, 2]), DG.latLng([7, 8]), DG.latLng([5, 6])]);\n        });\n    });\n\n    describe('#getTotalDistance', function () {\n        it('meters', function () {\n            mRuler.forEach(function (ll) {\n                ruler.addLatLng(ll);\n            });\n            // it makes no sense to check with higher accuracy than 1 cm.\n            var roundedDistance = Math.round(ruler.getTotalDistance() * 100) / 100;\n            expect(roundedDistance).to.eql(742);\n            expect(ruler._getFormatedDistance()).to.eql('742 м');\n        });\n        it('km', function () {\n            kmRuler.forEach(function (ll) {\n                ruler.addLatLng(ll);\n            });\n            // it makes no sense to check with higher accuracy than 1 cm.\n            var roundedDistance = Math.round(ruler.getTotalDistance() * 100) / 100;\n            expect(roundedDistance).to.eql(1901.31);\n            expect(ruler._getFormatedDistance()).to.eql('1,90 км');\n        });\n    });\n\n});\n"
  },
  {
    "path": "src/DGRulerControl/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>DGRulerControl demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            map = new DG.Map('map', {\n                'center': new DG.LatLng(51.7302800, 36.1938900),\n                'zoom': 17,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            map.addControl(DG.control.ruler());\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGRulerControl/lang/ar.js",
    "content": "DG.Control.Ruler.Dictionary.ar = {\n    button_title: 'مسطرة'\n};\n"
  },
  {
    "path": "src/DGRulerControl/lang/cs.js",
    "content": "DG.Control.Ruler.Dictionary.cs = {\n    button_title: 'Pravítko'\n};\n"
  },
  {
    "path": "src/DGRulerControl/lang/en.js",
    "content": "DG.Control.Ruler.Dictionary.en = {\n    button_title : 'Ruler'\n};\n"
  },
  {
    "path": "src/DGRulerControl/lang/es.js",
    "content": "DG.Control.Ruler.Dictionary.es = {\n    button_title : 'Regla'\n};\n"
  },
  {
    "path": "src/DGRulerControl/lang/it.js",
    "content": "DG.Control.Ruler.Dictionary.it = {\n    button_title : 'Righello'\n};\n"
  },
  {
    "path": "src/DGRulerControl/lang/ru.js",
    "content": "DG.Control.Ruler.Dictionary.ru = {\n    button_title: 'Линейка'\n};\n"
  },
  {
    "path": "src/DGRulerControl/skin/basic/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_ruler {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__rulerIcon');\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        margin: auto;\n        content: '';\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__rulerIconHover');\n    }\n\n    .dg-control-round__icon_state_active&:after,\n    .no-touch .dg-control-round__icon_state_active&:hover:after,\n    .dg-control-round__icon_state_active&:active:after {\n        .notRepeatableBg('DGRoundControl__rulerIconEnabled');\n    }\n}\n"
  },
  {
    "path": "src/DGRulerControl/src/Control.Ruler.js",
    "content": "DG.Control.Ruler = DG.RoundControl.extend({\n\n    options: {\n        position: 'topright',\n        iconClass: 'ruler'\n    },\n\n    statics: {\n        Dictionary: {}\n    },\n\n    initialize: function(options) {\n        DG.setOptions(this, options);\n        DG.extend(this, {\n            _active: false,\n            _drawingHelper: null,\n            _geoclickerNeedRestore: false\n        }).on(this._controlEvents, this);\n    },\n\n    _controlEvents: {\n        add: function() {\n            this._drawingHelper = DG.ruler([]);\n        },\n        click: function() {\n            this._active = !this._active;\n\n            if (this._active) {\n                this.setState('active');\n                this._startDrawing();\n            } else {\n                this.setState('');\n                this._finishDrawing();\n            }\n        },\n        remove: function() {\n            this.off(this._controlEvents, this);\n            if (this._active) {\n                this._map.removeLayer(this._drawingHelper);\n                this._active = false;\n            }\n            this._drawingHelper = null;\n        }\n    },\n\n    _startDrawing: function() { // ()\n        this._map\n            .addLayer(this._drawingHelper)\n            .on('click', this._handleMapClick, this);\n\n        this._map.fire('rulerstart');\n    },\n\n    _finishDrawing: function() { // ()\n        this._map\n            .off('click', this._handleMapClick, this)\n            .removeLayer(this._drawingHelper);\n\n        this._drawingHelper.setLatLngs([]);\n\n        this._map.fire('rulerend');\n    },\n\n    _handleMapClick: function(event) { // (MouseEvents)\n        this._drawingHelper.addLatLng(event.latlng);\n    },\n\n    _renderTranslation: function() { // ()\n        this._link.title = this.t('button_title');\n    }\n});\n\nDG.control.ruler = function(options) {\n    return new DG.Control.Ruler(options);\n};\n\nDG.Map.mergeOptions({\n    rulerControl: false\n});\n\nDG.Map.addInitHook(function() {\n    if (this.options.rulerControl) {\n        this.rulerControl = DG.control.ruler(this.options.rulerControl);\n        this.addControl(this.rulerControl);\n    }\n});\n"
  },
  {
    "path": "src/DGRulerControl/test/DGRulerControlSpec.js",
    "content": "describe('DG.Control.Ruler', function() {\n    var map, mapContainer, control, classControl, containerControl, ruler;\n\n    before(function() {\n        classControl = 'dg-control-round__icon_name_ruler';\n\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n\n        map = new DG.Map(mapContainer, {\n            center: [55.017493, 82.819576],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n\n        control = DG.control.ruler();\n    });\n\n    after(function() {\n        mapContainer.parentElement.removeChild(mapContainer);\n        map.remove();\n        map = mapContainer = control = classControl = containerControl = ruler = null;\n    });\n\n    describe('#addTo', function() {\n        before(function() {\n            control.addTo(map);\n        });\n\n        it('should map has ruler contrainer', function() {\n            containerControl = document.body.getElementsByClassName(classControl);\n            expect(containerControl.length).to.be(1);\n            containerControl = containerControl[0];\n            ruler = control._drawingHelper;\n        });\n    });\n\n    describe('drawing', function() {\n        it('should container has active class', function() {\n            happen.click(containerControl);\n            expect(containerControl.className).to.contain('active');\n        });\n\n        it('should change ruler after click on map', function() {\n            var latlng = DG.latLng(54.980206086231, 82.898068362003),\n                rulerLatLngs;\n\n            map.fire('click', {latlng: latlng});\n            rulerLatLngs = ruler.getLatLngs();\n\n            expect(rulerLatLngs.length).to.be(1);\n            expect(rulerLatLngs[0]).to.nearLatLng(latlng);\n        });\n\n        it('should change ruler after second click on map', function() {\n            var latlng = DG.latLng(54.980206086231, 82.891068362003),\n                rulerLatLngs;\n\n            map.fire('click', {latlng: latlng});\n            rulerLatLngs = ruler.getLatLngs();\n\n            expect(rulerLatLngs.length).to.be(2);\n            expect(rulerLatLngs[1]).to.nearLatLng(latlng);\n        });\n\n        it('should hasn\\'t ruler layer on map', function() {\n            happen.click(containerControl);\n            expect(map.hasLayer(ruler._layersContainer)).not.be.ok();\n        });\n    });\n\n    describe('#remove', function() {\n        before(function() {\n            happen.click(containerControl);\n            map.fire('click', {latlng: DG.latLng(54.980206086231, 82.891068362003)});\n\n            control.remove();\n        });\n\n        it('should hasn\\'t ruler layer on map', function() {\n            expect(map.hasLayer(ruler._layersContainer)).not.be.ok();\n        });\n\n        it('should map hasn\\'t ruler contrainer', function() {\n            expect(document.body.getElementsByClassName(classControl).length).to.be(0);\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGTraffic/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset='utf-8'>\n    <title>DGTraffic demo</title>\n    <script src=\"http://maps.api.2gis.dev/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = new DG.Map('map', {\n                \"center\": new DG.LatLng(54.95070983406191, 83.0569839477539),\n                \"zoom\": 11,\n                \"geoclicker\": false,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            var traffic = new DG.Traffic();\n            map.addLayer(traffic);\n\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGTraffic/lang/ar.js",
    "content": "DG.Traffic.Dictionary.ar = {\n    speed_unit_km_h: 'كم/ساعة'\n};\n"
  },
  {
    "path": "src/DGTraffic/lang/cs.js",
    "content": "DG.Traffic.Dictionary.cs = {\n    speed_unit_km_h: 'km/h'\n};\n"
  },
  {
    "path": "src/DGTraffic/lang/en.js",
    "content": "DG.Traffic.Dictionary.en = {\n    speed_unit_km_h: 'km/h'\n};\n"
  },
  {
    "path": "src/DGTraffic/lang/es.js",
    "content": "DG.Traffic.Dictionary.es = {\n    speed_unit_km_h: 'km/h'\n};\n"
  },
  {
    "path": "src/DGTraffic/lang/it.js",
    "content": "DG.Traffic.Dictionary.it = {\n    speed_unit_km_h: 'km/h'\n};\n"
  },
  {
    "path": "src/DGTraffic/lang/ru.js",
    "content": "DG.Traffic.Dictionary.ru = {\n    speed_unit_km_h: 'км/ч'\n};\n"
  },
  {
    "path": "src/DGTraffic/src/DGTraffic.js",
    "content": "DG.Traffic = DG.TileLayer.extend({\n    options: {\n        period: 0,\n        disableLabel: false,\n        updateWhenIdle: false // display new traffic tiles on move for mobile\n    },\n\n    statics: {\n        Dictionary: {}\n    },\n\n    initialize: function(options) {\n        this._tileUrl = DG.config.protocol + (DG.Browser.retina ? DG.config.retinaTrafficTileServer : DG.config.trafficTileServer);\n        this._metaUrl = DG.config.protocol + (DG.Browser.retina ? DG.config.retinaTrafficMetaServer : DG.config.trafficMetaServer);\n        this._timeUrl = DG.config.protocol + DG.config.trafficTimestampServer;\n        this._updateInterval = DG.config.trafficLayerUpdateInterval;\n\n        this._layersOptions = {\n            errorTileUrl: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',\n            subdomains: '012345679',\n            maxNativeZoom: 18,\n            detectRetina: DG.config.detectRetina,\n            minZoom: DG.config.trafficLayerMinZoom\n        };\n\n        options = DG.setOptions(this, DG.extend(options || {}, this._layersOptions));\n        this._metaLayer = DG.Meta.layer(null, {\n            detectRetina: options.detectRetina,\n            maxNativeZoom: options.maxNativeZoom,\n            dataFilter: DG.bind(this._processData, this),\n            minZoom: options.minZoom\n        });\n        this._isDg = true;\n        this._isOnRequest = false; // timestampString request flag\n        this._onTimer = DG.bind(this._onTimer, this);\n        DG.TileLayer.prototype.initialize.call(this, this._tileUrl, options);\n    },\n\n    // #setTime(day [0-6], time[0-23]) ????\n\n    onAdd: function(map) {\n        this._initContainer();\n        this._levels = {};\n        this._tiles = {};\n\n        if (this.options.period) {\n            this.options.timestampString = '';\n            this._onAddSetParams(map);\n        } else {\n            var self = this;\n            this._isOnRequest = true;\n            this._getTimestampString()\n                .then(\n                    function(response) {\n                        self.options.timestampString = '?' + response;\n                    },\n                    function() {\n                        self.options.timestampString = '?' + (new Date()).getTime();\n                    })\n                .then(\n                    function() {\n                        self._isOnRequest = false;\n                        if (self._map) { // if traffic layer has not been removed from map before server response and timestampString variable is assigned\n                            self._onAddSetParams(map);\n                        }\n                    }\n                );\n        }\n    },\n\n    onRemove: function(map) {\n        if (!this._isOnRequest) {\n            clearInterval(this._updateTimer);\n\n            map\n                .removeLayer(this._metaLayer)\n                .off('projectchange projectleave', this._onMapProjectChange, this);\n\n            if (!this.options.disableLabel) {\n                this._metaLayer.off(this._layerEventsListeners, this);\n                this._map.removeLayer(this._labelHelper);\n                this._labelHelper = null;\n                this._map.off('langchange', this._updateLang, this);\n            }\n\n            DG.TileLayer.prototype.onRemove.call(this, map);\n        } else {\n            L.DomUtil.remove(this._container);\n            map._removeZoomLimit(this);\n            this._container = null;\n        }\n    },\n\n    update: function() {\n        var self = this;\n        this._getTimestampString().then(\n            function(response) {\n                self.options.timestampString = '?' + response;\n            },\n            function() {\n                self.options.timestampString = '?' + (new Date()).getTime();\n            }).then(\n            function() {\n                self.fire('update', {timestamp: self.options.timestampString});\n                self._layerEventsListeners.mouseout.call(self);\n                self._metaLayer.getOrigin().setURL(self._prepareMetaURL(), self);\n                self.redraw();\n            }\n        );\n    },\n\n    getSubdomain: function() {\n        return this._layersOptions.subdomains[\n            Math.floor(Math.random() * this._layersOptions.subdomains.length)\n        ];\n    },\n\n    _updateLang: function() {\n        var lang = this._map.getLang();\n        if (lang === 'ar') {\n            this._labelHelper.options.textDirection = 'rtl';\n        } else {\n            this._labelHelper.options.textDirection = 'auto';\n        }\n    },\n\n    _getTimestampString: function() {\n        return DG.ajax(\n            DG.Util.template(\n                this._timeUrl,\n                DG.extend({\n                    s : this.getSubdomain(),\n                    projectCode: this._map.projectDetector.getProject().code\n                }, this.options || {})),\n            {type: 'get'}\n        );\n    },\n\n    _onTimer: function() {\n        if (this.options.period === 0) {\n            this.update();\n        }\n    },\n\n    _processData: function(trafficData, coord) {\n        var tileOriginPoint = coord.scaleBy(this.getTileSize());\n        var polygonLngLatToPoints = DG.bind(this._polygonLngLatToPoints, this, tileOriginPoint);\n        var hints = {};\n\n        if (!DG.Util.isArray(trafficData)) {    // TODO remove\n            return [];\n        }\n\n        trafficData[1].forEach(function(item) {\n            this[item.graph_id] = item.speed_text;\n        }, hints);\n\n        return trafficData[0]\n            .map(function(item) {\n                return {\n                    id: item.graph_id,\n                    speed: hints[item.graph_id],\n                    geometry: DG.Wkt.toGeoJSON(item.geometry[0].object[0])\n                };\n            })\n            .filter(function(item) {\n                return item.geometry.type == 'Polygon' ||\n                    item.geometry.type == 'MultiPolygon';\n            })\n            .map(function(item) {\n                var geoJson = item.geometry;\n\n                if (geoJson.type == 'Polygon') {\n                    geoJson.coordinates = polygonLngLatToPoints(geoJson.coordinates);\n                } else if (geoJson.type == 'MultiPolygon') {\n                    geoJson.coordinates = geoJson.coordinates.map(polygonLngLatToPoints);\n                }\n\n                return item;\n            });\n    },\n\n    _polygonLngLatToPoints: function(originPoint, polygon) {\n        var map = this._map;\n\n        return polygon.map(function(contour) {\n            return contour.map(function(lngLat) {\n                return map\n                    .project([lngLat[1], lngLat[0]]).round()\n                    .subtract(originPoint);\n            });\n        });\n    },\n\n    _prepareMetaURL: function() {\n        return DG.Util.template(this._metaUrl, DG.extend({\n            x: '{x}',\n            y: '{y}',\n            z: '{z}',\n            s: '{s}'\n        }, this.options));\n    },\n\n    _updateLayerProject: function() {\n        var project = this._map.projectDetector.getProject();\n        DG.setOptions(this, project && project.traffic ? {\n            projectCode: project.code,\n            bounds: project.latLngBounds,\n            minZoom: Math.max(project.minZoom, this._layersOptions.minZoom),\n            maxZoom: project.maxZoom\n        } : {\n            maxZoom: project ? project.maxZoom : DG.config.projectLeaveMaxZoom,\n            minZoom: 0\n        });\n        this._metaLayer.getOrigin().setURL(this._prepareMetaURL());\n    },\n\n    _onMapProjectChange: function() {\n        this._updateLayerProject();\n        this.redraw();\n    },\n\n    _layerEventsListeners: {\n        mouseover: function(e) { // (Object)\n            this._setCursor('pointer');\n            if (this._labelHelper && e.meta.speed) {\n                this._labelHelper\n                    .setPosition(e.latlng)\n                    .setContent(e.meta.speed + ' ' + this.t('speed_unit_km_h'))\n                    .addTo(this._map);\n            }\n        },\n        mouseout: function() {\n            this._setCursor('');\n            if (this._labelHelper) {\n                this._map.removeLayer(this._labelHelper);\n            }\n        },\n        mousemove: function(e) {\n            if (this._labelHelper) {\n                this._labelHelper.setPosition(e.latlng);\n            }\n        }\n    },\n\n    _setCursor: function(cursor) { // (String)\n        this._map.getContainer().style.cursor = cursor;\n    },\n\n    _onAddSetParams: function(map) {\n        this._updateLayerProject();\n\n        map\n            .addLayer(this._metaLayer)\n            .on('projectchange projectleave', this._onMapProjectChange, this);\n\n        if (!this.options.disableLabel) {\n            this._metaLayer.on(this._layerEventsListeners, this);\n            this._labelHelper = DG.label();\n            this._map.on('langchange', this._updateLang, this);\n        }\n\n        if (this._updateInterval) {\n            this._updateTimer = setInterval(this._onTimer, this._updateInterval);\n        }\n\n        this._resetView();\n        this._update();\n    },\n\n    _update: function(center) {\n        if (!this._isOnRequest) {\n            DG.TileLayer.prototype._update.call(this, center);\n        }\n    }\n\n});\n\nDG.Traffic.include(DG.Locale);\n\nDG.traffic = function(options) { // (Object)\n    return new DG.Traffic(options);\n};\n"
  },
  {
    "path": "src/DGTraffic/test/DGTrafficSpec.js",
    "content": "describe('DG.traffic', function () {\n    var map,\n        traffic,\n        mapContainer,\n        xhr,\n        requests;\n\n    before(function () {\n        mapContainer = document.createElement('div');\n        document.body.appendChild(mapContainer);\n        map = new DG.Map(mapContainer, {\n            center: new DG.LatLng(54.980156831455, 82.897440725094),\n            zoom: 17,\n            key: window.__karma__.config.secretKey,\n        });\n        xhr = sinon.useFakeXMLHttpRequest();\n        requests = [];\n\n        xhr.onCreate = function (xhr) {\n            requests.push(xhr);\n        };\n    });\n\n    afterEach(function () {\n        map.removeLayer(traffic);\n    });\n\n    after(function () {\n        map.remove();\n        document.body.removeChild(mapContainer);\n        map = traffic = mapContainer = null;\n        xhr.restore();\n    });\n\n    it('should present two layer', function (done) {\n        traffic = DG.traffic();\n        traffic.addTo(map);\n        requests[0].respond(200, {'Content-Type': 'application/x-www-form-urlencoded'}, (new Date()).getTime().toString());\n\n        setTimeout(function() {\n            var layers = mapContainer.querySelectorAll('.leaflet-layer');\n            expect(layers.length).to.eql(2);\n            done();\n        }, 0);\n    });\n\n});\n"
  },
  {
    "path": "src/DGTrafficControl/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>DGTrafficControl demo</title>\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n    <div id=\"map\"></div>\n    <script type=\"text/javascript\">\n        DG.then(function () {\n            map = new DG.Map('map', {\n                'center': new DG.LatLng(59.92160287366319, 30.313425064086918),\n                'zoom': 15,\n                key: DG.config.key || 'Your API access key'\n            });\n\n            map.addControl(DG.control.traffic());\n        });\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "src/DGTrafficControl/lang/ar.js",
    "content": "DG.Control.Traffic.Dictionary.ar = {\n    button_title: 'حركة السير'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/lang/cs.js",
    "content": "DG.Control.Traffic.Dictionary.cs = {\n    button_title: 'Zácpy'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/lang/en.js",
    "content": "DG.Control.Traffic.Dictionary.en = {\n    button_title: 'Traffic'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/lang/es.js",
    "content": "DG.Control.Traffic.Dictionary.es = {\n    button_title: 'Taco'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/lang/it.js",
    "content": "DG.Control.Traffic.Dictionary.it = {\n    button_title: 'Colonna'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/lang/ru.js",
    "content": "DG.Control.Traffic.Dictionary.ru = {\n    button_title: 'Пробки'\n};\n"
  },
  {
    "path": "src/DGTrafficControl/skin/basic/less/dg-control-round.less",
    "content": ".dg-control-round__icon_name_traffic {\n    &:after {\n        .notRepeatableBgWithSizes('DGRoundControl__trafficIcon');\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        margin: auto;\n        content: '';\n    }\n\n    .no-touch &:hover:after,\n    &:active:after {\n        .notRepeatableBg('DGRoundControl__trafficIconHover');\n    }\n\n    .dg-control-round__icon_state_active&:after,\n    .no-touch .dg-control-round__icon_state_active&:hover:after,\n    .dg-control-round__icon_state_active&:active:after {\n        background-image: none;\n    }\n}\n"
  },
  {
    "path": "src/DGTrafficControl/skin/basic/less/dg-traffic-control.ie.less",
    "content": ".dg-traffic-control {\n    .no-touch &_color_green {\n        background: #3fc03b !important;\n        font-weight: bold;\n    }\n\n    .no-touch &_color_yellow {\n        background: #f3b223 !important;\n        font-weight: bold;\n    }\n\n    .no-touch &_color_red {\n        background: #eb240c !important;\n        font-weight: bold;\n    }\n}\n"
  },
  {
    "path": "src/DGTrafficControl/skin/basic/less/dg-traffic-control.less",
    "content": "a.dg-traffic-control {\n    z-index: 0;\n    color: #f2f2f2;\n    text-decoration: none;\n    text-shadow: 0 1px 2px rgba(0, 0, 0, .3);\n    font: normal 15px/32px 'Arial narrow', Arial, sans-serif;\n\n    &_color_green:after,\n    &_color_yellow:after,\n    &_color_red:after {\n        position: absolute;\n        top: 0;\n        right: 0;\n        bottom: 0;\n        left: 0;\n        z-index: -1;\n        margin: auto;\n        width: 22px;\n        height: 22px;\n        border-radius: 50%;\n        box-shadow: inset 0 1px 0 0 rgba(0, 0, 0, .2), 0 1px 0 0 #fff;\n    }\n\n    .no-touch &:hover {\n        color: #f2f2f2;\n    }\n\n    .no-touch &_color_green:hover:after,\n    .no-touch &_color_yellow:hover:after,\n    .no-touch &_color_red:hover:after {\n        width: 22px;\n        height: 22px;\n    }\n\n    &_color_green:after {\n        background: #3fc03b;\n    }\n\n    .no-touch &_color_green:hover:after,\n    &_color_green:active:after {\n        background: linear-gradient(to top, #2aa731, #53e13a) #3ec435;\n    }\n\n    &_color_yellow:after {\n        background: #f3b223;\n    }\n\n    .no-touch &_color_yellow:hover:after,\n    &_color_yellow:active:after {\n        background: linear-gradient(to top, #ef931b, #f7be26) #f4a820;\n    }\n\n    &_color_red:after {\n        background: #eb240c;\n    }\n\n    .no-touch &_color_red:hover:after,\n    &_color_red:active:after {\n        background: linear-gradient(to top, #c01c0a, #f73416) #db2811;\n    }\n}\n"
  },
  {
    "path": "src/DGTrafficControl/src/Control.Traffic.js",
    "content": "DG.Control.Traffic = DG.RoundControl.extend({\n    options: {\n        position: 'topright',\n        iconClass: 'traffic'\n    },\n\n    statics: {\n        Dictionary: {}\n    },\n\n    initialize: function(options) {\n        this._trafficClass = 'dg-traffic-control';\n        this._controlHideClass = 'dg-control-round_is-hidden_true';\n\n        DG.setOptions(this, options);\n        DG.extend(this, {\n            _active: false,\n            _trafficLayer: null\n        }).on(this._controlEvents, this);\n    },\n\n    _controlEvents: {\n        add: function() {\n            this._trafficLayer = DG.traffic();\n            this._map.on('zoomend projectchange projectleave', this._updateControlVisibility, this);\n        },\n        click: function() {\n            this._active = !this._active;\n\n            if (this._active) {\n                this.setState('active');\n                this._showTraffic();\n            } else {\n                this.setState('');\n                this._hideTraffic();\n            }\n        },\n        remove: function() {\n            this.off(this._controlEvents, this);\n            this._map.off('zoomend projectchange projectleave', this._updateControlVisibility, this);\n            if (this._active) {\n                this._map.removeLayer(this._trafficLayer);\n                this._active = false;\n            }\n            this._trafficLayer = null;\n        }\n    },\n\n    _showTraffic: function() { // ()\n        this._updateTrafficScore();\n        this._map.addLayer(this._trafficLayer);\n    },\n\n    _hideTraffic: function() { // ()\n        this._handleDom('remove');\n        this._map.removeLayer(this._trafficLayer);\n    },\n\n    _handleDom: function(method, score) {\n        var a = this._link;\n\n        a.innerHTML = isNaN(score) ? '' : score;\n        DG.DomUtil[method + 'Class'](a, this._trafficClass);\n        DG.DomUtil[method + 'Class'](a, this._trafficClass + '_color_' + this._scoreRate);\n    },\n\n    _getTrafficColor: function(score) { // (Number) -> String\n        var result = 'green';\n\n        if (score > 7) {\n            result = 'red';\n        } else if (score > 4) {\n            result = 'yellow';\n        }\n\n        return result;\n    },\n\n    _updateControlVisibility: function() {\n        var project = this._map.projectDetector.getProject(),\n            projectHasTraffic = project && project.traffic,\n            method = ((this._map.getZoom() < DG.config.trafficLayerMinZoom) ||\n            (!projectHasTraffic)) ? 'addClass' : 'removeClass';\n\n        DG.DomUtil[method](this._container, this._controlHideClass);\n        if (this._active && projectHasTraffic) {\n            this._updateTrafficScore();\n        }\n    },\n\n    _updateTrafficScore: function() {\n        var self = this;\n\n        this._getTrafficScore().then(function(score) {\n            score = parseInt(score, 10); // sometimes webapi returns something like '5,+'\n\n            self._scoreRate = self._getTrafficColor(score);\n            self._handleDom('add', score);\n        });\n    },\n\n    _getTrafficScore: function() { // () -> Promise\n        var url = DG.Util.template(\n            DG.config.protocol + DG.config.trafficScoreServer,\n            {\n                s: this._trafficLayer.getSubdomain(),\n                projectCode: this._map.projectDetector.getProject().code\n            }\n        );\n\n        return DG.ajax(url, {type: 'get'});\n    },\n\n    _renderTranslation: function() { // ()\n        this._link.title = this.t('button_title');\n    }\n});\n\nDG.control.traffic = function(options) {\n    return new DG.Control.Traffic(options);\n};\n\nDG.Map.mergeOptions({\n    trafficControl: false\n});\n\nDG.Map.addInitHook(function() {\n    if (this.options.trafficControl) {\n        this.trafficControl = DG.control.traffic(this.options.trafficControl);\n        this.addControl(this.trafficControl);\n    }\n});\n"
  },
  {
    "path": "src/DGTrafficControl/test/TrafficControlSpec.js",
    "content": "describe('DG.TrafficControl', function() {\n    var controlClass = 'dg-control-round__icon_name_traffic',\n        controlParentActiveClass = 'dg-control-round_state_active',\n        controlParentHiddenClass = 'dg-control-round_is-hidden_true',\n\n        centerNsk = [55.017493, 82.819576],\n        centerSpb = [59.937706, 30.13249],\n        centerWithoutProject = [77.81307220458986, 55.363990665081126]; // севернее Новой земли\n\n    after(function () {\n        controlClass = controlParentActiveClass = controlParentHiddenClass = centerNsk = null;\n        centerSpb = centerWithoutProject = null;\n    });\n\n    describe('common traffic control test', function() {\n        var mapContainer,\n            map,\n            control,\n            trafficControl,\n            controlParent;\n\n        before(function () {\n            mapContainer = document.createElement('div');\n            map = new DG.Map(mapContainer, {\n                center: centerSpb,\n                zoom: 15,\n                key: window.__karma__.config.secretKey,\n            });\n\n            control = mapContainer.getElementsByClassName(controlClass);\n            trafficControl = DG.control.traffic();\n\n            document.body.appendChild(mapContainer);\n            map.addControl(trafficControl);\n        });\n\n        after(function () {\n            map.remove();\n            document.body.removeChild(mapContainer);\n            mapContainer = map = control = trafficControl = controlParent = null;\n        });\n\n        describe('module init', function () {\n            it('traffic control show', function () {\n                expect(control.length).to.be(1);\n\n                control = control[0];\n                controlParent = control.parentElement;\n            });\n\n            it('remove hide class from control parent element', function () {\n                expect(controlParent.className).not.contain(controlParentHiddenClass);\n            });\n        });\n\n        describe('turn on control', function () {\n            before(function () {\n                happen.click(controlParent);\n            });\n\n            it('add active class to control parent element', function () {\n                expect(controlParent.className).to.contain(controlParentActiveClass);\n            });\n\n            it('add traffic layer to map', function () {\n                expect(map.hasLayer(trafficControl._trafficLayer)).to.be(true);\n            });\n        });\n\n        describe('turn off control', function () {\n            before(function () {\n                happen.click(controlParent);\n            });\n\n            it('remove active class from control parent element', function () {\n                expect(controlParent.className).not.contain(controlParentActiveClass);\n            });\n\n            it('remove traffic layer from map', function () {\n                expect(map.hasLayer(trafficControl._trafficLayer)).to.be(false);\n            });\n        });\n\n        describe('traffic point request', function () {\n            var xhr, center, zoom, requests;\n\n            before(function () {\n                zoom = map.getZoom();\n                center = map.getCenter();\n                xhr = sinon.useFakeXMLHttpRequest();\n                requests =  [];\n\n                xhr.onCreate = function (xhr) {\n                    requests.push(xhr);\n                };\n\n                happen.click(controlParent);\n\n            });\n\n            after(function () {\n                xhr.restore();\n                map.setView(center, zoom);\n                happen.click(controlParent);\n            });\n\n            it('traffic points request called', function () {\n                var urlRE = new RegExp('http://traffic\\\\d+.maps.2gis.com/\\\\w+/meta/score/0/');\n                expect(urlRE.test(requests[0].url)).to.be(true);\n            });\n        });\n\n        describe('traffic point timer request', function () {\n            var xhr, center, zoom, requests, clock;\n\n            before(function () {\n                zoom = map.getZoom();\n                center = map.getCenter();\n                xhr = sinon.useFakeXMLHttpRequest();\n                clock = sinon.useFakeTimers();\n                requests =  [];\n\n                xhr.onCreate = function (xhr) {\n                    requests.push(xhr);\n                };\n\n                happen.click(controlParent);\n\n            });\n\n            after(function () {\n                xhr.restore();\n                clock.restore();\n                map.setView(center, zoom);\n                happen.click(controlParent);\n            });\n\n            it('traffic points update request called', function () {\n                var urlRE = new RegExp('http://traffic\\\\d+.maps.2gis.com/\\\\w+/meta/speed/time/');\n                clock.tick(DG.config.trafficLayerUpdateInterval + 1);\n                expect(urlRE.test(requests[1].url)).to.be(true);\n            });\n        });\n    });\n\n    describe('traffic test on project leave/enter/change', function () {\n        var mapContainer,\n            map,\n            control,\n            trafficControl,\n            controlParent;\n\n        beforeEach(function () {\n            mapContainer = document.createElement('div');\n            map = new DG.Map(mapContainer, {\n                center: centerSpb,\n                zoom: 15,\n                key: window.__karma__.config.secretKey,\n            });\n\n            trafficControl = DG.control.traffic();\n\n            document.body.appendChild(mapContainer);\n            map.addControl(trafficControl);\n\n            control = mapContainer.getElementsByClassName(controlClass)[0];\n            controlParent = control.parentElement;\n        });\n\n        afterEach(function () {\n            map.remove();\n            document.body.removeChild(mapContainer);\n            mapContainer = map = control = trafficControl = controlParent = null;\n        });\n\n        describe('with traffic off', function () {\n            // traffic layer is off after map initialization\n\n            it('control parent haven\\'t active and hide classes', function () {\n                expect(controlParent.className).not.contain(controlParentActiveClass);\n                expect(controlParent.className).not.contain(controlParentHiddenClass);\n            });\n\n            it('add hide class to control parent element', function (done) {\n                var onProjectLeave = function (ev) {\n                    map.off('projectleave', onProjectLeave);\n                    expect(controlParent.className).to.contain(controlParentHiddenClass);\n                    done();\n                };\n\n                map.on('projectleave', onProjectLeave);\n                map.setView(centerWithoutProject, 15, {animate: false});\n            });\n\n            it('remove hide class and control doesn\\'t have active class', function (done) {\n                var onProjectChange = function (ev) {\n                    map.off('projectchange', onProjectChange);\n                    expect(controlParent.className).not.contain(controlParentHiddenClass);\n                    expect(controlParent.className).not.contain(controlParentActiveClass);\n                    done();\n                };\n\n                map.setView(centerWithoutProject, 15, {animate: false});\n                map.on('projectchange', onProjectChange);\n                map.setView(centerSpb, 15, {animate: false});\n            });\n        });\n\n        describe('with traffic on', function () {\n            beforeEach(function () {\n                // traffic layer is on, click on traffic control\n                happen.click(controlParent);\n            });\n\n            it('control parent have active class', function () {\n                expect(controlParent.className).to.contain(controlParentActiveClass);\n            });\n\n            // skipped due to unstable behavior on map.remove() after this test\n            it.skip('add hide class to control parent element', function (done) {\n                var onProjectLeave = function (ev) {\n                    map.off('projectleave', onProjectLeave);\n                    expect(controlParent.className).to.contain(controlParentHiddenClass);\n                    done();\n                };\n\n                map.on('projectleave', onProjectLeave);\n                map.setView(centerWithoutProject, 15, {animate: false});\n            });\n\n            it('remove hide class and control has active class, ', function (done) {\n                var onProjectChange = function (ev) {\n                    map.off('projectchange', onProjectChange);\n                    expect(controlParent.className).not.contain(controlParentHiddenClass);\n                    expect(controlParent.className).to.contain(controlParentActiveClass);\n                    expect(map.hasLayer(trafficControl._trafficLayer)).to.be(true);\n                    done();\n                };\n\n                map.setView(centerWithoutProject, 15, {animate: false});\n                map.on('projectchange', onProjectChange);\n                map.setView(centerSpb, 15, {animate: false});\n            });\n\n            it('control parent element have active class', function () {\n                map.setView(centerNsk, 15, {animate: false});\n                expect(controlParent.className).to.contain(controlParentActiveClass);\n            });\n        });\n\n        describe('traffic test on project change', function () {\n            describe('with traffic off', function () {\n                    // traffic layer is off after map initialization\n\n                it('control parent element haven\\'t active class', function () {\n                    map.setView(centerNsk, 15, {animate: false});\n                    expect(controlParent.className).not.contain(controlParentActiveClass);\n                });\n            });\n\n            describe('with traffic on', function () {\n                beforeEach(function () {\n                    // traffic layer is on, click on traffic control\n                    happen.click(controlParent);\n                    control.innerHTML = -50;\n                });\n\n                it('control parent element have active class', function () {\n                    map.setView(centerNsk, 15, {animate: false});\n                    expect(controlParent.className).to.contain(controlParentActiveClass);\n                });\n\n                it('update traffic balls in control', function () {\n                    expect(control.innerHTML).not.be(-50);\n                });\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGWkt/DGWkt.js",
    "content": "DG.Wkt = {};\n\nDG.Wkt.toGeoJSON = function (data) {\n    if (DG.Util.isArray(data)) {\n        data = data[0];\n    }\n    var parts = data.split(';');\n    data = parts.pop();\n\n    var i = 0,\n        srid = (parts.shift() || '').split('=').pop();\n\n    function $(re) {\n        var match = data.substring(i).match(re);\n        if (!match) {\n            return null;\n        }\n        else {\n            i += match[0].length;\n            return match[0];\n        }\n    }\n\n    function crs(obj) {\n        if (obj && srid.match(/\\d+/)) {\n            obj.crs = {\n                type: 'name',\n                'properties': {\n                    name: 'urn:ogc:def:crs:EPSG::' + srid\n                }\n            };\n        }\n\n        return obj;\n    }\n\n    function white() { $(/^\\s*/); }\n\n    function multicoords() {\n        white();\n        var depth = 0, rings = [], stack = [rings],\n            pointer = rings, elem;\n        while (elem =\n            $(/^(\\()/) ||\n            $(/^(\\))/) ||\n            $(/^(\\,)/) ||\n            $(/^[-+]?([0-9]*\\.[0-9]+|[0-9]+)/)) {\n            if (elem === '(') {\n                stack.push(pointer);\n                pointer = [];\n                stack[stack.length - 1].push(pointer);\n                depth++;\n            } else if (elem === ')') {\n                pointer = stack.pop();\n                depth--;\n                if (depth === 0) {\n                    break;\n                }\n            } else if (elem === ',') {\n                pointer = [];\n                stack[stack.length - 1].push(pointer);\n            } else {\n                pointer.push(parseFloat(elem));\n            }\n            white();\n        }\n        stack.length = 0;\n        if (depth !== 0) {\n            return null;\n        }\n        return rings;\n    }\n\n    function coords() {\n        var list = [], item, pt;\n        while (pt =\n            $(/^[-+]?([0-9]*\\.[0-9]+|[0-9]+)/) ||\n            $(/^(\\,)/)) {\n            if (pt === ',') {\n                list.push(item);\n                item = [];\n            } else {\n                if (!item) {\n                    item = [];\n                }\n                item.push(parseFloat(pt));\n            }\n            white();\n        }\n        if (item) {\n            list.push(item);\n        }\n        return list.length ? list : null;\n    }\n\n    function point() {\n        if (!$(/^(point)/i)) { return null; }\n        white();\n        if (!$(/^(\\()/)) { return null; }\n        var c = coords();\n        white();\n        if (!$(/^(\\))/)) { return null; }\n        return {\n            type: 'Point',\n            coordinates: c[0]\n        };\n    }\n\n    function multipoint() {\n        if (!$(/^(multipoint)/i)) { return null; }\n        white();\n        var c = multicoords();\n        white();\n        return {\n            type: 'MultiPoint',\n            coordinates: c\n        };\n    }\n\n    function multilinestring() {\n        if (!$(/^(multilinestring)/i)) { return null; }\n        white();\n        var c = multicoords();\n        white();\n        return {\n            type: 'MultiLineString',\n            coordinates: c\n        };\n    }\n\n    function linestring() {\n        if (!$(/^(linestring)/i)) { return null; }\n        white();\n        if (!$(/^(\\()/)) { return null; }\n        var c = coords();\n        if (!$(/^(\\))/)) { return null; }\n        return {\n            type: 'LineString',\n            coordinates: c\n        };\n    }\n\n    function polygon() {\n        if (!$(/^(polygon)/i)) { return null; }\n        white();\n        return {\n            type: 'Polygon',\n            coordinates: multicoords()\n        };\n    }\n\n    function multipolygon() {\n        if (!$(/^(multipolygon)/i)) { return null; }\n        white();\n        return {\n            type: 'MultiPolygon',\n            coordinates: multicoords()\n        };\n    }\n\n    function geometrycollection() {\n        var geometries = [], geometry;\n\n        if (!$(/^(geometrycollection)/i)) { return null; }\n        white();\n\n        if (!$(/^(\\()/)) { return null; }\n        while (geometry = root()) {\n            geometries.push(geometry);\n            white();\n            $(/^(\\,)/);\n            white();\n        }\n        if (!$(/^(\\))/)) { return null; }\n\n        return {\n            type: 'GeometryCollection',\n            geometries: geometries\n        };\n    }\n\n    function root() {\n        return point() ||\n            linestring() ||\n            polygon() ||\n            multipoint() ||\n            multilinestring() ||\n            multipolygon() ||\n            geometrycollection();\n    }\n\n    return crs(root());\n};\n\nDG.Wkt.geoJsonLayer = function (data, opts) {\n    return DG.geoJson(DG.Wkt.toGeoJSON(data), opts);\n};\n\nDG.Wkt._coordsToLatLngs = function (coords) {\n    if (DG.Util.isArray(coords) && !DG.Util.isArray(coords[0])) {\n        return [DG.GeoJSON.coordsToLatLng(coords)];\n    }\n\n    return coords.map(function (el) {\n            return DG.Wkt._coordsToLatLngs(el);\n        })\n        .reduce(function (arr, coord) {\n            return arr.concat(coord);\n        });\n};\n\nDG.Wkt.toLatLngs = function (data) {\n    if (!DG.Util.isArray(data)) {\n        data = [data];\n    }\n\n    return data.map(function (el) {\n        var coords = DG.Wkt.toGeoJSON(el).coordinates;\n\n        return DG.Wkt._coordsToLatLngs(coords);\n    }).reduce(function (arr, coord) {\n        return arr.concat(coord);\n    });\n};\n\nDG.Wkt.toPoints = function (data) {\n    return DG.Wkt.toGeoJSON(data).coordinates;\n};\n\nDG.Wkt.pointsToLatLngOnMap = function (wkt, map) {\n    return (function parsePoints(points) {\n        return (Array.isArray(points) && Array.isArray(points[0])) ?\n            points.map(parsePoints) :\n            map.containerPointToLatLng(points);\n    })(DG.Wkt.toPoints(wkt));\n};\n"
  },
  {
    "path": "src/DGWkt/demo/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>DGWkt demo</title>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <script src=\"http://maps.api.2gis.ru/2.0/loader.js\"></script>\n    <style type=\"text/css\">\n        html,body { height: 100%; margin: 0; padding: 0; }\n        #map { width: 100%; height: 100%; }\n    </style>\n</head>\n<body>\n\n<div id=\"map\"</div>\n\n<script type=\"text/javascript\">\n    DG.then(function () {\n\n        var map = new DG.Map('map', {\n                center: new DG.LatLng(55.0412876099625, 82.9175228440822),\n                zoom: 17,\n                key: DG.config.key || 'Your API access key'\n            }),\n            converter = function (coords) {\n                return map.containerPointToLatLng(coords);\n            };\n\n        DG.Wkt.geoJsonLayer('POLYGON((82.916999581655 55.0421363815388, 82.9175228440822 55.0401876099625, 82.9180633669606 55.0402351774059, 82.9175402952564 55.0421841282563,82.916999581655 55.0421363815388))').addTo(map);\n\n        DG.Wkt.geoJsonLayer('POINT(82.918299581655 55.0414363815388)').addTo(map);\n\n        DG.Wkt.geoJsonLayer('POINT (300 100)', {\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('LINESTRING (300 100, 100 300, 400 400)', {\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('POLYGON ((300 100, 400 400, 200 400, 100 200, 300 100))', {\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('POLYGON ((850 100, 950 450, 650 400, 600 200, 850 100), (700 300, 850 350, 800 200, 700 300))', {\n            style: {color: 'red'},\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('MULTIPOINT (1000 400, 1400 300, 1200 200, 1300 100)', {\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('MULTILINESTRING ((600 100, 700 200, 600 400), (900 400, 800 300, 900 200, 800 100))', {\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('MULTIPOLYGON (((1300 200, 1450 400, 1100 400, 1300 200)), ((1150 50, 1400 100, 1100 200, 1150 100, 1150 50)))', {\n            style: {color: 'orange'},\n            coordsToLatLng: converter\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('MULTIPOLYGON (((1800 400, 1600 450, 1850 300, 1800 400)), ((1600 350, 1500 300, 1500 100, 1700 50, 1850 200, 1600 350), (1700 200, 1600 150, 1600 250, 1700 200)))', {\n            coordsToLatLng: converter,\n            style: {color: 'green'}\n        }).addTo(map);\n\n        DG.Wkt.geoJsonLayer('GEOMETRYCOLLECTION(MULTIPOINT(100 60, 70 300), LINESTRING(100 60, 70 100, 70 300))', {\n            coordsToLatLng: converter,\n            style: {color: 'grey'}\n        }).addTo(map);\n\n    });\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/DGWkt/test/DGWktSpec.js",
    "content": "describe('DG.Wkt', function() {\n    describe('check init', function() {\n        it('should be DG.Wkt object', function() {\n            expect(DG.Wkt).to.be.a('object');\n        });\n    });\n\n    describe('#geoJsonLayer', function() {\n        it('should return DG.GeoJSON', function() {\n            expect(DG.Wkt.geoJsonLayer('POLYGON((82.916999581655 55.0421363815388, 82.9175228440822 55.0401876099625, 82.9180633669606 55.0402351774059, 82.9175402952564 55.0421841282563,82.916999581655 55.0421363815388))'))\n                .to.be.a(DG.GeoJSON);\n        });\n    });\n\n    describe('#toPoints', function() {\n        it('should equel example points', function() {\n            var points = [\n                    [1, 2],\n                    [5, 10],\n                    [8, 7]\n                ],\n                example,\n                res;\n\n            example = 'POLYGON((';\n            example += points.map(function(el) {\n                return el.join(' ')\n            }).join(', ');\n            example += '))';\n\n            res = DG.Wkt.toPoints(example);\n\n            expect(res).to.be.a(Array);\n            expect(res[0]).to.eql(points);\n        });\n    });\n\n    describe('#pointsToLatLngOnMap', function() {\n        var map;\n\n        before(function() {\n            map = new DG.Map(document.createElement('div'), {\n                center: [55.017493, 82.819576],\n                zoom: 15,\n            });\n        });\n\n        after(function() {\n            map = null;\n        });\n\n        it('should return Array of DG.LatLng', function() {\n            var example = 'POLYGON((1 2, 5 10, 8 7))',\n                res;\n\n            res = DG.Wkt.pointsToLatLngOnMap(example, map);\n\n            expect(res).to.be.a(Array);\n            expect(res[0]).to.be.a(Array);\n\n            res[0].forEach(function(el) {\n                expect(el).to.be.a(DG.LatLng);\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGWkt/test/DGWktToGeoJSONSpec.js",
    "content": "describe('DG.Wkt#toLatlngs', function() {\n    // test cases took from https://github.com/mapbox/wellknown\n\n    it('POINT (1 1)', function() {\n        expect(DG.Wkt.toGeoJSON('POINT (1 1)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1, 1]\n        });\n    });\n\n    it('POINT(1 1)', function() {\n        expect(DG.Wkt.toGeoJSON('POINT(1 1)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1, 1]\n        });\n    });\n\n    it('POINT\\n\\r(1 1))', function() {\n        expect(DG.Wkt.toGeoJSON('POINT\\n\\r(1 1)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1, 1]\n        });\n    });\n\n    it('POINT(1.1 1.1)', function() {\n        expect(DG.Wkt.toGeoJSON('POINT(1.1 1.1)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1.1, 1.1]\n        });\n    });\n\n    it('point(1.1 1.1)', function() {\n        expect(DG.Wkt.toGeoJSON('point(1.1 1.1)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1.1, 1.1]\n        });\n    });\n\n    it('point(1 2 3)', function() {\n        expect(DG.Wkt.toGeoJSON('point(1 2 3)')).to.be.eql({\n            type: 'Point',\n            coordinates: [1, 2, 3]\n        });\n    });\n\n    it('LINESTRING (30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toGeoJSON('LINESTRING (30 10, 10 30, 40 40)')).to.be.eql({\n            type: 'LineString',\n            coordinates: [[30, 10], [10, 30], [40, 40]]\n        });\n    });\n\n    it('LINESTRING(30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toGeoJSON('LINESTRING(30 10, 10 30, 40 40)')).to.be.eql({\n            type: 'LineString',\n            coordinates: [[30, 10], [10, 30], [40, 40]]\n        });\n    });\n\n    it('LineString(30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toGeoJSON('LineString(30 10, 10 30, 40 40)')).to.be.eql({\n            type: 'LineString',\n            coordinates: [[30, 10], [10, 30], [40, 40]]\n        });\n    });\n\n    it('LINESTRING (1 2 3, 4 5 6)', function() {\n        expect(DG.Wkt.toGeoJSON('LINESTRING (1 2 3, 4 5 6)')).to.be.eql({\n            type: 'LineString',\n            coordinates: [[1, 2, 3], [4, 5, 6]]\n        });\n    });\n\n    it('POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))', function() {\n        expect(DG.Wkt.toGeoJSON('POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))')).to.be.eql({\n            type: 'Polygon',\n            coordinates: [[[30, 10], [10, 20], [20, 40], [40, 40], [30, 10]]]\n        });\n    });\n\n    it('POLYGON((30 10, 10 20, 20 40, 40 40, 30 10))', function() {\n        expect(DG.Wkt.toGeoJSON('POLYGON((30 10, 10 20, 20 40, 40 40, 30 10))')).to.be.eql({\n            type: 'Polygon',\n            coordinates: [[[30, 10], [10, 20], [20, 40], [40, 40], [30, 10]]]\n        });\n    });\n\n    it('POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))', function() {\n        expect(DG.Wkt.toGeoJSON('POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))')).to.be.eql({\n            type: 'Polygon',\n            coordinates:\n                [\n                    [\n                        [ 35, 10 ],\n                        [ 10, 20 ],\n                        [ 15, 40 ],\n                        [ 45, 45 ],\n                        [ 35, 10 ]\n                    ], [\n                    [ 20, 30 ],\n                    [ 35, 35 ],\n                    [ 30, 20 ],\n                    [ 20, 30 ]\n                ]\n                ]\n        });\n    });\n\n    it('MULTIPOINT (1 1, 2 3)', function() {\n        expect(DG.Wkt.toGeoJSON('MULTIPOINT (1 1, 2 3)')).to.be.eql({\n            type: 'MultiPoint',\n            coordinates: [[1, 1], [2, 3]]\n        });\n    });\n\n    it('MultiPoint (1 1, 2 3)', function() {\n        expect(DG.Wkt.toGeoJSON('MultiPoint (1 1, 2 3)')).to.be.eql({\n            type: 'MultiPoint',\n            coordinates: [[1, 1], [2, 3]]\n        });\n    });\n\n    it('MULTILINESTRING ((30 10, 10 30, 40 40), (30 10, 10 30, 40 40))', function() {\n        expect(DG.Wkt.toGeoJSON('MULTILINESTRING ((30 10, 10 30, 40 40), (30 10, 10 30, 40 40))')).to.be.eql({\n            type: 'MultiLineString',\n            coordinates: [\n                [[30, 10], [10, 30], [40, 40]],\n                [[30, 10], [10, 30], [40, 40]]]\n        });\n    });\n\n    it('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))', function() {\n        expect(DG.Wkt.toGeoJSON('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))')).to.be.eql({\n            type: 'MultiPolygon',\n            coordinates: [\n                [[[30, 20], [10, 40], [45, 40], [30, 20]]],\n                [[[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]]]\n        });\n    });\n\n    it('MULTIPOLYGON (((-74.03349399999999 40.688348)))', function() {\n        expect(DG.Wkt.toGeoJSON('MULTIPOLYGON (((-74.03349399999999 40.688348)))')).to.be.eql(\n            {\"type\":\"MultiPolygon\",\"coordinates\":[[[[-74.03349399999999,40.688348]]]]}\n        );\n    });\n\n    it('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5), (10 10, 15 10, 15 15, 10 10)))', function() {\n        expect(DG.Wkt.toGeoJSON('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5), (10 10, 15 10, 15 15, 10 10)))')).to.be.eql({\n            type: 'MultiPolygon',\n            coordinates: [\n                [[[30, 20], [10, 40], [45, 40], [30, 20]]],\n                [\n                    [[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]],\n                    [[10, 10], [15, 10], [15, 15], [10, 10]]]]\n        });\n    });\n});\n"
  },
  {
    "path": "src/DGWkt/test/DGWktToLatLngsSpec.js",
    "content": "describe('DG.Wkt#toLatLngs', function() {\n    it('POINT (1 1)', function() {\n        expect(DG.Wkt.toLatLngs('POINT (1 1)')).to.be.eql([\n            {lat: 1, lng: 1}\n        ]);\n    });\n\n    it('POINT(1 1)', function() {\n        expect(DG.Wkt.toLatLngs('POINT(1 1)')).to.be.eql([\n            {lat: 1, lng: 1}\n        ]);\n    });\n\n    it('POINT\\n\\r(1 1))', function() {\n        expect(DG.Wkt.toLatLngs('POINT\\n\\r(1 1)')).to.be.eql([\n            {lat: 1, lng: 1}\n        ]);\n    });\n\n    it('POINT(1.1 1.1)', function() {\n        expect(DG.Wkt.toLatLngs('POINT(1.1 1.1)')).to.be.eql([\n            {lat: 1.1, lng: 1.1}\n        ]);\n    });\n\n    it('point(1.1 1.1)', function() {\n        expect(DG.Wkt.toLatLngs('point(1.1 1.1)')).to.be.eql([\n            {lat: 1.1, lng: 1.1}\n        ]);\n    });\n\n    it('point(1 2 3)', function() {\n        expect(DG.Wkt.toLatLngs('point(1 2 3)')).to.be.eql([{\n            lng: 1,\n            lat: 2,\n            alt: 3\n        }]);\n    });\n\n    it('[\\'point(1 1)\\', \\'point(1.1 1.1)\\']', function() {\n        expect(DG.Wkt.toLatLngs(['point(1 1)', 'point(1.1 1.1)'])).to.be.eql([\n            {lat: 1, lng: 1},\n            {lat: 1.1, lng: 1.1}\n        ]);\n    });\n\n    it('LINESTRING (30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toLatLngs('LINESTRING (30 10, 10 30, 40 40)')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 30},\n            {lng: 40, lat: 40}\n        ])\n    });\n\n    it('LINESTRING(30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toLatLngs('LINESTRING(30 10, 10 30, 40 40)')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 30},\n            {lng: 40, lat: 40}\n        ]);\n    });\n\n    it('LineString(30 10, 10 30, 40 40)', function() {\n        expect(DG.Wkt.toLatLngs('LineString(30 10, 10 30, 40 40)')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 30},\n            {lng: 40, lat: 40}\n        ]);\n    });\n\n    it('LINESTRING (1 2 3, 4 5 6)', function() {\n        expect(DG.Wkt.toLatLngs('LINESTRING (1 2 3, 4 5 6)')).to.be.eql([\n            {lng: 1, lat: 2, alt: 3},\n            {lng: 4, lat: 5, alt: 6}\n        ]);\n    });\n\n    it('POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))', function() {\n        expect(DG.Wkt.toLatLngs('POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 20, lat: 40},\n            {lng: 40, lat: 40},\n            {lng: 30, lat: 10}\n        ]);\n    });\n\n    it('POLYGON((30 10, 10 20, 20 40, 40 40, 30 10))', function() {\n        expect(DG.Wkt.toLatLngs('POLYGON((30 10, 10 20, 20 40, 40 40, 30 10))')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 20, lat: 40},\n            {lng: 40, lat: 40},\n            {lng: 30, lat: 10}\n        ]);\n    });\n\n    it('POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))', function() {\n        expect(DG.Wkt.toLatLngs('POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))')).to.be.eql([\n            {lng: 35, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 15, lat: 40},\n            {lng: 45, lat: 45},\n            {lng: 35, lat: 10},\n            {lng: 20, lat: 30},\n            {lng: 35, lat: 35},\n            {lng: 30, lat: 20},\n            {lng: 20, lat: 30}\n        ]);\n    });\n\n    it('[\\'POLYGON ((30 20, 10 40, 45 40, 30 20))\\', \\'POLYGON ((15 5, 40 10, 10 20, 5 10, 15 5))\\']', function() {\n        expect(DG.Wkt.toLatLngs(['POLYGON ((30 20, 10 40, 45 40, 30 20))', 'POLYGON ((15 5, 40 10, 10 20, 5 10, 15 5))'])).to.be.eql([\n            {lng: 30, lat: 20},\n            {lng: 10, lat: 40},\n            {lng: 45, lat: 40},\n            {lng: 30, lat: 20},\n\n            {lng: 15, lat: 5},\n            {lng: 40, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 5, lat: 10},\n            {lng: 15, lat: 5}\n        ]);\n    });\n\n    it('MULTIPOINT (1 1, 2 3)', function() {\n        expect(DG.Wkt.toLatLngs('MULTIPOINT (1 1, 2 3)')).to.be.eql([\n            {lng: 1, lat: 1},\n            {lng: 2, lat: 3}\n        ]);\n    });\n\n    it('MultiPoint (1 1, 2 3)', function() {\n        expect(DG.Wkt.toLatLngs('MultiPoint (1 1, 2 3)')).to.be.eql([\n            {lng: 1, lat: 1},\n            {lng: 2, lat: 3}\n        ]);\n    });\n\n    it('MULTILINESTRING ((30 10, 10 30, 40 40), (30 10, 10 30, 40 40))', function() {\n        expect(DG.Wkt.toLatLngs('MULTILINESTRING ((30 10, 10 30, 40 40), (30 10, 10 30, 40 40))')).to.be.eql([\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 30},\n            {lng: 40, lat: 40},\n\n            {lng: 30, lat: 10},\n            {lng: 10, lat: 30},\n            {lng: 40, lat: 40}\n        ]);\n    });\n\n    it('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))', function() {\n        expect(DG.Wkt.toLatLngs('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5)))')).to.be.eql([\n            {lng: 30, lat: 20},\n            {lng: 10, lat: 40},\n            {lng: 45, lat: 40},\n            {lng: 30, lat: 20},\n\n            {lng: 15, lat: 5},\n            {lng: 40, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 5, lat: 10},\n            {lng: 15, lat: 5}\n        ]);\n    });\n\n    it('MULTIPOLYGON (((-74.03349399999999 40.688348)))', function() {\n        expect(DG.Wkt.toLatLngs('MULTIPOLYGON (((-74.03349399999999 40.688348)))')).to.be.eql([\n            {lng: -74.03349399999999, lat: 40.688348}\n        ]);\n    });\n\n    it('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5), (10 10, 15 10, 15 15, 10 10)))', function() {\n        expect(DG.Wkt.toLatLngs('MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)), ((15 5, 40 10, 10 20, 5 10, 15 5), (10 10, 15 10, 15 15, 10 10)))')).to.be.eql([\n            {lng: 30, lat: 20},\n            {lng: 10, lat: 40},\n            {lng: 45, lat: 40},\n            {lng: 30, lat: 20},\n\n            {lng: 15, lat: 5},\n            {lng: 40, lat: 10},\n            {lng: 10, lat: 20},\n            {lng: 5, lat: 10},\n            {lng: 15, lat: 5},\n\n            {lng: 10, lat: 10},\n            {lng: 15, lat: 10},\n            {lng: 15, lat: 15},\n            {lng: 10, lat: 10}\n        ]);\n    });\n});\n"
  },
  {
    "path": "src/DGZoomControl/lang/ar.js",
    "content": "DG.Control.Zoom.Dictionary.ar = {\n    zoom_in : '',\n    zoom_out : ''\n};\n"
  },
  {
    "path": "src/DGZoomControl/lang/cs.js",
    "content": "DG.Control.Zoom.Dictionary.cs = {\n    zoom_in : 'Přiblížit',\n    zoom_out : 'Oddálit'\n};\n"
  },
  {
    "path": "src/DGZoomControl/lang/en.js",
    "content": "DG.Control.Zoom.Dictionary.en = {\n    zoom_in : 'Zoom in',\n    zoom_out : 'Zoom out'\n};\n"
  },
  {
    "path": "src/DGZoomControl/lang/es.js",
    "content": "DG.Control.Zoom.Dictionary.es = {\n    zoom_in : 'Acercar',\n    zoom_out : 'Alejar'\n};\n"
  },
  {
    "path": "src/DGZoomControl/lang/it.js",
    "content": "DG.Control.Zoom.Dictionary.it = {\n    zoom_in : 'Zoom avanti',\n    zoom_out : 'Zoom indietro'\n};\n"
  },
  {
    "path": "src/DGZoomControl/lang/ru.js",
    "content": "DG.Control.Zoom.Dictionary.ru = {\n    zoom_in : 'Приблизить',\n    zoom_out : 'Отдалить'\n};\n"
  },
  {
    "path": "src/DGZoomControl/skin/basic/less/dg-zoom-control.less",
    "content": ".dg-zoom {\r\n    width: 40px;\r\n    height: 74px;\r\n}\r\n\r\n.dg-zoom__in {\r\n    position: absolute;\r\n    top: 0;\r\n    left: 0;\r\n\r\n    .leaflet-touch &:before {\r\n        position: absolute;\r\n        top: -5px;\r\n        right: -10px;\r\n        bottom: 0;\r\n        left: -10px;\r\n        content: '';\r\n    }\r\n\r\n    &:after {\r\n        position: absolute;\r\n        right: 0;\r\n        bottom: -1px;\r\n        left: 0;\r\n        z-index: -1;\r\n        margin: auto;\r\n        width: 12px;\r\n        height: 2px;\r\n        box-shadow: 0 0 3px 2px rgba(0, 0, 0, .3);\r\n        content: '';\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_in {\r\n    &:before,\r\n    .leaflet-touch &:before,\r\n    &:after {\r\n        position: absolute;\r\n        top: 0;\r\n        right: 0;\r\n        bottom: 0;\r\n        left: 0;\r\n        margin: auto;\r\n        width: 14px;\r\n        height: 2px;\r\n        background-color: #7a7a7a; // 48%\r\n        box-shadow: 0 1px #fff;\r\n        content: '';\r\n    }\r\n\r\n    &:after {\r\n        width: 2px;\r\n        height: 14px;\r\n    }\r\n\r\n    .no-touch &:hover:before,\r\n    .no-touch &:hover:after {\r\n        background-color: #616161; // 38%\r\n    }\r\n\r\n    &:active:before,\r\n    &:active:after,\r\n    .no-touch &:active:before,\r\n    .no-touch &:active:after {\r\n        background-color: #575757; // 34%\r\n    }\r\n\r\n    .leaflet-disabled &:before,\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:before,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:before,\r\n    .leaflet-disabled &:active:after {\r\n        box-shadow: none;\r\n    }\r\n}\r\n\r\n.dg-zoom__out {\r\n    position: absolute;\r\n    top: 40px;\r\n    right: 0;\r\n    left: 0;\r\n    margin: auto;\r\n    width: 22px;\r\n    height: 22px;\r\n\r\n    &:after {\r\n        position: absolute;\r\n        top: -1px;\r\n        right: 0;\r\n        left: 0;\r\n        margin: auto;\r\n        width: 12px;\r\n        height: 2px;\r\n        content: '';\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_out {\r\n    width: 22px;\r\n    height: 22px;\r\n\r\n    .leaflet-touch &:before {\r\n        top: -5px;\r\n        right: -19px;\r\n        bottom: -19px;\r\n        left: -19px;\r\n    }\r\n\r\n    &:after {\r\n        position: absolute;\r\n        top: 0;\r\n        right: 0;\r\n        bottom: 0;\r\n        left: 0;\r\n        margin: auto;\r\n        width: 10px;\r\n        height: 2px;\r\n        background: #7a7a7a; // 48%\r\n        box-shadow: 0 1px #fff;\r\n        content: '';\r\n    }\r\n\r\n    .no-touch &:hover:after {\r\n        background: #616161; // 38%\r\n    }\r\n\r\n    &:active:after,\r\n    .no-touch &:active:after {\r\n        background: #575757; // 34%\r\n    }\r\n\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:after {\r\n        box-shadow: none;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGZoomControl/skin/dark/less/dg-zoom-control.less",
    "content": ".dg-zoom__out {\r\n    box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .3);\r\n\r\n    &:after {\r\n        background-color: #3d3d3d; // 24%\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_in {\r\n    .leaflet-disabled &:before,\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:before,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:before,\r\n    .leaflet-disabled &:active:after {\r\n        background-color: #707070; // 44%\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_out {\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:after {\r\n        background-color: #707070; // 44%\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGZoomControl/skin/light/less/dg-zoom-control.less",
    "content": ".dg-zoom__out {\r\n    box-shadow: 0 0 0 1px #fff, 0 2px 3px 0 rgba(0, 0, 0, .3);\r\n\r\n    &:after {\r\n        border: solid #fff;\r\n        border-width: 0 1px;\r\n        background-color: #f0f0f0; // 94%\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_in {\r\n    .leaflet-disabled &:before,\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:before,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:before,\r\n    .leaflet-disabled &:active:after {\r\n        background-color: #999; // 60%\r\n    }\r\n}\r\n\r\n.dg-zoom__button_type_out {\r\n    .leaflet-disabled &:after,\r\n    .no-touch .leaflet-disabled &:hover:after,\r\n    .leaflet-disabled &:active:after {\r\n        background-color: #999; // 60%\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/DGZoomControl/src/DGZoomControl.js",
    "content": "DG.Control.Zoom.include(DG.Locale);\nDG.Control.Zoom.Dictionary = {};\n\nDG.Control.Zoom.include({\n    onAdd: function(map) {\n        var zoomName = 'dg-zoom',\n            buttonTemplate = '<div class=\"dg-control-round__icon ' + zoomName + '__control ' + zoomName + '__button ' + zoomName + '__button_type_{type}\"></div>',\n            container = DG.DomUtil.create('div', zoomName);\n\n        this._map = map;\n\n        this._zoomInButton = this._createButton(DG.Util.template(buttonTemplate, {type : 'in'}), this.t('zoom_in'), 'dg-control-round ' + zoomName + '__in', container, this._zoomIn, this);\n        this._zoomOutButton = this._createButton(DG.Util.template(buttonTemplate, {type : 'out'}), this.t('zoom_out'), 'dg-control-round ' + zoomName + '__out', container, this._zoomOut, this);\n\n        this._updateDisabled();\n        map.on('zoomend zoomlevelschange', this._updateDisabled, this);\n\n        return container;\n    },\n\n    _originalCreateButton: DG.Control.Zoom.prototype._createButton,\n\n    // set active state control on mobile devices\n    _createButton: function() {\n        var args = Array.prototype.slice.call(arguments);\n        var link = this._originalCreateButton.apply(this, args);\n\n        var icon = link.children[0];\n        var linkActiveClass = 'dg-control-round_state_active';\n        var iconActiveClass = 'dg-control-round__icon_state_active';\n\n        DG.DomEvent\n            .on(link, 'touchstart', function() {\n                DG.DomUtil.addClass(link, linkActiveClass);\n                DG.DomUtil.addClass(icon, iconActiveClass);\n            })\n            .on(link, 'touchend touchcancel', function() {\n                DG.DomUtil.removeClass(link, linkActiveClass);\n                DG.DomUtil.removeClass(icon, iconActiveClass);\n            });\n\n        return link;\n    },\n\n    _renderTranslation: function() {\n        if (!this._zoomInButton || !this._zoomOutButton) {\n            return;\n        }\n\n        this._zoomInButton.title = this.t('zoom_in');\n        this._zoomOutButton.title = this.t('zoom_out');\n    }\n});\n"
  },
  {
    "path": "src/DGZoomControl/test/DGZoomControlSpec.js",
    "content": "describe('DG.Zoom', function() {\n    var classZoomIn = 'dg-zoom__in',\n        classZoomOut = 'dg-zoom__out',\n        mapContainer,\n        map,\n        zoomControl,\n        zoomContainer,\n        zoomIn,\n        zoomOut;\n\n    before(function () {\n        zoomControl = DG.control.zoom();\n        mapContainer = document.createElement('div');\n        map = new DG.Map(mapContainer, {\n            center: [54.980206086231, 82.898068362003],\n            zoom: 15,\n            key: window.__karma__.config.secretKey,\n        });\n    });\n\n    after(function() {\n        map.remove();\n        classZoomIn = classZoomOut = map = zoomControl = zoomContainer = zoomIn = zoomOut = null;\n    });\n\n    function checkInitControl() {\n        before(function() {\n            zoomContainer = mapContainer.getElementsByClassName('dg-zoom');\n        });\n\n        it('should only one zoom container', function() {\n            expect(zoomContainer.length).to.be(1);\n            zoomContainer = zoomContainer[0];\n        });\n\n        it('should zoom container init zoom in button', function() {\n            zoomIn = zoomContainer.getElementsByClassName(classZoomIn);\n            expect(zoomIn.length).to.be(1);\n            zoomIn = zoomIn[0];\n        });\n\n        it('should zoom container init zoom out button', function() {\n            zoomOut = zoomContainer.getElementsByClassName(classZoomOut);\n            expect(zoomOut.length).to.be(1);\n            zoomOut = zoomOut[0];\n        });\n    }\n\n    describe('check auto init', checkInitControl);\n\n    describe('#remove', function() {\n        it('should remove zoom container', function() {\n            map.zoomControl.remove();\n            expect(mapContainer.getElementsByClassName('dg-zoom').length).to.be(0);\n        });\n    });\n\n    describe('#addTo', function() {\n        before(function() {\n            zoomControl.addTo(map);\n        });\n\n        describe('check init', checkInitControl);\n\n        describe('check clicks', function() {\n            it('should map zoom in', function() {\n                map.setZoom(15, {animate: false});\n                happen.click(zoomIn);\n                expect(map.getZoom()).to.be(16);\n            });\n\n            it('should map zoom out', function() {\n                map.setZoom(15, {animate: false});\n                happen.click(zoomOut);\n                expect(map.getZoom()).to.be(14);\n            });\n        });\n\n        describe('check enable/disable zoom controls', function() {\n            it('should disable zoomIn button', function() {\n                map.setZoom(map.getMaxZoom(), {animate: false});\n                expect(zoomIn.className).contain('leaflet-disabled');\n            });\n\n\n            it('should enable zoomIn button', function() {\n                map.zoomOut(1, {animate: false});\n                expect(zoomIn.className).not.contain('leaflet-disabled');\n            });\n\n            it('should disable zoomOut button', function() {\n                map.setZoom(map.getMinZoom(), {animate: false});\n                expect(zoomOut.className).contain('leaflet-disabled');\n            });\n\n            it('should enable zoomOut button', function() {\n                map.zoomIn(1, {animate: false});\n                expect(zoomOut.className).not.contain('leaflet-disabled');\n            });\n        });\n\n        describe('check several controls', function() {\n            it.skip('should only one container for one zoom control', function() {\n                map.addControl(zoomControl);\n                expect(mapContainer.getElementsByClassName('dg-zoom').length).to.be(1);\n            });\n\n            it('should two containers for two zoom controls', function() {\n                var zoomAnotherControl = DG.control.zoom();\n                map.addControl(zoomAnotherControl);\n                expect(mapContainer.getElementsByClassName('dg-zoom').length).to.be(2);\n                zoomAnotherControl.remove();\n            });\n        });\n    });\n});\n"
  },
  {
    "path": "src/copyright.js",
    "content": "/*\n Maps api created at 2GIS. Build on Leaflet.\n (c) 2013-2016, 2GIS\n*/\n\n"
  },
  {
    "path": "src/doc/en/examples/base.md",
    "content": "## Basic usage\n\n{toc}\n\n### Description\n\nThe following are examples of the basic usage of the map. For more information about the work with the map use the\n<a href=\"/doc/maps/en/manual/dg-loading\">Connect API</a> and <a href=\"/doc/maps/en/manual/map\">Map</a> documentation sections.\n\n### Create map\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Map creation</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Create map on demand\n\nMap initialization on demand (useful when displaying the map in a popup window):\n<input id=\"create\" type=\"button\" value=\"Show map\" />\n<div id=\"mapBlock\"></div>\n<script>\n    var createButton = document.getElementById('create');\n\n    createButton.onclick = function() {\n        var container = document.createElement('div'),\n            mapBlock = document.getElementById('mapBlock');\n\n        container.id = 'map1';\n        container.style.width = '100%';\n        container.style.height = '400px';\n        mapBlock.appendChild(container);\n\n        DG.then(function(){\n            DG.map('map1', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n        });\n\n        createButton.onclick = null;\n    }\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Create map on demand</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?lazy=true\"></script>\n        </head>\n        <body>\n            <input id=\"create\" type=\"button\" value=\"Display map\" />\n            <div id=\"mapBlock\"></div>\n            <script>\n                var createButton = document.getElementById('create');\n\n                createButton.onclick = function() {\n                    var container = document.createElement('div'),\n                        mapBlock = document.getElementById('mapBlock');\n\n                    container.id = 'map';\n                    container.style.width = '100%';\n                    container.style.height = '400px';\n                    mapBlock.appendChild(container);\n\n                    DG.then(function(){\n                        DG.map('map', {\n                            center: [54.98, 82.89],\n                            zoom: 13\n                        });\n                    });\n                }\n            </script>\n        </body>\n    </html>\n\n### The use of connection options\n\nThe following is an example of calling the map with the following set of options: <code>pkg=basic</code>, <code>skin=light</code>.\nAs the result we get a build with basic functionality in the light theme. All options can be viewed in the\n<a href=\"/doc/maps/en/manual/dg-loading#connectionoptions\">Connection Options</a> section.\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Use of connection options</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=basic&skin=light\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Change map size\n\nWhen you click the button, the size of the container changes and the map adjusts to the new size:\n<input id=\"changeSize\" type=\"button\" value=\"Change size\" />\n<div id=\"map3\" style=\"width: 100%; height: 200px;\"></div>\n<script>\n    var changeSizeButton = document.getElementById('changeSize');\n\n    DG.then(function() {\n        var map,\n            enabled = false;\n\n        map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 15,\n            animate: true\n        });\n\n        changeSizeButton.onclick = function() {\n            var mapDiv = document.getElementById('map3');\n            mapDiv.style.height = (enabled ? '200' : '400') + 'px';\n            enabled = !enabled;\n            map.invalidateSize();\n        }\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Change map size</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"changeSize\" type=\"button\" value=\"Change size\" />\n            <div id=\"map\" style=\"width: 100%; height: 200px;\"></div>\n            <script>\n                var changeSizeButton = document.getElementById('changeSize');\n\n                DG.then(function() {\n                    var map,\n                        enabled = false;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15,\n                        animate: true\n                    });\n\n                    changeSizeButton.onclick = function() {\n                        var mapDiv = document.getElementById('map');\n                        mapDiv.style.height = (enabled ? '200' : '400') + 'px';\n                        // map update\n                        map.invalidateSize();\n                    }\n                });\n            </script>\n        </body>\n    </html>\n\n### Disabling interaction options\n\nExample of static map display:\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 13,\n            dragging : false,\n            touchZoom: false,\n            scrollWheelZoom: false,\n            doubleClickZoom: false,\n            boxZoom: false,\n            geoclicker: false,\n            zoomControl: false,\n            fullscreenControl: false\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Disabling interaction options</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13,\n                        dragging : false,\n                        touchZoom: false,\n                        scrollWheelZoom: false,\n                        doubleClickZoom: false,\n                        boxZoom: false,\n                        geoclicker: false,\n                        zoomControl: false,\n                        fullscreenControl: false\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Determining the user's location\n\nAn example of determining the user's geographic location:\n\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map;\n\n        map = DG.map('map5', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        map.locate({setView: true, watch: true})\n            .on('locationfound', function(e) {\n                DG.marker([e.latitude, e.longitude]).addTo(map);\n            })\n            .on('locationerror', function(e) {\n                DG.popup()\n                  .setLatLng(map.getCenter())\n                  .setContent('Location access denied')\n                  .openOn(map);\n            });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Determination of user's location</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    map.locate({setView: true, watch: true})\n                        .on('locationfound', function(e) {\n                            DG.marker([e.latitude, e.longitude]).addTo(map);\n                        })\n                        .on('locationerror', function(e) {\n                            DG.popup()\n                              .setLatLng(map.getCenter())\n                              .setContent('Location access denied')\n                              .openOn(map);\n                        });\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/bounds.md",
    "content": "## Work with map bounds\n\n{toc}\n\n### Description\n\nThe following are examples of limitations of map boundaries and zoom levels. For more information about the work with\nthe map, see the <a href=\"/doc/maps/en/manual/map\">Map</a> documentation section.\n\n### Limit of boundaries and scale\n\nThe restriction of the viewable area by boundaries of Novosibirsk, as well as zoom levels ranging from 10 to 15:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 10,\n            maxBounds: [\n                [54.8220, 82.4304],\n                [55.1372, 83.3505]\n            ],\n            minZoom: 10,\n            maxZoom: 15\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Limitation of boarders and scale</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 10,\n                        maxBounds: [\n                            [54.8220, 82.4304],\n                            [55.1372, 83.3505]\n                        ],\n                        minZoom: 10,\n                        maxZoom: 15\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n<!--\n### Map with a panel\n\n<style>\n    #container {\n        height:400px;\n        position: relative;\n    }\n    #content {\n        position: absolute;\n        background:#000;\n        background:rgba(51,51,51,.9);\n        width:200px;\n        height: 400px;\n        z-index: 1000;\n    }\n</style>\n<div id='container'>\n    <div id='content'></div>\n    <div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n</div>\n<script>\n    DG.then(function() {\n        var map;\n        map = DG.map('map1', {\n            center: [55.753559, 37.609218],\n            zoom: 10,\n            zoomControl: false,\n            fullscreenControl: false\n        });\n        DG.control.zoom({position: 'topright'}).addTo(map);\n        map.fitBounds(map.getBounds(), {\n            paddingTopLeft: [200, 0]\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Map with a left panel</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <style>\n                #container {\n                    height:400px;\n                    position: relative;\n                }\n                #content {\n                    position: absolute;\n                    background:#000;\n                    background:rgba(51,51,51,.9);\n                    width:200px;\n                    height: 400px;\n                    z-index: 1000;\n                }\n            </style>\n        </head>\n        <body>\n            <div id='container'>\n                <div id='content'></div>\n                <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            </div>\n            <script>\n                DG.then(function() {\n                    var map;\n                    map = DG.map('map', {\n                        center: [55.753559, 37.609218],\n                        zoom: 10,\n                        zoomControl: false,\n                        fullscreenControl: false\n                    });\n                    DG.control.zoom({position: 'topright'}).addTo(map);\n                    map.fitBounds(map.getBounds(), {\n                        paddingTopLeft: [200, 0]\n                    });\n                });\n            </script>\n        </body>\n    </html>\n-->\n"
  },
  {
    "path": "src/doc/en/examples/controls.md",
    "content": "## Control elements\n\n{toc}\n\n### Description\n\nThe following are examples of adding, placing, and working with control elements. For more information about the work\nwith control elements use the <a href=\"/doc/maps/en/manual/controls\">Controls</a> section of documentation.\n\n### Hide the default control elements\n\nIf you need to obtain a \"clear\" map, with no extra control elements, then the following example will help you:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13,\n            fullscreenControl: false,\n            zoomControl: false\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Hide control elements by default</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### The display of control elements in different parts of the map\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.control.location({position: 'bottomright'}).addTo(map);\n        DG.control.scale().addTo(map);\n        DG.control.ruler({position: 'bottomleft'}).addTo(map);\n        DG.control.traffic().addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Dislay of control elements in different parts of the map</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.control.location({position: 'bottomright'}).addTo(map);\n                    DG.control.scale().addTo(map);\n                    DG.control.ruler({position: 'bottomleft'}).addTo(map);\n                    DG.control.traffic().addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/events.md",
    "content": "## Processing of events\n\n{toc}\n\n### Description\n\nThe following are examples of working with events. For more information go to the\n<a href=\"/doc/maps/en/manual/base-classes#dgevented\">DG.Evented</a> and the\n<a href=\"/doc/maps/en/manual/base-classes#events\">Events</a> sections of documentation.\n\n### Subscribe to events\n\nSample subscriptions to various events (click on the marker map, geometry):\n\nYou clicked on: <span id=\"clicked_element\">nowhere</span>\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            clickedElement = document.getElementById('clicked_element'),\n            coords = [\n                [54.99, 82.88],\n                [54.985, 82.94],\n                [54.984, 82.925],\n                [54.981, 82.928]\n            ];\n\n        map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        map.on('click', function(e) {\n            clickedElement.innerHTML = 'map, coorinates ' + e.latlng.lat + ', ' + e.latlng.lng;\n        });\n\n        DG.marker([54.98, 82.89])\n            .on('click', function() {\n                clickedElement.innerHTML = 'marker';\n            })\n            .addTo(map);\n\n        DG.polygon(coords)\n            .on('click', function() {\n                clickedElement.innerHTML = 'polygon';\n            })\n            .addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Subscribe to events</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            You clicked on: <span id=\"clicked_element\">nowhere</span>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        clickedElement = document.getElementById('clicked_element'),\n                        coords = [\n                            [54.99, 82.88],\n                            [54.985, 82.94],\n                            [54.984, 82.925],\n                            [54.981, 82.928]\n                        ];\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    map.on('click', function(e) {\n                        clickedElement.innerHTML = 'map, coorinates ' + e.latlng.lat + ', ' + e.latlng.lng;\n                    });\n\n                    DG.marker([54.98, 82.89])\n                        .on('click', function() {\n                            clickedElement.innerHTML = 'marker';\n                        })\n                        .addTo(map);\n\n                    DG.polygon(coords)\n                        .on('click', function() {\n                            clickedElement.innerHTML = 'polygon';\n                        })\n                        .addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Subscribe to changes of 2GIS project\n\nIf you change the <a href=\"/doc/maps/en/manual/map#map-projectdetector\">project</a> the boundaries of the current one are highlighted:\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map, currentProjectBound;\n\n        map = DG.map('map1', {\n            center: DG.latLng(54.98, 82.89),\n            zoom: 9\n        });\n\n        // subscribe to the changes of the current 2GIS project\n        map.on('projectchange', function(e) {\n            var bounds = e.getProject().bound;\n            currentProjectBound = DG.geoJSON(bounds, {\n                color:\"#f03\",\n                weight:1\n            }).addTo(map);\n        });\n\n        // subscribe to the event of leaving a 2GIS proejct\n        map.on('projectleave', function(e) {\n            if (currentProjectBound) {\n                map.removeLayer(currentProjectBound);\n            }\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Subscribe to changes of 2GIS project</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map, currentProjectBound;\n\n                    map = DG.map('map', {\n                        center: DG.latLng(54.98, 82.89),\n                        zoom: 9\n                    });\n\n                    // subscribe to the changes of the current 2GIS project\n                    map.on('projectchange', function(e) {\n                        var bounds = e.getProject().bound;\n                        currentProjectBound = DG.geoJSON(bounds, {\n                            color:\"#f03\",\n                            weight:1\n                        }).addTo(map);\n                    });\n\n                    // subscribe to the event of leaving a 2GIS project\n                    map.on('projectleave', function(e) {\n                        if (currentProjectBound) {\n                            map.removeLayer(currentProjectBound);\n                        }\n                    });\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/external-modules.md",
    "content": "## External modules\n\n{toc}\n\n### Description\n\nThe following are examples of connection and usage of external modules. For more information go to the\n<a href=\"/doc/maps/en/manual/dg-external-modules\">External Modules</a> section of documentation.\n\n### Clusterer\n\nExample of clusterer enabling. Clusterer is often used to display big amount of markers. The module code and its documentation\nis available on <a href=\"https://github.com/Leaflet/Leaflet.markercluster\" target=\"_blank\">GitHub repository</a> of the author.\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css\" />\n<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css\" />\n<script src=\"https://maps.api.2gis.ru/2.0/cluster_realworld.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        // module code loading\n        return DG.plugin('https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js');\n    }).then(function() {\n        map = DG.map('map', {\n            center: DG.latLng(54.92, 82.82),\n            zoom: 9\n        });\n\n        var markers = DG.markerClusterGroup();\n\n        // processing of coordinates for installation of markers\n        for (var i = 0; i < addressPoints.length; i++) {\n            var a = addressPoints[i];\n            var title = a[2];\n            var marker = DG.marker([a[0], a[1]], { title: title });\n            marker.bindPopup(title);\n            markers.addLayer(marker);\n        }\n\n        map.addLayer(markers);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Clusterer</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css\" />\n            <link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css\" />\n            <script src=\"https://maps.api.2gis.ru/2.0/cluster_realworld.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    // module code loading\n                    return DG.plugin('https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js');\n                }).then(function() {\n                    map = DG.map('map', {\n                        center: DG.latLng(54.92, 82.82),\n                        zoom: 9\n                    });\n\n                    var markers = DG.markerClusterGroup();\n\n                    // processing of coordinates for installation of markers\n                    for (var i = 0; i < addressPoints.length; i++) {\n                        var a = addressPoints[i];\n                        var title = a[2];\n                        var marker = DG.marker([a[0], a[1]], { title: title });\n                        marker.bindPopup(title);\n                        markers.addLayer(marker);\n                    }\n\n                    map.addLayer(markers);\n                });\n            </script>\n        </body>\n    </html>\n\n\n### Heat map\n\nExample of the heat map enabling. The heat map allows you to visualize the quantitative data depending on\na geographical region. The color intensity for each region depends on the values that correspond to it.\n\n<script src=\"https://maps.api.2gis.ru/2.0/heat_realworld.js\"></script>\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        // Module code loading\n        return DG.plugin('https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js');\n    }).then(function() {\n        map = DG.map('map1', {\n            center: DG.latLng(54.89, 82.45),\n            zoom: 10\n        });\n\n        DG.heatLayer(addressPoints1).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Heat map</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <script src=\"https://maps.api.2gis.ru/2.0/heat_realworld.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    // Module code loading\n                    return DG.plugin('https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js');\n                }).then(function() {\n                    map = DG.map('map', {\n                        center: DG.latLng(54.89, 82.45),\n                        zoom: 10\n                    });\n\n                    DG.heatLayer(addressPoints1).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/geojson.md",
    "content": "## Work with GeoJSON\n\n{toc}\n\n### Description\n\nThe following is an example of working with GeoJSON. For more information go to the\n<a href=\"/doc/maps/en/manual/other-layers#dggeojson\">GeoJSON</a> section of documentation.\n\n### Example of usage\n\nDisplay of objects described in the GeoJSON format:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map', {\n            center: [55.042136, 82.91699],\n            zoom: 16\n        });\n\n        var data = [\n            {\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"info\": \"Я маркер\"\n                },\n                \"geometry\": {\n                    \"type\": \"Point\",\n                    \"coordinates\": [82.91799, 55.043136]\n                }\n            },\n            {\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"info\": \"Я полигон\"\n                },\n                \"geometry\": {\n                    \"type\": \"Polygon\",\n                    \"coordinates\": [\n                        [\n                            [82.91699, 55.042136],\n                            [82.917522, 55.040187],\n                            [82.918063, 55.040235],\n                            [82.917540, 55.042184],\n                            [82.91699, 55.042136]\n                        ]\n                    ]\n                }\n            }\n        ];\n\n        DG.geoJson(data, {\n            onEachFeature: function (feature, layer) {\n                layer.bindPopup(feature.properties.info);\n            }\n        }).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>GeoJSON</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [55.042136, 82.91699],\n                        zoom: 16\n                    });\n\n                    var data = [\n                        {\n                            \"type\": \"Feature\",\n                            \"properties\": {\n                                \"info\": \"I am a marker\"\n                            },\n                            \"geometry\": {\n                                \"type\": \"Point\",\n                                \"coordinates\": [82.91799, 55.043136]\n                            }\n                        },\n                        {\n                            \"type\": \"Feature\",\n                            \"properties\": {\n                                \"info\": \"I am a polyline\"\n                            },\n                            \"geometry\": {\n                                \"type\": \"Polygon\",\n                                \"coordinates\": [\n                                    [\n                                        [82.91699, 55.042136],\n                                        [82.917522, 55.040187],\n                                        [82.918063, 55.040235],\n                                        [82.917540, 55.042184],\n                                        [82.91699, 55.042136]\n                                    ]\n                                ]\n                            }\n                        }\n                    ];\n\n                    DG.geoJson(data, {\n                        onEachFeature: function (feature, layer) {\n                            layer.bindPopup(feature.properties.info);\n                        }\n                    }).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/markers.md",
    "content": "## Work with markers\n\n{toc}\n\n### Description\n\nThe following are examples of usage of markers. A marker can be added to the map using the <code>addTo()</code> method,\nbut if you are planning to work with a group of markers, we recommend you to use <code>FeatureGroup</code>\n(see the Processing of events of markers group, and Multiple markers display and adjustment of boundaries sections).\nFor more information about markers, go to the <a href=\"/doc/maps/en/manual/markers\">Markers</a> section of documentation.\n\n### A marker with a popup\n\nA marker, clicking on which you open a popup with the information:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function () {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89]).addTo(map).bindPopup('I am a popup!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>A marker with a popup</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('I am a popup!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Draggable marker\n\nThe marker, which users can drag and drop:\n\nMarker coordinates: <div id=\"location\">54.981, 82.891</div>\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script type=\"text/javascript\">\n    var locationInfo = document.getElementById('location');\n    DG.then(function () {\n        var map,\n            marker;\n\n        map = DG.map('map1', {\n            center: [54.981, 82.891],\n            zoom: 15\n        });\n\n        marker = DG.marker([54.981, 82.891], {\n            draggable: true\n        }).addTo(map);\n\n        marker.on('drag', function(e) {\n            var lat = e.target._latlng.lat.toFixed(3),\n                lng = e.target._latlng.lng.toFixed(3);\n\n            locationInfo.innerHTML = lat + ', ' + lng;\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Draggable marker</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            Marker coordinates: <div id=\"location\">LatLng(54.98, 82.89)</div>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script type=\"text/javascript\">\n                var locationInfo = document.getElementById('location');\n\n                DG.then(function () {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.981, 82.891],\n                        zoom: 15\n                    });\n\n                    marker = DG.marker([54.981, 82.891], {\n                        draggable: true\n                    }).addTo(map);\n\n                    marker.on('drag', function(e) {\n                        var lat = e.target._latlng.lat.toFixed(3),\n                            lng = e.target._latlng.lng.toFixed(3);\n\n                        locationInfo.innerHTML = lat + ', ' + lng;\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### A marker with a custom icon\n\nYou can select a custom icon or a simple div element for the marker instead of an image:\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            myIcon,\n            myDivIcon;\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        myIcon = DG.icon({\n            iconUrl: 'https://maps.api.2gis.ru/2.0/example_logo.png',\n            iconSize: [48, 48]\n        });\n        DG.marker([54.98, 82.89], {\n            icon: myIcon\n        }).addTo(map);\n\n        myDivIcon = DG.divIcon({\n            iconSize: [70, 20],\n            html: '<b style=\"color:blue;\">HTML-код</b>'\n        });\n        DG.marker([54.98, 82.87], {\n            icon: myDivIcon\n        }).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>A marker with a custom icon</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        myIcon,\n                        myDivIcon;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    myIcon = DG.icon({\n                        iconUrl: 'https://maps.api.2gis.ru/2.0/example_logo.png',\n                        iconSize: [48, 48]\n                    });\n                    DG.marker([54.98, 82.89], {\n                        icon: myIcon\n                    }).addTo(map);\n\n                    myDivIcon = DG.divIcon({\n                        iconSize: [70, 20],\n                        html: '<b style=\"color:blue;\">HTML-код</b>'\n                    });\n                    DG.marker([54.98, 82.87], {\n                        icon: myDivIcon\n                    }).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Open a marker programmatically\n\nIt is possible to open a popup on demand. For example, by clicking on a link or button:\n\n<button id='open-popup'>Open popup</button>\n<div id=\"map3\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var openPopupBtn = document.getElementById('open-popup');\n\n    DG.then(function() {\n        var map,\n            marker;\n\n        map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        marker = DG.marker([54.98, 82.89]).addTo(map);\n        marker.bindPopup('I am a popup!');\n\n        openPopupBtn.onclick = function() {\n            marker.openPopup();\n        }\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Open a marker programmatically</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <button id='open-popup'>Open popup</button>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var openPopupBtn = document.getElementById('open-popup');\n\n                DG.then(function() {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    marker = DG.marker([54.98, 82.89]).addTo(map);\n                    marker.bindPopup('I am a popup!');\n\n                    openPopupBtn.onclick = function() {\n                        marker.openPopup();\n                    }\n                });\n            </script>\n        </body>\n    </html>\n\n### Marker with a tip\n\nThe marker has two kinds of tips: a regular and a static ones. Both options are considered in the following example:\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89])\n            .addTo(map)\n            .bindLabel('I am a static tip!', {\n                static: true\n            });\n\n        DG.marker([54.98, 82.88])\n            .addTo(map)\n            .bindLabel('I am a simple tip!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Marker with a tip</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89])\n                        .addTo(map)\n                        .bindLabel('I am a static tip!', {\n                            static: true\n                        });\n\n                    DG.marker([54.98, 82.88])\n                        .addTo(map)\n                        .bindLabel('I am a simple tip!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Processing events of the group of markers\n\nWhen clicking on the marker, the map will be centered in its position:\n\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            marker1,\n            marker2,\n            marker3,\n            group;\n\n        map = DG.map('map5', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        marker1 = DG.marker([54.96, 82.889]).addTo(map);\n        marker2 = DG.marker([54.98, 82.893]).addTo(map);\n        marker3 = DG.marker([54.99, 82.896]).addTo(map);\n\n        group = DG.featureGroup([marker1, marker2, marker3]);\n        group.addTo(map);\n        group.on('click', function(e) {\n            map.setView([e.latlng.lat, e.latlng.lng]);\n        });\n    });\n</script>\n\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Processing of events of markers group</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        marker1,\n                        marker2,\n                        marker3,\n                        group;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    marker1 = DG.marker([54.96, 82.889]).addTo(map);\n                    marker2 = DG.marker([54.98, 82.893]).addTo(map);\n                    marker3 = DG.marker([54.99, 82.896]).addTo(map);\n\n                    group = DG.featureGroup([marker1, marker2, marker3]);\n                    group.addTo(map);\n                    group.on('click', function(e) {\n                        map.setView([e.latlng.lat, e.latlng.lng]);\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Animated movement of marker\n\nAn example of a marker that moves along a given trajectory:\n<div id=\"map6\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            marker;\n\n        map = DG.map('map6', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        marker = DG.marker([54.98, 82.89]).addTo(map);\n\n        var increment = 0.001;\n\n        function move() {\n            if (!map.getBounds().contains(marker.getLatLng())) {\n                increment *= -1;\n            }\n\n            var newLat = marker.getLatLng().lat + increment,\n                newLng = marker.getLatLng().lng + increment;\n\n            marker.setLatLng([newLat, newLng]);\n        }\n\n        setInterval(move, 60);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Animated marker movement</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    marker = DG.marker([54.98, 82.89]).addTo(map);\n\n                    var increment = 0.001;\n\n                    function move() {\n                        if (!map.getBounds().contains(marker.getLatLng())) {\n                            increment *= -1;\n                        }\n\n                        var newLat = marker.getLatLng().lat + increment,\n                            newLng = marker.getLatLng().lng + increment;\n\n                        marker.setLatLng([newLat, newLng]);\n                    }\n\n                    setInterval(move, 60);\n                });\n            </script>\n        </body>\n    </html>\n\n### Multiple markers display and adjustment of boundaries\n\nExample of display and hiding of groups of markers with automatic detection of map boundaries:\n\n<input id=\"show\" type=\"button\" value=\"Show markers\" /><input id=\"hide\" type=\"button\" value=\"Hide markers\" />\n<div id=\"map7\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            markers = DG.featureGroup(),\n            coordinates = [];\n\n        map = DG.map('map7', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        for (var i = 0; i < 100; i++) {\n            coordinates[0] = 54.98 + Math.random();\n            coordinates[1] = 82.89 + Math.random();\n            DG.marker(coordinates).addTo(markers);\n        }\n\n        document.getElementById('hide').onclick = hideMarkers;\n        document.getElementById('show').onclick = showMarkers;\n\n        function showMarkers() {\n            markers.addTo(map);\n            map.fitBounds(markers.getBounds());\n        };\n\n        function hideMarkers() {\n            markers.removeFrom(map);\n        };\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display/removal of several markers, fitBounds</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"hide\" type=\"button\" value=\"hide markers\" />\n            <input id=\"show\" type=\"button\" value=\"show markers\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n            DG.then(function() {\n                var map,\n                    markers = DG.featureGroup(),\n                    coordinates = [];\n\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 13\n                });\n\n                for (var i = 0; i < 100; i++) {\n                    coordinates[0] = 54.98 + Math.random();\n                    coordinates[1] = 82.89 + Math.random();\n                    DG.marker(coordinates).addTo(markers);\n                }\n\n                document.getElementById('hide').onclick = hideMarkers;\n                document.getElementById('show').onclick = showMarkers;\n\n                function showMarkers() {\n                    markers.addTo(map);\n                    map.fitBounds(markers.getBounds());\n                };\n\n                function hideMarkers() {\n                    markers.removeFrom(map);\n                };\n            });\n        </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/popups.md",
    "content": "## Work with popups\n\n{toc}\n\n### Description\n\nThe following are examples of usage of pop-ups.\nFor more information go to the <a href=\"/doc/maps/en/manual/popup\">Popups</a> section of documentation.\n\n### Open a popup by clicking on a marker\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function () {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89]).addTo(map).bindPopup('I am a popup!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Opens a popup when clicking on the marker</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('I am a popup!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Open a popup by default and on demand\n\n<input id=\"showPopup\" type=\"button\" value=\"Open popup\" />\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var showButton = document.getElementById('showPopup');\n\n    DG.then(function() {\n        var map,\n            myPopUp;\n\n        map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.popup([54.98, 82.89])\n            .setLatLng([54.98, 82.89])\n            .setContent('I am opened by default')\n            .openOn(map);\n\n        myPopUp = DG.popup()\n            .setLatLng([54.98, 82.89])\n            .setContent('I have been opened on demand and closed the previous popup!');\n\n        showButton.onclick = function() {myPopUp.openOn(map)};\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Open a popup by default and on demand</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"showPopup\" type=\"button\" value=\"Открыть попап\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var showButton = document.getElementById('showPopup');\n\n                DG.then(function() {\n                    var map,\n                        myPopUp;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.popup([54.98, 82.89])\n                        .setLatLng([54.98, 82.89])\n                        .setContent('I am opened by default')\n                        .openOn(map);\n\n                    myPopUp = DG.popup()\n                        .setLatLng([54.98, 82.89])\n                        .setContent('I have been opened on demand and closed the previous popup!');\n\n                    showButton.onclick = function() {myPopUp.openOn(map)};\n                });\n            </script>\n        </body>\n    </html>\n\n### Add several popups to the map\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            popups = DG.featureGroup(),\n            coordinates = [];\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        for (var i = 0; i < 10; i++) {\n            coordinates[0] = 54.98 - Math.random();\n            coordinates[1] = 82.89 + Math.random();\n            DG.popup()\n                .setLatLng(coordinates)\n                .setContent('I am popup №' + i)\n                .addTo(popups);\n        }\n\n        popups.addTo(map);\n        map.fitBounds(popups.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Add several popups to the map</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        popups = DG.featureGroup(),\n                        coordinates = [];\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    // create 10 popups in random places and add them to the group\n                    for (var i = 0; i < 10; i++) {\n                        coordinates[0] = 54.98 - Math.random();\n                        coordinates[1] = 82.89 + Math.random();\n                        DG.popup()\n                            .setLatLng(coordinates)\n                            .setContent('I am popup №' + i)\n                            .addTo(popups);\n                    }\n\n                    popups.addTo(map);\n\n                    // focus the scope on popups\n                    map.fitBounds(popups.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### The behavior of a popup with the sprawling parameter\n\n<div id=\"map3\" style=\"width: 300px; height: 150px;\"></div>\n<input style=\"width: 300px;\" type=\"button\" id=\"sprawling\" value=\"The popup with enabled sprawling parameter\" />\n<input style=\"width: 300px;\" type=\"button\" id=\"no-sprawling\" value=\"Popup without the sprawling parameter\" />\n<input style=\"width: 300px;\" type=\"button\" id=\"minWidth\" value=\"Popup with a minimum width of 320px\" />\n<script>\n    DG.then(function () {\n        var latLng = DG.latLng([54.98, 82.89]),\n            map = DG.map('map3', {\n                center: latLng,\n                zoom: 13,\n                fullscreenControl: false,\n                zoomControl: false\n            });\n\n        document.getElementById('sprawling').onclick = function () {\n            DG.popup({\n                maxWidth: 350,\n                sprawling: true\n            })\n            .setLatLng(latLng)\n            .setContent('I am a popup!')\n            .openOn(map);\n        };\n\n        document.getElementById('no-sprawling').onclick = function () {\n            DG.popup({\n                maxWidth: 350\n            })\n            .setLatLng(latLng)\n            .setContent('I am a popup!')\n            .openOn(map);\n        };\n\n        document.getElementById('minWidth').onclick = function () {\n            DG.popup({\n                maxWidth: 350,\n                minWidth: 320\n            })\n            .setLatLng(latLng)\n            .setContent('I am a popup!')\n            .openOn(map);\n        };\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Behaviour of the popup with the sprawling parameter</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 300px; height: 150px;\"></div>\n            <input style=\"width: 300px;\" type=\"button\" id=\"sprawling\" value=\"The popup with enabled sprawling parameter\" />\n            <input style=\"width: 300px;\" type=\"button\" id=\"no-sprawling\" value=\"Popup without the sprawling parameter\" />\n            <input style=\"width: 300px;\" type=\"button\" id=\"minWidth\" value=\"Popup with a minimum width of 320px\" />\n            <script>\n                DG.then(function () {\n                    var latLng = DG.latLng([54.98, 82.89]),\n                        map;\n\n                    // let's initialize the map with a width of 300 pixels\n                    map = DG.map('map', {\n                        center: latLng,\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false\n                    });\n\n                    // the popup with the enabled sprawling parameter\n                    // will strech to the boundaries of the map\n                    document.getElementById('sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            sprawling: true\n                        })\n                        .setLatLng(latLng)\n                        .setContent('I am a popup!')\n                        .openOn(map);\n                    };\n\n                    // the popup with no sprawling parameter\n                    // will adjust to the width of the content\n                    document.getElementById('no-sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350\n                        })\n                        .setLatLng(latLng)\n                        .setContent('I am a popup!')\n                        .openOn(map);\n                    };\n\n                    // the popup with a minimum width of  320px\n                    // will go outside the boundaries of the map\n                    document.getElementById('minWidth').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            minWidth: 320\n                        })\n                        .setLatLng(latLng)\n                        .setContent('I am a popup!')\n                        .openOn(map);\n                    };\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/vector-layers.md",
    "content": "## Work with vector layers\n\n{toc}\n\n### Description\n\nThe following are basic examples of usage of geometric objects. For more information about the work with vector layers\nuse the <a href=\"/doc/maps/en/manual/vector-layers\">Vector Layers</a> section of documentation.\n\n### Polyline display\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 500px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coordinates,\n            polyline;\n\n        map = DG.map('map', {\n            center: [55.036446, 82.897983],\n            zoom: 11\n        });\n\n        coordinates = [[55.069288, 82.991367], [55.069288, 82.816615], [55.011648, 82.902103], [54.944714, 82.903152], [54.928935, 82.850967], [54.928541, 82.976280], [54.944517, 82.916541], [55.011704, 82.916885], [55.056508, 82.973514], [55.056508, 82.835498], [55.056705, 82.973857], [55.069288, 82.991367], [55.069288, 82.941928], [55.097193, 82.959094], [55.046282, 82.919956], [55.045692, 82.904163], [55.036446, 82.897983], [55.029756, 82.907596], [55.018932, 82.903819], [55.029362, 82.914119], [55.030543, 82.927165], [55.037823, 82.933345], [55.045101, 82.925105], [55.069681, 82.941928]];\n\n        // create a polyline from an array of geographical points\n        polyline = DG.polyline(coordinates, {color: 'blue'}).addTo(map);\n\n        // adjust the center of the map and the scale to make the polyline visible\n        map.fitBounds(polyline.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Polyline display</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 500px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coordinates,\n                        polyline;\n\n                    map = DG.map('map', {\n                        center: [55.036446, 82.897983],\n                        zoom: 11\n                    });\n\n                    coordinates = [[55.069288, 82.991367], [55.069288, 82.816615], [55.011648, 82.902103], [54.944714, 82.903152], [54.928935, 82.850967], [54.928541, 82.976280], [54.944517, 82.916541], [55.011704, 82.916885], [55.056508, 82.973514], [55.056508, 82.835498], [55.056705, 82.973857], [55.069288, 82.991367], [55.069288, 82.941928], [55.097193, 82.959094], [55.046282, 82.919956], [55.045692, 82.904163], [55.036446, 82.897983], [55.029756, 82.907596], [55.018932, 82.903819], [55.029362, 82.914119], [55.030543, 82.927165], [55.037823, 82.933345], [55.045101, 82.925105], [55.069681, 82.941928]];\n\n                    // create a polyline from an array of geographical points\n                    polyline = DG.polyline(coordinates, {\n                        color: 'blue'\n                    }).addTo(map);\n\n                    // adjust the center of the map and the scale to make the polyline visible\n                    map.fitBounds(polyline.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Display rectangles\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coords1 = [[54.98, 82.87], [54.975, 82.91]],\n            coords2 = [[54.985, 82.87], [54.982, 82.91]],\n            coords3 = [[54.99, 82.87], [54.987, 82.91]],\n            rectangles = DG.featureGroup();\n\n        map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        // Add rectangles to the group\n        DG.rectangle(coords1, {color: \"blue\"}).addTo(rectangles);\n        DG.rectangle(coords2, {color: \"red\"}).addTo(rectangles);\n        DG.rectangle(coords3, {color: \"green\"}).addTo(rectangles);\n\n        // Add group to the map\n        rectangles.addTo(map);\n\n        // Adjust boundaries of the map\n        map.fitBounds(rectangles.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display of rectangles</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coords1 = [[54.98, 82.87], [54.975, 82.91]],\n                        coords2 = [[54.985, 82.87], [54.982, 82.91]],\n                        coords3 = [[54.99, 82.87], [54.987, 82.91]],\n                        rectangles = DG.featureGroup();\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    // Add rectangles to the group\n                    DG.rectangle(coords1, {color: \"blue\"}).addTo(rectangles);\n                    DG.rectangle(coords2, {color: \"red\"}).addTo(rectangles);\n                    DG.rectangle(coords3, {color: \"green\"}).addTo(rectangles);\n\n                    // Add group to the map\n                    rectangles.addTo(map);\n\n                    // Adjust boundaries of the map\n                    map.fitBounds(rectangles.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Display polygons\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coords1 = [\n                [54.98, 82.87],\n                [54.975, 82.91],\n                [54.974, 82.915],\n                [54.971, 82.918],\n                [54.970, 82.921]\n            ],\n            coords2 = [\n                [54.985, 82.875],\n                [54.98, 82.96],\n                [54.979, 82.92],\n                [54.976, 82.923]\n            ],\n            coords3 = [\n                [54.99, 82.88],\n                [54.985, 82.971],\n                [54.984, 82.925],\n                [54.981, 82.928],\n                [54.980, 82.931]\n            ],\n            polygons = DG.featureGroup();\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.polygon(coords1, {color: \"blue\"}).addTo(polygons);\n        DG.polygon(coords2, {color: \"red\"}).addTo(polygons);\n        DG.polygon(coords3, {color: \"green\"}).addTo(polygons);\n\n        polygons.addTo(map);\n        map.fitBounds(polygons.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display polygons</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coords1 = [\n                            [54.98, 82.87],\n                            [54.975, 82.91],\n                            [54.974, 82.915],\n                            [54.971, 82.918],\n                            [54.970, 82.921]\n                        ],\n                        coords2 = [\n                            [54.985, 82.875],\n                            [54.98, 82.96],\n                            [54.979, 82.92],\n                            [54.976, 82.923]\n                        ],\n                        coords3 = [\n                            [54.99, 82.88],\n                            [54.985, 82.971],\n                            [54.984, 82.925],\n                            [54.981, 82.928],\n                            [54.980, 82.931]\n                        ],\n                        polygons = DG.featureGroup();\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    // Add polygons to a group\n                    DG.polygon(coords1, {color: \"blue\"}).addTo(polygons);\n                    DG.polygon(coords2, {color: \"red\"}).addTo(polygons);\n                    DG.polygon(coords3, {color: \"green\"}).addTo(polygons);\n\n                    // Add a group to the map\n                    polygons.addTo(map);\n\n                    // Adjust the boundaries of the map\n                    map.fitBounds(polygons.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Display a circle and a round marker\n\n<div id=\"map3\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        DG.circle([54.98, 82.89], 200, {color: 'red'}).addTo(map);\n        DG.circleMarker([54.985, 82.89]).setRadius(100).addTo(map);\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display a circle and a round marker</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    DG.circle([54.98, 82.89], 200, {color: 'red'}).addTo(map);\n                    DG.circleMarker([54.985, 82.89]).setRadius(100).addTo(map);\n                })\n            </script>\n        </body>\n    </html>\n\n### Vector layers with tips and pop-ups\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        DG.circle([54.98, 82.87], 200, {color: 'red'})\n            .bindPopup('I am a circle')\n            .bindLabel('Click on the circle')\n            .addTo(map);\n\n        DG.circleMarker([54.985, 82.89])\n            .bindPopup('I am a circle marker')\n            .bindLabel('Click on a circle marker')\n            .setRadius(100)\n            .addTo(map);\n\n        DG.rectangle(\n            [[54.98, 82.87], [54.975, 82.91]],\n            {color: 'green'})\n            .bindPopup('I am a rectangle')\n            .bindLabel('Click on a rectangle')\n            .addTo(map);\n\n        DG.polygon(\n            [[54.985, 82.875], [54.98, 82.96], [54.979, 82.92]],\n            {color: 'yellow'})\n            .bindPopup('I am a polygon')\n            .bindLabel('Click on a polygon')\n            .addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Vector layers with tips and pop-ups</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    DG.circle([54.98, 82.87], 200, {color: 'red'})\n                        .bindPopup('I am a circle')\n                        .bindLabel('Click on the circle')\n                        .addTo(map);\n\n                    DG.circleMarker([54.985, 82.89])\n                        .bindPopup('I am a circle marker')\n                        .bindLabel('Click on a circle marker')\n                        .setRadius(100)\n                        .addTo(map);\n\n                    DG.rectangle(\n                        [[54.98, 82.87], [54.975, 82.91]],\n                        {color: 'green'})\n                        .bindPopup('I am a rectangle')\n                        .bindLabel('Click on a rectangle')\n                        .addTo(map);\n\n                    DG.polygon(\n                        [[54.985, 82.875], [54.98, 82.96], [54.979, 82.92]],\n                        {color: 'yellow'})\n                        .bindPopup('I am a polygon')\n                        .bindLabel('Click on a polygon')\n                        .addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Animation of the polyline rendering\n\n<input id=\"playAnimation\" type=\"button\" value=\"Start animation\" />\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var playAnimationButton = document.getElementById('playAnimation');\n\n    DG.then(function() {\n        var map = DG.map('map5', {\n            center: [54.98, 82.94],\n            zoom: 13\n        });\n\n        playAnimation.onclick = function() {\n            var polyline = DG.polyline([]).addTo(map),\n                counter = 0;\n\n            (function draw() {\n                polyline.addLatLng([54.98, 82.89 + counter / 10000]);\n\n                if (++counter < 1000) {\n                    window.setTimeout(draw, 10);\n                } else {\n                    counter = 0;\n                    draw();\n                };\n            })();\n        }\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Animation of the polyline rendering</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"playAnimation\" type=\"button\" value=\"Start animation\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var playAnimationButton = document.getElementById('playAnimation');\n\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.94],\n                        zoom: 13\n                    });\n\n                    playAnimation.onclick = function() {\n                        var polyline = DG.polyline([]).addTo(map),\n                            counter = 0;\n\n                        (function draw() {\n                            polyline.addLatLng([54.98, 82.89 + counter / 10000]);\n\n                            if (++counter < 1000) {\n                                window.setTimeout(draw, 10);\n                            } else {\n                                counter = 0;\n                                draw();\n                            };\n                        })();\n                    }\n                })\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/examples/wkt.md",
    "content": "## Work with WKT\n\n{toc}\n\n### Description\n\nThe following is an example of working with WKT.\nFor more information go to the <a href=\"/doc/maps/en/manual/dg-wkt\">WKT</a> section of documentation.\n\n### Display of simple vector layers\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coord1 = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))',\n            coord2 = 'LINESTRING(82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235)',\n            coord3 = 'POINT(82.914 55.042136)';\n\n        map = DG.map('map', {\n            center: [55.042136, 82.91699],\n            zoom: 16\n        });\n\n        DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n        DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n        DG.Wkt.geoJsonLayer(coord3).addTo(map);\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display of simple vector layers</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coord1 = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))',\n                        coord2 = 'LINESTRING(82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235)',\n                        coord3 = 'POINT(82.914 55.042136)';\n\n                    map = DG.map('map', {\n                        center: [55.042136, 82.91699],\n                        zoom: 16\n                    });\n\n                    DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord3).addTo(map);\n                })\n            </script>\n        </body>\n    </html>\n\n### Display of complex vector layers\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map1', {\n            center: [55.041836, 82.91699],\n            zoom: 16\n        });\n\n        DG.Wkt.geoJsonLayer('MULTIPOLYGON(((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136)), ((82.91599 55.041136, 82.916522 55.039187, 82.917063 55.039235, 82.916540 55.041184,82.91599 55.041136)))').addTo(map);\n        DG.Wkt.geoJsonLayer('MULTILINESTRING((82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235), (82.91899 55.044136, 82.919522 55.042187, 82.920063 55.042235))').addTo(map);\n        DG.Wkt.geoJsonLayer('MULTIPOINT(82.914 55.042136, 82.915 55.043136, 82.915 55.042136, 82.914 55.043136)').addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Display of compound vector layers</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coord1 = 'MULTIPOLYGON(((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136)), ((82.91599 55.041136, 82.916522 55.039187, 82.917063 55.039235, 82.916540 55.041184,82.91599 55.041136)))',\n                        coord2 = 'MULTILINESTRING((82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235), (82.91899 55.044136, 82.919522 55.042187, 82.920063 55.042235))',\n                        coord3 = 'MULTIPOINT(82.914 55.042136, 82.915 55.043136, 82.915 55.042136, 82.914 55.043136)';\n\n                    map = DG.map('map', {\n                        center: [55.041836, 82.91699],\n                        zoom: 16\n                    });\n\n                    DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord3).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/en/manual/base-classes.md",
    "content": "## Base Classes\n\n{toc}\n\n### DG.Class\n\n<code>DG.Class</code> powers the OOP facilities of maps API and is used to create almost all of the classes documented here.\n\nIn addition to implementing a simple classical inheritance model, it introduces several special properties for\nconvenient code organization — <code>options</code>, <code>includes</code> and <code>statics</code>.\n\n    var MyClass = DG.Class.extend({\n        initialize: function (greeter) {\n            this.greeter = greeter;\n            // class constructor\n        },\n\n        greet: function (name) {\n            alert(this.greeter + ', ' + name)\n        }\n    });\n\n    // create instance of MyClass, passing \"Hello\" to the constructor\n    var a = new MyClass(\"Hello\");\n\n    // call greet method, alerting \"Hello, World\"\n    a.greet(\"World\");\n\n#### Class Factories\n\nYou may have noticed that maps API objects are created without using the <code>new</code> keyword. This is\nachieved by complementing each class with a lowercase factory method:\n\n    new DG.Map('map');  // becomes:\n    DG.map('map');\n\nThe factories are implemented very easily, and you can do this for your own classes:\n\n    DG.map = function (id, options) {\n        return new DG.Map(id, options);\n    };\n\n#### Inheritance\n\nYou use DG.Class.extend to define new classes, but you can use the same method on any class to inherit from it:\n\n    var MyChildClass = MyClass.extend({\n        // ... new properties and methods\n    });\n\nThis will create a class that inherits all methods and properties of the parent class (through a proper\nprototype chain), adding or overriding the ones you pass to extend. It will also properly react to <code>instanceof</code>:\n\n    var a = new MyChildClass();\n    a instanceof MyChildClass; // true\n    a instanceof MyClass; // true\n\nYou can call parent methods (including constructor) from corresponding child ones (as you do with super\ncalls in other languages) by accessing parent class prototype and using JavaScript's <code>call</code> or <code>apply</code>:\n\n    var MyChildClass = MyClass.extend({\n        initialize: function () {\n            MyClass.prototype.initialize.call(\"Yo\");\n        },\n\n        greet: function (name) {\n            MyClass.prototype.greet.call(this, 'bro ' + name + '!');\n        }\n    });\n\n    var a = new MyChildClass();\n    a.greet('Jason'); // alerts \"Yo, bro Jason!\"\n\n#### Options\n\n<code>options</code> is a special property that unlike other objects that you pass to <code>extend</code>\nwill be merged with the parent one instead of overriding it completely, which makes managing configuration\nof objects and default values convenient:\n\n    var MyClass = DG.Class.extend({\n        options: {\n            myOption1: 'foo',\n            myOption2: 'bar'\n        }\n    });\n\n    var MyChildClass = DG.Class.extend({\n        options: {\n            myOption1: 'baz',\n            myOption3: 5\n        }\n    });\n\n    var a = new MyChildClass();\n    a.options.myOption1; // 'baz'\n    a.options.myOption2; // 'bar'\n    a.options.myOption3; // 5\n\nThere&#39;s also <a href=\"/doc/maps/en/manual/utils#util-setoptions\"><code>DG.Util.setOptions</code></a>,\na method for conveniently merging options passed to constructor with the defaults defines in the class:\n\n    var MyClass = DG.Class.extend({\n        options: {\n            foo: 'bar',\n            bla: 5\n        },\n\n        initialize: function (options) {\n            DG.Util.setOptions(this, options);\n            ...\n        }\n    });\n\n    var a = new MyClass({bla: 10});\n    a.options; // {foo: 'bar', bla: 10}\n\n#### Includes\n\n<code>includes</code> is a special class property that merges all specified objects into the class\n(such objects are called mixins).\n\n     var MyMixin = {\n        foo: function () { ... },\n        bar: 5\n    };\n\n    var MyClass = DG.Class.extend({\n        includes: MyMixin\n    });\n\n    var a = new MyClass();\n    a.foo();\n\nYou can also do such includes in runtime with the <code>include</code> method:\n\n    MyClass.include(MyMixin);\n\n#### Statics\n\n<code>statics</code> is just a convenience property that injects specified object properties as the static\nproperties of the class, useful for defining constants:\n\n    var MyClass = DG.Class.extend({\n        statics: {\n            FOO: 'bar',\n            BLA: 5\n        }\n    });\n\n    MyClass.FOO; // 'bar'\n\n#### Constructor hooks\n\nIf you&#39;re a plugin developer, you often need to add additional initialization code to existing\nclasses (e.g. editing hooks for <a href=\"/doc/maps/en/manual/geometries#polyline\"><code>DG.Polyline</code></a>).\nMaps API comes with a way to do it easily using the <code>addInitHook</code> method:\n\n    MyClass.addInitHook(function () {\n        // ... do something in constructor additionally\n        // e.g. add event listeners, set custom properties etc.\n    });\n\nYou can also use the following shortcut when you just need to make one additional method call:\n\n    MyClass.addInitHook('methodName', arg1, arg2, …);\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"class-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;Object&gt; <i>props</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td><a href=\"#inheritance\">Extends the current class</a> given the properties to be included.\n                Returns a Javascript function that is a class constructor (to be called with <code>new</code>).</td>\n        </tr>\n        <tr id=\"class-include\">\n            <td><code><b>include</b>(\n                <nobr>&lt;Object&gt; <i>properties</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td><a href=\"#includes\">Includes a mixin</a> into the current class.</td>\n        </tr>\n        <tr id=\"class-mergeoptions\">\n            <td><code><b>mergeOptions</b>(\n                <nobr>&lt;Object&gt; <i>options</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td><a href=\"#options\">Merges <code>options</code></a> into the defaults of the class.</td>\n        </tr>\n        <tr id=\"class-addinithook\">\n            <td><code><b>addInitHook</b>(\n                <nobr>&lt;Function&gt; <i>fn</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td>Adds a <a href=\"#constructor-hooks\">constructor hook</a> to the class.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Evented\n\nA set of methods shared between event-powered classes (like <a href=\"/doc/maps/en/manual/map#dgmap\"><code>Map</code></a>\nand <a href=\"/doc/maps/en/manual/markers#dgmarker\"><code>Marker</code></a>). Generally, events allow you\nto execute some function when something happens with an object (e.g. the user clicks on the map, causing\nthe map to fire <code>&#39;click&#39;</code> event).\n\n    map.on('click', function(e) {\n        alert(e.latlng);\n    } );\n\nMaps API deals with event listeners by reference, so if you want to add a listener and then remove it,\ndefine it as a function:\n\n    function onClick(e) { ... }\n    map.on('click', onClick);\n    map.off('click', onClick);\n\n#### Methods\n\n<table id=\"dgevented-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"evented-on\">\n            <td><code><b>on</b>(\n                <nobr>&lt;String&gt; <i>type</i>,\n                <nobr>&lt;Function&gt; <i>fn</i>,\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds a listener function (<code>fn</code>) to a particular event type of the object.\n                You can optionally specify the context of the listener (object the this keyword will point to).\n                You can also pass several space-separated types (e.g. <code>&#39;click dblclick&#39;</code>).</td>\n        </tr>\n        <tr>\n            <td><code><b>on</b>(\n                <nobr>&lt;Object&gt; <i>eventMap</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds a set of type/listener pairs, e.g. <code>{click: onClick, mousemove: onMouseMove}</code></td>\n        </tr>\n        <tr id=\"evented-off\">\n            <td><code><b>off</b>(\n                <nobr>&lt;String&gt; <i>type</i>,\n                <nobr>&lt;Function&gt; <i>fn?</i>,\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes a previously added listener function. If no function is specified, it will remove all\n                the listeners of that particular event from the object. Note that if you passed a custom context\n                to <code>on</code>, you must pass the same context to <code>off</code> in order to remove\n                the listener.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>(\n                <nobr>&lt;Object&gt; <i>eventMap</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes a set of type/listener pairs.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Removes all listeners to all events on the object.</td>\n        </tr>\n        <tr id=\"evented-fire\">\n            <td><code><b>fire</b>(\n                <nobr>&lt;String&gt; <i>type</i>,\n                <nobr>&lt;Object&gt; <i>data?</i>,\n                <nobr>&lt;Boolean&gt; <i>propagate?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Fires an event of the specified type. You can optionally provide an data object — the first\n                argument of the listener function will contain its properties. The event might can optionally\n                be propagated to event parents.</td>\n        </tr>\n        <tr id=\"evented-listens\">\n            <td><code><b>listens</b>(\n                <nobr>&lt;String&gt; <i>type</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if a particular event type has any listeners attached to it.</td>\n        </tr>\n        <tr id=\"evented-once\">\n            <td><code><b>once</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Behaves as <a href=\"#evented-on\"><code>on(…)</code></a>, except the listener will only get\n                fired once and then removed.</td>\n        </tr>\n        <tr id=\"evented-addeventparent\">\n            <td><code><b>addEventParent</b>(\n                <nobr>&lt;<a href=\"#dgevented\">Evented</a>&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds an event parent - an <a href=\"#dgevented\"><code>Evented</code></a> that will receive\n                propagated events</td>\n        </tr>\n        <tr id=\"evented-removeeventparent\">\n            <td><code><b>removeEventParent</b>(\n                <nobr>&lt;<a href=\"#dgevented\">Evented</a>&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes an event parent, so it will stop receiving propagated events</td>\n        </tr>\n        <tr id=\"evented-addeventlistener\">\n            <td><code><b>addEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Alias to <a href=\"#evented-on\"><code>on(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-removeeventlistener\">\n            <td><code><b>removeEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Alias to <a href=\"#evented-off\"><code>off(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-clearalleventlisteners\">\n            <td><code><b>clearAllEventListeners</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Alias to <a href=\"#evented-off\"><code>off()</code></a></td>\n        </tr>\n        <tr id=\"evented-addonetimeeventlistener\">\n            <td><code><b>addOneTimeEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Alias to <a href=\"#evented-once\"><code>once(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-fireevent\">\n            <td><code><b>fireEvent</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Alias to <a href=\"#evented-fire\"><code>fire(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-haseventlisteners\">\n            <td><code><b>hasEventListeners</b>(<i>…</i>)</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Alias to <a href=\"#evented-listens\"><code>listens(…)</code></a></td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Layer\n\nA set of methods from the Layer base class that all maps API layers use. Inherits all methods,\noptions and events from <a href=\"#dgevented\"><code>DG.Evented</code></a>.\n\n    var layer = DG.Marker(latlng).addTo(map);\n    layer.addTo(map);\n    layer.remove();\n\n#### Options\n\n<table id=\"dglayer-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String</code></td>\n            <td><code>&#x27;overlayPane&#x27;</code></td>\n            <td>By default the layer will be added to the map&#39;s <a href=\"/doc/maps/en/manual/map#map-overlaypane\">overlay pane</a>.\n                Overriding this option will cause the layer to be placed on another pane by default.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\n<table id=\"dglayer-events\">\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"layer-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"#event-objects\">Event</a></code></td>\n            <td>Fired after the layer is added to a map</td>\n        </tr>\n        <tr id=\"layer-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"#event-objects\">Event</a></code></td>\n            <td>Fired after the layer is removed from a map</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Popup events\n\n<table id=\"dglayer-popup-events\">\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is opened</td>\n        </tr>\n        <tr id=\"layer-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is closed</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\nClasses extending <a href=\"#dglayer\"><code>DG.Layer</code></a> will inherit the following methods:\n\n<table id=\"dglayer-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-addto\">\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i>)</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds the layer to the given map</td>\n        </tr>\n        <tr id=\"layer-remove\">\n            <td><code><b>remove</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the layer from the map it is currently active on.</td>\n        </tr>\n        <tr id=\"layer-removefrom\">\n            <td><code><b>removeFrom</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the layer from the given map</td>\n        </tr>\n        <tr id=\"layer-getpane\">\n            <td><code><b>getPane</b>(\n                <nobr>&lt;String&gt; <i>name?</i> )</nobr>\n            </code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Returns the <code>HTMLElement</code> representing the named pane on the map.\n                If <code>name</code> is omitted, returns the pane for this layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Popup methods\n\nAll layers share a set of methods convenient for binding popups to it.\n\n    var layer = DG.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\n    layer.openPopup();\n    layer.closePopup();\n\nPopups will also be automatically opened when the layer is clicked on and closed when the layer\nis removed from the map or another popup is opened.\n\n<table id=\"dglayer-popup-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-bindpopup\">\n            <td><code><b>bindPopup</b>(\n                <nobr>&lt;String|HTMLElement|Function|Popup&gt; <i>content</i>,</nobr>\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Binds a popup to the layer with the passed <code>content</code> and sets up the\n                neccessary event listeners. If a <code>Function</code> is passed it will receive\n                the layer as the first argument and should return a <code>String</code> or <code>HTMLElement</code>.</td>\n        </tr>\n        <tr id=\"layer-unbindpopup\">\n            <td><code><b>unbindPopup</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the popup previously bound with <code>bindPopup</code>.</td>\n        </tr>\n        <tr id=\"layer-openpopup\">\n            <td><code><b>openPopup</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Opens the bound popup at the specificed <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>latlng</code></a>\n                or at the default popup anchor if no <code>latlng</code> is passed.</td>\n        </tr>\n        <tr id=\"layer-closepopup\">\n            <td><code><b>closePopup</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Closes the popup bound to this layer if it is open.\n                Opens or closes the popup bound to this layer depending on its current state.\n                Returns <code>true</code> if the popup bound to this layer is currently open.</td>\n        </tr>\n        <tr id=\"layer-setpopupcontent\">\n            <td><code><b>setPopupContent</b>(\n            <nobr>&lt;String|HTMLElement|Popup&gt; <i>content</i>,</nobr>\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Sets the content of the popup bound to this layer.</td>\n        </tr>\n        <tr id=\"layer-getpopup\">\n            <td><code><b>getPopup</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/popup#dgpopup\">Popup</a></code></td>\n            <td>Returns the popup bound to this layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Extension methods\n\nEvery layer should extend from <a href=\"#dglayer\"><code>DG.Layer</code></a> and (re-)implement the following methods.\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-onadd\">\n            <td><code><b>onAdd</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Should contain code that creates DOM elements for the layer, adds them to <code>map panes</code>\n                where they should belong and puts listeners on relevant map events. Called on\n                <a href=\"/doc/maps/en/manual/map#map-addlayer\"><code>map.addLayer(layer)</code></a>.</td>\n        </tr>\n        <tr id=\"layer-onremove\">\n            <td><code><b>onRemove</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Should contain all clean up code that removes the layer&#39;s elements from the DOM and removes\n                listeners previously added in <a href=\"#layer-onadd\"><code>onAdd</code></a>.\n                Called on <a href=\"/doc/maps/en/manual/map#map-removelayer\"><code>map.removeLayer(layer)</code></a>.</td>\n        </tr>\n        <tr id=\"layer-getevents\">\n            <td><code><b>getEvents</b>()</code></td>\n\n            <td><code>Object</code></td>\n            <td>This optional method should return an object like <code>{ viewreset: this._reset }</code>\n                for <a href=\"#evented-addeventlistener\"><code>addEventListener</code></a>.\n                These events will be automatically added and removed from the map with your layer.</td>\n        </tr>\n        <tr id=\"layer-beforeadd\">\n            <td><code><b>beforeAdd</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Optional method. Called on <a href=\"/doc/maps/en/manual/map#map-addlayer\"><code>map.addLayer(layer)</code></a>,\n                before the layer is added to the map, before events are initialized, without waiting until\n                the map is in a usable state. Use for early initialization only.</td>\n        </tr>\n    </tbody>\n</table>\n\nEvents inherited from <a href=\"#dgevented\">Evented</a> <!-- TODO: include events -->\n\n### DG.Control\n\nDG.Control is a base class for implementing map controls. Handles positioning. All other controls extend from this class.\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-position\">\n            <td><code><b>position</b></code></td>\n            <td><code>String</code></code></td>\n            <td><code>&#x27;topright&#x27;</code></td>\n            <td>The position of the control (one of the map corners). Possible values are <code>&#39;topleft&#39;</code>,\n                <code>&#39;topright&#39;</code>, <code>&#39;bottomleft&#39;</code> or <code>&#39;bottomright&#39;</code></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-getposition\">\n            <td><code><b>getPosition</b>()</code></td>\n\n            <td><code>string</code></td>\n            <td>Returns the position of the control.</td>\n        </tr>\n        <tr id=\"control-setposition\">\n            <td><code><b>setPosition</b>(\n                <nobr>&lt;string&gt; <i>position</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Sets the position of the control.</td>\n        </tr>\n        <tr id=\"control-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Returns the HTMLElement that contains the control.</td>\n        </tr>\n        <tr id=\"control-addto\">\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds the control to the given map.</td>\n        </tr>\n        <tr id=\"control-remove\">\n            <td><code><b>remove</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the control from the map it is currently active on.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Handler\n\nAbstract class for map interaction handlers.\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"handler-enable\">\n            <td><code><b>enable</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Enables the handler</td>\n        </tr>\n        <tr id=\"handler-disable\">\n            <td><code><b>disable</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Disables the handler</td>\n        </tr>\n        <tr id=\"handler-enabled\">\n            <td><code><b>enabled</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the handler is enabled</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Extension methods\n\nClasses inheriting from <a href=\"#dghandler\"><code>Handler</code></a> must implement the two following methods:\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"handler-addhooks\">\n            <td><code><b>addHooks</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Called when the handler is enabled, should add event hooks.</td>\n        </tr>\n        <tr id=\"handler-removehooks\">\n            <td><code><b>removeHooks</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Called when the handler is disabled, should remove the event hooks added previously.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Projection\n\nAn object with methods for projecting geographical coordinates of the world onto a flat surface (and back).\nSee <a href=\"http://en.wikipedia.org/wiki/Map_projection\">Map projection</a>.\n\nMaps API uses a Spherical Mercator projection. Assumes that Earth is a sphere.\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"projection-project\">\n            <td><code><b>project</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Projects geographical coordinates into a 2D point.</td>\n        </tr>\n        <tr id=\"projection-unproject\">\n            <td><code><b>unproject</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>The inverse of <code>project</code>. Projects a 2D point into a geographical location.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"projection-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#latlngbounds\">LatLngBounds</a></code></td>\n            <td>The bounds where the projection is valid</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Renderer\n\nBase class for vector renderer implementations (<code>DG.SVG</code>, <code>DG.Canvas</code>). Handles the\nDOM container of the renderer, its bounds, and its zoom animation. A <a href=\"#dgrenderer\"><code>Renderer</code></a>\nworks as an implicit layer group for all <a href=\"/doc/maps/en/manual/vector-layers#dgpath\"><code>DG.Path</code></a>s\n- the renderer itself can be added or removed to the map. All paths use a renderer, which can\nbe implicit (the map will decide the type of renderer and use it automatically) or explicit\n(using the <a href=\"/doc/maps/en/manual/vector-layers#path-renderer\"><code>renderer</code></a> option of the path).\nDo not use this class directly, use <code>DG.SVG</code> and <code>DG.Canvas</code> instead.\n\n##### Options\n\n<table id=\"dgrenderer-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"renderer-padding\">\n            <td><code><b>padding</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.1</code></td>\n            <td>How much to extend the clip area around the map view (relative to its size)\n                e.g. 0.1 would be 10% of map view in each direction</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\nMethods inherited from <a href=\"#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### Event objects\n\nWhenever a class inheriting from <a href=\"#dgevented\"><code>Evented</code></a> fires an event, a listener function\nwill be called with an event argument, which is a plain object containing information about the event. For example:\n\n    map.on('click', function(ev) {\n        alert(ev.latlng); // ev is an event object (MouseEvent in this case)\n    });\n\nThe information available depends on the event type:\n\n#### Event\n\nThe base event object. All other event objects contain these properties too.\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"event-type\">\n            <td><code><b>type</b></code></td>\n            <td><code>String</code></td>\n            <td>The event type (e.g. <code>&#39;click&#39;</code>).</td>\n        </tr>\n        <tr id=\"event-target\">\n            <td><code><b>target</b></code></td>\n            <td><code>Object</code></td>\n            <td>The object that fired the event.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### MouseEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"mouseevent-latlng\">\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#latlng\">LatLng</a></code></td>\n            <td>The geographical point where the mouse event occured.</td>\n        </tr>\n        <tr id=\"mouseevent-layerpoint\">\n            <td><code><b>layerPoint</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Pixel coordinates of the point where the mouse event occured relative to the map layer.</td>\n        </tr>\n        <tr id=\"mouseevent-containerpoint\">\n            <td><code><b>containerPoint</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Pixel coordinates of the point where the mouse event occured relative to the map сontainer.</td>\n        </tr>\n        <tr id=\"mouseevent-originalevent\">\n            <td><code><b>originalEvent</b></code></td>\n            <td><code>DOMMouseEvent</code></td>\n            <td>The original DOM mouse event fired by the browser.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LocationEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"locationevent-latlng\">\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#latlng\">LatLng</a></code></td>\n            <td>Detected geographical location of the user.</td>\n        </tr>\n        <tr id=\"locationevent-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#latlngbounds\">LatLngBounds</a></code></td>\n            <td>Geographical bounds of the area user is located in (with respect to the accuracy of location).</td>\n        </tr>\n        <tr id=\"locationevent-accuracy\">\n            <td><code><b>accuracy</b></code></td>\n            <td><code>Number</code></td>\n            <td>Accuracy of location in meters.</td>\n        </tr>\n        <tr id=\"locationevent-altitude\">\n            <td><code><b>altitude</b></code></td>\n            <td><code>Number</code></td>\n            <td>Height of the position above the WGS84 ellipsoid in meters.</td>\n        </tr>\n        <tr id=\"locationevent-altitudeaccuracy\">\n            <td><code><b>altitudeAccuracy</b></code></td>\n            <td><code>Number</code></td>\n            <td>Accuracy of altitude in meters.</td>\n        </tr>\n        <tr id=\"locationevent-heading\">\n            <td><code><b>heading</b></code></td>\n            <td><code>Number</code></td>\n            <td>The direction of travel in degrees counting clockwise from true North.</td>\n        </tr>\n        <tr id=\"locationevent-speed\">\n            <td><code><b>speed</b></code></td>\n            <td><code>Number</code></td>\n            <td>Current velocity in meters per second.</td>\n        </tr>\n        <tr id=\"locationevent-timestamp\">\n            <td><code><b>timestamp</b></code></td>\n            <td><code>Number</code></td>\n            <td>The time when the position was acquired.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### ErrorEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"errorevent-message\">\n            <td><code><b>message</b></code></td>\n            <td><code>String</code></td>\n            <td>Error message.</td>\n        </tr>\n        <tr id=\"errorevent-code\">\n            <td><code><b>code</b></code></td>\n            <td><code>Number</code></td>\n            <td>Error code (if applicable).</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LayerEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layerevent-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">ILayer</a></code></td>\n            <td>The layer that was added or removed.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LayersControlEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layerscontrolevent-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">ILayer</a></code></td>\n            <td>The layer that was added or removed.</td>\n        </tr>\n        <tr id=\"layerscontrolevent-name\">\n            <td><code><b>name</b></code></td>\n            <td><code>String</code></td>\n            <td>The name of the layer that was added or removed.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### TileEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"tileevent-tile\">\n            <td><code><b>tile</b></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>The tile element (image).</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### TileErrorEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"tileerrorevent-tile\">\n            <td><code><b>tile</b></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>The tile element (image).</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### ResizeEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"resizeevent-oldsize\">\n            <td><code><b>oldSize</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>The old size before resize event.</td>\n        </tr>\n        <tr id=\"resizeevent-newsize\">\n            <td><code><b>newSize</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>The new size after the resize event.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### GeoJSON event\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"geojson-event-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">ILayer</a></code></td>\n            <td>The layer for the GeoJSON feature that is being added to the map.</td>\n        </tr>\n        <tr id=\"geojson-event-properties\">\n            <td><code><b>properties</b></code></td>\n            <td><code>Object</code></td>\n            <td>GeoJSON properties of the feature.</td>\n        </tr>\n        <tr id=\"geojson-event-geometrytype\">\n            <td><code><b>geometryType</b></code></td>\n            <td><code>String</code></td>\n            <td>GeoJSON geometry type of the feature.</td>\n        </tr>\n        <tr id=\"geojson-event-id\">\n            <td><code><b>id</b></code></td>\n            <td><code>String</code></td>\n            <td>GeoJSON ID of the feature (if present).</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### Popup event\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"popup-event-popup\">\n            <td><code><b>popup</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/popup#dgpopup\">Popup</a></code></td>\n            <td>The popup that was opened or closed.</td>\n        </tr>\n    </tbody>\n</table>\n\nProperties inherited from <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### DragEndEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"dragendevent-distance\">\n            <td><code><b>distance</b></code></td>\n            <td><code>Number</code></td>\n            <td>The distance in pixels the draggable element was moved by.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### MetaEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>The geographical coordinates of the metalayer's point.</td>\n        </tr>\n        <tr>\n            <td><code><b>meta</b></code></td>\n            <td><code>Object</code></td>\n            <td>Metalayer's data.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### LangEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>lang</b></code></td>\n            <td><code>String</code></td>\n            <td>The current map's language.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/basic-types.md",
    "content": "## Basic Types\n\nThis section describes the classes of basic data types that are often found in the pages of maps API guide and\nrequired for use with many maps API objects.\n\n{toc}\n\n### DG.LatLng\n\nRepresents a geographical point with a certain latitude and longitude.\n\n    var latlng = DG.latLng(54.98, 82.89);\n\nAll methods that accept LatLng objects also accept them in a simple Array form and simple object form\n(unless noted otherwise), so these lines are equivalent:\n\n    map.panTo([54.98, 82.89]);\n    map.panTo({lon: 82.89, lat: 54.98});\n    map.panTo({lat: 54.98, lng: 82.89});\n    map.panTo(DG.latLng(54.98, 82.89));\n\n#### Constructor\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n\t\t</tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-l-latlng\">\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Number&gt; <i>latitude</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>longitude</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>altitude?</i> )</nobr>\n            </code></td>\n            <td>Creates an object representing a geographical point with the given latitude and longitude\n                (and optionally altitude).</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Array&gt; <i>coords</i> )</nobr>\n            </code></td>\n            <td>Expects an array of the form <code>[Number, Number]</code> or <code>[Number, Number, Number]</code>\n                instead.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Object&gt; <i>coords</i> )</nobr>\n            </code></td>\n            <td>Expects an plain object of the form <code>{lat: Number, lng: Number}</code> or\n                <code>{lat: Number, lng: Number, alt: Number}</code> instead.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>otherLatLng</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>maxMargin?</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the given <a href=\"#dglatlng\"><code>LatLng</code></a> point is at the\n                same position (within a small margin of error). The margin of error can be overriden by setting\n                <code>maxMargin</code> to a small number.</td>\n        </tr>\n        <tr id=\"latlng-tostring\">\n            <td><code><b>toString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Returns a string representation of the point (for debugging purposes).</td>\n        </tr>\n        <tr id=\"latlng-distanceto\">\n            <td><code><b>distanceTo</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>otherLatLng</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the distance (in meters) to the given <a href=\"#dglatlng\"><code>LatLng</code></a>\n                calculated using the <a href=\"http://en.wikipedia.org/wiki/Haversine_formula\">Haversine formula</a>.</td>\n        </tr>\n        <tr id=\"latlng-wrap\">\n            <td><code><b>wrap</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns a new <a href=\"#dglatlng\"><code>LatLng</code></a> object with the longitude wrapped\n                so it&#39;s always between -180 and +180 degrees.</td>\n        </tr>\n        <tr id=\"latlng-tobounds\">\n            <td><code><b>toBounds</b>(\n                <nobr>&lt;Number&gt; <i>sizeInMeters</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns a new <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a> object in which each boundary\n                is <code>sizeInMeters</code> meters apart from the <a href=\"#dglatlng\"><code>LatLng</code></a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-lat\">\n            <td><code><b>lat</b></code></td>\n            <td><code>Number</code></td>\n            <td>Latitude in degrees.</td>\n        </tr>\n        <tr id=\"latlng-lng\">\n            <td><code><b>lng</b></code></td>\n            <td><code>Number</code></td>\n            <td>Longitude in degrees.</td>\n        </tr>\n        <tr id=\"latlng-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>Number</code></td>\n            <td>Altitude in meters (optional).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.LatLngBounds\n\nRepresents a rectangular geographical area on a map.\n\n    var southWest = DG.latLng(54.9801, 82.8974),\n        northEast = DG.latLng(54.9901, 82.9074),\n        bounds = DG.latLngBounds(southWest, northEast);\n\nAll methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise),\nso the bounds example above can be passed like this:\n\n    map.fitBounds([\n        [54.9801, 82.8974],\n        [54.9901, 82.9074]\n    ]);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlngbounds-l-latlngbounds\">\n            <td><code><b>DG.latLngBounds</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>southWest</i>,</nobr>\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>northEast</i> )</nobr>\n            </code></td>\n            <td>Creates a <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a> object by defining south-west\n                and north-east corners of the rectangle.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLngBounds</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i>)</nobr>\n            </code></td>\n            <td>Creates a <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a> object defined by the geographical\n                points it contains. Very useful for zooming the map to fit a particular set of locations with\n                <a href=\"/doc/maps/en/manual/map#map-fitbounds\">fitBounds</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlngbounds-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Extend the bounds to contain the given point.</td>\n        </tr>\n        <tr>\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Extend the bounds to contain the given bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-pad\">\n            <td><code><b>pad</b>(\n                <nobr>&lt;Number&gt; <i>bufferRatio</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns bigger bounds created by extending the current bounds by a given percentage in each direction.</td>\n        </tr>\n        <tr id=\"latlngbounds-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns the center point of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsouthwest\">\n            <td><code><b>getSouthWest</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns the south-west point of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnortheast\">\n            <td><code><b>getNorthEast</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns the north-east point of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnorthwest\">\n            <td><code><b>getNorthWest</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns the north-west point of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsoutheast\">\n            <td><code><b>getSouthEast</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Returns the south-east point of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getwest\">\n            <td><code><b>getWest</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the west longitude of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsouth\">\n            <td><code><b>getSouth</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the south latitude of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-geteast\">\n            <td><code><b>getEast</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the east longitude of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnorth\">\n            <td><code><b>getNorth</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the north latitude of the bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle contains the given one.</td>\n        </tr>\n        <tr id=\"latlngbounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n             </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle contains the given point.</td>\n        </tr>\n        <tr id=\"latlngbounds-intersects\">\n            <td><code><b>intersects</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle intersects the given bounds. Two bounds intersect\n                if they have at least one point in common.</td>\n        </tr>\n        <tr id=\"latlngbounds-overlaps\">\n            <td><code><b>overlaps</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle overlaps the given bounds. Two bounds overlap\n                if their intersection is an area.</td>\n        </tr>\n        <tr id=\"latlngbounds-tobboxstring\">\n            <td><code><b>toBBoxString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Returns a string with bounding box coordinates in a\n                &#39;southwest_lng,southwest_lat,northeast_lng,northeast_lat&#39; format. Useful for sending\n                requests to web services that return geo data.</td>\n        </tr>\n        <tr id=\"latlngbounds-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle is equivalent (within a small margin of error)\n                to the given bounds.</td>\n        </tr>\n        <tr id=\"latlngbounds-isvalid\">\n            <td><code><b>isValid</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the bounds are properly initialized.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Point\n\nRepresents a point with x and y coordinates in pixels.\n\n    var point = DG.point(200, 300);\n\nAll methods and options that accept Point objects also accept them in a simple Array form\n(unless noted otherwise), so these lines are equivalent:\n\n    map.panBy([200, 300]);\n    map.panBy(DG.point(200, 300));\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"point-l-point\">\n            <td><code><b>DG.point</b>(\n                <nobr>&lt;Number&gt; <i>x</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>y</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n            </code></td>\n            <td>Creates a Point object with the given <code>x</code> and <code>y</code> coordinates.\n                If optional <code>round</code> is set to true, rounds the <code>x</code> and <code>y</code> values.</td>\n        </tr>\n        <tr id=\"point-l-point\">\n            <td><code><b>DG.point</b>(\n                <nobr>&lt;Number[]&gt; <i>coords</i>)</nobr>\n            </code></td>\n            <td>Expects an array of the form <code>[x, y]</code> instead.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"point-clone\">\n            <td><code><b>clone</b>()</nobr></code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns a copy of the current point.</td>\n        </tr>\n        <tr id=\"point-add\">\n            <td><code><b>add</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the result of addition of the current and the given points.</td>\n        </tr>\n        <tr id=\"point-subtract\">\n            <td><code><b>subtract</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the result of subtraction of the given point from the current.</td>\n        </tr>\n        <tr id=\"point-divideby\">\n            <td><code><b>divideBy</b>(\n                <nobr>&lt;Number&gt; <i>num</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the result of division of the current point by the given number.</td>\n        </tr>\n        <tr id=\"point-multiplyby\">\n            <td><code><b>multiplyBy</b>(\n                <nobr>&lt;Number&gt; <i>num</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the result of multiplication of the current point by the given number.</td>\n        </tr>\n        <tr id=\"point-scaleby\">\n            <td><code><b>scaleBy</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>scale</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Multiply each coordinate of the current point by each coordinate of\n                <code>scale</code>. In linear algebra terms, multiply the point by the\n                <a href=\"https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation\">scaling matrix</a>\n                defined by <code>scale</code>.</td>\n        </tr>\n        <tr id=\"point-unscaleby\">\n            <td><code><b>unscaleBy</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>scale</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Inverse of <code>scaleBy</code>. Divide each coordinate of the current point by\n                each coordinate of <code>scale</code>.</td>\n        </tr>\n        <tr id=\"point-round\">\n            <td><code><b>round</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns a copy of the current point with rounded coordinates.</td>\n        </tr>\n        <tr id=\"point-floor\">\n            <td><code><b>floor</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns a copy of the current point with floored coordinates (rounded down).</td>\n        </tr>\n        <tr id=\"point-ceil\">\n            <td><code><b>ceil</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns a copy of the current point with ceiled coordinates (rounded up).</td>\n        </tr>\n        <tr id=\"point-distanceto\">\n            <td><code><b>distanceTo</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the cartesian distance between the current and the given points.</td>\n        </tr>\n        <tr id=\"point-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the given point has the same coordinates.</td>\n        </tr>\n        <tr id=\"point-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if both coordinates of the given point are less than\n                the corresponding current point coordinates (in absolute values).</td>\n        </tr>\n        <tr id=\"point-tostring\">\n            <td><code><b>toString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Returns a string representation of the point for debugging purposes.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>x</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>x</code> coordinate.</td>\n        </tr>\n        <tr>\n            <td><code><b>y</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>y</code> coordinate.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Bounds\n\nRepresents a rectangular area in pixel coordinates.\n\n    var p1 = DG.point(10, 10),\n        p2 = DG.point(40, 60),\n        bounds = DG.bounds(p1, p2);\n\nAll methods that accept <a href=\"#dgbounds\"><code>Bounds</code></a> objects also accept them in a simple Array form\n(unless noted otherwise), so the bounds example above can be passed like this:</p>\n\n    otherBounds.intersects([[10, 10], [40, 60]]);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-l-bounds\">\n            <td><code><b>DG.bounds</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>topLeft</i>,</nobr>\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>bottomRight</i> )</nobr>\n            </code></td>\n            <td>Creates a Bounds object from two coordinates (usually top-left and bottom-right corners).</td>\n        </tr>\n        <tr id=\"bounds-l-bounds\">\n            <td><code><b>DG.bounds</b>(\n                <nobr>&lt;Point[]&gt; <i>points</i> )</nobr>\n            </code></td>\n            <td>Creates a Bounds object from the points it contains.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Extends the bounds to contain the given point.</td>\n        </tr>\n        <tr id=\"bounds-getcenter\">\n            <td><code><b>getCenter</b>(\n                <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the center point of the bounds.</td>\n        </tr>\n        <tr id=\"bounds-getbottomleft\">\n            <td><code><b>getBottomLeft</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the bottom-left point of the bounds.</td>\n        </tr>\n        <tr id=\"bounds-gettopright\">\n            <td><code><b>getTopRight</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the top-right point of the bounds.</td>\n        </tr>\n        <tr id=\"bounds-getsize\">\n            <td><code><b>getSize</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Returns the size of the given bounds.</td>\n        </tr>\n        <tr id=\"bounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle contains the given one.</td>\n        </tr>\n        <tr id=\"bounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle contains the given poing.</td>\n        </tr>\n        <tr id=\"bounds-intersects\">\n            <td><code><b>intersects</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle intersects the given bounds. Two bounds\n                intersect if they have at least one point in common.</td>\n        </tr>\n        <tr id=\"bounds-overlaps\">\n            <td><code><b>overlaps</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the rectangle overlaps the given bounds. Two bounds\n                overlap if their intersection is an area.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-min\">\n            <td><code><b>min</b></code></td>\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>The top left corner of the rectangle.</td>\n        </tr>\n        <tr id=\"bounds-max\">\n            <td><code><b>max</b></code></td>\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>The bottom right corner of the rectangle.</td>\n        </tr>\n\t</tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/controls.md",
    "content": "## Controls\n\nControls is a user interface components by which a user can interact with the map.\n\n{toc}\n\n### DG.Control.Zoom\n\nA basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless\nyou set its <a href=\"/doc/maps/en/manual/map#map-zoomcontrol\"><code>zoomControl</code> option</a> to <code>false</code>.\nExtends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>Control</code></a>.\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-zoom-l-control-zoom\">\n            <td><code><b>DG.control.zoom</b>(\n                <nobr>&lt;<a href=\"#control-zoom-option\">DG.Control.Zoom options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td>Creates a zoom control</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-zoom-zoomintext\">\n            <td><code><b>zoomInText</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;+&#x27;</code></td>\n            <td>The text set on the &#39;zoom in&#39; button.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomintitle\">\n            <td><code><b>zoomInTitle</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Zoom in&#x27;</code></td>\n            <td>The title set on the &#39;zoom in&#39; button.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomouttext\">\n            <td><code><b>zoomOutText</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;-&#x27;</code></td>\n            <td>The text set on the &#39;zoom out&#39; button.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomouttitle\">\n            <td><code><b>zoomOutTitle</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Zoom out&#x27;</code></td>\n            <td>The title set on the &#39;zoom out&#39; button.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Attribution\n\nThe attribution control allows you to display attribution data in a small text box on a map.\nIt is put on the map by default unless you set its\n<a href=\"/doc/maps/en/manual/map#map-attributioncontrol\"><code>attributionControl</code> option</a>\nto <code>false</code>, and it fetches attribution texts from layers with the\n<a href=\"/doc/maps/en/manual/base-classes#layer-getattribution\"><code>getAttribution</code> method</a> automatically.\nExtends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-attribution-l-control-attribution\">\n            <td><code><b>DG.control.attribution</b>(\n                <nobr>&lt;<a href=\"#control-attribution-option\">DG.Control.Attribution options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td>Creates an attribution control.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-attribution-prefix\">\n            <td><code><b>prefix</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Leaflet&#x27;</code></td>\n            <td>The HTML text shown before the attributions. Pass <code>false</code> to disable.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\n<table>\n    <thead>\n\t<tr>\n\t\t<th>Method</th>\n\t\t<th>Returns</th>\n\t\t<th>Description</th>\n\t</tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"control-attribution-setprefix\">\n            <td><code><b>setPrefix</b>(\n                <nobr>&lt;String&gt; <i>prefix</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Sets the text before the attributions.</td>\n        </tr>\n        <tr id=\"control-attribution-addattribution\">\n            <td><code><b>addAttribution</b>(\n                <nobr>&lt;String&gt; <i>text</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds an attribution text (e.g. <code>&#39;Vector data &amp;copy; Mapbox&#39;</code>).</td>\n        </tr>\n        <tr id=\"control-attribution-removeattribution\">\n            <td><code><b>removeAttribution</b>(\n                <nobr>&lt;String&gt; <i>text</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes an attribution text.</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Scale\n\nA simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial\n(mi/ft) systems. Extends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.scale().addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-scale-l-control-scale\">\n            <td><code><b>DG.control.scale</b>(\n                <nobr>&lt;<a href=\"#control-scale-option\">DG.Control.Scale options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates an scale control with the given options.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-scale-maxwidth\">\n            <td><code><b>maxWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>100</code></td>\n            <td>Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).</td>\n        </tr>\n        <tr id=\"control-scale-metric\">\n            <td><code><b>metric</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>True</code></td>\n            <td>Whether to show the metric scale line (m/km).</td>\n        </tr>\n        <tr id=\"control-scale-imperial\">\n            <td><code><b>imperial</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>True</code></td>\n            <td>Whether to show the imperial scale line (mi/ft).</td>\n        </tr>\n        <tr id=\"control-scale-updatewhenidle\">\n            <td><code><b>updateWhenIdle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, the control is updated on <a href=\"/doc/maps/en/manual/map#map-moveend\"><code>moveend</code></a>,\n                otherwise it&#39;s always up-to-date (updated on <a href=\"/doc/maps/en/manual/map#map-move\"><code>move</code></a>).</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Ruler\n\nWhen clicked opens a ruler - the tool for measurement of distances on a map.\nExtends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.ruler().addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-ruler-l-control-ruler\">\n            <td><code><b>DG.control.ruler</b>(\n                <nobr>&lt;<a href=\"#control-ruler-option\">DG.Control.Ruler options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a ruler control with the given options.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Traffic\n\nThe traffic control allows you to display traffic overlay data on a map.\nExtends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.traffic().addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-traffic-l-control-traffic\">\n            <td><code><b>DG.control.traffic</b>(\n                <nobr>&lt;<a href=\"#control-traffic-option\">DG.Control.Traffic options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a traffic control with the given options.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Fullscreen\n\nThe fullscreen control enables display of the map over fullscreen window which bounds are physical bounds of a given\nuser monitor. The button works like a trigger. It is put on the map by default unless you set its\n<a href=\"/doc/maps/en/manual/map#map-attributioncontrol\"><code>fullscreenControl</code> option</a> to <code>false</code>.\nExtends <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.fullscreen().addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-fullscreen-l-control-fullscreen\">\n            <td><code><b>DG.control.fullscreen</b>(\n                <nobr>&lt;<a href=\"#control-fullscreen-option\">DG.Control.Fullscreen options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a fullscreen control with the given options.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.LocationControl\n\nThe geo-location control allow users to detect their geographic positions and automatically pan the map layer to found coordinates.\nControl is disabled if geo-location API is not available.\n\n    DG.control.location().addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-location-l-control-location\">\n            <td><code><b>DG.control.location</b>(\n                <nobr>&lt;<a href=\"#control-location-option\">DG.Control.LocationControl options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a geo-location control with the given options.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-location-drawcircle\">\n            <td><code><b>drawCircle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Will the circle showing the accuracy of the detection be displayed or not.</td>\n        </tr>\n        <tr id=\"control-location-follow\">\n            <td><code><b>follow</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Update user location dynamically or not, works if <code>watch</code> and <code>setView</code> options are\n                exposed to <code>true</code> in <code>locateOptions</code>.</td>\n        </tr>\n        <tr id=\"control-location-stopfollowingondrag\">\n            <td><code><b>stopFollowingOnDrag</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Enables or disables the user's location update as he drag the map.</td>\n        </tr>\n        <tr id=\"control-location-metric\">\n            <td><code><b>metric</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Use metric or English units of measurement.</td>\n        </tr>\n        <tr id=\"control-location-locateoptions\">\n            <td><code><b>locateOptions</b></code></td>\n            <td><code>Object </code></td>\n            <td><code></code></td>\n            <td>See <a href=\"/doc/maps/en/manual/map#geolocation-options\">geo-location options</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Methods\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n"
  },
  {
    "path": "src/doc/en/manual/dg-ajax.md",
    "content": "## Asynchronous requests (AJAX)\n\n{toc}\n\n### DG.ajax\n\nThe DG.ajax function allows to send cross-domain AJAX requests.\n\n    var promise = DG.ajax('http://www.geonames.org/postalCodeLookupJSON', {\n        type: 'get',\n        data: {\n            postalcode: 10504,\n            country: 'US'\n        },\n        success: function(data) {\n            console.log('success', data);\n        },\n        error: function(error) {\n            console.log('error', error);\n        }\n    });\n\n    // to cancel the request:\n    // promise.abort();\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.ajax</b>(\n                <nobr>&lt;String&gt; <i>url</i>,</nobr>\n                <nobr>&lt;<a href=\"#options\">Ajax options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Sends a request to the server and returns a Promise object with the abort method,\n                with the help of which you can abort the sending of the request. Takes a URL as\n                input parameters, where we will send you a request and an optional object of options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>data</b></code></td>\n            <td><code>Object</code></td>\n            <td><code>null</code></td>\n            <td>The data that will be sent to the server.</td>\n        </tr>\n        <tr>\n            <td><code><b>type</b></code></td>\n            <td><code>String</code></td>\n            <td><code>get</code></td>\n            <td>Type of request ('get', 'post' or 'jsonp').</td>\n        </tr>\n        <tr>\n            <td><code><b>success</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>A function which is triggered in case of successful server response.\n                Takes the received data as a parameter.</td>\n        </tr>\n        <tr>\n            <td><code><b>error</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>A function that is triggered when an error occurs.\n                Takes the error information as a parameter.</td>\n        </tr>\n        <tr>\n            <td><code><b>url</b></code></td>\n            <td><code>String</code></td>\n            <td><code>null</code></td>\n            <td>The URL to which the request will be sent.</td>\n        </tr>\n        <tr>\n            <td><code><b>timeout</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>null</code></td>\n            <td>Query timeout (in milliseconds).</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-entrance.md",
    "content": "## DG.Entrance\n\nAllows to display an entrance to the building. The class supports simple animation and multiple inputs display.\nObjects of entrances themselves represent arrows which change their scale together with zooming, but not lower\nthan the level 16, after which the arrows disappear from the map (until reaching an acceptable level of zooming).\n\n{toc}\n\n### DG.Entrance\n\n#### Example of usage\n\nCreate and display the entrances to the building:\n\n    var options = {vectors: [\n        \"LINESTRING(82.897079 54.980906,82.897191 54.980844)\",\n        \"LINESTRING(82.897933 54.980649,82.898045 54.980587)\",\n        \"LINESTRING(82.897071 54.980122,82.897226 54.98013)\",\n        \"LINESTRING(82.897354 54.979515,82.89741 54.979599)\",\n        \"LINESTRING(82.898498 54.979826,82.898386 54.979889)\"\n    ]}\n    DG.entrance(options).addTo(map).show(true);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Usage</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Entrance</b>(\n                <nobr>&lt;<a href=\"#entrance-options\">Entrance options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td><code>DG.entrance(&hellip;)</code></td>\n            <td>Creates an entrance object based on the provided options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>vectors</b></code></td>\n            <td><code>Array</td>\n            <td><code>[]</code></td>\n            <td><b>(a required parameter)</b>An array of vectors describing the entrances to the building.\n                You can send several values in the array, if there is more than one entrance to the building.\n                Each element should represent a string in WKT format: LINESTRING(lng0 lat0,lng1 lat1[,... lngN latN]),\n                where the last coordinate pair should be a direct entrance point to the building, and the previous\n                coordinates - be the route to this point. Throughout the route there should not be mutual intersections.</td>\n        </tr>\n        <tr>\n            <td><code><b>fillColor</b></code></td>\n            <td><code>String</td>\n            <td><code>#0085a0</code></td>\n            <td>The fill color of the arrows.</td>\n        </tr>\n        <tr>\n            <td><code><b>strokeColor</b></code></td>\n            <td><code>String</td>\n            <td><code>#ffffff</code></td>\n            <td>The outline color of the arrows.</td>\n        </tr>\n        <tr>\n            <td><code><b>enableAnimation</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>true</code></td>\n            <td>Whether to animate the display of arrows when you change the zoom levels of the map and during the initial display.</td>\n        </tr>\n        <tr>\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>false</code></td>\n            <td>If the value is false, then the handler of the mouse actions is not called.</td>\n        </tr>\n        <tr>\n            <td><code><b>autoClose</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>true</code></td>\n            <td>Whether to remove objects of entrances after adding new layers to the map.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"#map\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds the object of entrances to the map.</td>\n        </tr>\n        <tr>\n            <td><code><b>removeFrom</b>(\n                <nobr>&lt;<a href=\"#map\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the object of entrances from the map.</td>\n        </tr>\n        <tr>\n            <td><code><b>show</b>(\n                <nobr>&lt;fitBounds&gt; <i>boolean</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Displays entrances on the map. If <code>fitBounds</code> is set to <code>true</code>,\n                then the map boundaries (and zoom level) are adjusted so that the user could see all\n                the entrances on one screen.</td>\n        </tr>\n        <tr>\n            <td><code><b>hide</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Hides entrances. The objects themselves are not deleted from the map and the entrances\n                can be re-displayed by calling the <code>show()</code> method.</td>\n        </tr>\n        <tr>\n            <td><code><b>isShown</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the entrances are currently displayed on the map.</td>\n        </tr>\n        <tr>\n            <td><code><b>setFillColor</b>()</code></td>\n            <td><code>String</code></td>\n            <td>Changes the fill color of the arrows.</td>\n        </tr>\n        <tr>\n            <td><code><b>setStrokeColor</b>()</code></td>\n            <td><code>String</code></td>\n            <td>Changes the outline color of the arrows.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-external-modules.md",
    "content": "## External modules\n\nBesides the possibility to connect one of the <a href=\"/doc/maps/en/manual/dg-loading#loading-pkg\">packages</a>\nof 2GIS modules, you can load other developers' modules from third-party servers. The maps API is compatible\nwith most of <a target=\"_blank\" href=\"http://leafletjs.com/plugins.html\">library modules</a> Leaflet.\nYou can also develop and connect <a href=\"https://github.com/2gis/maps-api-2.0/blob/master/CONTRIBUTING.md#%D0%9A%D0%B0%D0%BA-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%82%D1%8C-%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C\" target=\"_blank\">your own module</a>.\n\n{toc}\n\n### Connection\n\nTo include external modules, use the <code>DG.plugin</code> function. Below we take a look at several examples of its use.\n\nThe usage of the <code>DG.plugin</code> function in the case where the module should be loaded before the map initialization:\n\n    // loading of maps API code\n    DG.then(function() {\n        // module code loading\n        return DG.plugin('https://raw.github.com/mlevans/leaflet-hash/master/leaflet-hash.js');\n    })\n    .then(function() {\n        // map initialization\n        var map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n        // module initialization\n        L.hash(map);\n    });\n\nIf the module is not needed at the initial stage of work with the map, then you can use its deferred\nloading and initialization (for example, when you click on the button):\n\n    // loading of maps API code\n    DG.then(function() {\n        // map initialization\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\n    // the code can be called on demand\n    DG.then(function() {\n        // module code loading\n        return DG.plugin('https://raw.github.com/mlevans/leaflet-hash/master/leaflet-hash.js');\n    }).then(function () {\n        // module initialization\n        L.hash(map);\n    });\n\n### DG.plugin\n\nIs responsible for the loading of external modules. Function parameters:\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code>DG.plugin</b>(\n                <nobr>&lt;String&gt; <i>url</i>&nbsp;|&nbsp;</nobr>\n                <nobr>&lt;Array&gt; <i>[&lt;String&gt; url, &lt;String&gt; url, ...]</i></nobr>&nbsp;)\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Loads the modules. The direct links to js and css files must be specified as parameters.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-label.md",
    "content": "## Labels\n\n{toc}\n\n### DG.Label\n\n<code>DG.Label</code> class implements a small hint which may appear over a particular object on the map\n(above a marker or a vector layer, for example). Also, the tips can be shown not only when you\nhover the mouse over the object, but constantly, these tips are called static.\n\n#### Example of usage\n\nTo enable the display of tips when you hover over the marker is quite easy:\n\n    DG.marker([54.9502, 82.8380], {\n        label : 'I'm a tip!'\n    }).addTo(map);\n\nFor vector layers, you can specify a tip in this way, for example:\n\n    DG.polyline([\n        [55.02, 83.02],\n        [54.97, 83.03],\n        [54.95, 83.01],\n        [54.98, 82.97]\n    ], {\n        label: 'I am a hint!'\n    }).addTo(map);\n\nTo add a tip to an object that has been already created, you can call the <code>bindLabel</code> method:\n\n    var marker = DG.marker([54.9502, 82.8980]).addTo(map);\n    marker.bindLabel('I am a static tip!', { static: true });\n\n<!--\nTODO: JSAPI-3564\nShowing autonomous static labels on the map:\n\n    DG.label('I am an autonomous hint!')\n        .setLatLng([54.9502, 82.8980]);\n        .addTo(map);\n\n#### Creation\n...\n-->\n\n#### Options\n\nWhen you call the <code>bindLabel</code> method, you can set the following options for the tooltip:\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><b><code>offset</code></b></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td><nobr><code>Point(12, 15)</code></nobr></td>\n            <td>The offset of a tooltip container relative to the cursor position (the position\n                of the marker in the case when used with a marker).</td>\n        </tr>\n        <tr>\n            <td><b><code>className</code></b></td>\n            <td><code>String</code></td>\n            <td><code>'dg-label'</code></td>\n            <td>The CSS class that will be assigned to the DOM element of the tooltip.</td>\n        </tr>\n        <tr id=\"label-static\">\n            <td><b><code>static</code></b></td>\n            <td><code>Boolean</code></td>\n            <td><code>false</code></td>\n            <td>If the value is set to <code>true</code>, then the tooltip will be always visible\n                (this option is available only for a marker tip).</td>\n        </tr>\n        <tr id=\"label-textdirection\">\n            <td><code><b>textDirection</b></code></td>\n            <td><code>string</code></td>\n            <td><code>'auto'</code></td>\n            <td>The direction of the label text. The following values are possible: <code>'auto'</code>,\n                <code>'rtl'</code>, <code>'ltr'</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n<!--\nTODO: JSAPI-3564\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>setContent</b>(&lt;String&gt; content)</code></td>\n            <td><code>this</code></td>\n            <td>Sets the contents of the tooltip.</td>\n        </tr>\n        <tr>\n            <td><code><b>setLatLng</b>(&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; latlng)</code></td>\n            <td><code>this</code></td>\n            <td>Sets the geographical coordinates of the tip.</td>\n        </tr>\n        <tr>\n            <td><code><b>getLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Returns the geographical coordinates of the tip.</td>\n        </tr>\n    </tbody>\n</table>\n-->\n"
  },
  {
    "path": "src/doc/en/manual/dg-loading.md",
    "content": "## Loading API\n\n{toc}\n\n### Description\n\nWork with map is possible only after the code of Maps API is loaded to the browser.\nThere are several ways to download it.\n\n### Easy way\n\nFirst include the Maps API by adding the following code to the <code>head</code> section of the HTML page:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n\nThen use the <code>DG.then</code> function, into which we will place the initialization code of the map:\n\n    DG.then(function() {\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\nInside this function adds a handler for of the event of the page loading.\nThis very method was discussed in the [Quick start](/doc/maps/en/quickstart) section.\n\n### npm\n\nThe Maps API can be included via npm:\n\n    $ npm i 2gis-maps\n\nAfter the package is installed, enable it using <code>require</code>:\n\n    var DG = require('2gis-maps');\n    var map = DG.map('map', {\n        'center': [54.98, 82.89],\n        'zoom': 13\n    });\n\nPlease note that when you use the npm package, there is no need to use <code>DG.then</code>.\n\n### Download on demand\n\nYou can load the Maps API at the very moment when you need the map. To do this, you need to add the\n<code>lazy=true</code> parameter to the URL used to include API:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full&lazy=true\"></script>\n\nThen, at the right time (for example, when pressing the button) you must call the <code>DG.then</code> function:\n\n    DG.then(function() {\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\n### Connection options\n\nThe following are all options that can take the URL of the Maps API loading:\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"loading-pkg\">\n            <td><code>pkg</code></td>\n            <td><code>full</code></td>\n            <td>Package of loadable modules. Currently, 2 packages are supported: <code>full</code> — all API modules;\n                <code>basic</code> — basic functionality (popups, markers, vector objects).</td>\n        </tr>\n        <tr>\n            <td><code>skin</code></td>\n            <td><code>dark</code></td>\n            <td>The theme of controls (light or dark). Takes the value <code>light</code> or <code>dark</code>.</td>\n        </tr>\n        <tr>\n            <td><code>lazy</code></td>\n            <td><code>false</code></td>\n            <td>If you specify the <code>true</code> value, then the Maps API will load with delay,\n                when you first call <code>DG.then</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.then function\n\nAs described earlier, the function <code>DG.then</code> is responsible for tracking the moment of loading the Maps API\nand adding handlers for this action. Function parameters:\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code>DG.then</b>(\n                <nobr>&lt;Function&gt; <i>resolve</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>reject</i></nobr>&nbsp;)\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Registers API loading handlers. Parameters: <code>resolve</code> is a function triggered\n                in case of a successful loading of the Maps API, <code>reject</code> is a function triggered\n                in case of server errors.</td>\n        </tr>\n    </tbody>\n</table>\n\nThe call of the <code>DG.then</code> function at any time after the API loading will be immediately executed by the handler."
  },
  {
    "path": "src/doc/en/manual/dg-locale.md",
    "content": "## Localization\n\n{toc}\n\n### Description\n\nMaps API provides a possibility to display elements of user interface in several languages.\n\nThe default language is the same as that of the root html tag:\n\n    <html lang=\"it\">\n        <head></head>\n        <body></body>\n    </html>\n\nIf the language is not specified in the root tag, then the default language — Russian — will be used.\n\nGet or dynamically change the language using the corresponding methods of the map\n<a href=\"/doc/maps/en/manual/map#map-getlang\">getLang</a> and <a href=\"/doc/maps/en/manual/map#map-setlang\">setLang</a>:\n\n    map.setLang('it');\n    map.getLang(); // returns 'it'\n\nor by initializing the map with the following option <a href=\"/doc/maps/en/manual/map#map-currentlang\">currentLang</a>.\n\nCurrently supports the following languages:\n\n* en &mdash; English;\n* ru &mdash; Russian;\n* it &mdash; Italian;\n* cs &mdash; Czech;\n* es &mdash; Spanish;\n* ar &mdash; Arabic.\n\n### DG.Locale\n\nPerforms <a href=\"/doc/maps/en/manual/dg-locale\">the translation of the user interface</a>.\n\n\nAdds two methods to the map: <a href=\"/doc/maps/en/manual/map#map-setlang\">setLang</a>\nand <a href=\"/doc/maps/en/manual/map#map-getlang\">getLang</a>. There is also a DG object.Locale object,\nwhich you can add to any <a href=\"/doc/maps/en/manual/dg-external-modules\">external module</a>,\nand there will appear the t method which you can use to perform a translation.\nClasses of modules, to which DG.Locale is added must contain the <code>_map</code> property and the <code>Dictionary</code>\nstatic property inside.\n\nThe basic dictionary for all dictionaries is <code>DG.Dictionary</code>, which stores the translation rules\nfor words in plural forms (plural rules). When you create a module which uses its own dictionaries,\nyou need to put them to the lang folder. For example, if you want to use Italian and Russian languages,\nyou need to create the <code>lang/it.js</code> and <code>lang/ru.js</code> files. Examples of creation of dictionaries are given below.\n\n#### Example of usage\n\nMixing of localization features to the module:\n\n    DG.LocaleExample = DG.Control.extend({\n        includes: DG.Locale,\n        statics: {\n            Dictionary: {}\n        }\n        ...\n    }\n\nSubscribe to the langchange event:\n\n    this._map.on('langchange', this._updateText, this);\n\nThe translation of the string to the current language of the map:\n\n    container.innerHTML = this.t(\"{n} people\", 16700000) + ' ' + this.t(\"regularly use 2GIS\");\n\nCreate your own dictionaries in Italian and Russian:\n\nlang/it.js file contents:\n\n    DG.LocaleExample.Dictionary.it = DG.extend({\n        \"{n} people\" : [\"{n} utente\", \"{n} utenti\"],\n        \"regularly use 2GIS\" : \"utilizzano regolarmente 2GIS\"\n    }, DG.Dictionary.it);\n\nlang/ru.js file contents:\n\n     DG.LocaleExample.Dictionary.ru = DG.extend({\n        \"{n} people\" : [\"{n} пользователь\", \"{n} пользователя\", \"{n} пользователей\"],\n        \"regularly use 2GIS\" : \"регулярно используют 2GIS\"\n    }, DG.Dictionary.ru);\n"
  },
  {
    "path": "src/doc/en/manual/dg-metalayers.md",
    "content": "## Meta Layers\n\nAllows you to create additional layers of meta information and add them to the map.\n\n{toc}\n\n### DG.Meta.layer\n\nInherits from <a href=\"/doc/maps/en/manual/base-classes#dglayer\"><code>DG.Layer</code></a>.\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Usage</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Meta.layer</b>(\n                <nobr>&lt;String&gt; <i>source</i>,</nobr>\n                <nobr>&lt;<a href=\"#options\">DG.Meta.layer options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Meta.layer(&hellip;)</code></td>\n            <td>Creates additional layer with meta-information. Takes the source URL as a parameter\n                with which the tiles of an additional layer are available.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>tileSize</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>256</code></td>\n            <td>The tile size (width and height in pixels, it is assumed that the tile is square).</td>\n        </tr>\n        <tr>\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>0</code></td>\n            <td>The minimum zoom level.</td>\n        </tr>\n        <tr>\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>18</code></td>\n            <td>The maximum zoom level.</td>\n        </tr>\n        <tr>\n            <td><code><b>zoomOffset</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>0</code></td>\n            <td>Value which will shift the zoom level in the tile's address.</td>\n        </tr>\n        <tr>\n            <td><code><b>eventBubbling</b></code></td>\n            <td><code>String</code></td>\n            <td><code><span class=\"string\">'transparent'</span>||<span class=\"string\">'layer'</span></td>\n            <td>The way in which meta-layer handles events. Accepts values <b>layer</b>\n                or <b>transparent</b> (default):<ul><li>transparent &mdash; meta-layer receives all of the events\n                and carry them to the map</li><li>layer &mdash; meta-layer receives all of the events and stops\n                them after processing</li></ul></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\nYou can subscribe to the following events using\n<a href=\"/doc/maps/en/manual/base-classes#dgevented\">these</a> methods.\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code>\n            <td>Called when you hover the mouse over the additional layer object.</td>\n        </tr>\n        <tr>\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code>\n            <td>Called when the mouse cursor leaves the bounds of an additional layer object.</td>\n        </tr>\n        <tr>\n          <td><code><b>mousemove</b></code></td>\n          <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Called when the mouse cursor moves over an additional layer object.</td>\n        </tr>\n        <tr>\n          <td><code><b>click</b></code></td>\n          <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Called when the mouse click in the additional layer.</td>\n        </tr>\n        <tr>\n          <td><code><b>dblclick</b></code></td>\n          <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Called when the mouse double-click in the additional layer.</td>\n        </tr>\n        <tr>\n          <td><code><b>mousedown</b></code></td>\n          <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Called when the mouse button is pressed while the cursor is over the additional layer.</td>\n        </tr>\n        <tr>\n          <td><code><b>contextmenu</b></code></td>\n          <td><code><a href=\"/doc/maps/en/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Called when you click the right mouse button in the additional layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>getOrigin</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Returns origin-instance of additional layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Meta.origin\n\nWorks with the meta data of a layer, inherits from <a href=\"/doc/maps/en/manual/base-classes#dgclass\"><code>DG.Class</code></a>.\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Usage</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Meta.origin</b>(\n                <nobr>&lt;String&gt; <i>source</i>,</nobr>\n                <nobr>&lt;DG.Meta.layer options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Meta.origin(&hellip;)</code></td>\n            <td>Creates an instance for work with the meta layer data. Takes the source URL as a parameter\n                with which the tiles of an additional layer are available.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>subdomains</b></code></td>\n            <td><code>String</code> или <code>String[]</code></td>\n            <td><code>'0123'</code></td>\n            <td>Tile service subdomains. Can be sent as one string (where each letter &mdash;\n                is a subdomain name) or as an array of strings.</td>\n        </tr>\n        <tr>\n            <td><code><b>dataFilter</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>Optional parameter, which takes a function to filter or convert the meta data\n                received from the server.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>getTileData</b>(\n                <nobr>&lt;Object&gt; <i>coord</i>)</nobr>\n            </code>\n            <td><code>Object</code></td>\n            <td>Returns the metadata of the meta layer for the specified tile.</td>\n        </tr>\n        <tr>\n            <td><code><b>setTileData</b>(\n                <nobr>&lt;String&gt;/&lt;Object&gt; <i>coord</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>data</i>)</nobr>\n            </code>\n            <td><code>this</code></td>\n            <td>Assigns data for the tile with the coord key.</td>\n        </tr>\n        <tr>\n            <td><code><b>flush</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Clear cached data for all tiles.</td>\n        </tr>\n        <tr>\n            <td><code><b>setURL</b>(\n                <nobr>&lt;String&gt; <i>url</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>flush?</i>)</nobr>\n            </code>\n            <td><code>this</code></td>\n            <td>Sets the url used to get the meta data. If the parameter flush=true,\n                the cached data will be cleared.</td>\n        </tr>\n        <tr>\n            <td><code><b>getTileKey</b>(\n                <nobr>&lt;Object&gt; <i>coord</i>)</nobr>\n            </code>\n            <td><code>String</code></td>\n            <td>Returns the key of the tile as a string.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-project-detector.md",
    "content": "## 2GIS Project Detection Module\n\nProject is agglomeration, which includes a major city and the surrounding areas.\nThis plugin allows to get information about the project which is being viewed at the current moment of time.\n\n{toc}\n\n### Examples of usage\n\nSubscribe to the projectchange event:\n\n    map.on('projectchange', function (e) {\n        console.log(e);\n    });\n\nSubscribe to the projectleave event:\n\n    map.on('projectleave', function (e) {\n       console.log(e);\n    });\n\n### Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>projectchange</td>\n            <td>ProjectEvent</td>\n            <td>Occurs when the user goes from one project to another.</td>\n        </tr>\n        <tr>\n            <td>projectleave</td>\n            <td>ProjectEvent</td>\n            <td>Occurs when the user is outside of the current project.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>getProjectsList</td>\n            <td>Object</td>\n            <td>Returns all available projects.</td>\n        </tr>\n        <tr>\n            <td>getProject</td>\n            <td>Object</td>\n            <td>Returns the current project.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-ruler.md",
    "content": "## Ruler\n\nDisplays a ruler on the map that allows to measure distances between geographical points.\n\n{toc}\n\n### DG.Ruler\n\n#### Example of usage\n\nCreate and display a ruler on the map:\n\n    var latLngs = [\n        [51.7314, 36.1938],\n        [51.7307, 36.1894],\n        [51.7297, 36.1926],\n        [51.7299, 36.1968],\n        [51.7307, 36.1968]]\n    DG.ruler(latLngs).addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Usage</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Ruler</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>[]&gt; <i>latlngs</i>,</nobr>\n                <nobr>&lt;<a href=\"#dgruler-options\">Ruler options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.ruler(&hellip;)</code></td>\n            <td>Creates the ruler object by the given array of geographical points and optional object of options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id='dgruler-options'>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>editable</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code><span class=\"string\">'true'</span></td>\n            <td>Is it possible to change the intermediate points of the ruler.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Adds a ruler to the map.</td>\n        </tr>\n        <tr>\n            <td><code><b>getTotalDistance</b>()</nobr></code></td>\n            <td><code>Number</code></td>\n            <td>Returns the distance (in meters) between the start and end points.</td>\n        </tr>\n        <tr>\n            <td><code><b>addLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Adds a point to the ruler.</td>\n        </tr>\n        <tr>\n            <td><code><b>setLatLngs</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>[]&gt; <i>latlngs</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Replaces all the pixels of the ruler with an array of the transferred geographical locations.</td>\n        </tr>\n        <tr>\n            <td><code><b>getLatLngs</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>[]</code></td>\n            <td>Returns an array of points of the ruler.</td>\n        </tr>\n        <tr>\n            <td><code><b>spliceLatLngs</b>(\n                <nobr>&lt;Number&gt; <i>index</i></nobr>,\n                <nobr>&lt;Number&gt; <i>pointsToRemove</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng?</i>, &hellip; )</nobr>\n            </code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>[]</code></td>\n            <td>Allows you to add, remove or replace the points in the ruler. The syntax is similar\n                <a target=\"_blank\" href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice\">Array#splice</a>.\n                Returns an array of remote points.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-traffic.md",
    "content": "## Traffic information\n\nCreates a layer with information about traffic jams. When you hover over a section of a road,\nit displays additional meta-information.\n\n{toc}\n\n### DG.Traffic\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Usage</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Traffic</b>(\n                <nobr>&lt;<a href=\"#options\">DG.Traffic options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Traffic(&hellip;)</code></td>\n            <td>Creates a traffic jams layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>disableLabel</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code><span class=\"string\">false</span></td>\n            <td>If you send the value= true, then, when you hover over a section of a road,\n                the additional information will not be displayed.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dg-wkt.md",
    "content": "## Well-known text\n\n\nIs used to obtain the vector layers of API maps based on their description in\n<a target=\"_blank\" href=\"http://en.wikipedia.org/wiki/Well-known_text\">WKT format</a>.\n\n{toc}\n\n### DG.Wkt\n\n#### Example of usage\n\nReads the description of the polygon in WKT format and displays it on the map:\n\n    var polygonComponents = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))';\n    DG.Wkt.geoJsonLayer(polygonComponents).addTo(map);\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Wkt.toGeoJSON</b>(\n                <nobr>&lt;String&gt; <i>wkt</i>)</nobr>\n            </code></td>\n            <td><code>geoJSON</code></td>\n            <td>Reads a string in WKT format and verifies its correctness. Returns\n                <a href=\"http://geojson.org/geojson-spec.html\" target=\"_blank\">GeoJSON</a>.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.Wkt.toLatLngs</b>(\n                <nobr>&lt;String | Array&gt; <i>wkt</i>)</nobr>\n            </code></td>\n            <td><code>Array</code></td>\n            <td>Reads a string in WKT format and returns the pixel array in the\n                <a href=\"/doc/maps/en/manual/basic-types/#dglatlng\">LatLng</a> format (its internal representation).\n                Can take an array of WKT strings.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.Wkt.geoJsonLayer</b>(\n                <nobr>&lt;String&gt; <i>wkt</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/other-layers#geojson-option\">GeoJSON options</a>&gt; <i>options?</i>)</nobr></code></td>\n            <td><code>Object</code></td>\n            <td>Creates a GeoJSON layer. Takes a string in WKT format to display the data on the map\n                and the object of options. Generates a vector layer of maps AP based on the data read\n                with the DG.Wkt.toGeoJSON method. This method supports all the options of the constructor\n                of the <a href=\"/doc/maps/en/manual/other-layers#dggeojson\">DG.GeoJSON</a> class.\n                For example, you can send the <code>DG.Wkt.geoJsonLayer(polygonComponents, {clickable:false})</code>\n                parameter, to make the layer non-clickable.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/dom-utils.md",
    "content": "## Working with DOM\n\n{toc}\n\n### DG.DomEvent\n\nUtility functions to work with the <a href=\"https://developer.mozilla.org/docs/Web/API/Event\">DOM events</a>.\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"domevent-on\">\n            <td><code><b>on</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;String&gt; <i>types</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Adds a listener function (<code>fn</code>) to a particular DOM event type of the\n                element <code>el</code>. You can optionally specify the context of the listener\n                (object the <code>this</code> keyword will point to). You can also pass several\n                space-separated types (e.g. <code>&#39;click dblclick&#39;</code>).</td>\n        </tr>\n        <tr>\n            <td><code><b>on</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>eventMap</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds a set of type/listener pairs, e.g. <code>{click: onClick, mousemove: onMouseMove}</code></td>\n        </tr>\n        <tr id=\"domevent-off\">\n            <td><code><b>off</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;String&gt; <i>types</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes a previously added listener function. If no function is specified,\n                it will remove all the listeners of that particular DOM event from the element.\n                Note that if you passed a custom context to on, you must pass the same\n                context to <code>off</code> in order to remove the listener.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>eventMap</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes a set of type/listener pairs.</td>\n        </tr>\n        <tr id=\"domevent-stoppropagation\">\n            <td><code><b>stopPropagation</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Stop the given event from propagation to parent elements. Used inside the listener functions:\n                <pre><code>DG.DomEvent.on(div, &#39;click&#39;, function (ev) {\n    DG.DomEvent.stopPropagation(ev);\n});</code></pre></td>\n        </tr>\n        <tr id=\"domevent-disablescrollpropagation\">\n            <td><code><b>disableScrollPropagation</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds <code>stopPropagation</code> to the element&#39;s <code>&#39;mousewheel&#39;</code> events (plus browser variants).</td>\n        </tr>\n        <tr id=\"domevent-disableclickpropagation\">\n            <td><code><b>disableClickPropagation</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds <code>stopPropagation</code> to the element&#39;s <code>&#39;click&#39;</code>, <code>&#39;doubleclick&#39;</code>,\n                <code>&#39;mousedown&#39;</code> and <code>&#39;touchstart&#39;</code> events (plus browser variants).</td>\n        </tr>\n        <tr id=\"domevent-preventdefault\">\n            <td><code><b>preventDefault</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Prevents the default action of the DOM Event <code>ev</code> from happening (such as\n                following a link in the href of the a element, or doing a POST request\n                with page reload when a <code>&lt;form&gt;</code> is submitted).\n                Use it inside listener functions.</td>\n        </tr>\n        <tr id=\"domevent-stop\">\n            <td><code><b>stop</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Does <code>stopPropagation</code> and <code>preventDefault</code> at the same time.</td>\n        </tr>\n        <tr id=\"domevent-getmouseposition\">\n            <td><code><b>getMousePosition</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i>,</nobr>\n                <nobr>&lt;HTMLElement&gt; <i>container?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Gets normalized mouse position from a DOM event relative to the\n                <code>container</code> or to the whole page if not specified.</td>\n        </tr>\n        <tr id=\"domevent-getwheeldelta\">\n            <td><code><b>getWheelDelta</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Gets normalized wheel delta from a mousewheel DOM event, in vertical\n                pixels scrolled (negative if scrolling down).\n                Events from pointing devices without precise scrolling are mapped to\n                a best guess of between 50-60 pixels.</td>\n        </tr>\n        <tr id=\"domevent-addlistener\">\n            <td><code><b>addListener</b>(\n                <nobr><i>…</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Alias to <a href=\"#domevent-on\"><code>DG.DomEvent.on</code></a></td>\n        </tr>\n        <tr id=\"domevent-removelistener\">\n            <td><code><b>removeListener</b>(\n                <nobr><i>…</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Alias to <a href=\"#domevent-off\"><code>DG.DomEvent.off</code></a></td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.DomUtil\n\nUtility functions to work with the <a href=\"https://developer.mozilla.org/docs/Web/API/Document_Object_Model\">DOM</a> tree.\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"domutil-get\">\n    \t\t<td><code><b>get</b>(\n    \t\t    <nobr>&lt;String|HTMLElement&gt; <i>id</i> )</nobr>\n    \t\t</code></td>\n\n\t\t    <td><code>HTMLElement</code></td>\n            <td>Returns an element given its DOM id, or returns the element itself\n                if it was passed directly.</td>\n\t    </tr>\n        <tr id=\"domutil-getstyle\">\n    \t\t<td><code><b>getStyle</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>styleAttrib</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>String</code></td>\n\t\t    <td>Returns the value for a certain style attribute on an element,\n                including computed values or values set through CSS.</td>\n    \t</tr>\n        <tr id=\"domutil-create\">\n\t\t    <td><code><b>create</b>(\n\t\t        <nobr>&lt;String&gt; <i>tagName</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>className?</i>,</nobr>\n\t\t        <nobr>&lt;HTMLElement&gt; <i>container?</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>HTMLElement</code></td>\n            <td>Creates an HTML element with <code>tagName</code>, sets its class to <code>className</code>,\n                and optionally appends it to <code>container</code> element.</td>\n    \t</tr>\n        <tr id=\"domutil-remove\">\n\t\t    <td><code><b>remove</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Removes <code>el</code> from its parent element</td>\n\t    </tr>\n        <tr id=\"domutil-empty\">\n\t\t    <td><code><b>empty</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n\t\t    <td>Removes all of <code>el</code>&#39;s children elements from <code>el</code></td>\n    \t</tr>\n        <tr id=\"domutil-tofront\">\n\t\t    <td><code><b>toFront</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Makes <code>el</code> the last children of its parent, so it renders in front of the other children.</td>\n    \t</tr>\n        <tr id=\"domutil-toback\">\n\t\t    <td><code><b>toBack</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Makes <code>el</code> the first children of its parent, so it renders back from the other children.</td>\n\t    </tr>\n        <tr id=\"domutil-hasclass\">\n\t\t    <td><code><b>hasClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the element&#39;s class attribute contains <code>name</code>.</td>\n\t    </tr>\n        <tr id=\"domutil-addclass\">\n    \t\t<td><code><b>addClass</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;String&gt; <i>name</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n            <td>Adds <code>name</code> to the element&#39;s class attribute.</td>\n    \t</tr>\n        <tr id=\"domutil-removeclass\">\n\t\t    <td><code><b>removeClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n            <td>Removes <code>name</code> from the element&#39;s class attribute.</td>\n\t    </tr>\n        <tr id=\"domutil-setclass\">\n\t\t    <td><code><b>setClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Sets the element&#39;s class.</td>\n\t    </tr>\n        <tr id=\"domutil-getclass\">\n    \t\t<td><code><b>getClass</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code>String</code></td>\n    \t\t<td>Returns the element&#39;s class.</td>\n    \t</tr>\n        <tr id=\"domutil-setopacity\">\n    \t\t<td><code><b>setOpacity</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;Number&gt; <i>opacity</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Set the opacity of an element. <code>opacity</code> must be a number from <code>0</code> to <code>1</code>.</td>\n    \t</tr>\n        <tr id=\"domutil-testprop\">\n\t\t    <td><code><b>testProp</b>(\n\t\t        <nobr>&lt;String[]&gt; <i>props</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>String|false</code></td>\n\t\t    <td>Goes through the array of style names and returns the first name\n                that is a valid style name for an element. If no such name is found,\n                it returns false. Useful for vendor-prefixed styles like <code>transform</code>.</td>\n\t    </tr>\n        <tr id=\"domutil-settransform\">\n\t\t    <td><code><b>setTransform</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>scale?</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Resets the 3D CSS transform of <code>el</code> so it is translated by <code>offset</code> pixels\n                and optionally scaled by <code>scale</code>. Does not have an effect if the\n                browser doesn&#39;t support 3D CSS transforms.</td>\n\t    </tr>\n        <tr id=\"domutil-setposition\">\n    \t\t<td><code><b>setPosition</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>position</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Sets the position of <code>el</code> to coordinates specified by <code>position</code>,\n                using CSS translate or top/left positioning depending on the browser\n                (used by Leaflet internally to position its layers).</td>\n\t    </tr>\n        <tr id=\"domutil-getposition\">\n\t\t    <td><code><b>getPosition</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n\t\t    <td>Returns the coordinates of an element previously positioned with setPosition.</td>\n\t    </tr>\n        <tr id=\"domutil-disabletextselection\">\n    \t\t<td><code><b>disableTextSelection</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Prevents the user from generating <code>selectstart</code> DOM events, usually generated\n                when the user drags the mouse through a page with text. Used internally\n                by Leaflet to override the behaviour of any click-and-drag interaction on\n                the map. Affects drag interactions on the whole document.</td>\n\t    </tr>\n        <tr id=\"domutil-enabletextselection\">\n\t\t    <td><code><b>enableTextSelection</b>()</code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Cancels the effects of a previous <a href=\"#domutil-disabletextselection\"><code>DG.DomUtil.disableTextSelection</code></a>.</td>\n\t    </tr>\n        <tr id=\"domutil-disableimagedrag\">\n\t\t    <td><code><b>disableImageDrag</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>As <a href=\"#domutil-disabletextselection\"><code>DG.DomUtil.disableTextSelection</code></a>, but\n                for <code>dragstart</code> DOM events, usually generated when the user drags an image.</td>\n\t    </tr>\n\t    <tr id=\"domutil-enableimagedrag\">\n    \t\t<td><code><b>enableImageDrag</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Cancels the effects of a previous <a href=\"#domutil-disabletextselection\"><code>DG.DomUtil.disableImageDrag</code></a>.</td>\n    \t</tr>\n        <tr id=\"domutil-preventoutline\">\n\t\t    <td><code><b>preventOutline</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Makes the <a href=\"https://developer.mozilla.org/docs/Web/CSS/outline\">outline</a>\n                of the element <code>el</code> invisible. Used internally by Leaflet to prevent\n                focusable elements from displaying an outline when the user performs a\n                drag interaction on them.</td>\n    \t</tr>\n    \t<tr id=\"domutil-restoreoutline\">\n\t    \t<td><code><b>restoreOutline</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Cancels the effects of a previous <a href=\"#domutil-preventoutline\"><code>DG.DomUtil.preventOutline</code></a>.</td>\n    \t</tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>TRANSFORM</b></code></td>\n            <td><code>String</code></td>\n            <td>Vendor-prefixed fransform style name (e.g. <code>&#39;webkitTransform&#39;</code> for WebKit).</td>\n        </tr>\n        <tr>\n            <td><code><b>TRANSITION</b></code></td>\n            <td><code>String</code></td>\n            <td>Vendor-prefixed transition style name.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.PosAnimation\n\nUsed internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.\n\n    var fx = new DG.PosAnimation();\n    fx.run(el, [300, 500], 0.5);\n\n#### Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"posanimation-start\">\n            <td><code><b>start</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired when the animation starts.</td>\n        </tr>\n        <tr id=\"posanimation-step\">\n            <td><code><b>step</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired continuously during the animation.</td>\n        </tr>\n        <tr id=\"posanimation-end\">\n            <td><code><b>end</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired when the animation ends.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"posanimation-run\">\n\t\t    <td><code><b>run</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>newPos</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>duration?</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>easeLinearity?</i>)</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n            <td>Run an animation of a given element to a new position, optionally setting\n                duration in seconds (<code>0.25</code> by default) and easing linearity factor (3rd\n                argument of the <a href=\"http://cubic-bezier.com/#0,0,.5,1\">cubic bezier curve</a>,\n                <code>0.5</code> by default).</td>\n\t    </tr>\n\t    <tr id=\"posanimation-stop\">\n\t\t    <td><code><b>stop</b>()</code></td>\n\t\t    <td><code></code></td>\n\t\t    <td>Stops the animation (if currently running).</td>\n\t    </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Draggable\n\nA class for making DOM elements draggable (including touch support).\nUsed internally for map and marker dragging. Only works for elements\nthat were positioned with [DG.DomUtil.setPosition](#domutil-setposition)\n\n    var draggable = new DG.Draggable(elementToDrag);\n    draggable.enable();\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"draggable-clicktolerance\">\n\t\t    <td><code><b>clickTolerance</b></code></td>\n\t\t    <td><code>Number</code></td>\n\t\t    <td><code>3</code></td>\n\t\t    <td>The max number of pixels a user can shift the mouse pointer during a click\n                for it to be considered a valid click (as opposed to a mouse drag).</td>\n    \t</tr>\n    </tbody>\n</table>\n\n#### Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n    \t<tr id=\"draggable-down\">\n    \t\t<td><code><b>down</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired when a drag is about to start.</td>\n    \t</tr>\n    \t<tr id=\"draggable-dragstart\">\n    \t\t<td><code><b>dragstart</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired when a drag starts</td>\n    \t</tr>\n    \t<tr id=\"draggable-predrag\">\n    \t\t<td><code><b>predrag</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired continuously during dragging <em>before</em> each corresponding\n                update of the element&#39;s position.\n                Fired continuously during dragging.</td>\n\t    </tr>\n\t    <tr id=\"draggable-dragend\">\n    \t\t<td><code><b>dragend</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/en/manual/events#event\">Event</a></code></td>\n            <td>Fired when the drag ends.</td>\n\t    </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"draggable-enable\">\n            <td><code><b>enable</b>()</code></td>\n            <td><code></code></td>\n            <td>Enables the dragging ability.</td>\n        </tr>\n        <tr id=\"draggable-disable\">\n            <td><code><b>disable</b>()</code></td>\n            <td><code></code></td>\n            <td>Disables the dragging ability.</td>\n        </td>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/manual/map.md",
    "content": "## Map\n\nThis section describes the central class of the maps API which is used to create a map on a page and manipulate it.\n\n{toc}\n\n### DG.Map\n\n#### Usage example\n\nInitialize the map on the &quot;map&quot; div with a given center and zoom:\n\n    var map = DG.map('map', {\n        center: [54.98, 82.89],\n        zoom: 13\n    });\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-l-map\">\n            <td><code><b>DG.map</b>(\n                <nobr>&lt;String&gt; <i>id</i></nobr>,\n                <nobr>&lt;Map options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Instantiates a map object given the DOM ID of a <code>&lt;div&gt;</code> element\n                and optionally an object literal with <code>Map options</code>.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.map</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i></nobr>,\n                <nobr>&lt;Map options&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Instantiates a map object given an instance of a <code>&lt;div&gt;</code> HTML element\n                and optionally an object literal with <code>Map options</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-prefercanvas\">\n            <td><code><b>preferCanvas</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Whether <a href=\"/doc/maps/en/manual/vector-layers#dgpath\"><code>Path</code></a>s\n                should be rendered on a <a href=\"/doc/maps/en/manual/vector-layers#dgcanvas\">\n                <code>Canvas</code></a> renderer. By default, all <code>Path</code>s are\n                rendered in a <a href=\"/doc/maps/en/manual/vector-layers#dgsvg\"><code>SVG</code></a> renderer.\n            </td>\n        </tr>\n        <tr id=\"map-protocol\">\n            <td><code><b>protocol</b></code></td>\n            <td><code>String </code></td>\n            <td><code>''</code></td>\n            <td>Network protocol used in tiles requests.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Control Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"map-zoomcontrol\">\n            <td><code><b>zoomControl</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether a <a href=\"/doc/maps/en/manual/controls#dgcontrolzoom\">zoom control</a>\n                is added to the map by default.\n            </td>\n        </tr>\n        <tr id=\"map-fullscreencontrol\">\n            <td><code><b>fullscreenControl</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether a <a href=\"/doc/maps/en/manual/controls#dgcontrolfullscreen\">fullscreen control</a>\n                is added to the map by default.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Interaction Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-closepopuponclick\">\n            <td><code><b>closePopupOnClick</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Set it to <code>false</code> if you don&#39;t want popups to close when user clicks the map.</td>\n        </tr>\n        <tr id=\"map-zoomsnap\">\n            <td><code><b>zoomSnap</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>Forces the map&#39;s zoom level to always be a multiple of this,\n                particularly right after a <a href=\"#map-fitbounds\"><code>fitBounds()</code></a>\n                or a pinch-zoom. By default, the zoom level snaps to the nearest integer;\n                lower values (e.g. <code>0.5</code> or <code>0.1</code>) allow for greater\n                granularity. A value of <code>0</code> means the zoom level will not be snapped after\n                <code>fitBounds</code> or a pinch-zoom.\n            </td>\n        </tr>\n        <tr id=\"map-zoomdelta\">\n            <td><code><b>zoomDelta</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>Controls how much the map&#39;s zoom level will change after a\n                <a href=\"#map-zoomin\"><code>zoomIn()</code></a>,\n                <a href=\"#map-zoomout\"><code>zoomOut()</code></a>, pressing <code>+</code> or\n                <code>-</code> on the keyboard, or using the\n                <a href=\"/doc/maps/en/manual/controls#dgcontrolzoom\">zoom controls</a>.\n                Values smaller than <code>1</code> (e.g. <code>0.5</code>) allow for greater granularity.\n            </td>\n        </tr>\n        <tr id=\"map-trackresize\">\n            <td><code><b>trackResize</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the map automatically handles browser window resize to update itself.</td>\n        </tr>\n        <tr id=\"map-boxzoom\">\n            <td><code><b>boxZoom</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the map can be zoomed to a rectangular area specified by dragging\n                the mouse while pressing the shift key.\n            </td>\n        </tr>\n        <tr id=\"map-doubleclickzoom\">\n            <td><code><b>doubleClickZoom</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the map can be zoomed in by double clicking on it and zoomed out by\n                double clicking while holding shift. If passed <code>&#39;center&#39;</code>,\n                double-click zoom will zoom to the center of the view regardless of where the mouse was.\n            </td>\n        </tr>\n        <tr id=\"map-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the map be draggable with mouse/touch or not.</td>\n        </tr>\n        <tr id=\"map-geoclicker\">\n            <td><code><b>geoclicker</b></code></td>\n            <td><code>Boolean | Object</code></td>\n            <td><code>false</code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-projectdetector\">\n            <td><code><b>projectDetector</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-tilescheck\">\n            <td><code><b>tilesCheck</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-museum\">\n            <td><code><b>museum</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Whether the message about unsupported browser will be displayed.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Map State Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-center\">\n            <td><code><b>center</b></code></td>\n            <td><code>LatLng </code></td>\n            <td><code>undefined</code></td>\n            <td>Initial geographic center of the map</td>\n        </tr>\n        <tr id=\"map-zoom\">\n            <td><code><b>zoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Initial map zoom level</td>\n        </tr>\n        <tr id=\"map-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Minimum zoom level of the map. Overrides any <code>minZoom</code> option set on map layers.</td>\n        </tr>\n        <tr id=\"map-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Maximum zoom level of the map. Overrides any <code>maxZoom</code> option set on map layers.</td>\n        </tr>\n        <tr id=\"map-layers\">\n            <td><code><b>layers</b></code></td>\n            <td><code>Layer[] </code></td>\n            <td><code>[]</code></td>\n            <td>Array of layers that will be added to the map initially</td>\n        </tr>\n        <tr id=\"map-maxbounds\">\n            <td><code><b>maxBounds</b></code></td>\n            <td><code>LatLngBounds </code></td>\n            <td><code>null</code></td>\n            <td>When this option is set, the map restricts the view to the given geographical bounds,\n                bouncing the user back when he tries to pan outside the view. To set the restriction\n                dynamically, use <a href=\"#map-setmaxbounds\"><code>setMaxBounds</code></a> method.</td>\n        </tr>\n        <tr id=\"map-renderer\">\n            <td><code><b>renderer</b></code></td>\n            <td><code>Renderer </code></td>\n            <td><code>*</code></td>\n            <td>The default method for drawing vector layers on the map.\n                <a href=\"/doc/maps/en/manual/vector-layers#dgsvg\"><code>DG.SVG</code></a>\n                or <a href=\"/doc/maps/en/manual/vector-layers#dgcanvas\"><code>DG.Canvas</code></a>\n                by default depending on browser support.\n            </td>\n        </tr>\n        <tr id=\"map-poi\">\n            <td><code><b>poi</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-currentlang\">\n            <td><code><b>currentLang</b></code></td>\n            <td><code>string</code></td>\n            <td><code>''</code></td>\n            <td>Language of user interface (see <a href=\"/doc/maps/en/manual/dg-locale/\">Localization</a>)</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Animation Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-fadeanimation\">\n            <td><code><b>fadeAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the tile fade animation is enabled. By default it&#39;s enabled\n                in all browsers that support CSS3 Transitions except Android.\n            </td>\n        </tr>\n        <tr id=\"map-markerzoomanimation\">\n            <td><code><b>markerZoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether markers animate their zoom with the zoom animation, if disabled they\n                will disappear for the length of the animation. By default it&#39;s enabled\n                in all browsers that support CSS3 Transitions except Android.\n            </td>\n        </tr>\n        <tr id=\"map-transform3dlimit\">\n            <td><code><b>transform3DLimit</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>2^23</code></td>\n            <td>Defines the maximum size of a CSS translation transform. The default value should\n                not be changed unless a web browser positions layers in the wrong place after doing\n                a large <code>panBy</code>.\n            </td>\n        </tr>\n        <tr id=\"map-zoomanimation\">\n            <td><code><b>zoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the map zoom animation is enabled. By default it&#39;s enabled in all browsers\n                that support CSS3 Transitions except Android.\n            </td>\n        </tr>\n        <tr id=\"map-zoomanimationthreshold\">\n            <td><code><b>zoomAnimationThreshold</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>4</code></td>\n            <td>Won&#39;t animate zoom if the zoom difference exceeds this value.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Panning Inertia Options\n\n<table>\n    <thead>\n\t<tr>\n\t\t<th>Option</th>\n\t\t<th>Type</th>\n\t\t<th>Default</th>\n\t\t<th>Description</th>\n\t</tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-inertia\">\n            <td><code><b>inertia</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>*</code></td>\n            <td>If enabled, panning of the map will have an inertia effect where the map builds\n                momentum while dragging and continues moving in the same direction for some time.\n                Feels especially nice on touch devices. Enabled by default unless running on old\n                Android devices.\n            </td>\n        </tr>\n        <tr id=\"map-inertiadeceleration\">\n            <td><code><b>inertiaDeceleration</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>3000</code></td>\n            <td>The rate with which the inertial movement slows down, in pixels/second².</td>\n        </tr>\n        <tr id=\"map-inertiamaxspeed\">\n            <td><code><b>inertiaMaxSpeed</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>Infinity</code></td>\n            <td>Max speed of the inertial movement, in pixels/second.</td>\n        </tr>\n        <tr id=\"map-easelinearity\">\n            <td><code><b>easeLinearity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.2</code></td>\n            <td></td>\n        </tr>\n        <tr id=\"map-worldcopyjump\">\n            <td><code><b>worldCopyJump</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>With this option enabled, the map tracks when you pan to another &quot;copy&quot;\n                of the world and seamlessly jumps to the original one so that all overlays like\n                markers and vector layers are still visible.\n            </td>\n        </tr>\n        <tr id=\"map-maxboundsviscosity\">\n            <td><code><b>maxBoundsViscosity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.0</code></td>\n            <td>If <code>maxBounds</code> is set, this option will control how solid the bounds\n                are when dragging the map around. The default value of <code>0.0</code> allows\n                the user to drag outside the bounds at normal speed, higher values will slow down\n                map dragging outside bounds, and <code>1.0</code> makes the bounds fully solid,\n                preventing the user from dragging outside the bounds.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Keyboard Navigation Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Makes the map focusable and allows users to navigate the map with keyboard\n                arrows and <code>+</code>/<code>-</code> keys.\n            </td>\n        </tr>\n        <tr id=\"map-keyboardpandelta\">\n            <td><code><b>keyboardPanDelta</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>80</code></td>\n            <td>Amount of pixels to pan when pressing an arrow key.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Mousewheel options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-scrollwheelzoom\">\n            <td><code><b>scrollWheelZoom</b></code></td>\n            <td><code>Boolean | String</code></td>\n            <td><code>true</code></td>\n            <td>Whether the map can be zoomed by using the mouse wheel. If passed\n                <code>&#39;center&#39;</code>, it will zoom to the center of the view\n                regardless of where the mouse was.</td>\n        </tr>\n        <tr id=\"map-wheeldebouncetime\">\n            <td><code><b>wheelDebounceTime</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>40</code></td>\n            <td>Limits the rate at which a wheel can fire (in milliseconds). By default\n                user can&#39;t zoom via wheel more often than once per 40 ms.\n            </td>\n        </tr>\n        <tr id=\"map-wheelpxperzoomlevel\">\n            <td><code><b>wheelPxPerZoomLevel</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>50</code></td>\n            <td>How many scroll pixels (as reported by\n                <a href=\"/doc/maps/en/manual/dom-utils#domevent-getwheeldelta>DG.DomEvent.getWheelDelta</a>)\n                mean a change of one full zoom level. Smaller values will make wheel-zooming\n                faster (and vice versa).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Touch interaction options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-tap\">\n            <td><code><b>tap</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Enables mobile hacks for supporting instant taps (fixing 200ms click\n                delay on iOS/Android) and touch holds (fired as <code>contextmenu</code> events).\n            </td>\n        </tr>\n        <tr id=\"map-taptolerance\">\n            <td><code><b>tapTolerance</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>15</code></td>\n            <td>The max number of pixels a user can shift his finger during touch\n                for it to be considered a valid tap.\n            </td>\n        </tr>\n        <tr id=\"map-touchzoom\">\n            <td><code><b>touchZoom</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>*</code></td>\n            <td>Whether the map can be zoomed by touch-dragging with two fingers. If\n                passed <code>&#39;center&#39;</code>, it will zoom to the center of the view regardless of\n                where the touch events (fingers) were. Enabled for touch-capable web\n                browsers except for old Androids.\n            </td>\n        </tr>\n        <tr id=\"map-bounceatzoomlimits\">\n            <td><code><b>bounceAtZoomLimits</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Set it to false if you don&#39;t want the map to zoom beyond min/max zoom\n                and then bounce back when pinch-zooming.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\n##### Layer events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-layeradd\">\n            <td><code><b>layeradd</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#layerevent\">LayerEvent</a></code></td>\n            <td>Fired when a new layer is added to the map.</td>\n        </tr>\n        <tr id=\"map-layerremove\">\n            <td><code><b>layerremove</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#layerevent\">LayerEvent</a></code></td>\n            <td>Fired when some layer is removed from the map</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Map state change events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-zoomlevelschange\">\n            <td><code><b>zoomlevelschange</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the number of zoomlevels on the map is changed due\n                to adding or removing a layer.\n            </td>\n        </tr>\n        <tr id=\"map-resize\">\n            <td><code><b>resize</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map is resized.</td>\n        </tr>\n        <tr id=\"map-unload\">\n            <td><code><b>unload</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map is destroyed with <a href=\"#map-remove\">remove</a> method.</td>\n        </tr>\n        <tr id=\"map-viewreset\">\n            <td><code><b>viewreset</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map needs to redraw its content (this usually happens\n                on map zoom or load). Very useful for creating custom overlays.\n            </td>\n        </tr>\n        <tr id=\"map-load\">\n            <td><code><b>load</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map is initialized (when its center and zoom are set\n                for the first time).\n            </td>\n        </tr>\n        <tr id=\"map-zoomstart\">\n            <td><code><b>zoomstart</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map zoom is about to change (e.g. before zoom animation).</td>\n        </tr>\n        <tr id=\"map-movestart\">\n            <td><code><b>movestart</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the view of the map starts changing (e.g. user starts dragging the map).</td>\n        </tr>\n        <tr id=\"map-zoom\">\n            <td><code><b>zoom</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired repeteadly during any change in zoom level, including zoom\n                and fly animations.\n            </td>\n        </tr>\n        <tr id=\"map-move\">\n            <td><code><b>move</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired repeteadly during any movement of the map, including pan and\n                fly animations.\n            </td>\n        </tr>\n        <tr id=\"map-zoomend\">\n            <td><code><b>zoomend</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the map has changed, after any animations.</td>\n        </tr>\n        <tr id=\"map-moveend\">\n            <td><code><b>moveend</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the center of the map stops changing (e.g. user stopped\n                dragging the map).\n            </td>\n        </tr>\n        <tr id=\"map-projectchange\">\n            <td><code><b>projectchange</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#projectevent\">ProjectEvent</a></code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-projectleave\">\n            <td><code><b>projectleave</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#projectevent\">ProjectEvent</a></code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n        <tr id=\"map-entranceshow\">\n            <td><code><b>entranceshow</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-entrancehide\">\n            <td><code><b>entrancehide</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-poihover\">\n            <td><code><b>poihover</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#poievent\">MetaEvent</a></code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-poileave\">\n            <td><code><b>poileave</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#poievent\">MetaEvent</a></code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-langchange\">\n            <td><code><b>langchange</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#langevent\">LangEvent</a></code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n    </tbody>\n</table>\n\n##### Popup events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup is opened in the map</td>\n        </tr>\n        <tr id=\"map-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup in the map is closed</td>\n        </tr>\n        <tr id=\"map-autopanstart\">\n            <td><code><b>autopanstart</b></code></td>\n            <td><code></code></td>\n            <td>Fired when the map starts autopanning when opening a popup.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Interaction events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-click\">\n            <td><code><b>click</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user clicks (or taps) the map.</td>\n        </tr>\n        <tr id=\"map-dblclick\">\n            <td><code><b>dblclick</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user double-clicks (or double-taps) the map.</td>\n        </tr>\n        <tr id=\"map-mousedown\">\n            <td><code><b>mousedown</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user pushes the mouse button on the map.</td>\n        </tr>\n        <tr id=\"map-mouseup\">\n            <td><code><b>mouseup</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user releases the mouse button on the map.</td>\n        </tr>\n        <tr id=\"map-mouseover\">\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the mouse enters the map.</td>\n        </tr>\n        <tr id=\"map-mouseout\">\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the mouse leaves the map.</td>\n        </tr>\n        <tr id=\"map-mousemove\">\n            <td><code><b>mousemove</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired while the mouse moves over the map.</td>\n        </tr>\n        <tr id=\"map-contextmenu\">\n            <td><code><b>contextmenu</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user pushes the right mouse button on the map, prevents\n                default browser context menu from showing if there are listeners on\n                this event. Also fired on mobile when the user holds a single touch\n                for a second (also called long press).\n            </td>\n        </tr>\n        <tr id=\"map-keypress\">\n            <td><code><b>keypress</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the user presses a key from the keyboard while the map is focused.</td>\n        </tr>\n        <tr id=\"map-preclick\">\n            <td><code><b>preclick</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired before mouse click on the map (sometimes useful when you\n                want something to happen on click before any existing click\n                handlers start running).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Animation Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-zoomanim\">\n            <td><code><b>zoomanim</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#zoomanimevent\">ZoomAnimEvent</a></code></td>\n            <td>Fired on every frame of a zoom animation</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Location Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-locationerror\">\n            <td><code><b>locationerror</b></code></td>\n            <td><code><a href=\"#errorevent\">ErrorEvent</a></code></td>\n            <td>Fired when geolocation (using the <a href=\"#map-locate\"><code>locate</code></a> method) failed.</td>\n        </tr>\n        <tr id=\"map-locationfound\">\n            <td><code><b>locationfound</b></code></td>\n            <td><code><a href=\"#locationevent\">LocationEvent</a></code></td>\n            <td>Fired when geolocation (using the <a href=\"#map-locate\"><code>locate</code></a> method)\n                went successfully.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getrenderer\">\n            <td>\n                <code>\n                    <b>getRenderer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/vector-layers#dgpath\">Path</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dgrenderer\">Renderer</a></code></td>\n            <td>Returns the instance of\n                <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\"><code>Renderer</code></a>\n                that should be used to render the given\n                <a href=\"/doc/maps/en/manual/vector-layers#dgpath\"><code>Path</code></a>.\n                It will ensure that the\n                <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\"><code>renderer</code></a>\n                options of the map and paths are respected, and that the renderers do exist on the map.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Methods for Layers and Controls\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-addlayer\">\n            <td>\n                <code>\n                    <b>addLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Adds the given layer to the map</td>\n        </tr>\n        <tr id=\"map-removelayer\">\n            <td>\n                <code>\n                    <b>removeLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Removes the given layer from the map.</td>\n        </tr>\n        <tr id=\"map-haslayer\">\n            <td>\n                <code>\n                    <b>hasLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the given layer is currently added to the map</td>\n        </tr>\n        <tr id=\"map-eachlayer\">\n            <td>\n                <code>\n                    <b>eachLayer</b>(\n                    <nobr>&lt;Function&gt; <i>fn</i></nobr>,\n                    <nobr>&lt;Object&gt; <i>context?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>\n                Iterates over the layers of the map, optionally specifying context of the iterator function.\n<pre><code>map.eachLayer(function(layer){\n    layer.bindPopup(&#39;Hello&#39;);\n});\n</code></pre>\n            </td>\n        </tr>\n        <tr id=\"map-openpopup\">\n            <td>\n                <code>\n                    <b>openPopup</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/popup#dgpopup\">Popup</a>&gt; <i>popup</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Opens the specified popup while closing the previously opened (to make\n                sure only one is opened at one time for usability).\n            </td>\n        </tr>\n        <tr id=\"map-openpopup\">\n            <td>\n                <code>\n                    <b>openPopup</b>(\n                    <nobr>&lt;String|HTMLElement&gt; <i>content</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Creates a popup with the specified content and options and opens\n                it in the given point on a map.\n            </td>\n        </tr>\n        <tr id=\"map-closepopup\">\n            <td>\n                <code>\n                    <b>closePopup</b>(<nobr>&lt;<a href=\"/doc/maps/en/manual/popup#dgpopup\">Popup</a>&gt; <i>popup?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Closes the popup previously opened with <a href=\"#map-openpopup\">openPopup</a>\n                (or the given one).\n            </td>\n        </tr>\n        <tr id=\"map-addcontrol\">\n            <td>\n                <code>\n                    <b>addControl</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/controls#dgcontrol\">Control</a>&gt; <i>control</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Adds the given control to the map</td>\n        </tr>\n        <tr id=\"map-removecontrol\">\n            <td>\n                <code>\n                    <b>removeControl</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/controls#dgcontrol\">Control</a>&gt; <i>control</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Removes the given control from the map</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Methods for modifying map state\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-setview\">\n            <td>\n                <code>\n                    <b>setView</b>(\n                    <nobr>&lt;LatLnt&gt; <i>center</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets the view of the map (geographical center and zoom) with the given\n                animation options.\n            </td>\n        </tr>\n        <tr id=\"map-setzoom\">\n            <td>\n                <code>\n                    <b>setZoom</b>(\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets the zoom of the map.</td>\n        </tr>\n        <tr id=\"map-zoomin\">\n            <td>\n                <code>\n                    <b>zoomIn</b>(\n                    <nobr>&lt;Number&gt; <i>delta?</i></nobr>,\n                    <nobr>&lt;<a href=\"#zoom-options\">Zoom options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Increases the zoom of the map by <code>delta</code>\n                (<a href=\"#map-zoomdelta\"><code>zoomDelta</code></a> by default).\n            </td>\n        </tr>\n        <tr id=\"map-zoomout\">\n            <td>\n                <code>\n                    <b>zoomOut</b>(\n                    <nobr>&lt;Number&gt; <i>delta?</i></nobr>,\n                    <nobr>&lt;<a href=\"#zoom-options\">Zoom options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Decreases the zoom of the map by <code>delta</code>\n                (<a href=\"#map-zoomdelta\"><code>zoomDelta</code></a> by default).\n            </td>\n        </tr>\n        <tr id=\"map-setzoomaround\">\n            <td>\n                <code>\n                    <b>setZoomAround</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;<a href=\"#zoom-options\">Zoom options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Zooms the map while keeping a specified geographical point on the map\n                stationary (e.g. used internally for scroll zoom and double-click zoom).\n            </td>\n        </tr>\n        <tr id=\"map-setzoomaround\">\n            <td>\n                <code>\n                    <b>setZoomAround</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;<a href=\"#zoom-options\">Zoom options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Zooms the map while keeping a specified pixel on the map\n                (relative to the top-left corner) stationary.\n            </td>\n        </tr>\n        <tr id=\"map-fitbounds\">\n            <td>\n                <code>\n                    <b>fitBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#fitbounds-options\">fitBounds options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets a map view that contains the given geographical bounds with the\n                maximum zoom level possible.\n            </td>\n        </tr>\n        <tr id=\"map-fitworld\">\n            <td>\n                <code>\n                    <b>fitWorld</b>(\n                    <nobr>&lt;<a href=\"#fitbounds-options\">fitBounds options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets a map view that mostly contains the whole world with the maximum\n                zoom level possible.\n            </td>\n        </tr>\n        <tr id=\"map-panto\">\n            <td>\n                <code>\n                    <b>panTo</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"#pan-options\">Pan options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Pans the map to a given center.\n            </td>\n        </tr>\n        <tr id=\"map-panby\">\n            <td>\n                <code>\n                    <b>panBy</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Pans the map by a given number of pixels (animated).\n            </td>\n        </tr>\n        <tr id=\"map-setmaxbounds\">\n            <td>\n                <code>\n                    <b>setMaxBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgbounds\">Bounds</a>&gt; <i>bounds</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Restricts the map view to the given bounds (see the\n                <a href=\"#map-maxbounds\">maxBounds</a> option).\n            </td>\n        </tr>\n        <tr id=\"map-setminzoom\">\n            <td><code><b>setMinZoom</b>(<nobr>&lt;Number&gt; <i>zoom</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the lower limit for the available zoom levels\n                (see the <a href=\"#map-minzoom\">minZoom</a> option).\n            </td>\n        </tr>\n        <tr id=\"map-setmaxzoom\">\n            <td><code><b>setMaxZoom</b>(<nobr>&lt;Number&gt; <i>zoom</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the upper limit for the available zoom levels\n                (see the <a href=\"#map-maxzoom\">maxZoom</a> option).\n            </td>\n        </tr>\n        <tr id=\"map-paninsidebounds\">\n            <td>\n                <code>\n                    <b>panInsideBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#pan-options\">Pan options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Pans the map to the closest view that would lie inside the given bounds\n                (if it&#39;s not already), controlling the animation using the options specific, if any.\n            </td>\n        </tr>\n        <tr id=\"map-invalidatesize\">\n            <td><code><b>invalidateSize</b>(<nobr>&lt;Zoom/Pan options&gt; <i>options</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Checks if the map container size changed and updates the map if so —\n                call it after you&#39;ve changed the map size dynamically, also animating\n                pan by default. If <code>options.pan</code> is <code>false</code>, panning will not occur.\n                If <code>options.debounceMoveend</code> is <code>true</code>, it will delay <code>moveend</code>\n                event so that it doesn&#39;t happen often even if the method is called many\n                times in a row.\n            </td>\n        </tr>\n        <tr id=\"map-invalidatesize\">\n            <td><code><b>invalidateSize</b>(<nobr>&lt;Boolean&gt; <i>animate</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Checks if the map container size changed and updates the map if so —\n                call it after you&#39;ve changed the map size dynamically, also animating\n                pan by default.\n            </td>\n        </tr>\n        <tr id=\"map-stop\">\n            <td><code><b>stop</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Stops the currently running <code>panTo</code> or <code>flyTo</code> animation, if any.\n            </td>\n        </tr>\n        <tr id=\"map-flyto\">\n            <td>\n                <code>\n                    <b>flyTo</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom?</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets the view of the map (geographical center and zoom) performing a smooth\n                pan-zoom animation.\n            </td>\n        </tr>\n        <tr id=\"map-flytobounds\">\n            <td>\n                <code>\n                    <b>flyToBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#fitbounds-options\">fitBounds options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Sets the view of the map with a smooth animation like\n                <a href=\"#map-flyto\"><code>flyTo</code></a>,\n                but takes a bounds parameter like <a href=\"#map-fitbounds\"><code>fitBounds</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-setlang\">\n            <td><code><b>setLang</b>( <nobr>&lt;String&gt; <i>lang</i> )</nobr></code></td>\n            <td><code>String</code></td>\n            <td>\n                <!-- TODO: translation -->\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Other Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-addhandler\">\n            <td>\n                <code>\n                    <b>addHandler</b>(\n                    <nobr>&lt;String&gt; <i>name</i></nobr>,\n                    <nobr>&lt;Function&gt; <i>HandlerClass</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Adds a new <a href=\"/doc/maps/en/manual/base-classes#dghandler\"><code>Handler</code></a> to the map,\n                given its name and constructor function.\n            </td>\n        </tr>\n        <tr id=\"map-remove\">\n            <td><code><b>remove</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Destroys the map and clears all related event listeners.\n        </td>\n        </tr>\n        <tr id=\"map-createpane\">\n            <td>\n                <code>\n                    <b>createPane</b>(\n                    <nobr>&lt;String&gt; <i>name</i></nobr>,\n                    <nobr>&lt;HTMLElement&gt; <i>container?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>HTMLElement</code></td>\n            <td>Creates a new map pane with the given name if it doesn&#39;t exist already,\n                then returns it. The pane is created as a children of <code>container</code>, or\n                as a children of the main map pane if not set.\n            </td>\n        </tr>\n        <tr id=\"map-getpane\">\n            <td><code><b>getPane</b>(<nobr>&lt;String|HTMLElement&gt; <i>pane</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Returns a map pane, given its name or its HTML element (its identity).</td>\n        </tr>\n        <tr id=\"map-getpanes\">\n            <td><code><b>getPanes</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Returns a plain object containing the names of all panes as keys and\n                the panes as values.\n            </td>\n        </tr>\n        <tr id=\"map-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Returns the HTML element that contains the map.</td>\n        </tr>\n        <tr id=\"map-whenready\">\n            <td>\n                <code>\n                    <b>whenReady</b>(\n                    <nobr>&lt;Function&gt; <i>fn</i></nobr>,\n                    <nobr>&lt;Object&gt; <i>context?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Runs the given function <code>fn</code> when the map gets initialized with\n                a view (center and zoom) and at least one layer, or immediately\n                if it&#39;s already initialized, optionally passing a function context.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Methods for Getting Map State\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns the geographical center of the map view</td>\n        </tr>\n        <tr id=\"map-getzoom\">\n            <td><code><b>getZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Returns the current zoom level of the map view</td>\n        </tr>\n        <tr id=\"map-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns the geographical bounds visible in the current map view</td>\n        </tr>\n        <tr id=\"map-getminzoom\">\n            <td><code><b>getMinZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Returns the minimum zoom level of the map (if set in the <code>minZoom</code>\n                option of the map or of any layers), or <code>0</code> by default.\n            </td>\n        </tr>\n        <tr id=\"map-getmaxzoom\">\n            <td><code><b>getMaxZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Returns the maximum zoom level of the map (if set in the <code>maxZoom</code>\n                option of the map or of any layers).\n            </td>\n        </tr>\n        <tr id=\"map-getboundszoom\">\n            <td>\n                <code>\n                    <b>getBoundsZoom</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;Boolean&gt; <i>inside?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Returns the maximum zoom level on which the given bounds fit to the map\n                view in its entirety. If <code>inside</code> (optional) is set to <code>true</code>, the method\n                instead returns the minimum zoom level on which the map view fits into\n                the given bounds in its entirety.\n            </td>\n        </tr>\n        <tr id=\"map-getsize\">\n            <td><code><b>getSize</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Returns the current size of the map container (in pixels).</td>\n        </tr>\n        <tr id=\"map-getpixelbounds\">\n            <td><code><b>getPixelBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgbounds\">Bounds</a></code></td>\n            <td>Returns the bounds of the current map view in projected pixel\n                coordinates (sometimes useful in layer and overlay implementations).\n            </td>\n        </tr>\n        <tr id=\"map-getpixelorigin\">\n            <td><code><b>getPixelOrigin</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Returns the projected pixel coordinates of the top left point of\n                the map layer (useful in custom layer and overlay implementations).\n            </td>\n        </tr>\n        <tr id=\"map-getpixelworldbounds\">\n            <td>\n                <code>\n                    <b>getPixelWorldBounds</b>(\n                    <nobr>&lt;Number&gt; <i>zoom?</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgbounds\">Bounds</a></code></td>\n            <td>Returns the world&#39;s bounds in pixel coordinates for zoom level <code>zoom</code>.\n                If <code>zoom</code> is omitted, the map&#39;s current zoom level is used.\n            </td>\n        </tr>\n        <tr id=\"map-getlang\">\n            <td><code><b>getLang</b>()</code></td>\n            <td><code>String</code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n    </tbody>\n</table>\n\n##### Conversion Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getzoomscale\">\n            <td>\n                <code>\n                    <b>getZoomScale</b>(\n                    <nobr>&lt;Number&gt; <i>toZoom</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>fromZoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Returns the scale factor to be applied to a map transition from zoom level\n                <code>fromZoom</code> to <code>toZoom</code>. Used internally to help with zoom animations.\n            </td>\n        </tr>\n        <tr id=\"map-getscalezoom\">\n            <td>\n                <code><b>getScaleZoom</b>(\n                <nobr>&lt;Number&gt; <i>scale</i></nobr>,\n                <nobr>&lt;Number&gt; <i>fromZoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Returns the zoom level that the map would end up at, if it is at <code>fromZoom</code>\n                level and everything is scaled by a factor of <code>scale</code>. Inverse of\n                <a href=\"#map-getZoomScale\"><code>getZoomScale</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-project\">\n            <td>\n                <code>\n                    <b>project</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Projects a geographical coordinate <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a>\n                according to the projection of the map&#39;s CRS, then scales it according to\n                <code>zoom</code> and the CRS&#39;s\n                <a href=\"#transformation\"><code>Transformation</code></a>. The result is pixel coordinate relative to\n                the CRS origin.\n            </td>\n        </tr>\n        <tr id=\"map-unproject\">\n            <td>\n                <code>\n                    <b>unproject</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Inverse of <a href=\"#map-project\"><code>project</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-layerpointtolatlng\">\n            <td>\n                <code>\n                    <b>layerPointToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Given a pixel coordinate relative to the <a href=\"#map-getpixelorigin\">origin pixel</a>,\n                returns the corresponding geographical coordinate (for the current zoom level).\n            </td>\n        </tr>\n        <tr id=\"map-latlngtolayerpoint\">\n            <td>\n                <code>\n                    <b>latLngToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a geographical coordinate, returns the corresponding pixel coordinate\n                relative to the <a href=\"#map-getpixelorigin\">origin pixel</a>.\n            </td>\n        </tr>\n        <tr id=\"map-wraplatlng\">\n            <td>\n                <code>\n                    <b>wrapLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns a <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a> where <code>lat</code>\n                and <code>lng</code> has been wrapped according to the\n                map&#39;s CRS&#39;s <code>wrapLat</code> and <code>wrapLng</code> properties, if they are outside the\n                CRS&#39;s bounds.\n                By default this means longitude is wrapped around the dateline so its\n                value is between -180 and +180 degrees.\n            </td>\n        </tr>\n        <tr id=\"map-distance\">\n            <td>\n                <code>\n                    <b>distance</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng1</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng2</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Returns the distance between two geographical coordinates according to\n                the map&#39;s CRS. By default this measures distance in meters.\n            </td>\n        </tr>\n        <tr id=\"map-containerpointtolayerpoint\">\n            <td>\n                <code>\n                    <b>containerPointToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a pixel coordinate relative to the map container, returns the corresponding\n                pixel coordinate relative to the <a href=\"#map-getpixelorigin\">origin pixel</a>.\n            </td>\n        </tr>\n        <tr id=\"map-layerpointtocontainerpoint\">\n            <td>\n                <code>\n                    <b>layerPointToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a pixel coordinate relative to the <a href=\"#map-getpixelorigin\">origin pixel</a>,\n                returns the corresponding pixel coordinate relative to the map container.\n            </td>\n        </tr>\n        <tr id=\"map-containerpointtolatlng\">\n            <td>\n                <code>\n                    <b>containerPointToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a pixel coordinate relative to the map container, returns\n                the corresponding geographical coordinate (for the current zoom level).\n            </td>\n        </tr>\n        <tr id=\"map-latlngtocontainerpoint\">\n            <td>\n                <code>\n                    <b>latLngToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a geographical coordinate, returns the corresponding pixel coordinate\n                relative to the map container.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtocontainerpoint\">\n            <td>\n                <code>\n                    <b>mouseEventToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a MouseEvent object, returns the pixel coordinate relative to the\n                map container where the event took place.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtolayerpoint\">\n            <td>\n                <code>\n                    <b>mouseEventToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Given a MouseEvent object, returns the pixel coordinate relative to\n                the <a href=\"#map-getpixelorigin\">origin pixel</a> where the event took place.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtolatlng\">\n            <td>\n                <code>\n                    <b>mouseEventToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Given a MouseEvent object, returns geographical coordinate where the\n                event took place.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Geolocation methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead\n    ><tbody>\n        <tr id=\"map-locate\">\n            <td>\n                <code>\n                    <b>locate</b>(\n                    <nobr>&lt;<a href=\"#locate-options\">Locate options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Tries to locate the user using the Geolocation API, firing a <code>locationfound</code>\n                event with location data on success or a <code>locationerror</code> event on failure,\n                and optionally sets the map view to the user&#39;s location with respect to\n                detection accuracy (or to the world view if geolocation failed).\n                See <a href=\"#locate-options\"><code>Locate options</code></a> for more details.\n            </td>\n        </tr>\n        <tr id=\"map-stoplocate\">\n            <td><code><b>stopLocate</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Stops watching location previously initiated by <code>map.locate({watch: true})</code>\n                and aborts resetting the map view if map.locate was called with\n                <code>{setView: true}</code>.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Methods inherited from Evented\n\nMethods inherited from Evented see <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">here</a>.\n\n### Properties\n\n<!-- TODO: translation -->\n\n#### Handlers\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-boxzoom\">\n            <td><code><b>boxZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Box (shift-drag with mouse) zoom handler.</td>\n        </tr>\n        <tr id=\"map-doubleclickzoom\">\n            <td><code><b>doubleClickZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Double click zoom handler.</td>\n        </tr>\n        <tr id=\"map-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Map dragging handler (by both mouse and touch).</td>\n        </tr>\n        <tr id=\"map-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Keyboard navigation handler.</td>\n        </tr>\n        <tr id=\"map-scrollwheelzoom\">\n            <td><code><b>scrollWheelZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Scroll wheel zoom handler.</td>\n        </tr>\n        <tr id=\"map-tap\">\n            <td><code><b>tap</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Mobile touch hacks (quick tap and touch hold) handler.</td>\n        </tr>\n        <tr id=\"map-touchzoom\">\n            <td><code><b>touchZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Touch zoom handler.</td>\n        </tr>\n        <tr id=\"map-geoclicker\">\n            <td><code><b>geoclicker</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/base-classes#dghandler\"><code>Handler</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-projectDetector\">\n            <td><code><b>projectDetector</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/base-classes#dghandler\"><code>Handler</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-zoomControl\">\n            <td><code><b>zoomControl</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/controls#dgcontrol.zoom\"><code>Control.Zoom</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-fullscreenControl\">\n            <td><code><b>fullscreenControl</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/controls#dgcontrol.fullscreen\"><code>Control.FullScreen</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-rulerControl\">\n            <td><code><b>rulerControl</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/controls#dgcontrol.ruler\"><code>Control.Ruler</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-trafficControl\">\n            <td><code><b>trafficControl</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/controls#dgcontrol.traffic\"><code>Control.Traffic</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"map-baseLayer\">\n            <td><code><b>baseLayer</b></code></td>\n            <td><a href=\"/doc/maps/en/manual/raster-layers#dgtilelayer\"><code>TileLayer</code></a></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Map panes\n\nPanes are DOM elements used to control the ordering of layers on the map. You\ncan access panes with <a href=\"#map-getpane\"><code>map.getPane</code></a> or\n<a href=\"#map-getpanes\"><code>map.getPanes</code></a> methods. New panes can be created with the\n<a href=\"#map-createpane\"><code>map.createPane</code></a> method.\nEvery map has the following default panes that differ only in zIndex.\n\n<table>\n    <thead>\n        <tr>\n            <th>Pane</th>\n            <th>Type</th>\n            <th>Z-index</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-mappane\">\n            <td><code><b>mapPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>&#x27;auto&#x27;</code></td>\n            <td>Pane that contains all other map panes</td>\n        </tr>\n        <tr id=\"map-tilepane\">\n            <td><code><b>tilePane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>2</code></td>\n            <td>Pane for tile layers</td>\n        </tr>\n        <tr id=\"map-overlaypane\">\n            <td><code><b>overlayPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>4</code></td>\n            <td>Pane for overlays like polylines and polygons</td>\n        </tr>\n        <tr id=\"map-shadowpane\">\n            <td><code><b>shadowPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>5</code></td>\n            <td>Pane for overlay shadows (e.g. marker shadows)</td>\n        </tr>\n        <tr id=\"map-markerpane\">\n            <td><code><b>markerPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>6</code></td>\n            <td>Pane for marker icons</td>\n        </tr>\n        <tr id=\"map-popuppane\">\n            <td><code><b>popupPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>7</code></td>\n            <td>Pane for popups.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Locate options\n\nSome of the geolocation methods for <a href=\"#dgmap\"><code>Map</code></a> take in an <code>options</code> parameter.\nThis is a plain javascript object with the following optional components:\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"locate-options-watch\">\n            <td><code><b>watch</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, starts continous watching of location changes (instead of detecting it\n                once) using W3C <code>watchPosition</code> method. You can later stop watching using\n                <code>map.stopLocate()</code> method.\n            </td>\n        </tr>\n        <tr id=\"locate-options-setview\">\n            <td><code><b>setView</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, automatically sets the map view to the user location with respect to\n                detection accuracy, or to world view if geolocation failed.\n            </td>\n        </tr>\n        <tr id=\"locate-options-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>Infinity</code></td>\n            <td>The maximum zoom for automatic view setting when using <code>setView</code> option.</td>\n        </tr>\n        <tr id=\"locate-options-timeout\">\n            <td><code><b>timeout</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>10000</code></td>\n            <td>Number of milliseconds to wait for a response from geolocation before firing a\n                <code>locationerror</code> event.\n            </td>\n        </tr>\n        <tr id=\"locate-options-maximumage\">\n            <td><code><b>maximumAge</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Maximum age of detected location. If less than this amount of milliseconds\n                passed since last geolocation response, <code>locate</code> will return a cached location.\n            </td>\n        </tr>\n        <tr id=\"locate-options-enablehighaccuracy\">\n            <td><code><b>enableHighAccuracy</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Enables high accuracy, see\n                <a href=\"http://dev.w3.org/geo/api/spec-source.html#high-accuracy\">description in the W3C spec</a>.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n\n#### Zoom options\n\nSome of the <a href=\"#dgmap\"><code>Map</code></a> methods which modify the zoom level take in an <code>options</code>\nparameter. This is a plain javascript object with the following optional\ncomponents:\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"zoom-options-animate\">\n            <td><code><b>animate</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code></code></td>\n            <td>If not specified, zoom animation will happen if the zoom origin is inside the\n                current view. If <code>true</code>, the map will attempt animating zoom disregarding where\n                zoom origin is. Setting <code>false</code> will make it always reset the view completely\n                without animation.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Pan options\n\nSome of the <a href=\"#map\"><code>Map</code></a> methods which modify the center of the map take in an\n<code>options</code> parameter. This is a plain javascript object with the following optional components:\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"pan-options-animate\">\n            <td><code><b>animate</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code></code></td>\n            <td>If <code>true</code>, panning will always be animated if possible. If <code>false</code>, it will\n                not animate panning, either resetting the map view if panning more than a\n                screen away, or just setting a new offset for the map pane (except for <code>panBy</code>\n                which always does the latter).\n            </td>\n        </tr>\n        <tr id=\"pan-options-duration\">\n            <td><code><b>duration</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.25</code></td>\n            <td>Duration of animated panning, in seconds.</td>\n        </tr>\n        <tr id=\"pan-options-easelinearity\">\n            <td><code><b>easeLinearity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.25</code></td>\n            <td>The curvature factor of panning animation easing (third parameter of the\n                <a href=\"http://cubic-bezier.com/\">Cubic Bezier curve</a>). 1.0 means linear animation,\n                the less the more bowed the curve.\n            </td>\n        </tr>\n        <tr id=\"pan-options-nomovestart\">\n            <td><code><b>noMoveStart</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, panning won&#39;t fire <code>movestart</code> event on\n                start (used internally for panning inertia).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Zoom/pan options\n\nOptions inherited from <a href=\"#zoom-options\">Zoom options</a>\n\nOptions inherited from <a href=\"#pan-options\">Pan options</a>\n\n#### FitBounds options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n\t<tr id=\"fitbounds-options-paddingtopleft\">\n\t\t<td><code><b>paddingTopLeft</b></code></td>\n\t\t<td><code>Point </code></td>\n\t\t<td><code>[0, 0]</code></td>\n\t\t<td>Sets the amount of padding in the top left corner of a map container that\n            shouldn&#39;t be accounted for when setting the view to fit bounds. Useful if you\n            have some control overlays on the map like a sidebar and you don&#39;t want them\n            to obscure objects you&#39;re zooming to.\n        </td>\n        </tr>\n        <tr id=\"fitbounds-options-paddingbottomright\">\n            <td><code><b>paddingBottomRight</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>The same for the bottom right corner of the map.</td>\n        </tr>\n        <tr id=\"fitbounds-options-padding\">\n            <td><code><b>padding</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>Equivalent of setting both top left and bottom right padding to the same value.</td>\n        </tr>\n        <tr id=\"fitbounds-options-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>The maximum possible zoom to use.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/markers.md",
    "content": "## Markers\n\n{toc}\n\n### DG.Marker\n\nDG.Marker is used to display clickable/draggable icons on the map.\n\n\tDG.marker([54.98, 82.89]).addTo(map);\n\n#### Creation\n\n<table>\n\t<thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n\t\t<tr>\n\t\t\t<td><code><b>DG.Marker</b>(\n\t\t\t\t<nobr>&lt;<a href=\"/doc/maps/en/manual/base-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>,</nobr>\n\t\t\t\t<nobr>&lt;<a href=\"#options\">Marker options</a>&gt; <i>options?</i> )</nobr>\n\t\t\t</code></td>\n\t\t\t<td>Instantiates a Marker object given a geographical point and optionally an options object.</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-icon\">\n            <td><code><b>icon</b></code></td>\n            <td><code><a href=\"#dgicon\">Icon</a></code></td>\n            <td><code>*</code></td>\n            <td>Icon class to use for rendering the marker. See <a href=\"#dgicon\">Icon documentation</a>\n                for details on how to customize the marker icon. Set to new\n                <code>DG.Icon.Default()</code> by default.</td>\n        </tr>\n        <tr id=\"marker-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>If <code>false</code>, the marker will not emit mouse events and will act as a part of\n                the underlying map.</td>\n        </tr>\n        <tr id=\"marker-draggable\">\n            <td><code><b>draggable</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Whether the marker is draggable with mouse/touch or not.</td>\n        </tr>\n        <tr id=\"marker-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.</td>\n        </tr>\n        <tr id=\"marker-title\">\n            <td><code><b>title</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Text for the browser tooltip that appear on marker hover (no tooltip by default).</td>\n        </tr>\n        <tr id=\"marker-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Text for the <code>alt</code> attribute of the icon image (useful for accessibility).</td>\n        </tr>\n        <tr id=\"marker-zindexoffset\">\n            <td><code><b>zIndexOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>By default, marker images zIndex is set automatically based on its latitude.\n                Use this option if you want to put the marker on top of all others (or below),\n                specifying a high value like <code>1000</code> (or high negative value, respectively).</td>\n        </tr>\n        <tr id=\"marker-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>The opacity of the marker.</td>\n        </tr>\n        <tr id=\"marker-riseonhover\">\n            <td><code><b>riseOnHover</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, the marker will get on top of others when you hover the mouse over it.</td>\n        </tr>\n        <tr id=\"marker-riseoffset\">\n            <td><code><b>riseOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>250</code></td>\n            <td>The z-index offset used for the <code>riseOnHover</code> feature.</td>\n        </tr>\n        <tr id=\"marker-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;markerPane&#x27;</code></td>\n            <td><code>Map pane</code> where the markers icon will be added.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-click\">\n            <td><code><b>click</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user clicks (or taps) the marker.</td>\n        </tr>\n        <tr id=\"marker-dblclick\">\n            <td><code><b>dblclick</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user double-clicks (or double-taps) the marker.</td>\n        </tr>\n        <tr id=\"marker-mousedown\">\n            <td><code><b>mousedown</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user pushes the mouse button on the marker.</td>\n        </tr>\n        <tr id=\"marker-mouseover\">\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the mouse enters the marker.</td>\n        </tr>\n        <tr id=\"marker-mouseout\">\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the mouse leaves the marker.</td>\n        </tr>\n        <tr id=\"marker-contextmenu\">\n            <td><code><b>contextmenu</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Fired when the user right-clicks on the marker.</td>\n        </tr>\n        <tr id=\"marker-move\">\n            <td><code><b>move</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the marker is moved via <a href=\"#marker-setlatlng\"><code>setLatLng</code></a>\n                or by <a href=\"#marker-dragging\">dragging</a>. Old and new coordinates are included in\n                event arguments as <code>oldLatLng</code>, <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>latlng</code></a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Dragging events\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-dragstart\">\n            <td><code><b>dragstart</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the user starts dragging the marker.</td>\n        </tr>\n        <tr id=\"marker-movestart\">\n            <td><code><b>movestart</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the marker starts moving (because of dragging).</td>\n        </tr>\n        <tr id=\"marker-drag\">\n            <td><code><b>drag</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired repeatedly while the user drags the marker.</td>\n        </tr>\n        <tr id=\"marker-dragend\">\n            <td><code><b>dragend</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dragendevent\">DragEndEvent</a></code></td>\n            <td>Fired when the user stops dragging the marker.</td>\n        </tr>\n        <tr id=\"marker-moveend\">\n            <td><code><b>moveend</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the marker stops moving (because of dragging).</td>\n        </tr>\n    </tbody>\n</table>\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired after the layer is added to a map</td>\n        </tr>\n        <tr id=\"marker-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired after the layer is removed from a map</td>\n        </tr>\n    </tbody>\n</table>\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is opened</td>\n        </tr>\n        <tr id=\"marker-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is closed</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-getlatlng\">\n            <td><code><b>getLatLng</b>()</nobr></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns the current geographical position of the marker.</td>\n        </tr>\n        <tr id=\"marker-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Changes the marker position to the given point.</td>\n        </tr>\n        <tr id=\"marker-setzindexoffset\">\n            <td><code><b>setZIndexOffset</b>(\n                    <nobr>&lt;Number&gt; <i>offset</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Changes the <a href=\"#marker-zindexoffset\">zIndex offset</a> of the marker.</td>\n        </tr>\n        <tr id=\"marker-seticon\">\n            <td><code><b>setIcon</b>(\n                    <nobr>&lt;<a href=\"#dgicon\">Icon</a>&gt; <i>icon</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Changes the marker icon.</td>\n        </tr>\n        <tr id=\"marker-setopacity\">\n            <td><code><b>setOpacity</b>(\n                    <nobr>&lt;Number&gt; <i>opacity</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Changes the opacity of the marker. </td>\n        </tr>\n\t    <tr id=\"marker-bindlabel\">\n\t        <td><code><b>bindLabel</b>(&lt;String&gt; content, &lt;<a href=\"/doc/maps/en/manual/dg-label#опции\">Label options</a>&gt; options?)</code></td>\n            <td><code>this</code></td>\n            <td><!-- TODO: translate --></td>\n\t    </tr>\n\t    <tr id=\"marker-unbindlabel\">\n\t        <td><code><b>unbindLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td><!-- TODO: translate --></td>\n\t    </tr>\n\t    <tr id=\"marker-showLabel\">\n\t        <td><code><b>showLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td><!-- TODO: translate --></td>\n\t    </tr>\n\t    <tr id=\"marker-hideLabel\">\n\t        <td><code><b>hideLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td><!-- TODO: translate --></td>\n\t    </tr>\n    </tbody>\n</table>\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n#### Interaction handlers\n\nInteraction handlers are properties of a marker instance that allow you to control interaction\nbehavior in runtime, enabling or disabling certain features such as dragging\n(see Handler methods). Example: \n\n\tmarker.dragging.disable();\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code><a href=\"/doc/maps/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Marker dragging handler (by both mouse and touch).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Icon\n\nRepresents an icon to provide when creating a marker.\n\n    var myIcon = DG.icon({\n        iconUrl: 'my-icon.png',\n        iconRetinaUrl: 'my-icon@2x.png',\n        iconSize: [38, 95],\n        iconAnchor: [22, 94],\n        popupAnchor: [-3, -76],\n        shadowUrl: 'my-icon-shadow.png',\n        shadowRetinaUrl: 'my-icon-shadow@2x.png',\n        shadowSize: [68, 95],\n        shadowAnchor: [22, 94]\n    });\n\n    DG.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n\n#### Creation\n\n<table>\n\t<thead>\n\t    <tr>\n\t        <th>Factory</th>\n\t        <th>Description</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n\t    <tr>\n            <td><code><b>DG.icon</b>(\n                <nobr>&lt;<a href=\"#icon-option\">Icon options</a>&gt; <i>options</i>)</nobr>\n            </code></td>\n            <td>Creates an icon instance with the given options.</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table id=\"dgicon-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"icon-iconurl\">\n            <td><code><b>iconUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td><strong>(required)</strong> The URL to the icon image (absolute or relative to your script path).</td>\n        </tr>\n        <tr id=\"icon-iconretinaurl\">\n            <td><code><b>iconRetinaUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>The URL to a retina sized version of the icon image (absolute or relative to your\n                script path). Used for Retina screen devices.</td>\n        </tr>\n        <tr id=\"icon-iconsize\">\n            <td><code><b>iconSize</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>Size of the icon image in pixels.</td>\n        </tr>\n        <tr id=\"icon-iconanchor\">\n            <td><code><b>iconAnchor</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>The coordinates of the &quot;tip&quot; of the icon (relative to its top left corner). The icon\n                will be aligned so that this point is at the marker&#39;s geographical location. Centered\n                by default if size is specified, also can be set in CSS with negative margins.</td>\n        </tr>\n        <tr id=\"icon-popupanchor\">\n            <td><code><b>popupAnchor</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>The coordinates of the point from which popups will &quot;open&quot;, relative to the icon anchor.</td>\n        </tr>\n        <tr id=\"icon-shadowurl\">\n            <td><code><b>shadowUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>The URL to the icon shadow image. If not specified, no shadow image will be created.</td>\n        </tr>\n        <tr id=\"icon-shadowretinaurl\">\n            <td><code><b>shadowRetinaUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td></td>\n        </tr>\n        <tr id=\"icon-shadowsize\">\n            <td><code><b>shadowSize</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>Size of the shadow image in pixels.</td>\n        </tr>\n        <tr id=\"icon-shadowanchor\">\n            <td><code><b>shadowAnchor</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>The coordinates of the &quot;tip&quot; of the shadow (relative to its top left corner) (the same\n                as iconAnchor if not specified).</td>\n        </tr>\n        <tr id=\"icon-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>A custom class name to assign to both icon and shadow images. Empty by default.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table id=\"dgicon-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"icon-createicon\">\n            <td><code><b>createIcon</b>(<nobr>&lt;HTMLElement&gt; <i>oldIcon?</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Called internally when the icon has to be shown,\n                returns a <code>&lt;img&gt;</code> HTML element\n                styled according to the options.</td>\n        </tr>\n        <tr id=\"icon-createshadow\">\n            <td><code><b>createShadow</b>(<nobr>&lt;HTMLElement&gt; <i>oldIcon?</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>As <code>createIcon</code>, but for the shadow beneath it.</td>\n        </tr>\n    </tbody>\n</table>\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.DivIcon\n\nRepresents a lightweight icon for markers that uses a simple <code>&lt;div&gt;</code>\nelement instead of an image. Inherits from <a href=\"#dgicon\"><code>Icon</code></a>\nbut ignores the <code>iconUrl</code> and shadow options.\n\n    // you can set .my-div-icon styles in CSS\n    var myIcon = DG.divIcon({className: 'my-div-icon'}); \n\n    DG.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n\n#### Creation\n\n<table>\n\t<thead>\n\t    <tr>\n\t        <th>Factory</th>\n\t        <th>Description</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n\t    <tr>\n\t        <td><code><b>DG.DivIcon</b>(\n\t            <nobr>&lt;<a href=\"#divicon-options\">DivIcon options</a>&gt; <i>options</i> )</nobr>\n\t        </code></td>\n            <td>Creates a <code>DivIcon</code> instance with the given options.</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Options\n\n<table>\n\t<thead>\n\t    <tr>\n\t        <th>Option</th>\n\t        <th>Type</th>\n\t        <th>Default</th>\n\t        <th>Description</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"divicon-html\">\n            <td><code><b>html</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Custom HTML code to put inside the div element, empty by default.</td>\n        </tr>\n        <tr id=\"divicon-bgpos\">\n            <td><code><b>bgPos</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>Optional relative position of the background, in pixels</td>\n        </tr>\n\t</tbody>\n</table>\n\n\nOptions inherited from <a href=\"#dgicon-options\">Icon</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\nMethods inherited from <a href=\"#dgicon-methods\">Icon</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/manual/other-layers.md",
    "content": "## Other Layers\n\n{toc}\n\n### DG.LayerGroup\n\nUsed to group several layers and handle them as one. If you add it to the map,\nany layers added or removed from the group will be added/removed on the map as\nwell. Extends <a href=\"/doc/maps/en/manual/base-classes#dglayer\"><code>DG.Layer</code></a>.\n\n    DG.layerGroup([marker1, marker2])\n        .addLayer(polyline)\n        .addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"layergroup-l-layergroup\">\n            <td><code><b>DG.layerGroup</b>(\n                <nobr>&lt;Layer[]&gt; <i>layers</i> )</nobr>\n            </code></td>\n            <td>Create a layer group, optionally given an initial set of layers.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layergroup-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n\n            <td><code>Object</code></td>\n            <td>Returns a <a href=\"http://en.wikipedia.org/wiki/GeoJSON\">\n                <code>GeoJSON</code></a> representation of the layer group (as a GeoJSON <code>GeometryCollection</code>).</td>\n        </tr>\n        <tr id=\"layergroup-addlayer\">\n            <td><code><b>addLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Adds the given layer to the group.</td>\n        </tr>\n        <tr id=\"layergroup-removelayer\">\n            <td><code><b>removeLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the given layer from the group.</td>\n        </tr>\n        <tr>\n            <td><code><b>removeLayer</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Removes the layer with the given internal ID from the group.</td>\n        </tr>\n        <tr id=\"layergroup-haslayer\">\n            <td><code><b>hasLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the given layer is currently added to the group.</td>\n        </tr>\n        <tr id=\"layergroup-clearlayers\">\n            <td><code><b>clearLayers</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Removes all the layers from the group.</td>\n        </tr>\n        <tr id=\"layergroup-invoke\">\n            <td><code><b>invoke</b>(\n                <nobr>&lt;string&gt; <i>methodName</i>, <i>…</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Calls <code>methodName</code> on every layer contained in this group, passing any\n                additional parameters. Has no effect if the layers contained do not\n                implement <code>methodName</code>.</td>\n        </tr>\n        <tr id=\"layergroup-eachlayer\">\n            <td><code><b>eachLayer</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Iterates over the layers of the group, optionally specifying context of the iterator function.\n                <code class=\"lang-js\">group.eachLayer(function (layer) {\n                    layer.bindPopup(&#39;Hello&#39;);\n                });</code></td>\n        </tr>\n        <tr id=\"layergroup-getlayer\">\n            <td><code><b>getLayer</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a></code></td>\n            <td>Returns the layer with the given internal ID.</td>\n        </tr>\n        <tr id=\"layergroup-getlayers\">\n            <td><code><b>getLayers</b>()</code></td>\n\n            <td><code>Layer[]</code></td>\n            <td>Returns an array of all the layers added to the group.</td>\n        </tr>\n        <tr id=\"layergroup-setzindex\">\n            <td><code><b>setZIndex</b>(\n                <nobr>&lt;Number&gt; <i>zIndex</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Calls <code>setZIndex</code> on every layer contained in this group, passing the z-index.</td>\n        </tr>\n        <tr id=\"layergroup-getlayerid\">\n            <td><code><b>getLayerId</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the internal ID for a layer</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.FeatureGroup\n\nExtended <a href=\"#dglayergroup\"><code>DG.LayerGroup</code></a> that also has mouse events\n(propagated from members of the group) and a shared bindPopup method.\n\n    DG.featureGroup([marker1, marker2, polyline])\n        .bindPopup('Hello world!')\n        .on('click', function() { alert('Clicked on a group!'); })\n        .addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"featuregroup-l-featuregroup\">\n            <td><code><b>DG.featureGroup</b>(\n                <nobr>&lt;Layer[]&gt; <i>layers</i> )</nobr>\n            </code></td>\n            <td>Create a feature group, optionally given an initial set of layers.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"featuregroup-setstyle\">\n            <td><code><b>setStyle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/vector-layers#dgpath-options\">Path options</a>&gt; <i>style</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Sets the given path options to each layer of the group that has a <code>setStyle</code> method.</td>\n        </tr>\n        <tr id=\"featuregroup-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Brings the layer group to the top of all other layers</td>\n        </tr>\n        <tr id=\"featuregroup-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Brings the layer group to the top of all other layers</td>\n        </tr>\n        <tr id=\"featuregroup-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"#dglayergroup\">LayerGroup</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.GeoJSON\n\nRepresents a GeoJSON object or an array of GeoJSON objects. Allows you to parse\nGeoJSON data and display it on the map. Extends <a href=\"#dgfeaturegroup\"><code>DG.FeatureGroup</code></a>.\n\n    DG.geoJson(data, {\n        style: function (feature) {\n            return {color: feature.properties.color};\n        }\n    }).bindPopup(function (layer) {\n        return layer.feature.properties.description;\n    }).addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-l-geojson\">\n            <td><code><b>DG.geoJSON</b>(\n                <nobr>&lt;Object&gt; <i>geojson?</i>,</nobr>\n                <nobr>&lt;<a href=\"#geojson-option\">GeoJSON options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a GeoJSON layer. Optionally accepts an object in\n                <a href=\"http://geojson.org/geojson-spec.html\">GeoJSON format</a> to display on the map\n                (you can alternatively add it later with <code>addData</code> method) and an <code>options</code> object.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id=\"geojson-option\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-pointtolayer\">\n            <td><code><b>pointToLayer</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td>A <code>Function</code> defining how GeoJSON points spawn maps API layers. It is internally\n                called when data is added, passing the GeoJSON point feature and its\n                <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a>.\n                The default is to spawn a default <a href=\"/doc/maps/en/manual/markers#dgmarker\"><code>Marker</code></a>:\n                <code class=\"lang-js\">function(geoJsonPoint, latlng) {\n                    return DG.marker(latlng);\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-style\">\n            <td><code><b>style</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td>A <code>Function</code> defining the\n                <a href=\"/doc/maps/en/manual/vector-layers#dgpath-options\"><code>Path options</code></a>\n                for styling GeoJSON lines and polygons, called internally when data is added.\n                The default value is to not override any defaults:\n                <code class=\"lang-js\">function (geoJsonFeature) {\n                    return {}\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-oneachfeature\">\n            <td><code><b>onEachFeature</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td>A <code>Function</code> that will be called once for each created\n                <a href=\"/doc/maps/en/manual/base-classes#dglayer\"><code>Layer</code></a>,\n                after it has been created and styled. Useful for attaching events and popups to features.\n                The default is to do nothing with the newly created layers:\n                <code class=\"lang-js\">function (layer) {}\n                </code></td>\n        </tr>\n        <tr id=\"geojson-filter\">\n            <td><code><b>filter</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td>A <code>Function</code> that will be used to decide whether to show a feature or not.\n                The default is to show all features:\n                <code class=\"lang-js\">function (geoJsonFeature) {\n                    return true;\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-coordstolatlng\">\n            <td><code><b>coordsToLatLng</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td>A <code>Function</code> that will be used for converting GeoJSON coordinates to\n                <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a>s.\n                The default is the <code>coordsToLatLng</code> static method.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\nMethods inherited from <a href=\"#dgfeaturegroup\">FeatureGroup</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"#dglayergroup\">LayerGroup</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n#### Functions\n\nThere are several static functions which can be called without instantiating DG.GeoJSON:\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-geometrytolayer\">\n            <td><code><b>geometryToLayer</b>(\n                <nobr>&lt;Object&gt; <i>featureData</i>,</nobr>\n                <nobr>&lt;<a href=\"#geojson-option\">GeoJSON options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a></code></td>\n            <td>Creates a <a href=\"/doc/maps/en/manual/base-classes#dglayer\"><code>Layer</code></a> from a given\n                GeoJSON feature. Can use a custom <a href=\"#geojson-pointtolayer\"><code>pointToLayer</code></a> and/or\n                <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a> functions if provided as options.</td>\n        </tr>\n        <tr id=\"geojson-coordstolatlng\">\n            <td><code><b>coordsToLatLng</b>(\n                <nobr>&lt;Array&gt; <i>coords</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Creates a <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a> object from an array\n                of 2 numbers (longitude, latitude) or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.</td>\n        </tr>\n        <tr>\n            <td><code><b>coordsToLatLngs</b>(\n                <nobr>&lt;Array&gt; <i>coords</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>levelsDeep?</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>coordsToLatLng?</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Creates a multidimensional array of <a href=\"/doc/maps/en/manual/basic-types#dglatlng\"><code>LatLng</code></a>s\n                from a GeoJSON coordinates array. <code>levelsDeep</code> specifies the nesting level (0 is for an array\n                of points, 1 for an array of arrays of points, etc., 0 by default). Can use a custom\n                <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a> function.</td>\n        </tr>\n        <tr id=\"geojson-latlngtocoords\">\n            <td><code><b>latLngToCoords</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Reverse of <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a></td>\n        </tr>\n        <tr id=\"geojson-latlngstocoords\">\n            <td><code><b>latLngsToCoords</b>(\n                <nobr>&lt;Array&gt; <i>latlngs</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>levelsDeep?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>closed?</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Reverse of <a href=\"#geojson-coordstolatlngs\"><code>coordsToLatLngs</code></a>\n                <code>closed</code> determines whether the first point should be appended to the end of\n                the array to close the feature, only used when <code>levelsDeep</code> is 0. False by default.</td>\n        </tr>\n        <tr id=\"geojson-asfeature\">\n            <td><code><b>asFeature</b>(\n                <nobr>&lt;Object&gt; <i>geojson</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Normalize GeoJSON geometries/features into GeoJSON features.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.GridLayer\n\nGeneric class for handling a tiled grid of HTML elements. This is the base class for all tile layers and\nreplaces <code>TileLayer.Canvas</code>. GridLayer can be extended to create a tiled grid of HTML Elements\nlike <code>&lt;canvas&gt;</code>, <code>&lt;img&gt;</code> or <code>&lt;div&gt;</code>. GridLayer will\nhandle creating and animating these DOM elements for you.\n\n#### Synchronous usage\n\nTo create a custom layer, extend GridLayer and impliment the <code>createTile()</code> method,\nwhich will be passed a <a href=\"/doc/maps/en/manual/basic-types#dgpoint\"><code>Point</code></a> object with the <code>x</code>,\n<code>y</code>, and <code>z</code> (zoom level) coordinates to draw your tile.\n\n    var CanvasLayer = DG.GridLayer.extend({\n        createTile: function(coords){\n            // create a <canvas> element for drawing\n            var tile = DG.DomUtil.create('canvas', 'leaflet-tile');\n            // setup tile width and height according to the options\n            var size = this.getTileSize();\n            tile.width = size.x;\n            tile.height = size.y;\n            // get a canvas context and draw something on it using coords.x, coords.y and coords.z\n            var ctx = canvas.getContext('2d');\n            // return the tile so it can be rendered on screen\n            return tile;\n        }\n    });\n\n#### Asynchrohous usage\n\nTile creation can also be asyncronous, this is useful when using a third-party drawing library.\nOnce the tile is finsihed drawing it can be passed to the done() callback.\n\n    var CanvasLayer = DG.GridLayer.extend({\n        createTile: function(coords, done){\n            var error;\n            // create a <canvas> element for drawing\n            var tile = DG.DomUtil.create('canvas', 'leaflet-tile');\n            // setup tile width and height according to the options\n            var size = this.getTileSize();\n            tile.width = size.x;\n            tile.height = size.y;\n            // draw something and pass the tile to the done() callback\n            done(error, tile);\n        }\n    });\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"gridlayer-l-gridlayer\">\n            <td><code><b>DG.gridLayer</b>(\n                <nobr>&lt;GridLayer options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Creates a new instance of GridLayer with the supplied options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id='gridlayer-options'>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-tilesize\">\n            <td><code><b>tileSize</b></code></td>\n            <td><code>Number|Point </code></td>\n            <td><code>256</code></td>\n            <td>Width and height of tiles in the grid. Use a number if width and height are equal,\n                or <code>DG.point(width, height)</code> otherwise.</td>\n        </tr>\n        <tr id=\"gridlayer-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>Opacity of the tiles. Can be used in the <code>createTile()</code> function.</td>\n        </tr>\n        <tr id=\"gridlayer-updatewhenidle\">\n            <td><code><b>updateWhenIdle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>depends</code></td>\n            <td>If <code>false</code>, new tiles are loaded during panning, otherwise only after it (for better\n                performance). <code>true</code> by default on mobile browsers, otherwise <code>false</code>.</td>\n        </tr>\n        <tr id=\"gridlayer-updateinterval\">\n            <td><code><b>updateInterval</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>200</code></td>\n            <td>Tiles will not update more than once every <code>updateInterval</code> milliseconds.</td>\n        </tr>\n        <tr id=\"gridlayer-attribution\">\n            <td><code><b>attribution</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>String to be shown in the attribution control, describes the layer data, e.g. &quot;© 2GIS&quot;.</td>\n        </tr>\n        <tr id=\"gridlayer-zindex\">\n            <td><code><b>zIndex</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>The explicit zIndex of the tile layer.</td>\n        </tr>\n        <tr id=\"gridlayer-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code>LatLngBounds </code></td>\n            <td><code>undefined</code></td>\n            <td>If set, tiles will only be loaded inside inside the set\n                <a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\"><code>LatLngBounds</code></a>.</td>\n        </tr>\n        <tr id=\"gridlayer-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>The minimum zoom level that tiles will be loaded at. By default the entire map.</td>\n        </tr>\n        <tr id=\"gridlayer-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>The maximum zoom level that tiles will be loaded at.</td>\n        </tr>\n        <tr id=\"gridlayer-nowrap\">\n            <td><code><b>noWrap</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Whether the layer is wrapped around the antimeridian. If <code>true</code>, the\n                GridLayer will only be displayed once at low zoom levels.</td>\n        </tr>\n        <tr id=\"gridlayer-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;tilePane&#x27;</code></td>\n            <td><code>Map pane</code> where the grid layer will be added.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\n<table id='gridlayer-events'>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-loading\">\n            <td><code><b>loading</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired when the grid layer starts loading tiles</td>\n        </tr>\n        <tr id=\"gridlayer-tileunload\">\n            <td><code><b>tileunload</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Fired when a tile is removed (e.g. when a tile goes off the screen).</td>\n        </tr>\n        <tr id=\"gridlayer-tileloadstart\">\n            <td><code><b>tileloadstart</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Fired when a tile is requested and starts loading.</td>\n        </tr>\n        <tr id=\"gridlayer-tileerror\">\n            <td><code><b>tileerror</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Fired when there is an error loading a tile.</td>\n        </tr>\n        <tr id=\"gridlayer-tileload\">\n            <td><code><b>tileload</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Fired when a tile loads.</td>\n        </tr>\n        <tr id=\"gridlayer-load\">\n            <td><code><b>load</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Fired when the grid layer loaded all visible tiles.</td>\n        </tr>\n    </tbody>\n</table>\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\n<table id='gridlayer-methods'>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Brings the tile layer to the top of all tile layers.</td>\n        </tr>\n        <tr id=\"gridlayer-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Brings the tile layer to the bottom of all tile layers.</td>\n        </tr>\n        <tr id=\"gridlayer-getattribution\">\n            <td><code><b>getAttribution</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Used by the <code>attribution control</code>, returns the\n                <a href=\"#gridlayer-attribution\">attribution option</a>.</td>\n        </tr>\n        <tr id=\"gridlayer-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Returns the HTML element that contains the tiles for this layer.</td>\n        </tr>\n        <tr id=\"gridlayer-setopacity\">\n            <td><code><b>setOpacity</b>(\n                <nobr>&lt;Number&gt; <i>opacity</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Changes the <a href=\"#gridlayer-opacity\">opacity</a> of the grid layer.</td>\n        </tr>\n        <tr id=\"gridlayer-setzindex\">\n            <td><code><b>setZIndex</b>(\n                <nobr>&lt;Number&gt; <i>zIndex</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Changes the <a href=\"#gridlayer-zindex\">zIndex</a> of the grid layer.</td>\n        </tr>\n        <tr id=\"gridlayer-isloading\">\n            <td><code><b>isLoading</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if any tile in the grid layer has not finished loading.</td>\n        </tr>\n        <tr id=\"gridlayer-redraw\">\n            <td><code><b>redraw</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Causes the layer to clear all the tiles and request them again.</td>\n        </tr>\n        <tr id=\"gridlayer-gettilesize\">\n            <td><code><b>getTileSize</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Normalizes the <a href=\"#gridlayer-tilesize\">tileSize option</a> into a point.\n                Used by the <code>createTile()</code> method.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Extension methods\n\nLayers extending <a href=\"#dggridlayer\"><code>DG.GridLayer</code></a> shall reimplement the following method.\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"gridlayer-createtile\">\n            <td><code><b>createTile</b>(\n                <nobr>&lt;Object&gt; <i>coords</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>done?</i> )</nobr>\n            </code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Called only internally, must be overriden by classes extending\n                <a href=\"#dggridlayer\"><code>GridLayer</code></a>. Returns the <code>HTMLElement</code>\n                corresponding to the given <code>coords</code>. If the <code>done</code> callback\n                is specified, it must be called when the tile has finished loading and drawing.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/manual/popup.md",
    "content": "## Popups\n\nPopup is a window in which you can display arbitrary HTML-code.\nPopup associated with a particular location on the map.\n\n{toc}\n\n### DG.Popup\n\nUsed to open popups in certain places of the map. Use\n<a href=\"/doc/maps/en/manual/map#map-openpopup\">Map.openPopup</a> to\nopen popups while making sure that only one popup is open at one time\n(recommended for usability), or use <a href=\"/doc/maps/en/manual/map#map-addlayer\">Map.addLayer</a>\nto open as many as you want.\n\n#### Usage example\n\nIf you want to just bind a popup to marker click and then open it, it&#39;s really easy:\n\n\tmarker.bindPopup(popupContent).openPopup();\n\nPath overlays like polylines also have a <code>bindPopup</code> method.\nHere&#39;s a more complicated way to open a popup on a map:\n\n\tvar popup = DG.popup()\n\t\t.setLatLng(latlng)\n\t\t.setContent(&#39;&lt;p&gt;Hello world!&lt;br /&gt;This is a nice popup.&lt;/p&gt;&#39;)\n\t\t.openOn(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-dg-popup\">\n            <td><code><b>DG.popup</b>(\n                    <nobr>&lt;<a href=\"#options\">Popup options</a>&gt; <i>options?</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>&gt; <i>source?</i>)</nobr>\n                </code></td>\n            <td>Instantiates a Popup object given an optional <code>options</code> object that describes\n                its appearance and location and an optional <code>source</code> object that is used to tag\n                the popup with a reference to the Layer to which it refers.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-maxwidth\">\n            <td><code><b>maxWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>300</code></td>\n            <td>Max width of the popup, in pixels.</td>\n        </tr>\n        <tr id=\"popup-minwidth\">\n            <td><code><b>minWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>50</code></td>\n            <td>Min width of the popup, in pixels.</td>\n        </tr>\n        <tr id=\"popup-maxheight\">\n            <td><code><b>maxHeight</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>If set, creates a scrollable container of the given height\n                inside a popup if its content exceeds it.</td>\n        </tr>\n        <tr id=\"popup-autopan\">\n            <td><code><b>autoPan</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Set it to <code>false</code> if you don&#39;t want the map to do panning animation\n                to fit the opened popup.</td>\n        </tr>\n        <tr id=\"popup-autopanpaddingtopleft\">\n            <td><code><b>autoPanPaddingTopLeft</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>The margin between the popup and the top left corner of the map\n                view after autopanning was performed.</td>\n        </tr>\n        <tr id=\"popup-autopanpaddingbottomright\">\n            <td><code><b>autoPanPaddingBottomRight</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>The margin between the popup and the bottom right corner of the map\n                view after autopanning was performed.</td>\n        </tr>\n        <tr id=\"popup-autopanpadding\">\n            <td><code><b>autoPanPadding</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>Point(5, 5)</code></td>\n            <td>Equivalent of setting both top left and bottom right autopan padding to the same value.</td>\n        </tr>\n        <tr id=\"popup-keepinview\">\n            <td><code><b>keepInView</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Set it to <code>true</code> if you want to prevent users from panning the popup\n                off of the screen while it is open.</td>\n        </tr>\n        <tr id=\"popup-closebutton\">\n            <td><code><b>closeButton</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Controls the presence of a close button in the popup.</td>\n        </tr>\n        <tr id=\"popup-offset\">\n            <td><code><b>offset</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>Point(0, 7)</code></td>\n            <td>The offset of the popup position. Useful to control the anchor\n                of the popup when opening it on some overlays.</td>\n        </tr>\n        <tr id=\"popup-autoclose\">\n            <td><code><b>autoClose</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Set it to <code>false</code> if you want to override the default behavior of\n                the popup closing when user clicks the map (set globally by the Map&#39;s\n                <a href=\"/doc/maps/en/manual/map#map-closepopuponclick\">closePopupOnClick</a> option).</td>\n        </tr>\n        <tr id=\"popup-zoomanimation\">\n            <td><code><b>zoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether to animate the popup on zoom. Disable it if you have\n                problems with Flash content inside popups.</td>\n        </tr>\n        <tr id=\"popup-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>A custom CSS class name to assign to the popup.</td>\n        </tr>\n        <tr id=\"popup-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;popupPane&#x27;</code></td>\n            <td><code>Map pane</code> where the popup will be added.</td>\n        </tr>\n        <tr id=\"popup-sprawling\">\n            <td><code><b>sprawling</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>false</code></td>\n            <td><!-- TODO: translation --></td>\n        </tr>\n        <tr id=\"popup-textdirection\">\n            <td><code><b>textDirection</b></code></td>\n            <td><code>string</code></td>\n            <td><code>'auto'</code></td>\n            <td>The direction of the popup content text. The following values are possible: <code>'auto'</code>,\n                <code>'rtl'</code>, <code>'ltr'</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired after the layer is added to a map</td>\n        </tr>\n        <tr id=\"popup-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#event\">Event</a></code></td>\n            <td>Fired after the layer is removed from a map</td>\n        </tr>\n    </tbody>\n</table>\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Event</th>\n            <th>Data</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is opened</td>\n        </tr>\n        <tr id=\"popup-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Fired when a popup bound to this layer is closed</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-addto\">\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Adds the popup to the map.</td>\n        </tr>\n        <tr id=\"popup-openon\">\n            <td><code><b>openOn</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/map#dgmap\">Map</a>&gt; <i>map</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Adds the popup to the map and closes the previous one. The same as <code>map.openPopup(popup)</code>.</td>\n        </tr>\n        <tr id=\"popup-getlatlng\">\n            <td><code><b>getLatLng</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns the geographical point of popup.</td>\n        </tr>\n        <tr id=\"popup-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the geographical point where the popup will open.</td>\n        </tr>\n        <tr id=\"popup-getcontent\">\n            <td><code><b>getContent</b>()</code></td>\n            <td><code>String|HTMLElement</code></td>\n            <td>Returns the main content of the popup.</td>\n        </tr>\n        <tr id=\"popup-setcontent\">\n            <td><code><b>setContent</b>(\n                <nobr>&lt;String | HTMLElement | Function&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Sets the HTML content of the popup (in main section). If a function is passed the source layer will\n                be passed to the function. The function should return a <code>String</code> or\n                <code>HTMLElement</code> to be used in the popup.</td>\n        </tr>\n        <tr id=\"popup-getheadercontent\">\n            <td><code><b>getHeaderContent</b>()</code></td>\n            <td><code>String | HTMLElement</code></td>\n            <td>Returns the content of the header section of the popup.</td>\n        </tr>\n        <tr id=\"popup-setheadercontent\">\n            <td><code><b>setHeaderContent</b>(\n                <nobr>&lt;String|HTMLElement&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Sets the content of the header section of the popup.</td>\n        </tr>\n        <tr id=\"popup-getfootercontent\">\n            <td><code><b>getFooterContent</b>()</code></td>\n            <td><code>String | HTMLElement</code></td>\n            <td>Returns the content of the footer section of the popup.</td>\n        </tr>\n        <tr id=\"popup-setfootercontent\">\n            <td><code><b>setFooterContent</b>(\n                <nobr>&lt;String | HTMLElement&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Sets the content of the footer section of the popup.</td>\n        </tr>\n        <tr id=\"popup-getelement\">\n            <td><code><b>getElement</b>()</code></td>\n            <td><code>String | HTMLElement</code></td>\n            <td>Alias for <a href=\"#popup-getcontent\">getContent()</a></td>\n        </tr>\n        <tr id=\"popup-update\">\n            <td><code><b>update</b>()</code></td>\n            <td><code>null</code></td>\n            <td>Updates the popup content, layout and position. Useful for updating the popup after\n                something inside changed, e.g. image loaded.</td>\n        </tr>\n        <tr id=\"popup-isopen\">\n            <td><code><b>isOpen</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> when the popup is visible on the map.</td>\n        </tr>\n        <tr id=\"popup-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Brings this popup in front of other popups (in the same map pane).</td>\n        </tr>\n        <tr id=\"popup-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Brings this popup to the back of other popups (in the same map pane).</td>\n        </tr>\n    </tbody>\n</table>\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/manual/raster-layers.md",
    "content": "## Raster Layers\n\nThis section describes working with raster layers, such as a tile layer\nor an image bound to specific geographic boundaries.\n\n{toc}\n\n### DG.TileLayer\n\nUsed to load and display tile layers on the map. Extends <a href=\"/doc/maps/en/manual/other-layers#dggridlayer\">GridLayer</a>.\n\n#### Usage Example\n\n    DG.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);\n\n##### URL Template\n\nA string of the following form:\n\n    'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\n\nYou can use custom keys in the template, which will be evaluated from TileLayer options, like this:\n\n    DG.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\n\n#### Creation\n\nExtension methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-dg-tilelayer\">\n            <td><code>\n                    <b>DG.tilelayer</b>(\n                    <nobr>&lt;String&gt;</nobr> <i>urlTemplate</i>,\n                    <nobr><i>options</i></nobr>)\n                </code>\n            </td>\n            <td>Instantiates a tile layer object given a <code>URL template</code> and optionally an options object.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id=\"tilelayer-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Minimum zoom number.</td>\n        </tr>\n        <tr id=\"tilelayer-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>18</code></td>\n            <td>Maximum zoom number.</td>\n        </tr>\n        <tr id=\"tilelayer-maxnativezoom\">\n            <td><code><b>maxNativeZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>Maximum zoom number the tile source has available. If it is specified,\n                the tiles on all zoom levels higher than <code>maxNativeZoom</code> will be loaded\n                from <code>maxNativeZoom</code> level and auto-scaled.\n            </td>\n        </tr>\n        <tr id=\"tilelayer-subdomains\">\n            <td><code><b>subdomains</b></code></td>\n            <td><code>String|String[] </code></td>\n            <td><code>&#x27;abc&#x27;</code></td>\n            <td>Subdomains of the tile service. Can be passed in the form of one string (where each letter\n                is a subdomain name) or an array of strings.\n            </td>\n        </tr>\n        <tr id=\"tilelayer-errortileurl\">\n            <td><code><b>errorTileUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>URL to the tile image to show in place of the tile that failed to load.</td>\n        </tr>\n        <tr id=\"tilelayer-zoomoffset\">\n            <td><code><b>zoomOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>The zoom number used in tile URLs will be offset with this value.</td>\n        </tr>\n        <tr id=\"tilelayer-tms\">\n            <td><code><b>tms</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, inverses Y axis numbering for tiles (turn this on for TMS services).</td>\n        </tr>\n        <tr id=\"tilelayer-zoomreverse\">\n            <td><code><b>zoomReverse</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If set to true, the zoom number used in tile URLs will be reversed\n                (<code>maxZoom - zoom</code> instead of <code>zoom</code>)\n            </td>\n        </tr>\n        <tr id=\"tilelayer-detectretina\">\n            <td><code><b>detectRetina</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code> and user is on a retina display, it will request four tiles of half\n                the specified size and a bigger zoom level in place of one to utilize the high resolution.\n            </td>\n        </tr>\n        <tr id=\"tilelayer-crossorigin\">\n            <td><code><b>crossOrigin</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If true, all tiles will have their crossOrigin attribute set to &#39;&#39;. This is needed if\n                you want to access tile pixel data.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/other-layers#gridlayer-options\">GridLayer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/other-layers#gridlayer-events\">GridLayer</a> <!-- TODO: include events -->\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table id=\"tilelayer-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-seturl\">\n            <td><code><b>setUrl</b>(\n                <nobr>&lt;String&gt; <i>url</i></nobr>\n                <nobr>&lt;Boolean&gt; <i>noRedraw?</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Updates the layer&#39;s URL template and redraws it (unless <code>noRedraw</code>\n                is set to <code>true</code>).\n            </td>\n        </tr>\n        <tr id=\"tilelayer-createtile\">\n            <td><code><b>createTile</b>(\n                <nobr>&lt;Object&gt;</nobr> <i>coords</i>,\n                <nobr>&lt;Function&gt;</nobr> <i>done?</i>)</nobr>\n            </code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Called only internally, overrides GridLayer&#39;s\n                <a href=\"/doc/maps/en/manual/other-layers#gridlayer-createtile\"><code>createTile()</code></a>\n                to return an <code>&lt;img&gt;</code> HTML element with the appropiate\n                image URL given <code>coords</code>. The <code>done</code>\n                callback is called when the tile has been loaded.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Extension methods\n\nLayers extending <a href=\"#dgtilelayer\">TileLayer</a> might reimplement the following method.\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-gettileurl\">\n            <td><code><b>getTileUrl</b>(<nobr>&lt;Object&gt;</nobr> <i>coords</i>)</nobr></code></td>\n            <td><code>String</code></td>\n            <td>Called only internally, returns the URL for a tile given its coordinates.\n                Classes extending <a href=\"#dgtilelayer\"><code>TileLayer</code></a> can override\n                this function to provide custom tile URL naming schemes.</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from GridLayer <a href=\"/doc/maps/en/manual/other-layers#gridlayer-methods\">GridLayer</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.TileLayer.wms\n\nUsed to display WMS services as tile layers on the map. Extends <a href=\"#dgtilelayer\">TileLayer</a>.\n\n#### Usage Example\n\n    var nexrad = DG.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\n        layers: 'nexrad-n0r-900913',\n        format: 'image/png',\n        transparent: true,\n        attribution: \"Weather data © 2012 IEM Nexrad\"\n    });\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-dg-tilelayer-wms\">\n            <td><code><b>DG.tileLayer.wms</b>(\n                <nobr>&lt;String&gt; <i>baseUrl</i></nobr>,\n                <nobr>&lt;<a href=\"#tilelayer-wms-options\">TileLayer.WMS options</a>&gt; <i>options</i>)</nobr>\n            </code></td>\n            <td>Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS\n                parameters/options object.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id=\"tilelayer-wms-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-layers\">\n            <td><code><b>layers</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td><strong>(required)</strong> Comma-separated list of WMS layers to show.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-styles\">\n            <td><code><b>styles</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Comma-separated list of WMS styles.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-format\">\n            <td><code><b>format</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;image/jpeg&#x27;</code></td>\n            <td>WMS image format (use <code>&#39;image/png&#39;</code> for layers with transparency).</td>\n        </tr>\n        <tr id=\"tilelayer-wms-transparent\">\n            <td><code><b>transparent</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, the WMS service will return images with transparency.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-version\">\n            <td><code><b>version</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;1.1.1&#x27;</code></td>\n            <td>Version of the WMS service to use</td>\n        </tr>\n        <tr id=\"tilelayer-wms-crs\">\n            <td><code><b>crs</b></code></td>\n            <td><code>CRS </code></td>\n            <td><code>null</code></td>\n            <td>Coordinate Reference System to use for the WMS requests, defaults to\n                map CRS. Don&#39;t change this if you&#39;re not sure what it means.\n            </td>\n        </tr>\n        <tr id=\"tilelayer-wms-uppercase\">\n            <td><code><b>uppercase</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, WMS request parameter keys will be uppercase.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"#tilelayer-options\">TileLayer</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/other-layers#gridlayer-options\">GridLayer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/other-layers#gridlayer-events\">GridLayer</a> <!-- TODO: include events -->\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-setparams\">\n            <td><code><b>setParams</b>(\n                <nobr>&lt;Object&gt; <i>params</i></nobr>,\n                <nobr>&lt;Boolean&gt; <i>noRedraw?</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Merges an object with the new parameters and re-requests tiles on the current screen\n                (unless <code>noRedraw</code> was set to true).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from TileLayer <a href=\"#tilelayer-methods\">TileLayer</a> <!-- TODO: include methods -->\n\nMethods inherited from GridLayer <a href=\"/doc/maps/en/manual/other-layers#gridlayer-methods\">GridLayer</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.ImageOverlay\n\nUsed to load and display a single image over specific bounds of the map. Extends Layer.\n\n#### Usage Example\n\n    var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\n        imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\n    DG.imageOverlay(imageUrl, imageBounds).addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-l-imageoverlay\">\n            <td><code><b>L.imageOverlay</b>(\n                <nobr>&lt;String&gt; <i>imageUrl</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                <nobr>&lt;ImageOverlay options&gt;</nobr> <i>options?</i></nobr>)\n            </code></td>\n            <td>Instantiates an image overlay object given the URL of the image and the\n                geographical bounds it is tied to.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>The opacity of the image overlay.</td>\n        </tr>\n        <tr id=\"imageoverlay-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Text for the <code>alt</code> attribute of the image (useful for accessibility).</td>\n        </tr>\n        <tr id=\"imageoverlay-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If <code>true</code>, the image overlay will emit mouse events when clicked or hovered.</td>\n        </tr>\n        <tr id=\"imageoverlay-attribution\">\n            <td><code><b>attribution</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>An optional string containing HTML to be shown on the <code>Attribution control</code></td>\n        </tr>\n        <tr id=\"imageoverlay-crossorigin\">\n            <td><code><b>crossOrigin</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>If true, the image will have its crossOrigin attribute set to &#39;&#39;.\n                This is needed if you want to access image pixel data.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Mehtods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-setopacity\">\n            <td><code><b>setOpacity</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the opacity of the overlay.</td>\n        </tr>\n        <tr id=\"imageoverlay-bringtofront\">\n            <td><code><b>bringToFront</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Brings the layer to the top of all overlays.</td>\n        </tr>\n        <tr id=\"imageoverlay-bringtoback\">\n            <td><code><b>bringToBack</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Brings the layer to the bottom of all overlays.</td>\n        </tr>\n        <tr id=\"imageoverlay-seturl\">\n            <td><code><b>setUrl</b>(<nobr>&lt;String&gt; <i>url</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Changes the URL of the image.</td>\n        </tr>\n    </tbody>\n</table>\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/manual/utils.md",
    "content": "## Utility\n\n{toc}\n\n### DG.Browser\n\nA namespace with static properties for browser/feature detection.\n\n    if (DG.Browser.ie6) {\n        alert('Upgrade your browser, dude!');\n    }\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"browser-ie\">\n            <td><code><b>ie</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all Internet Explorer versions (not Edge).</td>\n        </tr>\n        <tr id=\"browser-ielt9\">\n            <td><code><b>ielt9</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for Internet Explorer versions less than 9.</td>\n        </tr>\n        <tr id=\"browser-edge\">\n            <td><code><b>edge</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for the Edge web browser.</td>\n        </tr>\n        <tr id=\"browser-webkit\">\n            <td><code><b>webkit</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for webkit-based browsers like Chrome and Safari (including mobile versions).</td>\n        </tr>\n        <tr id=\"browser-gecko\">\n            <td><code><b>gecko</b></code></td>\n            <td><code>Boolean</code></td>\n\t\t    <td><code>true</code> for gecko-based browsers like Firefox.</td>\n        </tr>\n        <tr id=\"browser-android\">\n            <td><code><b>android</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for any browser running on an Android platform.</td>\n        </tr>\n        <tr id=\"browser-android23\">\n            <td><code><b>android23</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for browsers running on Android 2 or Android 3.</td>\n        </tr>\n        <tr id=\"browser-chrome\">\n            <td><code><b>chrome</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for the Chrome browser.</td>\n        </tr>\n        <tr id=\"browser-safari\">\n            <td><code><b>safari</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for the Safari browser.</td>\n        </tr>\n        <tr id=\"browser-ie3d\">\n            <td><code><b>ie3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all Internet Explorer versions supporting CSS transforms.</td>\n        </tr>\n        <tr id=\"browser-webkit3d\">\n            <td><code><b>webkit3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for webkit-based browsers supporting CSS transforms.</td>\n        </tr>\n        <tr id=\"browser-gecko3d\">\n            <td><code><b>gecko3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for gecko-based browsers supporting CSS transforms.</td>\n        </tr>\n        <tr id=\"browser-opera12\">\n            <td><code><b>opera12</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for the Opera browser supporting CSS transforms (version 12 or later).</td>\n        </tr>\n        <tr id=\"browser-any3d\">\n            <td><code><b>any3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all browsers supporting CSS transforms.</td>\n        </tr>\n        <tr id=\"browser-mobile\">\n            <td><code><b>mobile</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all browsers running in a mobile device.</td>\n        </tr>\n        <tr id=\"browser-mobilewebkit\">\n            <td><code><b>mobileWebkit</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all webkit-based browsers in a mobile device.</td>\n        </tr>\n        <tr id=\"browser-mobilewebkit3d\">\n            <td><code><b>mobileWebkit3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all webkit-based browsers in a mobile device supporting CSS transforms.</td>\n        </tr>\n        <tr id=\"browser-mobileopera\">\n            <td><code><b>mobileOpera</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for the Opera browser in a mobile device.</td>\n        </tr>\n        <tr id=\"browser-mobilegecko\">\n            <td><code><b>mobileGecko</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for gecko-based browsers running in a mobile device.</td>\n        </tr>\n        <tr id=\"browser-touch\">\n            <td><code><b>touch</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all browsers supporting <a href=\"https://developer.mozilla.org/docs/Web/API/Touch_events\">touch events</a>.</td>\n        </tr>\n        <tr id=\"browser-mspointer\">\n            <td><code><b>msPointer</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for browsers implementing the Microsoft touch events model (notably IE10).</td>\n        </tr>\n        <tr id=\"browser-pointer\">\n            <td><code><b>pointer</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for all browsers supporting <a href=\"https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx\">pointer events</a>.</td>\n        </tr>\n        <tr id=\"browser-retina\">\n            <td><code><b>retina</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> for browsers on a high-resolution &quot;retina&quot; screen.</td>\n        </tr>\n        <tr id=\"browser-canvas\">\n            <td><code><b>canvas</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> when the browser supports <a href=\"https://developer.mozilla.org/docs/Web/API/Canvas_API\"><code>&lt;canvas&gt;</code></a>.</td>\n        </tr>\n        <tr id=\"browser-vml\">\n            <td><code><b>vml</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> if the browser supports <a href=\"https://en.wikipedia.org/wiki/Vector_Markup_Language\">VML</a>.</td>\n        </tr>\n        <tr id=\"browser-svg\">\n            <td><code><b>svg</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> when the browser supports <a href=\"https://developer.mozilla.org/docs/Web/SVG\">SVG</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Util\n\nVarious utility functions.\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"util-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;Object&gt; <i>dest</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>src?</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Merges the properties of the <code>src</code> object (or multiple objects) into <code>dest</code>\n                object and returns the latter. Has an <code>DG.extend</code> shortcut.</td>\n        </tr>\n        <tr id=\"util-create\">\n            <td><code><b>create</b>(\n                <nobr>&lt;Object&gt; <i>proto</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>properties?</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Compatibility polyfill for\n                <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create\">Object.create</a></td>\n        </tr>\n        <tr id=\"util-bind\">\n            <td><code><b>bind</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>, <i>…</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td>Returns a new function bound to the arguments passed, like\n                <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind\">Function.prototype.bind</a>.\n                Has a <code>DG.bind()</code> shortcut.</td>\n        </tr>\n        <tr id=\"util-stamp\">\n            <td><code><b>stamp</b>(\n                <nobr>&lt;Object&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the unique ID of an object, assiging it one if it doesn&#39;t have it.</td>\n        </tr>\n        <tr id=\"util-throttle\">\n            <td><code><b>throttle</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>time</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td>Returns a function which executes function <code>fn</code> with the given scope <code>context</code>\n                (so that the <code>this</code> keyword refers to <code>context</code> inside <code>fn</code>&#39;s code).\n                The arguments received by the bound function will be any arguments passed when binding the function,\n                followed by any arguments passed when invoking the bound function. Has an <code>DG.bind</code> shortcut.</td>\n        </tr>\n        <tr id=\"util-wrapnum\">\n            <td><code><b>wrapNum</b>(\n                <nobr>&lt;Number&gt; <i>num</i>,</nobr>\n                <nobr>&lt;Number[]&gt; <i>range</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>includeMax?</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the number <code>num</code> modulo <code>range</code> in such a way so it lies within\n                <code>range[0]</code> and <code>range[1]</code>. The returned value will be always smaller than\n                <code>range[1]</code> unless <code>includeMax</code> is set to <code>true</code>.</td>\n        </tr>\n        <tr id=\"util-falsefn\">\n            <td><code><b>falseFn</b>()</code></td>\n\n            <td><code>Function</code></td>\n            <td>Returns a function which always returns <code>false</code>.</td>\n        </tr>\n        <tr id=\"util-formatnum\">\n            <td><code><b>formatNum</b>(\n                <nobr>&lt;Number&gt; <i>num</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>digits?</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the number <code>num</code> rounded to <code>digits</code> decimals, or to 5 decimals by default.</td>\n        </tr>\n        <tr id=\"util-trim\">\n            <td><code><b>trim</b>(\n                <nobr>&lt;String&gt; <i>str</i> )</nobr>\n            </code></td>\n\n            <td><code>String</code></td>\n            <td>Compatibility polyfill for\n                <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim\">String.prototype.trim</a></td>\n        </tr>\n        <tr id=\"util-splitwords\">\n            <td><code><b>splitWords</b>(\n                <nobr>&lt;String&gt; <i>str</i> )</nobr>\n            </code></td>\n\n            <td><code>String[]</code></td>\n            <td>Trims and splits the string on whitespace and returns the array of parts.</td>\n        </tr>\n        <tr id=\"util-setoptions\">\n            <td><code><b>setOptions</b>(\n                <nobr>&lt;Object: options: Object&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Merges the given properties to the <code>options</code> of the <code>obj</code> object, returning\n                the resulting options. See <code>Class options</code>. Has an <code>DG.setOptions</code> shortcut.</td>\n        </tr>\n        <tr id=\"util-getparamstring\">\n            <td><code><b>getParamString</b>(\n                <nobr>&lt;Object&gt; <i>obj</i>,</nobr>\n                <nobr>&lt;String&gt; <i>existingUrl?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>uppercase?</i> )</nobr>\n            </code></td>\n\n            <td><code>String</code></td>\n            <td>Converts an object into a parameter URL string, e.g. <code>{a: &quot;foo&quot;, b: &quot;bar&quot;}</code>\n                translates to <code>&#39;?a=foo&amp;b=bar&#39;</code>. If <code>existingUrl</code> is set, the parameters will\n                be appended at the end. If <code>uppercase</code> is <code>true</code>, the parameter names will\n                be uppercased (e.g. <code>&#39;?A=foo&amp;B=bar&#39;</code>)\n                Simple templating facility, accepts a template string of the form <code>&#39;Hello {a}, {b}&#39;</code>\n                and a data object like <code>{a: &#39;foo&#39;, b: &#39;bar&#39;}</code>, returns evaluated string\n                <code>(&#39;Hello foo, bar&#39;)</code>. You can also specify functions instead of strings for\n                data values — they will be evaluated passing <code>data</code> as an argument.</td>\n        </tr>\n        <tr id=\"util-isarray\">\n            <td><code><b>isArray</b>(<i>obj</i>)</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Compatibility polyfill for\n                <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray\">Array.isArray</a></td>\n        </tr>\n        <tr id=\"util-indexof\">\n            <td><code><b>indexOf</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Compatibility polyfill for\n                <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf\">Array.prototype.indexOf</a></td>\n        </tr>\n        <tr id=\"util-requestanimframe\">\n            <td><code><b>requestAnimFrame</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>immediate?</i> )</nobr>\n            </code></td>\n\n            <td><code>requestId: Number</code></td>\n            <td>Schedules <code>fn</code> to be executed when the browser repaints. <code>fn</code> is bound to\n                <code>context</code> if given. When <code>immediate</code> is set, <code>fn</code> is called immediately if\n                the browser doesn&#39;t have native support for\n                <a href=\"https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame\"><code>window.requestAnimationFrame</code></a>,\n                otherwise it&#39;s delayed. Returns an id that can be used to cancel the request.</td>\n        </tr>\n        <tr id=\"util-cancelanimframe\">\n            <td><code><b>cancelAnimFrame</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n            <td><code></code></td>\n            <td>Cancels a previous <code>requestAnimFrame</code>. See also\n                <a href=\"https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame\">window.cancelAnimationFrame</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Properties\n\n<table>\n    <thead>\n        <tr>\n            <th>Property</th>\n            <th>Type</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"util-lastid\">\n            <td><code><b>lastId</b></code></td>\n            <td><code>Number</code></td>\n            <td>Last unique ID used by <a href=\"#util-stamp\"><code>stamp()</code></a></td>\n        </tr>\n        <tr id=\"util-emptyimageurl\">\n            <td><code><b>emptyImageUrl</b></code></td>\n            <td><code>String</code></td>\n            <td>Data URI string containing a base64-encoded empty GIF image.\n                Used as a hack to free memory from unused images on WebKit-powered\n                mobile devices (by setting image <code>src</code> to this string).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.LineUtil\n\nVarious utility functions for polyine points processing, used by Leaflet internally to make polylines lightning-fast.\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"lineutil-simplify\">\n            <td><code><b>simplify</b>(\n                <nobr>&lt;Point[]&gt; <i>points</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>tolerance</i> )</nobr>\n            </code></td>\n\n            <td><code>Point[]</code></td>\n            <td>Dramatically reduces the number of points in a polyline while retaining\n                its shape and returns a new array of simplified points, using the\n                <a href=\"http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm\">Douglas-Peucker algorithm</a>.\n                Used for a huge performance boost when processing/displaying Leaflet polylines for\n                each zoom level and also reducing visual noise. tolerance affects the amount of\n                simplification (lesser value means higher quality but slower and with more points).\n                Also released as a separated micro-library <a href=\"http://mourner.github.com/simplify-js/\">Simplify.js</a>.</td>\n        </tr>\n        <tr id=\"lineutil-pointtosegmentdistance\">\n            <td><code><b>pointToSegmentDistance</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p1</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p2</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the distance between point <code>p</code> and segment <code>p1</code> to <code>p2</code>.</td>\n        </tr>\n        <tr id=\"lineutil-closestpointonsegment\">\n            <td><code><b>closestPointOnSegment</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p1</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgpoint\">Point</a>&gt; <i>p2</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Returns the closest point from a point <code>p</code> on a segment <code>p1</code> to <code>p2</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.PolyUtil\n\nVarious utility functions for polygon geometries.\n\n#### Functions\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"polyutil-clippolygon\">\n\t\t    <td><code><b>clipPolygon</b>(\n\t\t        <nobr>&lt;Point[]&gt; <i>points</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dgbounds\">Bounds</a>&gt; <i>bounds</i>,</nobr>\n\t\t        <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code>Point[]</code></td>\n    \t\t<td>Clips the polygon geometry defined by the given <code>points</code> by the given bounds\n    \t\t    (using the <a href=\"https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm\">Sutherland-Hodgeman algorithm</a>).\n                Used by Leaflet to only show polygon points that are on the screen or near, increasing\n                performance. Note that polygon points needs different algorithm for clipping\n                than polyline, so there&#39;s a seperate method for it.</td>\n    \t</tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/en/manual/vector-layers.md",
    "content": "## Vector Layers\n\nThis section describes classes for working with vector layers - a geometrical\nobjects like circles, polylines and polygons.\n\n{toc}\n\n### DG.Path\n\nAn abstract class that contains options and constants shared between vector overlays \n(Polygon, Polyline, Circle). Do not use it directly. Extends <a href=\"/doc/maps/en/manual/base-classes#dglayer\">Layer</a>.\n\n#### Options\n\n<table id=\"dgpath-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"path-stroke\">\n            <td><code><b>stroke</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Whether to draw stroke along the path. Set it to <code>false</code>\n                to disable borders on polygons or circles.</td>\n        </tr>\n        <tr id=\"path-color\">\n            <td><code><b>color</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;#3388ff&#x27;</code></td>\n            <td>Stroke color</td>\n        </tr>\n        <tr id=\"path-weight\">\n            <td><code><b>weight</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>3</code></td>\n            <td>Stroke width in pixels</td>\n        </tr>\n        <tr id=\"path-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>Stroke opacity</td>\n        </tr>\n        <tr id=\"path-linecap\">\n            <td><code><b>lineCap</b></code></td>\n            <td><code>String</code></td>\n            <td><code>&#x27;round&#x27;</code></td>\n            <td>A string that defines\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap\">shape to be\n                used at the end</a> of the stroke.</td>\n        </tr>\n        <tr id=\"path-linejoin\">\n            <td><code><b>lineJoin</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;round&#x27;</code></td>\n            <td>A string that defines\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin\">shape to\n                be used at the corners</a> of the stroke.</td>\n        </tr>\n        <tr id=\"path-dasharray\">\n            <td><code><b>dashArray</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>A string that defines the stroke\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray\">dash pattern</a>.\n                Doesn&#39;t work on canvas-powered layers (e.g. Android 2).</td>\n        </tr>\n        <tr id=\"path-dashoffset\">\n            <td><code><b>dashOffset</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>A string that defines the\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset\">distance\n                into the dash pattern to start the dash</a>. Doesn&#39;t work on canvas-powered layers</td>\n        </tr>\n        <tr id=\"path-fill\">\n            <td><code><b>fill</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>depends</code></td>\n            <td>Whether to fill the path with color. Set it to <code>false</code> to disable\n                filling on polygons or circles.</td>\n        </tr>\n        <tr id=\"path-fillcolor\">\n            <td><code><b>fillColor</b></code></td>\n            <td><code>String </code></td>\n            <td><code>*</code></td>\n            <td>Fill color. Defaults to the value of the <a href=\"#path-color\"><code>color</code></a> option</td>\n        </tr>\n        <tr id=\"path-fillopacity\">\n            <td><code><b>fillOpacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.2</code></td>\n            <td>Fill opacity.</td>\n        </tr>\n        <tr id=\"path-fillrule\">\n            <td><code><b>fillRule</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;evenodd&#x27;</code></td>\n            <td>A string that defines\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule\">how the inside\n                of a shape</a> is determined.</td>\n        </tr>\n        <tr id=\"path-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>If <code>false</code>, the vector will not emit mouse events and will\n                act as a part of the underlying map.</td>\n        </tr>\n        <tr id=\"path-renderer\">\n            <td><code><b>renderer</b></code></td>\n            <td><code><a href=\"/doc/maps/en/manual/base-classes#dgrenderer\">Renderer</a></code></td>\n            <td><code></code></td>\n            <td>Use this specific instance of <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\"><code>Renderer</code></a> for this path. Takes\n                precedence over the map&#39;s <a href=\"/doc/maps/en/manual/map#map-renderer\">default renderer</a>.</td>\n        </tr>\n        <tr id=\"path-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>string </code></td>\n            <td><code>null</code></td>\n            <td>Custom class name set on an element. Only for SVG renderer.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table id=\"dgpath-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"path-redraw\">\n            <td><code><b>redraw</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.</td>\n        </tr>\n        <tr id=\"path-setstyle\">\n            <td><code>\n                <b>setStyle</b>(\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>style</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Changes the appearance of a Path based on the options in the <a href=\"#dgpath-options\">\n                <code>Path options</code></a> object.</td>\n        </tr>\n        <tr id=\"path-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Brings the layer to the top of all path layers.</td>\n        </tr>\n        <tr id=\"path-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Brings the layer to the bottom of all path layers. </td>\n        </tr>\n    </tbody>\n</table>\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Polyline\n\nA class for drawing polyline overlays on a map. Extends <a href=\"#dgpath\">Path</a>.\n\n#### Usage example\n\n    // create a red polyline from an array of LatLng points\n    var latlngs = [\n        [-122.68, 45.51],\n        [-122.43, 37.77],\n        [-118.2, 34.04]\n    ];\n    var polyline = DG.polyline(latlngs, {color: 'red'}).addTo(map);\n    // zoom the map to the polyline\n    map.fitBounds(polyline.getBounds());\n\nYou can also pass a multi-dimensional array to represent a MultiPolyline shape:\n\n    // create a red polyline from an array of arrays of LatLng points\n    var latlngs = [\n        [[-122.68, 45.51],\n         [-122.43, 37.77],\n         [-118.2, 34.04]],\n        [[-73.91, 40.78],\n         [-87.62, 41.83],\n         [-96.72, 32.76]]\n    ];\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-l-polyline\">\n            <td><code><b>DG.polyline</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i></nobr>,\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Instantiates a polyline object given an array of geographical points and\n                optionally an options object. You can create a <a href=\"#dgpolyline\"><code>Polyline</code></a>\n                object with multiple separate lines (<code>MultiPolyline</code>) by passing an array of arrays\n                of geographic points.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table id=\"dgpolyline-options\">\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-smoothfactor\">\n            <td><code><b>smoothFactor</b></code></td>\n            <td><code>Number </code>\n            <td><code>1.0</code></td>\n            <td>How much to simplify the polyline on each zoom level. More means\n                better performance and smoother look, and less means more accurate representation.</td>\n        </tr>\n        <tr id=\"polyline-noclip\">\n            <td><code><b>noClip</b></code></td>\n            <td><code>Boolean: false</code>\n            <td><code></code></td>\n            <td>Disable polyline clipping.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table id=\"dgpolyline-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Returns a <a href=\"http://en.wikipedia.org/wiki/GeoJSON\">\n                <code>GeoJSON</code></a> representation of the polyline\n                (as a GeoJSON <code>LineString</code> or <code>MultiLineString</code> Feature).</td>\n        </tr>\n        <tr id=\"polyline-getlatlngs\">\n            <td><code><b>getLatLngs</b>()</code></td>\n            <td><code>LatLng[]</code></td>\n            <td>Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.</td>\n        </tr>\n        <tr id=\"polyline-setlatlngs\">\n            <td><code><b>setLatLngs</b>(<nobr>&lt;LatLng[]&gt; <i>latlngs</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Replaces all the points in the polyline with the given array of geographical points.</td>\n        </tr>\n        <tr id=\"polyline-isempty\">\n            <td><code><b>isEmpty</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Returns <code>true</code> if the Polyline has no LatLngs.</td>\n        </tr>\n        <tr id=\"polyline-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns the center (<a href=\"http://en.wikipedia.org/wiki/Centroid\">centroid</a>) of the\n            polyline.</td>\n        </tr>\n        <tr id=\"polyline-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns the <a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\"><code>LatLngBounds</code></a> of the path.</td>\n        </tr>\n        <tr id=\"polyline-addlatlng\">\n            <td><code><b>addLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>\n                    Adds a given point to the polyline. By default, adds to the first ring of\n                    the polyline in case of a multi-polyline, but can be overridden by passing\n                    a specific ring as a LatLng array (that you can earlier access with\n                    <a href=\"#polyline-getlatlngs\"><code>getLatLngs</code></a>).\n                </td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Polygon\n\nA class for drawing polygon overlays on a map. Extends <a href=\"#dgpolyline\">Polyline</a>.\nNote that points you pass when creating a polygon shouldn't have an additional last point equal\nto the first one — it's better to filter out such points.\n\n#### Usage example\n\n    // create a red polygon from an array of LatLng points\n    var latlngs = [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]];\n    var polygon = DG.polygon(latlngs, {color: 'red'}).addTo(map);\n    // zoom the map to the polygon\n    map.fitBounds(polygon.getBounds());\n\nYou can also pass an array of arrays of latlngs, with the first array representing the outer shape\nand the other arrays representing holes in the outer shape:\n\n    var latlngs = [\n      [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring\n      [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole\n    ];\n\nAdditionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.\n\n    var latlngs = [\n      [ // first polygon\n        [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring\n        [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole\n      ],\n      [ // second polygon\n        [[-109.05, 37],[-109.03, 41],[-102.05, 41],[-102.04, 37],[-109.05, 38]]\n      ]\n    ];\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polygon-l-polygon\">\n            <td><code>\n                <b>DG.polygon</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i></nobr>,\n                <nobr>&lt;Polyline options&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td></td>\n        </tr>\n    </tbody>\n</table>\n\n\n#### Options\n\nOptions inherited from <a href=\"#dgpolyline-options\">Polyline</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<span id=\"#dgpolygon-methods\"></span>\n\nMethods inherited from <a href=\"#dgpolyline-methods\">Polyline</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Rectangle\n\nA class for drawing rectangle overlays on a map. Extends <a href=\"#dgpolygon\">Polygon</a>.\n\n#### Usage example\n\n    // define rectangle geographical bounds\n    var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n    // create an orange rectangle\n    DG.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n    // zoom the map to the rectangle bounds\n    map.fitBounds(bounds);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"rectangle-l-rectangle\">\n            <td><code>\n                <b>DG.rectangle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>latLngBounds</i></nobr>,\n                <nobr>&lt;Polyline options&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"#dgpolyline-options\">Polyline</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"rectangle-setbounds\">\n            <td><code><b>setBounds</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>latLngBounds</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Redraws the rectangle with the passed bounds.</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"#dgpolygon-method\">Polygon</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Circle\n\nA class for drawing circle overlays on a map. Extends <a href=\"#dgcirclemarker\">CircleMarker</a>. It's an approximation\nand starts to diverge from a real circle closer to poles (due to projection distortion).\n\n#### Usage example\n\n    DG.circle([50.5, 30.5], 200).addTo(map);\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-l-circle\">\n            <td><code>\n                <b>DG.circle</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Instantiates a circle object given a geographical point, and an options object\n                which contains the circle radius.</td>\n        </tr>\n        <tr id=\"circle-l-circle-2\">\n            <td><code><b>DG.circle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                <nobr>&lt;Number&gt; <i>radius</i></nobr>,\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Obsolete way of instantiating a circle, for compatibility with old code.\n                Do not use in new applications or plugins.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-radius\">\n            <td><code><b>radius</b></code></td>\n            <td><code>Number</code>\n            <td><code></code></td>\n            <td>Radius of the circle, in meters.</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table>\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-setradius\">\n            <td><code>\n                <b>setRadius</b>(\n                <nobr>&lt;Number&gt; <i>radius</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Sets the radius of a circle. Units are in meters.</td>\n        </tr>\n        <tr id=\"circle-getradius\">\n            <td><code><b>getRadius</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Returns the current radius of a circle. Units are in meters.</td>\n        </tr>\n        <tr id=\"circle-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Returns the <a href=\"/doc/maps/en/manual/basic-types#dglatlngbounds\"><code>LatLngBounds</code></a>\n                of the path.</td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"#dgcirclemarker-methods\">CircleMarker</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.CircleMarker\n\nA circle of a fixed size with radius specified in pixels. Extends <a href=\"#dgpath\">Path</a>.\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-dg-circlemarker\">\n            <td><code>\n                <b>DG.circleMarker</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                <i>options</i>)</code></td>\n            <td>Instantiates a circle marker object given a geographical point, and an optional options object.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\n<table>\n    <thead>\n        <tr>\n            <th>Option</th>\n            <th>Type</th>\n            <th>Default</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-radius\">\n            <td><code><b>radius</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>10</code></td>\n            <td>Radius of the circle marker, in pixels</td>\n        </tr>\n    </tbody>\n</table>\n\nOptions inherited from <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\n<table id=\"dgcirclemarker-methods\">\n    <thead>\n        <tr>\n            <th>Method</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>\n                    Returns a <a href=\"http://en.wikipedia.org/wiki/GeoJSON\"><code>GeoJSON</code></a>\n                    representation of the circle marker (as a GeoJSON <a href=\"/doc/maps/en/manual/basic-types#point\"><code>Point</code></a>\n                    Feature).\n                </td>\n        </tr>\n        <tr id=\"circlemarker-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latLng</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the position of a circle marker to a new location. </td>\n        </tr>\n        <tr id=\"circlemarker-getlatlng\">\n            <td><code><b>getLatLng</b>()</code></td>\n            <td><code><a href=\"/doc/maps/en/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Returns the current geographical position of the circle marker </td>\n        </tr>\n        <tr id=\"circlemarker-setradius\">\n            <td><code><b>setRadius</b>(<nobr>&lt;Number&gt; <i>radius</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Sets the radius of a circle marker. Units are in pixels. </td>\n        </tr>\n        <tr id=\"circlemarker-getradius\">\n            <td><code><b>getRadius</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Returns the current radius of the circle </td>\n        </tr>\n    </tbody>\n</table>\n\nMethods inherited from <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n\n### DG.Svg\n\nAllows vector layers to be displayed with <a href=\"https://developer.mozilla.org/docs/Web/SVG\">SVG</a>.\nInherits <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\">Renderer</a>.\n\nDue to <a href=\"http://caniuse.com/#search=svg\">technical limitations</a>, SVG is not\navailable in all web browsers, notably Android 2.x and 3.x.\n\nAlthough SVG is not available on IE8, this browser supports\n<a href=\"https://en.wikipedia.org/wiki/Vector_Markup_Language\">VML</a>\n(a now deprecated technology), and the SVG renderer will fall back to VML in\nthis case.\n\n\n#### Usage example\n\nUse SVG by default for all paths in the map:\n\n    var map = DG.map(\"map\", {\n        renderer: DG.svg();\n    });\n\nUse a SVG renderer with extra padding for specific vector geometries:\n\n    var map = DG.map(\"map\");\n    var myRenderer = DG.svg({ padding: 0.5 });\n    var line = DG.polyline( coordinates, { renderer: myRenderer } );\n    var circle = DG.circle( center, { renderer: myRenderer } );\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"svg-dg-svg\">\n            <td><code><b>DG.svg</b>(<nobr>&lt;SVG options&gt; <i>options?</i>)</nobr></code></td>\n            <td>Creates a SVG renderer with the given options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgrenderer-options\">Renderer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n#### Functions\n\nThere are several static functions which can be called without instantiating DG.SVG:\n\n<table>\n    <thead>\n        <tr>\n            <th>Function</th>\n            <th>Returns</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"svg-create\">\n            <td><code><b>create</b>(<nobr>&lt;String&gt; <i>name</i>)</nobr></code></td>\n            <td><code>SVGElement</code></td>\n            <td>Returns a instance of <a href=\"https://developer.mozilla.org/docs/Web/API/SVGElement\">SVGElement</a>,\n                corresponding to the class name passed. For example, using &#39;line&#39; will return\n                an instance of <a href=\"https://developer.mozilla.org/docs/Web/API/SVGLineElement\">SVGLineElement</a>.</td>\n        </tr>\n        <tr id=\"svg-pointstopath\">\n            <td><code>\n                <b>pointsToPath</b>(\n                <nobr>&lt;[]&gt; <i>rings</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>closed</i>)</nobr>\n            </code></td>\n            <td><code>String</code></td>\n            <td>Generates a SVG path string for multiple rings, with each ring turning\n                into &quot;M..L..L..&quot; instructions</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Canvas\n\nAllows vector layers to be displayed with <a href=\"https://developer.mozilla.org/docs/Web/API/Canvas_API\">canvas</a>.\nInherits <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\"><code>Renderer</code></a>.\nInherits <a href=\"/doc/maps/en/manual/base-classes#dgrenderer\">Renderer</a>.\nDue to <a href=\"http://caniuse.com/#search=canvas\">technical limitations</a>, Canvas is not\navailable in all web browsers, notably IE8, and overlapping geometries might\nnot display properly in some edge cases.\n\n#### Usage example\n\nUse Canvas by default for all paths in the map:\n\n    var map = DG.map('map', {\n        renderer: DG.canvas();\n    });\n\nUse a Canvas renderer with extra padding for specific vector geometries:\n\n    var map = DG.map('map');\n    var myRenderer = DG.canvas({ padding: 0.5 });\n    var line = DG.polyline( coordinates, { renderer: myRenderer } );\n    var circle = DG.circle( center, { renderer: myRenderer } );\n\n#### Creation\n\n<table>\n    <thead>\n        <tr>\n            <th>Factory</th>\n            <th>Description</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"canvas-dg-canvas\">\n            <td><code><b>DG.canvas</b>(<nobr>&lt;Canvas options&gt; <i>options?</i>)</nobr></code></td>\n            <td>Creates a Canvas renderer with the given options.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Options\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dgrenderer-options\">Renderer</a> <!-- TODO: include options -->\n\nOptions inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nEvents inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nPopup events inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Methods\n\nPopup methods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nMethods inherited from <a href=\"/doc/maps/en/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/en/quickstart/quickstart.md",
    "content": "## All capabilities of 2GIS API&SDK\n[dev.2gis.com](https://dev.2gis.com/)\n\n## Full updated documentation\n[docs.2gis.com/en](https://docs.2gis.com/en)\n\n\n## General information\n\nWith maps API you can:\n\n* <span style=\"color:323232\">create interactive maps on the web page;</span>\n* <span style=\"color:323232\">display various objects on the map (markers, pop-ups, geometric objects);</span>\n* <span style=\"color:323232\">search on the map: to determine the coordinates of geoobjects by their names and the names by the coordinates.</span>\n\nThe source code of the maps API is available on [GitHub](https://github.com/2gis/mapsapi), the project is open to suggestions and pull-requests.\n\n### Getting started\n\nThe following is a simple example of creating a map.\n\n#### Connect API\n\nTo connect API JavaScript code, add the following code to the head section of the HTML page:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n\nIf you are interested in including the API code using npm, go to the [Connection API](/doc/maps/en/manual/dg-loading#npm) section.\n\n#### Create a map container\n\nTo create a container in which the map will be displayed, you must add a block HTML element of the required size:\n\n    <body>\n        <div id=\"map\" style=\"width:500px; height:400px\"></div>\n    </body>\n\n\n#### Create map\n\nNow everything is prepared for the map creation. To do this, add the following code to the head section:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n        });\n    </script>\n\nIn this example map takes two parameters:\n\n* <span style=\"color:323232\">center - the coordinates of the center of the map in the following format [latitude, longitude];</span>\n* <span style=\"color:323232\">zoom - the scale factor in the range from 1 to 18.</span>\n\n#### Add marker to the map\n\nAfter creating the map you can display a marker on it by adding one line of the code to the previously written one:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n\n            DG.marker([54.98, 82.89]).addTo(map);\n        });\n    </script>\n\n#### Show pop-up with information\n\nIf to extend a little the above added string of the code with a marker, then when clicking on the marker, a popup\nwill be displayed (pop up block) with the information you need:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n\n            DG.marker([54.98, 82.89]).addTo(map).bindPopup('You've clicked on me!');\n        });\n    </script>\n\n#### All together\n\nResulting code:\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>API карт 2ГИС</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n            <script type=\"text/javascript\">\n                var map;\n\n                DG.then(function () {\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('You have clicked on me!');\n                });\n            </script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width:500px; height:400px\"></div>\n        </body>\n    </html>\n\n### Further steps\n\nWas everything successful? Now you can see the <a href=\"/doc/maps/en/manual/dg-loading\">developer guide</a>\nand <a href=\"/doc/maps/en/examples/base\">examples of use</a>.\n\n### Technical support\n\nIf you have any difficulties in working with the maps API &mdash;\n<a href=\"mailto:api@2gis.ru\">email us</a> and we will help you to solve the problem.\n"
  },
  {
    "path": "src/doc/ru/examples/base.md",
    "content": "## Базовое использование\n\n{toc}\n\n### Описание\n\nНиже приведены примеры базового использования карты. Для получения подробной информации о работе с картой воспользуйтесь\nразделами документации <a href=\"/doc/maps/ru/manual/dg-loading\">Подключение API</a> и <a href=\"/doc/maps/ru/manual/map\">Карта</a>.\n\n### Создание карты\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Создание карты</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Создание карты по требованию\n\nИнициализация карты по требованию (удобно при отображении карты во всплывающем окне):\n<input id=\"create\" type=\"button\" value=\"Показать карту\" />\n<div id=\"mapBlock\"></div>\n<script>\n    var createButton = document.getElementById('create');\n\n    createButton.onclick = function() {\n        var container = document.createElement('div'),\n            mapBlock = document.getElementById('mapBlock');\n\n        container.id = 'map1';\n        container.style.width = '100%';\n        container.style.height = '400px';\n        mapBlock.appendChild(container);\n\n        DG.then(function(){\n            DG.map('map1', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n        });\n\n        createButton.onclick = null;\n    }\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Создание карты по требованию</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?lazy=true\"></script>\n        </head>\n        <body>\n            <input id=\"create\" type=\"button\" value=\"Показать карту\" />\n            <div id=\"mapBlock\"></div>\n            <script>\n                var createButton = document.getElementById('create');\n\n                createButton.onclick = function() {\n                    var container = document.createElement('div'),\n                        mapBlock = document.getElementById('mapBlock');\n\n                    container.id = 'map';\n                    container.style.width = '100%';\n                    container.style.height = '400px';\n                    mapBlock.appendChild(container);\n\n                    DG.then(function(){\n                        DG.map('map', {\n                            center: [54.98, 82.89],\n                            zoom: 13\n                        });\n                    });\n                }\n            </script>\n        </body>\n    </html>\n\n### Использование опций подключения\n\nНиже представлен пример вызова карты с таким набором опций: <code>pkg=basic</code>, <code>skin=light</code>. Как\nрезультат мы получим сборку с базовой функциональностью в светлой теме. Все возможные опции можно посмотреть в разделе\n<a href=\"/doc/maps/ru/manual/dg-loading#опцииподключения\">Опции подключения</a>.\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Использование опций подключения</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=basic&skin=light\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Изменение размера карты\n\nПри клике на кнопку изменяется размер контейнера и карта подстраивается под новый размер:\n<input id=\"changeSize\" type=\"button\" value=\"Изменить размер\" />\n<div id=\"map3\" style=\"width: 100%; height: 200px;\"></div>\n<script>\n    var changeSizeButton = document.getElementById('changeSize');\n\n    DG.then(function() {\n        var map,\n            enabled = false;\n\n        map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 15,\n            animate: true\n        });\n\n        changeSizeButton.onclick = function() {\n            var mapDiv = document.getElementById('map3');\n            mapDiv.style.height = (enabled ? '200' : '400') + 'px';\n            enabled = !enabled;\n            map.invalidateSize();\n        }\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Изменение размера карты</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"changeSize\" type=\"button\" value=\"Изменить размер\" />\n            <div id=\"map\" style=\"width: 100%; height: 200px;\"></div>\n            <script>\n                var changeSizeButton = document.getElementById('changeSize');\n\n                DG.then(function() {\n                    var map,\n                        enabled = false;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15,\n                        animate: true\n                    });\n\n                    changeSizeButton.onclick = function() {\n                        var mapDiv = document.getElementById('map');\n                        mapDiv.style.height = (enabled ? '200' : '400') + 'px';\n                        // обновление карты\n                        map.invalidateSize();\n                    }\n                });\n            </script>\n        </body>\n    </html>\n\n### Отключение опций взаимодействия\n\nПример отображения статической карты:\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 13,\n            dragging : false,\n            touchZoom: false,\n            scrollWheelZoom: false,\n            doubleClickZoom: false,\n            boxZoom: false,\n            geoclicker: false,\n            zoomControl: false,\n            fullscreenControl: false\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отключение опций взаимодействия</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13,\n                        dragging : false,\n                        touchZoom: false,\n                        scrollWheelZoom: false,\n                        doubleClickZoom: false,\n                        boxZoom: false,\n                        geoclicker: false,\n                        zoomControl: false,\n                        fullscreenControl: false\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Определение местоположения пользователя\n\nПример определения географического расположения пользователя:\n\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map;\n\n        map = DG.map('map5', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        map.locate({setView: true, watch: true})\n            .on('locationfound', function(e) {\n                DG.marker([e.latitude, e.longitude]).addTo(map);\n            })\n            .on('locationerror', function(e) {\n                DG.popup()\n                  .setLatLng(map.getCenter())\n                  .setContent('Доступ к определению местоположения отключён')\n                  .openOn(map);\n            });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Определение местоположения пользователя</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    map.locate({setView: true, watch: true})\n                        .on('locationfound', function(e) {\n                            DG.marker([e.latitude, e.longitude]).addTo(map);\n                        })\n                        .on('locationerror', function(e) {\n                            DG.popup()\n                              .setLatLng(map.getCenter())\n                              .setContent('Доступ к определению местоположения отключён')\n                              .openOn(map);\n                        });\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/bounds.md",
    "content": "## Работа с границами карты\n\n{toc}\n\n### Описание\n\nНиже приведены примеры ограничения границ карты и уровней масштабирования. Для получения подробной информации о работе\nс картой воспользуйтесь разделом документации <a href=\"/doc/maps/ru/manual/map\">Карта</a>.\n\n### Ограничение границ и масштаба\n\nОграничение просматриваемой области границами города Новосибирск, а также уровней масштабирования диапазоном от 10 до 15:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 10,\n            maxBounds: [\n                [54.8220, 82.4304],\n                [55.1372, 83.3505]\n            ],\n            minZoom: 10,\n            maxZoom: 15\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Ограничение границ и масштаба</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 10,\n                        maxBounds: [\n                            [54.8220, 82.4304],\n                            [55.1372, 83.3505]\n                        ],\n                        minZoom: 10,\n                        maxZoom: 15\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n<!--\n### Карта с панелью\n\nПосле инициализации карты её центр подстраивается таким образом, чтобы центр Москвы был посередине видимой области\n(с учетом левой панели):\n\n<style>\n    #container {\n        height:400px;\n        position: relative;\n    }\n    #content {\n        position: absolute;\n        background:#000;\n        background:rgba(51,51,51,.9);\n        width:200px;\n        height: 400px;\n        z-index: 1000;\n    }\n</style>\n<div id='container'>\n    <div id='content'></div>\n    <div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n</div>\n<script>\n    DG.then(function() {\n        var map;\n        map = DG.map('map1', {\n            center: [55.753559, 37.609218],\n            zoom: 10,\n            zoomControl: false,\n            fullscreenControl: false\n        });\n        DG.control.zoom({position: 'topright'}).addTo(map);\n        map.fitBounds(map.getBounds(), {\n            paddingTopLeft: [200, 0]\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Карта с левой панелью</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <style>\n                #container {\n                    height:400px;\n                    position: relative;\n                }\n                #content {\n                    position: absolute;\n                    background:#000;\n                    background:rgba(51,51,51,.9);\n                    width:200px;\n                    height: 400px;\n                    z-index: 1000;\n                }\n            </style>\n        </head>\n        <body>\n            <div id='container'>\n                <div id='content'></div>\n                <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            </div>\n            <script>\n                DG.then(function() {\n                    var map;\n                    map = DG.map('map', {\n                        center: [55.753559, 37.609218],\n                        zoom: 10,\n                        zoomControl: false,\n                        fullscreenControl: false\n                    });\n                    DG.control.zoom({position: 'topright'}).addTo(map);\n                    map.fitBounds(map.getBounds(), {\n                        paddingTopLeft: [200, 0]\n                    });\n                });\n            </script>\n        </body>\n    </html>\n-->\n"
  },
  {
    "path": "src/doc/ru/examples/controls.md",
    "content": "## Элементы управления\n\n{toc}\n\n### Описание\n\nНиже приведены примеры добавления, размещения и работы с элементами управления. Для получения подробной информации о работе\nс элементами управления воспользуйтесь разделом документации <a href=\"/doc/maps/ru/manual/controls\">Элементы управления</a>.\n\n### Скрытие элементов управления по умолчанию\n\nЕсли необходимо получить \"чистую\" карту, без лишних элементов управления, тогда вам поможет следующий пример:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13,\n            fullscreenControl: false,\n            zoomControl: false\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Скрытие элементов управления по умолчанию</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Отображение элементов управления в разных частях карты\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.control.location({position: 'bottomright'}).addTo(map);\n        DG.control.scale().addTo(map);\n        DG.control.ruler({position: 'bottomleft'}).addTo(map);\n        DG.control.traffic().addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение элементов управления в разных частях карты</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.control.location({position: 'bottomright'}).addTo(map);\n                    DG.control.scale().addTo(map);\n                    DG.control.ruler({position: 'bottomleft'}).addTo(map);\n                    DG.control.traffic().addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/events.md",
    "content": "## Обработка событий\n\n{toc}\n\n### Описание\n\nНиже приведены примеры работы с событиями. Для получения подробной информации перейдите в разделы документации\n<a href=\"/doc/maps/ru/manual/base-classes#dgevented\">DG.Evented</a> и <a href=\"/doc/maps/ru/manual/base-classes#events\">Events</a>.\n\n### Подписка на события\n\nПример подписки на различные события (клик в маркер, карту, геометрию):\n\nВы кликнули в: <span id=\"clicked_element\">никуда</span>\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            clickedElement = document.getElementById('clicked_element'),\n            coords = [\n                [54.99, 82.88],\n                [54.985, 82.94],\n                [54.984, 82.925],\n                [54.981, 82.928]\n            ];\n\n        map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        map.on('click', function(e) {\n            clickedElement.innerHTML = 'карту, координаты ' + e.latlng.lat + ', ' + e.latlng.lng;\n        });\n\n        DG.marker([54.98, 82.89])\n            .on('click', function() {\n                clickedElement.innerHTML = 'маркер';\n            })\n            .addTo(map);\n\n        DG.polygon(coords)\n            .on('click', function() {\n                clickedElement.innerHTML = 'многоугольник';\n            })\n            .addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Подписка на события</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            Вы кликнули в: <span id=\"clicked_element\">никуда</span>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        clickedElement = document.getElementById('clicked_element'),\n                        coords = [\n                            [54.99, 82.88],\n                            [54.985, 82.94],\n                            [54.984, 82.925],\n                            [54.981, 82.928]\n                        ];\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    map.on('click', function(e) {\n                        clickedElement.innerHTML = 'карту, координаты ' + e.latlng.lat + ', ' + e.latlng.lng;\n                    });\n\n                    DG.marker([54.98, 82.89])\n                        .on('click', function() {\n                            clickedElement.innerHTML = 'маркер';\n                        })\n                        .addTo(map);\n\n                    DG.polygon(coords)\n                        .on('click', function() {\n                            clickedElement.innerHTML = 'многоугольник';\n                        })\n                        .addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Подписка на изменение проекта 2ГИС\n\nПри изменении <a href=\"/doc/maps/ru/manual/map#map-projectdetector\">проекта</a>, выделяются границы текущего:\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map, currentProjectBound;\n\n        map = DG.map('map1', {\n            center: DG.latLng(54.98, 82.89),\n            zoom: 9\n        });\n\n        // подписываемся на событие изменения текущего проекта 2GIS\n        map.on('projectchange', function(e) {\n            var bounds = e.getProject().bound;\n            currentProjectBound = DG.geoJSON(bounds, {\n                color:\"#f03\",\n                weight:1\n            }).addTo(map);\n        });\n\n        // подписываемся на событие выхода из проекта 2GIS\n        map.on('projectleave', function(e) {\n            if (currentProjectBound) {\n                map.removeLayer(currentProjectBound);\n            }\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Подписка на изменение проекта 2ГИС</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map, currentProjectBound;\n\n                    map = DG.map('map', {\n                        center: DG.latLng(54.98, 82.89),\n                        zoom: 9\n                    });\n\n                    // подписываемся на событие изменения текущего проекта 2GIS\n                    map.on('projectchange', function(e) {\n                        var bounds = e.getProject().bound;\n                        currentProjectBound = DG.geoJSON(bounds, {\n                            color:\"#f03\",\n                            weight:1\n                        }).addTo(map);\n                    });\n\n                    // подписываемся на событие выхода из проекта 2GIS\n                    map.on('projectleave', function(e) {\n                        if (currentProjectBound) {\n                            map.removeLayer(currentProjectBound);\n                        }\n                    });\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/external-modules.md",
    "content": "## Внешние модули\n\n{toc}\n\n### Описание\n\nНиже приведены примеры подключения и использования внешних модулей. Для получения подробной информации перейдите\nв раздел документации <a href=\"/doc/maps/ru/manual/dg-external-modules\">Внешние модули</a>.\n\n### Кластеризатор\n\nПример подключения кластеризатора. Кластеризатор часто используется для отображения большого количества маркеров.\nКод модуля и его документация доступна в <a href=\"https://github.com/Leaflet/Leaflet.markercluster\" target=\"_blank\">GitHub-репозитории</a> автора.\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css\" />\n<link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css\" />\n<script src=\"https://maps.api.2gis.ru/2.0/cluster_realworld.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        // загрузка кода модуля\n        return DG.plugin('https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js');\n    }).then(function() {\n        map = DG.map('map', {\n            center: DG.latLng(54.92, 82.82),\n            zoom: 9\n        });\n\n        var markers = DG.markerClusterGroup();\n\n        for (var i = 0; i < addressPoints.length; i++) {\n            var a = addressPoints[i];\n            var title = a[2];\n            var marker = DG.marker([a[0], a[1]], { title: title });\n            marker.bindPopup(title);\n            markers.addLayer(marker);\n        }\n\n        map.addLayer(markers);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Кластеризатор</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css\" />\n            <link rel=\"stylesheet\" href=\"https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css\" />\n            <script src=\"https://maps.api.2gis.ru/2.0/cluster_realworld.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    // загрузка кода модуля\n                    return DG.plugin('https://unpkg.com/leaflet.markercluster@1.4.1/dist/leaflet.markercluster.js');\n                }).then(function() {\n                    map = DG.map('map', {\n                        center: DG.latLng(54.92, 82.82),\n                        zoom: 9\n                    });\n\n                    var markers = DG.markerClusterGroup();\n\n                    // обработка координат для установки маркеров\n                    for (var i = 0; i < addressPoints.length; i++) {\n                        var a = addressPoints[i];\n                        var title = a[2];\n                        var marker = DG.marker([a[0], a[1]], { title: title });\n                        marker.bindPopup(title);\n                        markers.addLayer(marker);\n                    }\n\n                    map.addLayer(markers);\n                });\n            </script>\n        </body>\n    </html>\n\n\n### Тепловая карта\n\nПример подключения тепловой карты. Тепловая карта позволяет визуализировать количественные данные в зависимости\nот географического региона. Интенсивность окраски каждого региона зависит от соответствующих ему значений.\n\n<script src=\"https://maps.api.2gis.ru/2.0/heat_realworld.js\"></script>\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        // загрузка кода модуля\n        return DG.plugin('https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js');\n    }).then(function() {\n        map = DG.map('map1', {\n            center: DG.latLng(54.89, 82.45),\n            zoom: 10\n        });\n\n        DG.heatLayer(addressPoints1).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Тепловая карта</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n            <script src=\"https://maps.api.2gis.ru/2.0/heat_realworld.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    // загрузка кода модуля\n                    return DG.plugin('https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js');\n                }).then(function() {\n                    map = DG.map('map', {\n                        center: DG.latLng(54.89, 82.45),\n                        zoom: 10\n                    });\n\n                    DG.heatLayer(addressPoints1).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/geojson.md",
    "content": "## Работа с GeoJSON\n\n{toc}\n\n### Описание\n\nНиже приведен пример работы с GeoJSON. Для получения подробной информации перейдите в раздел документации\n<a href=\"/doc/maps/ru/manual/other-layers#dggeojson\">GeoJSON</a>.\n\n### Пример использования\n\nОтображение объектов, описанных в формате GeoJSON:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map', {\n            center: [55.042136, 82.91699],\n            zoom: 16\n        });\n\n        var data = [\n            {\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"info\": \"Я маркер\"\n                },\n                \"geometry\": {\n                    \"type\": \"Point\",\n                    \"coordinates\": [82.91799, 55.043136]\n                }\n            },\n            {\n                \"type\": \"Feature\",\n                \"properties\": {\n                    \"info\": \"Я полигон\"\n                },\n                \"geometry\": {\n                    \"type\": \"Polygon\",\n                    \"coordinates\": [\n                        [\n                            [82.91699, 55.042136],\n                            [82.917522, 55.040187],\n                            [82.918063, 55.040235],\n                            [82.917540, 55.042184],\n                            [82.91699, 55.042136]\n                        ]\n                    ]\n                }\n            }\n        ];\n\n        DG.geoJson(data, {\n            onEachFeature: function (feature, layer) {\n                layer.bindPopup(feature.properties.info);\n            }\n        }).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>GeoJSON</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [55.042136, 82.91699],\n                        zoom: 16\n                    });\n\n                    var data = [\n                        {\n                            \"type\": \"Feature\",\n                            \"properties\": {\n                                \"info\": \"Я маркер\"\n                            },\n                            \"geometry\": {\n                                \"type\": \"Point\",\n                                \"coordinates\": [82.91799, 55.043136]\n                            }\n                        },\n                        {\n                            \"type\": \"Feature\",\n                            \"properties\": {\n                                \"info\": \"Я полигон\"\n                            },\n                            \"geometry\": {\n                                \"type\": \"Polygon\",\n                                \"coordinates\": [\n                                    [\n                                        [82.91699, 55.042136],\n                                        [82.917522, 55.040187],\n                                        [82.918063, 55.040235],\n                                        [82.917540, 55.042184],\n                                        [82.91699, 55.042136]\n                                    ]\n                                ]\n                            }\n                        }\n                    ];\n\n                    DG.geoJson(data, {\n                        onEachFeature: function (feature, layer) {\n                            layer.bindPopup(feature.properties.info);\n                        }\n                    }).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/markers.md",
    "content": "## Работа с маркерами\n\n{toc}\n\n### Описание\n\nНиже приведены примеры использования маркеров. Маркер можно добавить на карту с помощью метода\n<code>addTo()</code>, но если вы планируете работать с группой марекров, мы рекомендуем использовать для этого\n<code>FeatureGroup</code> (смотрите разделы \"Обработка событий группы маркеров\" и \"Отображение нескольких\nмаркеров и подстройка границ\"). Для получения подробной информации о маркерах перейдите в раздел документации\n<a href=\"/doc/maps/ru/manual/markers\">Маркеры</a>.\n\n### Маркер с попапом\n\nМаркер, при клике на который открывается попап с информацией:\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function () {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89]).addTo(map).bindPopup('Я попап!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Маркер с попапом</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('Я попап!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Перетаскиваемый маркер\n\nМаркер, который пользователи могут перетаскивать:\n\nКоординаты маркера: <div id=\"location\">54.981, 82.891</div>\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script type=\"text/javascript\">\n    var locationInfo = document.getElementById('location');\n    DG.then(function () {\n        var map,\n            marker;\n\n        map = DG.map('map1', {\n            center: [54.981, 82.891],\n            zoom: 15\n        });\n\n        marker = DG.marker([54.981, 82.891], {\n            draggable: true\n        }).addTo(map);\n\n        marker.on('drag', function(e) {\n            var lat = e.target._latlng.lat.toFixed(3),\n                lng = e.target._latlng.lng.toFixed(3);\n\n            locationInfo.innerHTML = lat + ', ' + lng;\n        });\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Перетаскиваемый маркер</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            Координаты маркера: <div id=\"location\">LatLng(54.98, 82.89)</div>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script type=\"text/javascript\">\n                var locationInfo = document.getElementById('location');\n\n                DG.then(function () {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.981, 82.891],\n                        zoom: 15\n                    });\n\n                    marker = DG.marker([54.981, 82.891], {\n                        draggable: true\n                    }).addTo(map);\n\n                    marker.on('drag', function(e) {\n                        var lat = e.target._latlng.lat.toFixed(3),\n                            lng = e.target._latlng.lng.toFixed(3);\n\n                        locationInfo.innerHTML = lat + ', ' + lng;\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Маркер с пользовательской иконкой\n\nВы можете задать маркеру собственную иконку или простой элемент div вместо изображения:\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            myIcon,\n            myDivIcon;\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        myIcon = DG.icon({\n            iconUrl: 'https://maps.api.2gis.ru/2.0/example_logo.png',\n            iconSize: [48, 48]\n        });\n        DG.marker([54.98, 82.89], {\n            icon: myIcon\n        }).addTo(map);\n\n        myDivIcon = DG.divIcon({\n            iconSize: [70, 20],\n            html: '<b style=\"color:blue;\">HTML-код</b>'\n        });\n        DG.marker([54.98, 82.87], {\n            icon: myDivIcon\n        }).addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Маркер с пользовательской иконкой</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        myIcon,\n                        myDivIcon;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    myIcon = DG.icon({\n                        iconUrl: 'https://maps.api.2gis.ru/2.0/example_logo.png',\n                        iconSize: [48, 48]\n                    });\n                    DG.marker([54.98, 82.89], {\n                        icon: myIcon\n                    }).addTo(map);\n\n                    myDivIcon = DG.divIcon({\n                        iconSize: [70, 20],\n                        html: '<b style=\"color:blue;\">HTML-код</b>'\n                    });\n                    DG.marker([54.98, 82.87], {\n                        icon: myDivIcon\n                    }).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Программное открытие маркера\n\nЕсть возможность открыть попап \"по требованию\". К примеру, по клику в ссылку или кнопку:\n\n<button id='open-popup'>Открыть попап</button>\n<div id=\"map3\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var openPopupBtn = document.getElementById('open-popup');\n\n    DG.then(function() {\n        var map,\n            marker;\n\n        map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        marker = DG.marker([54.98, 82.89]).addTo(map);\n        marker.bindPopup('Я попап!');\n\n        openPopupBtn.onclick = function() {\n            marker.openPopup();\n        }\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Программное открытие маркера</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <button id='open-popup'>Открыть попап</button>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var openPopupBtn = document.getElementById('open-popup');\n\n                DG.then(function() {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    marker = DG.marker([54.98, 82.89]).addTo(map);\n                    marker.bindPopup('Я попап!');\n\n                    openPopupBtn.onclick = function() {\n                        marker.openPopup();\n                    }\n                });\n            </script>\n        </body>\n    </html>\n\n### Маркер с подсказкой\n\nУ маркера есть два вида подсказок, обычная и статическая. Оба варианта рассматриваются в следующем примере:\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89])\n            .addTo(map)\n            .bindLabel('Я статическая подсказка!', {\n                static: true\n            });\n\n        DG.marker([54.98, 82.88])\n            .addTo(map)\n            .bindLabel('Я обычная подсказка!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Маркер с подсказкой</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89])\n                        .addTo(map)\n                        .bindLabel('Я статическая подсказка!', {\n                            static: true\n                        });\n\n                    DG.marker([54.98, 82.88])\n                        .addTo(map)\n                        .bindLabel('Я обычная подсказка!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Обработка событий группы маркеров\n\nПри клике в маркер, карта будет центрироваться по его позиции:\n\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            marker1,\n            marker2,\n            marker3,\n            group;\n\n        map = DG.map('map5', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        marker1 = DG.marker([54.96, 82.889]).addTo(map);\n        marker2 = DG.marker([54.98, 82.893]).addTo(map);\n        marker3 = DG.marker([54.99, 82.896]).addTo(map);\n\n        group = DG.featureGroup([marker1, marker2, marker3]);\n        group.addTo(map);\n        group.on('click', function(e) {\n            map.setView([e.latlng.lat, e.latlng.lng]);\n        });\n    });\n</script>\n\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Обработка событий группы маркеров</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        marker1,\n                        marker2,\n                        marker3,\n                        group;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    marker1 = DG.marker([54.96, 82.889]).addTo(map);\n                    marker2 = DG.marker([54.98, 82.893]).addTo(map);\n                    marker3 = DG.marker([54.99, 82.896]).addTo(map);\n\n                    group = DG.featureGroup([marker1, marker2, marker3]);\n                    group.addTo(map);\n                    group.on('click', function(e) {\n                        map.setView([e.latlng.lat, e.latlng.lng]);\n                    });\n                });\n            </script>\n        </body>\n    </html>\n\n### Анимированное движение маркера\n\nПример маркера, который двигается по заданой траектории:\n<div id=\"map6\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            marker;\n\n        map = DG.map('map6', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        marker = DG.marker([54.98, 82.89]).addTo(map);\n\n        var increment = 0.001;\n\n        function move() {\n            if (!map.getBounds().contains(marker.getLatLng())) {\n                increment *= -1;\n            }\n\n            var newLat = marker.getLatLng().lat + increment,\n                newLng = marker.getLatLng().lng + increment;\n\n            marker.setLatLng([newLat, newLng]);\n        }\n\n        setInterval(move, 60);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Анимированное движение маркера</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        marker;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    marker = DG.marker([54.98, 82.89]).addTo(map);\n\n                    var increment = 0.001;\n\n                    function move() {\n                        if (!map.getBounds().contains(marker.getLatLng())) {\n                            increment *= -1;\n                        }\n\n                        var newLat = marker.getLatLng().lat + increment,\n                            newLng = marker.getLatLng().lng + increment;\n\n                        marker.setLatLng([newLat, newLng]);\n                    }\n\n                    setInterval(move, 60);\n                });\n            </script>\n        </body>\n    </html>\n\n### Отображение нескольких маркеров и подстройка границ\n\nПример отображения и скрытия группы маркеров с автоматическим определением рамок карты:\n\n<input id=\"show\" type=\"button\" value=\"Показать маркеры\" /><input id=\"hide\" type=\"button\" value=\"Скрыть маркеры\" />\n<div id=\"map7\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            markers = DG.featureGroup(),\n            coordinates = [];\n\n        map = DG.map('map7', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        for (var i = 0; i < 100; i++) {\n            coordinates[0] = 54.98 + Math.random();\n            coordinates[1] = 82.89 + Math.random();\n            DG.marker(coordinates).addTo(markers);\n        }\n\n        document.getElementById('hide').onclick = hideMarkers;\n        document.getElementById('show').onclick = showMarkers;\n\n        function showMarkers() {\n            markers.addTo(map);\n            map.fitBounds(markers.getBounds());\n        };\n\n        function hideMarkers() {\n            markers.removeFrom(map);\n        };\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение/удаление нескольких маркеров, fitBounds</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"hide\" type=\"button\" value=\"hide markers\" />\n            <input id=\"show\" type=\"button\" value=\"show markers\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n            DG.then(function() {\n                var map,\n                    markers = DG.featureGroup(),\n                    coordinates = [];\n\n                map = DG.map('map', {\n                    center: [54.98, 82.89],\n                    zoom: 13\n                });\n\n                for (var i = 0; i < 100; i++) {\n                    coordinates[0] = 54.98 + Math.random();\n                    coordinates[1] = 82.89 + Math.random();\n                    DG.marker(coordinates).addTo(markers);\n                }\n\n                document.getElementById('hide').onclick = hideMarkers;\n                document.getElementById('show').onclick = showMarkers;\n\n                function showMarkers() {\n                    markers.addTo(map);\n                    map.fitBounds(markers.getBounds());\n                };\n\n                function hideMarkers() {\n                    markers.removeFrom(map);\n                };\n            });\n        </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/popups.md",
    "content": "## Работа с попапами\n\n{toc}\n\n### Описание\n\nНиже приведены примеры использования попапов. Для получения подробной информации перейдите в раздел документации\n<a href=\"/doc/maps/ru/manual/popup\">Попапы</a>.\n\n### Открытие попапа при клике на маркер\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function () {\n        var map = DG.map('map', {\n            center: [54.98, 82.89],\n            zoom: 15\n        });\n\n        DG.marker([54.98, 82.89]).addTo(map).bindPopup('Я попап!');\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Открытие попапа при клике на маркер</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 15\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('Я попап!');\n                });\n            </script>\n        </body>\n    </html>\n\n### Открытие попапа по умолчанию и по требованию\n\n<input id=\"showPopup\" type=\"button\" value=\"Открыть попап\" />\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var showButton = document.getElementById('showPopup');\n\n    DG.then(function() {\n        var map,\n            myPopUp;\n\n        map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.popup([54.98, 82.89])\n            .setLatLng([54.98, 82.89])\n            .setContent('Я открыт по умолчанию')\n            .openOn(map);\n\n        myPopUp = DG.popup()\n            .setLatLng([54.98, 82.89])\n            .setContent('Я открылся по требованию и закрыл прошлый попап!');\n\n        showButton.onclick = function() {myPopUp.openOn(map)};\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Открытие попапа по умолчанию и по требованию</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"showPopup\" type=\"button\" value=\"Открыть попап\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var showButton = document.getElementById('showPopup');\n\n                DG.then(function() {\n                    var map,\n                        myPopUp;\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.popup([54.98, 82.89])\n                        .setLatLng([54.98, 82.89])\n                        .setContent('Я открыт по умолчанию')\n                        .openOn(map);\n\n                    myPopUp = DG.popup()\n                        .setLatLng([54.98, 82.89])\n                        .setContent('Я открылся по требованию и закрыл прошлый попап!');\n\n                    showButton.onclick = function() {myPopUp.openOn(map)};\n                });\n            </script>\n        </body>\n    </html>\n\n### Добавление нескольких попапов на карту\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            popups = DG.featureGroup(),\n            coordinates = [];\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        for (var i = 0; i < 10; i++) {\n            coordinates[0] = 54.98 - Math.random();\n            coordinates[1] = 82.89 + Math.random();\n            DG.popup()\n                .setLatLng(coordinates)\n                .setContent('Я попап №' + i)\n                .addTo(popups);\n        }\n\n        popups.addTo(map);\n        map.fitBounds(popups.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Добавление нескольких попапов на карту</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        popups = DG.featureGroup(),\n                        coordinates = [];\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    // создаем 10 попапов в случайных местах и добавляем их в группу\n                    for (var i = 0; i < 10; i++) {\n                        coordinates[0] = 54.98 - Math.random();\n                        coordinates[1] = 82.89 + Math.random();\n                        DG.popup()\n                            .setLatLng(coordinates)\n                            .setContent('Я попап №' + i)\n                            .addTo(popups);\n                    }\n\n                    popups.addTo(map);\n\n                    // фокусируем область видимости на попапах\n                    map.fitBounds(popups.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Поведение попапа с параметром sprawling\n\n<div id=\"map3\" style=\"width: 300px; height: 150px;\"></div>\n<input style=\"width: 300px;\" type=\"button\" id=\"sprawling\" value=\"Попап с включенным параметром sprawling\"><br />\n<input style=\"width: 300px;\" type=\"button\" id=\"no-sprawling\" value=\"Попап без параметра sprawling\"><br />\n<input style=\"width: 300px;\" type=\"button\" id=\"minWidth\" value=\"Попап с минимальной шириной 320px\">\n<script>\n    DG.then(function () {\n        var latLng = DG.latLng([54.98, 82.89]),\n            map = DG.map('map3', {\n                center: latLng,\n                zoom: 13,\n                fullscreenControl: false,\n                zoomControl: false\n            });\n\n        document.getElementById('sprawling').onclick = function () {\n            DG.popup({\n                maxWidth: 350,\n                sprawling: true\n            })\n            .setLatLng(latLng)\n            .setContent('Я попап!')\n            .openOn(map);\n        };\n\n        document.getElementById('no-sprawling').onclick = function () {\n            DG.popup({\n                maxWidth: 350\n            })\n            .setLatLng(latLng)\n            .setContent('Я попап!')\n            .openOn(map);\n        };\n\n        document.getElementById('minWidth').onclick = function () {\n            DG.popup({\n                maxWidth: 350,\n                minWidth: 320\n            })\n            .setLatLng(latLng)\n            .setContent('Я попап!')\n            .openOn(map);\n        };\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Поведение попапа с параметром sprawling</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 300px; height: 150px;\"></div>\n            <input style=\"width: 300px;\" type=\"button\" id=\"sprawling\" value=\"Попап с включенным параметром sprawling\"><br />\n            <input style=\"width: 300px;\" type=\"button\" id=\"no-sprawling\" value=\"Попап без параметра sprawling\"><br />\n            <input style=\"width: 300px;\" type=\"button\" id=\"minWidth\" value=\"Попап с минимальной шириной 320px\">\n            <script>\n                DG.then(function () {\n                    var latLng = DG.latLng([54.98, 82.89]),\n                        map;\n\n                    // проинициализируем карту с шириной 300 пикселей\n                    map = DG.map('map', {\n                        center: latLng,\n                        zoom: 13,\n                        fullscreenControl: false,\n                        zoomControl: false\n                    });\n\n                    // попап с включенным параметром sprawling\n                    // растянется до границ карты\n                    document.getElementById('sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            sprawling: true\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я попап!')\n                        .openOn(map);\n                    };\n\n                    // попап без параметра sprawling\n                    // подстроится под ширину контента\n                    document.getElementById('no-sprawling').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я попап!')\n                        .openOn(map);\n                    };\n\n                    // попап с минимальной шириной 320px\n                    // выйдет за границы карты\n                    document.getElementById('minWidth').onclick = function () {\n                        DG.popup({\n                            maxWidth: 350,\n                            minWidth: 320\n                        })\n                        .setLatLng(latLng)\n                        .setContent('Я попап!')\n                        .openOn(map);\n                    };\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/vector-layers.md",
    "content": "## Работа с векторными слоями\n\n{toc}\n\n### Описание\n\nНиже приведены базовые примеры использования геометрических объектов. Для получения подробной информации о работе\nс векторными слоями воспользуйтесь разделом документации <a href=\"/doc/maps/ru/manual/vector-layers\">Векторные слои</a>.\n\n### Отображение ломаной\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 500px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coordinates,\n            polyline;\n\n        map = DG.map('map', {\n            center: [55.036446, 82.897983],\n            zoom: 11\n        });\n\n        coordinates = [[55.069288, 82.991367], [55.069288, 82.816615], [55.011648, 82.902103], [54.944714, 82.903152], [54.928935, 82.850967], [54.928541, 82.976280], [54.944517, 82.916541], [55.011704, 82.916885], [55.056508, 82.973514], [55.056508, 82.835498], [55.056705, 82.973857], [55.069288, 82.991367], [55.069288, 82.941928], [55.097193, 82.959094], [55.046282, 82.919956], [55.045692, 82.904163], [55.036446, 82.897983], [55.029756, 82.907596], [55.018932, 82.903819], [55.029362, 82.914119], [55.030543, 82.927165], [55.037823, 82.933345], [55.045101, 82.925105], [55.069681, 82.941928]];\n\n        // создаем ломаную из массива географических точек\n        polyline = DG.polyline(coordinates, {color: 'blue'}).addTo(map);\n\n        // подстраиваем центр карты и масштаб так, чтобы ломаную было видно\n        map.fitBounds(polyline.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение ломаной</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 500px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coordinates,\n                        polyline;\n\n                    map = DG.map('map', {\n                        center: [55.036446, 82.897983],\n                        zoom: 11\n                    });\n\n                    coordinates = [[55.069288, 82.991367], [55.069288, 82.816615], [55.011648, 82.902103], [54.944714, 82.903152], [54.928935, 82.850967], [54.928541, 82.976280], [54.944517, 82.916541], [55.011704, 82.916885], [55.056508, 82.973514], [55.056508, 82.835498], [55.056705, 82.973857], [55.069288, 82.991367], [55.069288, 82.941928], [55.097193, 82.959094], [55.046282, 82.919956], [55.045692, 82.904163], [55.036446, 82.897983], [55.029756, 82.907596], [55.018932, 82.903819], [55.029362, 82.914119], [55.030543, 82.927165], [55.037823, 82.933345], [55.045101, 82.925105], [55.069681, 82.941928]];\n\n                    // создаем ломаную из массива географических точек\n                    polyline = DG.polyline(coordinates, {\n                        color: 'blue'\n                    }).addTo(map);\n\n                    // подстраиваем центр карты и масштаб, чтобы ломаную было видно\n                    map.fitBounds(polyline.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Отображение прямоугольников\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coords1 = [[54.98, 82.87], [54.975, 82.91]],\n            coords2 = [[54.985, 82.87], [54.982, 82.91]],\n            coords3 = [[54.99, 82.87], [54.987, 82.91]],\n            rectangles = DG.featureGroup();\n\n        map = DG.map('map1', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        // Добавление прямоугольников в группу\n        DG.rectangle(coords1, {color: \"blue\"}).addTo(rectangles);\n        DG.rectangle(coords2, {color: \"red\"}).addTo(rectangles);\n        DG.rectangle(coords3, {color: \"green\"}).addTo(rectangles);\n\n        // Добавление группы на карту\n        rectangles.addTo(map);\n\n        // Подстройка границ карты\n        map.fitBounds(rectangles.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение прямоугольников</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coords1 = [[54.98, 82.87], [54.975, 82.91]],\n                        coords2 = [[54.985, 82.87], [54.982, 82.91]],\n                        coords3 = [[54.99, 82.87], [54.987, 82.91]],\n                        rectangles = DG.featureGroup();\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    // Добавление прямоугольников в группу\n                    DG.rectangle(coords1, {color: \"blue\"}).addTo(rectangles);\n                    DG.rectangle(coords2, {color: \"red\"}).addTo(rectangles);\n                    DG.rectangle(coords3, {color: \"green\"}).addTo(rectangles);\n\n                    // Добавление группы на карту\n                    rectangles.addTo(map);\n\n                    // Подстройка границ карты\n                    map.fitBounds(rectangles.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Отображение многоугольников\n\n<div id=\"map2\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coords1 = [\n                [54.98, 82.87],\n                [54.975, 82.91],\n                [54.974, 82.915],\n                [54.971, 82.918],\n                [54.970, 82.921]\n            ],\n            coords2 = [\n                [54.985, 82.875],\n                [54.98, 82.96],\n                [54.979, 82.92],\n                [54.976, 82.923]\n            ],\n            coords3 = [\n                [54.99, 82.88],\n                [54.985, 82.971],\n                [54.984, 82.925],\n                [54.981, 82.928],\n                [54.980, 82.931]\n            ],\n            polygons = DG.featureGroup();\n\n        map = DG.map('map2', {\n            center: [54.98, 82.89],\n            zoom: 13\n        });\n\n        DG.polygon(coords1, {color: \"blue\"}).addTo(polygons);\n        DG.polygon(coords2, {color: \"red\"}).addTo(polygons);\n        DG.polygon(coords3, {color: \"green\"}).addTo(polygons);\n\n        polygons.addTo(map);\n        map.fitBounds(polygons.getBounds());\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение многоугольников</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coords1 = [\n                            [54.98, 82.87],\n                            [54.975, 82.91],\n                            [54.974, 82.915],\n                            [54.971, 82.918],\n                            [54.970, 82.921]\n                        ],\n                        coords2 = [\n                            [54.985, 82.875],\n                            [54.98, 82.96],\n                            [54.979, 82.92],\n                            [54.976, 82.923]\n                        ],\n                        coords3 = [\n                            [54.99, 82.88],\n                            [54.985, 82.971],\n                            [54.984, 82.925],\n                            [54.981, 82.928],\n                            [54.980, 82.931]\n                        ],\n                        polygons = DG.featureGroup();\n\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    // Добавление многоугольников в группу\n                    DG.polygon(coords1, {color: \"blue\"}).addTo(polygons);\n                    DG.polygon(coords2, {color: \"red\"}).addTo(polygons);\n                    DG.polygon(coords3, {color: \"green\"}).addTo(polygons);\n\n                    // Добавление группы на карту\n                    polygons.addTo(map);\n\n                    // Подстройка границ карты\n                    map.fitBounds(polygons.getBounds());\n                });\n            </script>\n        </body>\n    </html>\n\n### Отображение окружности и круглого маркера\n\n<div id=\"map3\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map3', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        DG.circle([54.98, 82.89], 200, {color: 'red'}).addTo(map);\n        DG.circleMarker([54.985, 82.89]).setRadius(100).addTo(map);\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение круга и круглого маркера</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    DG.circle([54.98, 82.89], 200, {color: 'red'}).addTo(map);\n                    DG.circleMarker([54.985, 82.89]).setRadius(100).addTo(map);\n                })\n            </script>\n        </body>\n    </html>\n\n### Векторные слои с подсказками и попапами\n\n<div id=\"map4\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map4', {\n            center: [54.98, 82.89],\n            zoom: 14\n        });\n\n        DG.circle([54.98, 82.87], 200, {color: 'red'})\n            .bindPopup('Я круг.')\n            .bindLabel('нажми на круг')\n            .addTo(map);\n\n        DG.circleMarker([54.985, 82.89])\n            .bindPopup('Я круглый маркер')\n            .bindLabel('Нажми на круглый маркер')\n            .setRadius(100)\n            .addTo(map);\n\n        DG.rectangle(\n            [[54.98, 82.87], [54.975, 82.91]],\n            {color: 'green'})\n            .bindPopup('Я прямоугольник')\n            .bindLabel('Нажми на прямоугольник')\n            .addTo(map);\n\n        DG.polygon(\n            [[54.985, 82.875], [54.98, 82.96], [54.979, 82.92]],\n            {color: 'yellow'})\n            .bindPopup('Я многоугольник')\n            .bindLabel('Нажми на многоугольник')\n            .addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Векторные слои с подсказками и попапами</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 14\n                    });\n\n                    DG.circle([54.98, 82.87], 200, {color: 'red'})\n                        .bindPopup('Я круг')\n                        .bindLabel('Нажми на круг')\n                        .addTo(map);\n\n                    DG.circleMarker([54.985, 82.89])\n                        .bindPopup('Я круглый маркер')\n                        .bindLabel('Нажми на круглый маркер')\n                        .setRadius(100)\n                        .addTo(map);\n\n                    DG.rectangle(\n                        [[54.98, 82.87], [54.975, 82.91]],\n                        {color: 'green'})\n                        .bindPopup('Я прямоугольник')\n                        .bindLabel('Нажми на прямоугольник')\n                        .addTo(map);\n\n                    DG.polygon(\n                        [[54.985, 82.875], [54.98, 82.96], [54.979, 82.92]],\n                        {color: 'yellow'})\n                        .bindPopup('Я многоугольник')\n                        .bindLabel('Нажми на многоугольник')\n                        .addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n\n### Анимация отрисовки ломаной\n\n<input id=\"playAnimation\" type=\"button\" value=\"Запустить анимацию\" />\n<div id=\"map5\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    var playAnimationButton = document.getElementById('playAnimation'); \n\n    DG.then(function() {\n        var map = DG.map('map5', {\n            center: [54.98, 82.94],\n            zoom: 13\n        });\n\n        playAnimation.onclick = function() {\n            var polyline = DG.polyline([]).addTo(map),\n                counter = 0;\n\n            (function draw() {\n                polyline.addLatLng([54.98, 82.89 + counter / 10000]);\n\n                if (++counter < 1000) {\n                    window.setTimeout(draw, 10);\n                } else {\n                    counter = 0;\n                    draw();\n                };\n            })();\n        }\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Анимация отрисовки ломаной</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <input id=\"playAnimation\" type=\"button\" value=\"Запустить анимацию\" />\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                var playAnimationButton = document.getElementById('playAnimation'); \n\n                DG.then(function() {\n                    var map = DG.map('map', {\n                        center: [54.98, 82.94],\n                        zoom: 13\n                    });\n\n                    playAnimation.onclick = function() {\n                        var polyline = DG.polyline([]).addTo(map),\n                            counter = 0;\n\n                        (function draw() {\n                            polyline.addLatLng([54.98, 82.89 + counter / 10000]);\n\n                            if (++counter < 1000) {\n                                window.setTimeout(draw, 10);\n                            } else {\n                                counter = 0;\n                                draw();\n                            };\n                        })();\n                    }\n                })\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/examples/wkt.md",
    "content": "## Работа с WKT\n\n{toc}\n\n### Описание\n\nНиже приведены примеры работы с WKT. Для получения подробной информации перейдите в раздел документации\n<a href=\"/doc/maps/ru/manual/dg-wkt\">WKT</a>.\n\n### Отображение простых векторных слоев\n\n<script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n<div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map,\n            coord1 = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))',\n            coord2 = 'LINESTRING(82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235)',\n            coord3 = 'POINT(82.914 55.042136)';\n\n        map = DG.map('map', {\n            center: [55.042136, 82.91699],\n            zoom: 16\n        });\n\n        DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n        DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n        DG.Wkt.geoJsonLayer(coord3).addTo(map);\n    })\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение простых векторных слоев</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coord1 = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))',\n                        coord2 = 'LINESTRING(82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235)',\n                        coord3 = 'POINT(82.914 55.042136)';\n\n                    map = DG.map('map', {\n                        center: [55.042136, 82.91699],\n                        zoom: 16\n                    });\n\n                    DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord3).addTo(map);\n                })\n            </script>\n        </body>\n    </html>\n\n### Отображение составных векторных слоев\n\n<div id=\"map1\" style=\"width: 100%; height: 400px;\"></div>\n<script>\n    DG.then(function() {\n        var map = DG.map('map1', {\n            center: [55.041836, 82.91699],\n            zoom: 16\n        });\n\n        DG.Wkt.geoJsonLayer('MULTIPOLYGON(((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136)), ((82.91599 55.041136, 82.916522 55.039187, 82.917063 55.039235, 82.916540 55.041184,82.91599 55.041136)))').addTo(map);\n        DG.Wkt.geoJsonLayer('MULTILINESTRING((82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235), (82.91899 55.044136, 82.919522 55.042187, 82.920063 55.042235))').addTo(map);\n        DG.Wkt.geoJsonLayer('MULTIPOINT(82.914 55.042136, 82.915 55.043136, 82.915 55.042136, 82.914 55.043136)').addTo(map);\n    });\n</script>\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>Отображение составных векторных слоев</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js\"></script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width: 100%; height: 400px;\"></div>\n            <script>\n                DG.then(function() {\n                    var map,\n                        coord1 = 'MULTIPOLYGON(((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136)), ((82.91599 55.041136, 82.916522 55.039187, 82.917063 55.039235, 82.916540 55.041184,82.91599 55.041136)))',\n                        coord2 = 'MULTILINESTRING((82.91799 55.043136, 82.918522 55.041187, 82.919063 55.041235), (82.91899 55.044136, 82.919522 55.042187, 82.920063 55.042235))',\n                        coord3 = 'MULTIPOINT(82.914 55.042136, 82.915 55.043136, 82.915 55.042136, 82.914 55.043136)';\n\n                    map = DG.map('map', {\n                        center: [55.041836, 82.91699],\n                        zoom: 16\n                    });\n\n                    DG.Wkt.geoJsonLayer(coord1).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord2).addTo(map);\n\n                    DG.Wkt.geoJsonLayer(coord3).addTo(map);\n                });\n            </script>\n        </body>\n    </html>\n"
  },
  {
    "path": "src/doc/ru/manual/base-classes.md",
    "content": "## Базовые классы\n\nСлужебные классы библотеки, необходимые для работы API карт и разработки\n<a href=\"https://github.com/2gis/maps-api-2.0/blob/master/CONTRIBUTING.md#%D0%9A%D0%B0%D0%BA-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%82%D1%8C-%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C\" target=\"_blank\">собственных модулей</a>.\n\n{toc}\n\n### DG.Class\n\n<code>DG.Class</code> предоставляет возможность использовать ООП подход в разработке API карт, и используется\nдля реализации большинства классов, приведенных в этой документации.\n\nКроме реализации простой классической модели наследования, имеются несколько свойств для удобной организации кода,\nтакие как <code>options</code>, <code>includes</code> и <code>statics</code>.\n\n    var MyClass = DG.Class.extend({\n        initialize: function (greeter) {\n            this.greeter = greeter;\n            // конструктор класса\n        },\n\n        greet: function (name) {\n            alert(this.greeter + ', ' + name)\n        }\n    });\n\n    // создает объект класса MyClass и передает \"Hello\" в конструктор\n    var a = new MyClass(\"Hello\");\n\n    // вызывает метод greet, который показывает всплывающее окно с текстом \"Hello, World\"\n    a.greet(\"World\");\n\n#### Фабрики классов\n\nОбъекты в API карт можно создавать без использования ключевого слова <code>new</code>. Это достигается путем\nдополнения описания каждого класса статическим методом, имеющим наименование класса, только в нижнем регистре.\n\n    new DG.Map('map');\n    DG.map('map');      // эквивалентный вызов\n\nВы можете использовать такой подход в своих классах, т.к. подобные методы реализованы достаточно просто:\n\n    DG.map = function (id, options) {\n        return new DG.Map(id, options);\n    };\n\n#### Наследование\n\nДля определения новых классов используется <code>DG.Class.extend</code>, также метод <code>extend</code> можно использовать\nв любом другом классе, который наследуется от <code>DG.Class</code>:\n\n    var MyChildClass = MyClass.extend({\n        // ... новые свойства и методы\n    });\n\nДанный код создаст класс, который унаследует все методы и свойства родительского класса (через цепочку прототипов),\nпри необходимости добавляя или переопределяя родительские методы и свойства. Кроме того, корректно обрабатывается\nоператор <code>instanceof</code>:\n\n    var a = new MyChildClass();\n    a instanceof MyChildClass; // true\n    a instanceof MyClass; // true\n\nВы можете вызывать родительские методы (включая конструктор) из дочерних классов (так, как вы бы делали это с помощью\nвызова <code>super</code> в других языках программирования) с помощью JavaScript функций <code>call</code> или <code>apply</code>:\n\n    var MyChildClass = MyClass.extend({\n        initialize: function () {\n            MyClass.prototype.initialize.call(this, \"Yo\");\n        },\n\n        greet: function (name) {\n            MyClass.prototype.greet.call(this, 'bro ' + name + '!');\n        }\n    });\n\n    var a = new MyChildClass();\n    a.greet('Jason'); // выведет \"Yo, bro Jason!\"\n\n#### Объект опций\n\n<code>options</code> &mdash; ссылка на специальный объект, свойства которого, в отличии от других объектов\nпередаваемых через <code>extend</code>, будут объединены со свойствами аналогичного объекта родителя, вместо\nполного переопределения объекта. Это позволяет управлять конфигурацией объектов и значениями по умолчанию:\n\n    var MyClass = DG.Class.extend({\n        options: {\n            myOption1: 'foo',\n            myOption2: 'bar'\n        }\n    });\n\n    var MyChildClass = DG.Class.extend({\n        options: {\n            myOption1: 'baz',\n            myOption3: 5\n        }\n    });\n\n    var a = new MyChildClass();\n    a.options.myOption1; // 'baz'\n    a.options.myOption2; // 'bar'\n    a.options.myOption3; // 5\n\nТакже существует метод <a href=\"/doc/maps/ru/manual/utils#util-setoptions\"><code>DG.Util.setOptions</code></a>,\nкоторый позволяет объединять опции, переданные в конструктор, с опциями, заданными по умолчанию:\n\n    var MyClass = DG.Class.extend({\n        options: {\n            foo: 'bar',\n            bla: 5\n        },\n\n        initialize: function (options) {\n            DG.Util.setOptions(this, options);\n            ...\n        }\n    });\n\n    var a = new MyClass({bla: 10});\n    a.options; // {foo: 'bar', bla: 10}\n\n#### Поддержка создания миксинов\n\n<code>includes</code> &mdash; ссылка на специальный объект, свойства и методы которого будут объединены со свойствами\nи методами экземпляров класса (такие объекты называются mixin-ами).\n\n     var MyMixin = {\n        foo: function () { ... },\n        bar: 5\n    };\n\n    var MyClass = DG.Class.extend({\n        includes: MyMixin\n    });\n\n    var a = new MyClass();\n    a.foo();\n\nТакже, вы можете подмешивать объекты в процессе выполнения программы, с помощью метода <code>include</code>:\n\n    MyClass.include(MyMixin);\n\n#### Поддержка статических членов класса\n\n<code>statics</code> &mdash; ссылка на специальный объект, свойства и методы которого будут объединены со статическими\nсвойствами и методами класса. Бывает удобно использовать для определения констант:\n\n    var MyClass = DG.Class.extend({\n        statics: {\n            FOO: 'bar',\n            BLA: 5\n        }\n    });\n\n    MyClass.FOO; // 'bar'\n\n#### Перехватчики конструктора\n\nЕсли вы разрабатываете модуль к API карт, существует вероятность того, что вам понадобится выполнить\nдополнительные действия при инициализации объектов существующих классов (например, при инициализации\nобъекта <a href=\"/doc/maps/ru/manual/geometries#polyline\"><code>DG.Polyline</code></a>).\n\nДля подобного рода задач есть метод <code>addInitHook</code>:\n\n    MyClass.addInitHook(function () {\n        // ... выполнить дополнительные действия при вызове конструктора\n        // например, добавить обработчики событий, установить значения свойств и т.п.\n    });\n\nТакже можно использовать сокращенную запись, если вам надо сделать всего лишь один дополнительный вызов метода:\n\n    MyClass.addInitHook('methodName', arg1, arg2, …);\n\n#### Функции\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"class-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;Object&gt; <i>props</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td>Возвращает функцию Javascript, являющуюся конструктором класса (в дальнейшем, функция должна вызываться с\n                <code>new</code>), который <a href=\"#наследование\">наследует</a> методы и свойства базового класса.</td>\n        </tr>\n        <tr id=\"class-include\">\n            <td><code><b>include</b>(\n                <nobr>&lt;Object&gt; <i>properties</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td>Подмешивает методы и свойства объекта в текущий класс.</td>\n        </tr>\n        <tr id=\"class-mergeoptions\">\n            <td><code><b>mergeOptions</b>(\n                <nobr>&lt;Object&gt; <i>options</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td>Объединяет объект опций с объектом опций класса по умолчанию.</td>\n        </tr>\n        <tr id=\"class-addinithook\">\n            <td><code><b>addInitHook</b>(\n                <nobr>&lt;Function&gt; <i>fn</i> )</nobr>\n            </code></td>\n\n            <td><code></code></td>\n            <td>Добавляет функцию-перехватчик конструктора к классу.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Evented\n\nКлассы, использующие событийную модель (такие как <a href=\"/doc/maps/ru/manual/map#dgmap\"><code>Map</code></a>\nи <a href=\"/doc/maps/ru/manual/markers#dgmarker\"><code>Marker</code></a>), наследуют методы <code>DG.Evented</code>.\nВ общем случае, класс дает возможность инициировать выполнение последовательности функций, при возникновении\nкакого-либо события, связанного с объектом (например, пользователь щелкнул мышью по карте, тем самым создав\nсобытие <code>&#39;click&#39;</code>).\n\n    map.on('click', function(e) {\n        alert(e.latlng);\n    } );\n\nДля того, чтобы можно было добавить и впоследствии удалить обработчик события, опишите обработчик\nс помощью внешней функции, ссылку на которую потом можно будет передать в методы данного класса:\n\n    function onClick(e) { ... }\n    map.on('click', onClick);\n    map.off('click', onClick);\n\n#### Методы\n\n<table id=\"dgevented-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"evented-on\">\n            <td><code><b>on</b>(\n                <nobr>&lt;String&gt; <i>type</i></nobr>,\n                <nobr>&lt;Function&gt; <i>fn</i></nobr>,\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет обработчик (<code>fn</code>) для определенного типа событий. Вы также можете указать\n                контекст вызова обработчика (объект, на который ссылается ключевое слово <code>this</code>\n                внутри обработчика). Также, можно указать несколько типов событий, разделив их пробелами\n                (например: <code>&#39;click dblclick&#39;</code>).</td>\n        </tr>\n        <tr>\n            <td><code><b>on</b>(\n                <nobr>&lt;Object&gt; <i>eventMap</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет набор пар &#39;тип/обработчик&#39; в качестве обработчиков событий\n                (например: <code>{click: onClick, mousemove: onMouseMove}</code>).</td>\n        </tr>\n        <tr id=\"evented-off\">\n            <td><code><b>off</b>(\n                <nobr>&lt;String&gt; <i>type</i></nobr>,\n                <nobr>&lt;Function&gt; <i>fn?</i></nobr>,\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет ранее добавленную функцию обработчика событий. Если функция не указана, то у объекта будут удалены\n                все обработчики для данного типа событий. Замечание: если методу <code>on</code> передавался\n                контекст, этот же контекст должен быть передан и методу <code>off</code>, для того чтобы обработчик был удален.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>(\n                <nobr>&lt;Object&gt; <i>eventMap</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет набор пар &#39;тип/обработчик&#39; обработчиков событий.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет все обработчики для всех типов событий.</td>\n        </tr>\n        <tr id=\"evented-fire\">\n            <td><code><b>fire</b>(\n                <nobr>&lt;String&gt; <i>type</i></nobr>,\n                <nobr>&lt;Object&gt; <i>data?</i></nobr>,\n                <nobr>&lt;Boolean&gt; <i>propagate?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Инициирует событие определенного типа. Опционально можно передать объект с данными события,\n                который будет передан первым параметром в функцию-обработчик. Также возможно указать,\n                чтобы событие распространилось на родительские объекты.</td>\n        </tr>\n        <tr id=\"evented-listens\">\n            <td><code><b>listens</b>(\n                <nobr>&lt;String&gt; <i>type</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если существуют хотя бы один обработчик для заданного типа событий.</td>\n        </tr>\n        <tr id=\"evented-once\">\n            <td><code><b>once</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Метод эквивалентен <a href=\"#evented-on\"><code>on(…)</code></a>, но обработчик события будет вызван\n                один раз, после чего удален.</td>\n        </tr>\n        <tr id=\"evented-addeventparent\">\n            <td><code><b>addEventParent</b>(\n                <nobr>&lt;<a href=\"#dgevented\">Evented</a>&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет объект <a href=\"#dgevented\"><code>Evented</code></a> в качестве получателя событий от\n                текущего объекта.</td>\n        </tr>\n        <tr id=\"evented-removeeventparent\">\n            <td><code><b>removeEventParent</b>(\n                <nobr>&lt;<a href=\"#dgevented\">Evented</a>&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет объект, ранее добавленный методом <a href=\"#evented-addeventparent\"><code>addEventParent</code></a>.</td>\n        </tr>\n        <tr id=\"evented-addeventlistener\">\n            <td><code><b>addEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#evented-on\"><code>on(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-removeeventlistener\">\n            <td><code><b>removeEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#evented-off\"><code>off(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-clearalleventlisteners\">\n            <td><code><b>clearAllEventListeners</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#evented-off\"><code>off()</code></a></td>\n        </tr>\n        <tr id=\"evented-addonetimeeventlistener\">\n            <td><code><b>addOneTimeEventListener</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#evented-once\"><code>once(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-fireevent\">\n            <td><code><b>fireEvent</b>(<i>…</i>)</code></td>\n\n            <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#evented-fire\"><code>fire(…)</code></a></td>\n        </tr>\n        <tr id=\"evented-haseventlisteners\">\n            <td><code><b>hasEventListeners</b>(<i>…</i>)</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Псевдоним для <a href=\"#evented-listens\"><code>listens(…)</code></a></td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Layer\n\nВсе объекты слоев API карт, так или иначе, задействуют методы базового класса <code>DG.Layer</code>.\nКласс наследует все методы, свойства и событийную модель от <a href=\"#dgevented\"><code>DG.Evented</code></a>.\n\n    var layer = DG.Marker(latlng).addTo(map);\n    layer.addTo(map);\n    layer.remove();\n\n#### Опции\n\n<table id=\"dglayer-options\">\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String</code></td>\n            <td><code>&#x27;overlayPane&#x27;</code></td>\n            <td>По умолчанию, слои добавляются в т.н. <a href=\"/doc/maps/ru/manual/map#map-overlaypane\">панель слоев</a>.\n                Поведение по умолчанию можно изменить, переопределив данную опцию.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\n<table id=\"dglayer-events\">\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"layer-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"#объекты-событий\">Event</a></code></td>\n            <td>Возникает после того, как слой будет добавлен к карте.</td>\n        </tr>\n        <tr id=\"layer-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"#объекты-событий\">Event</a></code></td>\n            <td>Возникает после того, как слой будет удален с карты.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События попапов\n\n<table id=\"dglayer-popup-events\">\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Возникает при открытии попапа, прикрепленного к данному слою.</td>\n        </tr>\n        <tr id=\"layer-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Возникает при закрытии попапа, привязанного к данному слою.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table id=\"dglayer-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-addto\">\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i>)</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет слой на карту.</td>\n        </tr>\n        <tr id=\"layer-remove\">\n            <td><code><b>remove</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет слой с карты, к которой он в данный момент прикреплен.</td>\n        </tr>\n        <tr id=\"layer-removefrom\">\n            <td><code><b>removeFrom</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет слой с карты.</td>\n        </tr>\n        <tr id=\"layer-getpane\">\n            <td><code><b>getPane</b>(\n                <nobr>&lt;String&gt; <i>name?</i> )</nobr>\n            </code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Возвращает <code>HTMLElement</code>, представляющий панель на карте с данным именем.\n                Если аргумент <code>name</code> не задан, возвращает панель, в которой находится данный слой.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы попапов\n\nВсе слои поддерживают набор методов, удобных для связывания с ними попапов.\n\n    var layer = DG.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\n    layer.openPopup();\n    layer.closePopup();\n\nПопапы автоматически открываются при щелчке мышью по слою, а также закрываются,\nпри удалении слоя или открытии другого попапа.\n\n<table id=\"dglayer-popup-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-bindpopup\">\n            <td><code><b>bindPopup</b>(\n                <nobr>&lt;String|HTMLElement|Function|Popup&gt; <i>content</i>,</nobr>\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Связывает попап со слоем и устанавливает необходимые обработчики событий.\n                Если в качестве параметра передать функцию, она получит текущий объект в качестве своего\n                первого аргумента и должна вернуть <code>String</code> или <code>HTMLElement</code>.</td>\n        </tr>\n        <tr id=\"layer-unbindpopup\">\n            <td><code><b>unbindPopup</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет попап, ранее привязанный с помощью <code>bindPopup</code>.</td>\n        </tr>\n        <tr id=\"layer-openpopup\">\n            <td><code><b>openPopup</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Открывает, связанный со слоем попап, в заданных координатах\n                <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>latlng</code></a>\n                или в координатах, сохраненных в параметрах самого элемента.</td>\n        </tr>\n        <tr id=\"layer-closepopup\">\n            <td><code><b>closePopup</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Закрывает, связанный со слоем попап, если он ранее был открыт. Также, может работать\n                как триггер, открывая или закрывая связанный элемент, в зависимости от его предыдущего состояния.\n                Возвращает <code>true</code>, если попап, был открыт в момент вызова метода.</td>\n        </tr>\n        <tr id=\"layer-setpopupcontent\">\n            <td><code><b>setPopupContent</b>(\n            <nobr>&lt;String|HTMLElement|Popup&gt; <i>content</i>,</nobr>\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Задает содержимое попапа, связанного с данным слоем.</td>\n        </tr>\n        <tr id=\"layer-getpopup\">\n            <td><code><b>getPopup</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/popup#dgpopup\">Popup</a></code></td>\n            <td>Возвращает попап, связанный с данным слоем.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы расширения\n\nКаждый слой, который наследуется от <a href=\"#dglayer\"><code>DG.Layer</code></a>, должен реализовать следующие методы.\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layer-onadd\">\n            <td><code><b>onAdd</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Должен содержать код, который создает DOM элемент для слоя и добавляет его в одну из панелей карты,\n                а также создает обработчики для соответствующих событий карты. Вызывается из\n                <a href=\"/doc/maps/ru/manual/map#map-addlayer\"><code>map.addLayer(layer)</code></a>.</td>\n        </tr>\n        <tr id=\"layer-onremove\">\n            <td><code><b>onRemove</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Должен содержать код, который убирает слой и сопутствующие элементы из DOM, а также удаляет обработчики,\n                ранее выставленные в <a href=\"#layer-onadd\"><code>onAdd</code></a>. Вызывается из\n                <a href=\"/doc/maps/ru/manual/map#map-removelayer\"><code>map.removeLayer(layer)</code></a>.</td>\n        </tr>\n        <tr id=\"layer-getevents\">\n            <td><code><b>getEvents</b>()</code></td>\n\n            <td><code>Object</code></td>\n            <td>Опциональный метод, который должен возвращать объект вида <code>{ viewreset: this._reset }</code>,\n                подходящего для вызова <a href=\"#evented-addeventlistener\"><code>addEventListener</code></a>.\n                Эти обработчики будут автоматически добавлены и удалены для событий карты вместе с операциями добавления\n                и удаления слоя.</td>\n        </tr>\n        <tr id=\"layer-beforeadd\">\n            <td><code><b>beforeAdd</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Опциональный метод, который вызывается из <a href=\"/doc/maps/ru/manual/map#map-addlayer\"><code>map.addLayer(layer)</code></a>,\n                перед тем как слой будет добавлен к карте и инициализированы соответствующие обработчики событий.\n                Объект карты может быть не до конца подготовлен к использованию (не загружены необходимые данные и т.п.)\n                в момент вызова. Поэтому метод можно использовать только для базовой инициализации структур данных слоя.</td>\n        </tr>\n    </tbody>\n</table>\n\nСобытия, унаследованные от <a href=\"#dgevented\">Evented</a> <!-- TODO: include events -->\n\n### DG.Control\n\nБазовый класс, от которого наследуют все элементы управления. Обеспечивает позиционирование элементов управления.\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-position\">\n            <td><code><b>position</b></code></td>\n            <td><code>String</code></code></td>\n            <td><code>&#x27;topright&#x27;</code></td>\n            <td>Местоположение элемента управления (один из углов карты). Возможные значения: <code>&#39;topleft&#39;</code>,\n                <code>&#39;topright&#39;</code>, <code>&#39;bottomleft&#39;</code> или <code>&#39;bottomright&#39;</code></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-getposition\">\n            <td><code><b>getPosition</b>()</code></td>\n\n            <td><code>string</code></td>\n            <td>Возвращает позицию элемента управления.</td>\n        </tr>\n        <tr id=\"control-setposition\">\n            <td><code><b>setPosition</b>(\n                <nobr>&lt;string&gt; <i>position</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Задает позицию элемента управления.</td>\n        </tr>\n        <tr id=\"control-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Возвращает объект HTMLElement, который содержит элемент управления.</td>\n        </tr>\n        <tr id=\"control-addto\">\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет элемент управления на карту.</td>\n        </tr>\n        <tr id=\"control-remove\">\n            <td><code><b>remove</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет элемент управления с карты, на которой он сейчас активен.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Handler\n\nБазовый класс для обработчиков взаимодействия с картой.\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"handler-enable\">\n            <td><code><b>enable</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Включает обработчик</td>\n        </tr>\n        <tr id=\"handler-disable\">\n            <td><code><b>disable</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Отключает обработчик</td>\n        </tr>\n        <tr id=\"handler-enabled\">\n            <td><code><b>enabled</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если обработчик активен</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы расширения функционала\n\nКлассы, наследующие от <a href=\"#dghandler\"><code>Handler</code></a>, должны реализовывать следующие методы:\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"handler-addhooks\">\n            <td><code><b>addHooks</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Вызывается при включении обработчика, должен добавлять обработчики событий.</td>\n        </tr>\n        <tr id=\"handler-removehooks\">\n            <td><code><b>removeHooks</b>()</code></td>\n\n            <td><code></code></td>\n            <td>Вызывается при отключении обработчика, должен удалять обработчики событий.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Projection\n\nОбъект для работы с <a href=\"http://en.wikipedia.org/wiki/Map_projection\">картографической проекцией</a>.\nСодержит методы для перевода географических координат в координаты на плоскости и обратно.\n\nAPI карт использует сферическую проекцию Меркатора (EPSG:3857).\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"projection-project\">\n            <td><code><b>project</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Осуществляет проекцию географических координат на двухмерную координатную плоскость.</td>\n        </tr>\n        <tr id=\"projection-unproject\">\n            <td><code><b>unproject</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Обратная операция от <code>project</code>. Осуществляет проекцию двухмерных координат в плоскости\n                на географические координаты.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"projection-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#latlngbounds\">LatLngBounds</a></code></td>\n            <td>Географические границы области, в пределах которой возможно осуществление преобразований.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Renderer\n\nБазовый класс, использующийся для реализации движков отображения векторных объектов (<code>DG.SVG</code>,\n<code>DG.Canvas</code>). В общем случае, используется для отображения геометрических объектов.\n\nОбслуживает операции, связанные с DOM-контейнером, его размерами и анимацией процесса\nмасштабирования. <a href=\"#dgrenderer\"><code>Renderer</code></a> выступает в качестве неявной группы слоев для\nвсех элементов, которые наследуются от <a href=\"/doc/maps/ru/manual/vector-layers#dgpath\"><code>DG.Path</code></a>.\nВсе векторные элементы используют движок отображения, который может быть задан неявно (и тогда API карт примет решение\nо том, какой тип движка использовать для отображения) или явно (с помощью опции векторного слоя\n<a href=\"/doc/maps/ru/manual/vector-layers#path-renderer\"><code>renderer</code></a>). Не используйте этот класс\nнапрямую. Используйте классы, которые наследуются от него, такие как <code>DG.SVG</code> или <code>DG.Canvas</code>.\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>Значение по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"renderer-padding\">\n            <td><code><b>padding</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.1</code></td>\n            <td>Насколько расширять границы отсечения выводимых объектов относительно границ окна, в котором отображается карта.\n                Измеряется в относительных единицах, где 0.1 соответствует 10% размера окна в каждом из направлений.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### Events\n\nСобытия, унаследованные от <a href=\"#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Methods\n\nМетоды, унаследованные от <a href=\"#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### Объекты событий\n\nКогда класс, унаследованный от <a href=\"#dgevented\"><code>Evented</code></a>, инициирует событие,\nвызывается функция-обработчик с аргументом, представляющим собой объект с данными о событии, например:\n\n    map.on('click', function(ev) {\n        alert(ev.latlng); // ev объект с данными о событии (MouseEvent, в данном случае)\n    });\n\nИнформация, которая попадает в функцию обработчик, зависит от типа события:\n\n#### Event\n\nБазовый объект события и другие объекты событий содержат следующие свойства:\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"event-type\">\n            <td><code><b>type</b></code></td>\n            <td><code>String</code></td>\n            <td>Тип события (например, <code>&#39;click&#39;</code>).</td>\n        </tr>\n        <tr id=\"event-target\">\n            <td><code><b>target</b></code></td>\n            <td><code>Object</code></td>\n            <td>Объект, который инициировал событие.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### MouseEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"mouseevent-latlng\">\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#latlng\">LatLng</a></code></td>\n            <td>Географические координаты точки, в которой было инициировано событие мыши.</td>\n        </tr>\n        <tr id=\"mouseevent-layerpoint\">\n            <td><code><b>layerPoint</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Пиксельные координаты, в которых было инициировано событие мыши, относительно слоя карты.</td>\n        </tr>\n        <tr id=\"mouseevent-containerpoint\">\n            <td><code><b>containerPoint</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Пиксельные координаты, в которых было инициировано событие мыши, относительно объекта-контейнера карты.</td>\n        </tr>\n        <tr id=\"mouseevent-originalevent\">\n            <td><code><b>originalEvent</b></code></td>\n            <td><code>DOMMouseEvent</code></td>\n            <td>Данные оригинального события мыши, инициированного браузером.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LocationEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"locationevent-latlng\">\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#latlng\">LatLng</a></code></td>\n            <td>Географическое положение пользователя</td>\n        </tr>\n        <tr id=\"locationevent-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#latlngbounds\">LatLngBounds</a></code></td>\n            <td>Географические границы, в которых находится пользователь (с учетом точности определения местоположения).</td>\n        </tr>\n        <tr id=\"locationevent-accuracy\">\n            <td><code><b>accuracy</b></code></td>\n            <td><code>Number</code></td>\n            <td>Точность определения местоположения в метрах.</td>\n        </tr>\n        <tr id=\"locationevent-altitude\">\n            <td><code><b>altitude</b></code></td>\n            <td><code>Number</code></td>\n            <td>Высота над поверхностью земли в метрах, согласно координатной системе WGS84.</td>\n        </tr>\n        <tr id=\"locationevent-altitudeaccuracy\">\n            <td><code><b>altitudeAccuracy</b></code></td>\n            <td><code>Number</code></td>\n            <td>Точность определения высоты в метрах.</td>\n        </tr>\n        <tr id=\"locationevent-heading\">\n            <td><code><b>heading</b></code></td>\n            <td><code>Number</code></td>\n            <td>Направление движения в градусах, считается с севера, в направлении по часовой стрелке.</td>\n        </tr>\n        <tr id=\"locationevent-speed\">\n            <td><code><b>speed</b></code></td>\n            <td><code>Number</code></td>\n            <td>Скорость в метрах в секунду.</td>\n        </tr>\n        <tr id=\"locationevent-timestamp\">\n            <td><code><b>timestamp</b></code></td>\n            <td><code>Number</code></td>\n            <td>Момент времени измерения местоположения.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### ErrorEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"errorevent-message\">\n            <td><code><b>message</b></code></td>\n            <td><code>String</code></td>\n            <td>Сообщение об ошибке.</td>\n        </tr>\n        <tr id=\"errorevent-code\">\n            <td><code><b>code</b></code></td>\n            <td><code>Number</code></td>\n            <td>Код ошибки (если имеется).</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LayerEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layerevent-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">Layer</a></code></td>\n            <td>Слой, который был добавлен или удален.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### LayersControlEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layerscontrolevent-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">Layer</a></code></td>\n            <td>Слой, который был добавлен или удален.</td>\n        </tr>\n        <tr id=\"layerscontrolevent-name\">\n            <td><code><b>name</b></code></td>\n            <td><code>String</code></td>\n            <td>Наименовани слоя, который был добавлен или удален.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### TileEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"tileevent-tile\">\n            <td><code><b>tile</b></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Элемент тайла (изображение).</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### TileErrorEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"tileerrorevent-tile\">\n            <td><code><b>tile</b></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Элемент тайла (изображение).</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### ResizeEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"resizeevent-oldsize\">\n            <td><code><b>oldSize</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Старый размер, до изменения размера.</td>\n        </tr>\n        <tr id=\"resizeevent-newsize\">\n            <td><code><b>newSize</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Новый размер, после изменения размера.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### GeoJSON event\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"geojson-event-layer\">\n            <td><code><b>layer</b></code></td>\n            <td><code><a href=\"#dglayer\">Layer</a></code></td>\n            <td>Слой GeoJSON объекта, добавленного на карту.</td>\n        </tr>\n        <tr id=\"geojson-event-properties\">\n            <td><code><b>properties</b></code></td>\n            <td><code>Object</code></td>\n            <td>Опции GeoJSON объекта.</td>\n        </tr>\n        <tr id=\"geojson-event-geometrytype\">\n            <td><code><b>geometryType</b></code></td>\n            <td><code>String</code></td>\n            <td>Тип геометрии GeoJSON объекта.</td>\n        </tr>\n        <tr id=\"geojson-event-id\">\n            <td><code><b>id</b></code></td>\n            <td><code>String</code></td>\n            <td>GeoJSON ID объекта (если задан).</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### Popup event\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n        </thead><tbody>\n        <tr id=\"popup-event-popup\">\n            <td><code><b>popup</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/popup#dgpopup\">Popup</a></code></td>\n            <td>Попап, который был открыт или закрыт.</td>\n        </tr>\n    </tbody>\n</table>\n\nСвойства, унаследованные от <a href=\"#event\">Event</a> <!-- TODO: include properties -->\n\n#### DragEndEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"dragendevent-distance\">\n            <td><code><b>distance</b></code></td>\n            <td><code>Number</code></td>\n            <td>Расстояние в пикселях на которое был сдвинут элемент.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### MetaEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>latlng</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Географические координаты точки объекта допслоя.</td>\n        </tr>\n        <tr>\n            <td><code><b>meta</b></code></td>\n            <td><code>Object</code></td>\n            <td>Метаданные объекта допслоя.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### LangEvent\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>lang</b></code></td>\n            <td><code>String</code></td>\n            <td>Текущий язык карты.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/basic-types.md",
    "content": "## Базовые типы данных\n\nВ данном разделе описаны классы базовых типов данных, которые часто встречаются на страницах руководства API карт\nи которые необходимы для работы с многими объектами карты.\n\n{toc}\n\n### DG.LatLng\n\nГеографическая точка с определенной широтой и долготой.\n\n    var latlng = DG.latLng(54.98, 82.89);\n\nВсе методы, которые принимают объекты LatLng, также принимают широту и долготу в виде простого массива или объекта\n(если не указано иное), то есть данные записи эквивалентны:\n\n    map.panTo([54.98, 82.89]);\n    map.panTo({lon: 82.89, lat: 54.98});\n    map.panTo({lat: 54.98, lng: 82.89});\n    map.panTo(DG.latLng(54.98, 82.89));\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-l-latlng\">\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Number&gt; <i>latitude</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>longitude</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>altitude?</i> )</nobr>\n            </code></td>\n            <td>Создает объект, представляющий географическую точку с определенной широтой и долготой\n                (и опционально высотой).</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Array&gt; <i>coords</i> )</nobr>\n            </code></td>\n            <td>Ожидает массив вида <code>[Number, Number]</code> или <code>[Number, Number, Number]</code>\n                в качестве аргумента.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLng</b>(\n                <nobr>&lt;Object&gt; <i>coords</i> )</nobr>\n            </code></td>\n            <td>Ожидает объект вида <code>{lat: Number, lng: Number}</code> или\n                <code>{lat: Number, lng: Number, alt: Number}</code> в качестве аргумента.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>otherLatLng</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>maxMargin?</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если переданная широта и долгота находится в той же позиции\n                (с небольшой погрешностью). Погрешность, используемую по умолчанию, можно изменить\n                передав аргумент <code>maxMargin</code>.</td>\n        </tr>\n        <tr id=\"latlng-tostring\">\n            <td><code><b>toString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Возвращает строковое представление позиции (удобно при отладке).</td>\n        </tr>\n        <tr id=\"latlng-distanceto\">\n            <td><code><b>distanceTo</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>otherLatLng</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает расстояние (в метрах) до переданной широты и долготы, рассчитанное по\n                <a target=\"_blank\" href=\"http://en.wikipedia.org/wiki/Haversine_formula\">формуле Haversine</a>.</td>\n        </tr>\n        <tr id=\"latlng-wrap\">\n            <td><code><b>wrap</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td><p>Возвращает новый объект <a href=\"#dglatlng\"><code>LatLng</code></a>, в котором долгота нормализуется\n                в диапазон от -180 до 180 градусов.</td>\n        </tr>\n        <tr id=\"latlng-tobounds\">\n            <td><code><b>toBounds</b>(\n                <nobr>&lt;Number&gt; <i>sizeInMeters</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td><p>Возвращает новый объект, <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a> в котором\n                каждая из границ отстоит от указанной точки на <code>sizeInMeters</code> метров.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlng-lat\">\n            <td><code><b>lat</b></code></td>\n            <td><code>Number</code></td>\n            <td>Широта в градусах.</td>\n        </tr>\n        <tr id=\"latlng-lng\">\n            <td><code><b>lng</b></code></td>\n            <td><code>Number</code></td>\n            <td>Долгота в градусах.</td>\n        </tr>\n        <tr id=\"latlng-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>Number</code></td>\n            <td>Высота в метрах (опционально).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.LatLngBounds\n\nОписывает прямоугольную географическую область на карте.\n\n    var southWest = DG.latLng(54.9801, 82.8974),\n        northEast = DG.latLng(54.9901, 82.9074),\n        bounds = DG.latLngBounds(southWest, northEast);\n\nВсе методы, которые принимают объекты LatLngBounds также принимают их в виде простого массива\n(если не указано иное), то есть границы могут быть указаны, как в этом примере:\n\n    map.fitBounds([\n        [54.9801, 82.8974],\n        [54.9901, 82.9074]\n    ]);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlngbounds-l-latlngbounds\">\n            <td><code><b>DG.latLngBounds</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>southWest</i>,</nobr>\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>northEast</i> )</nobr>\n            </code></td>\n            <td>Создает объект <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a>, определяя юго-западный и северо-восточный углы прямоугольника.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.latLngBounds</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i>)</nobr>\n            </code></td>\n            <td>Создает объект <a href=\"#dglatlngbounds\"><code>LatLngBounds</code></a> на основе географических точек,\n                которые находятся внутри описываемой области. Удобно использовать, если необходимо подстроить центр\n                и масштаб карты с помощью метода <a href=\"/doc/maps/ru/manual/map#map-fitbounds\">fitBounds</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"latlngbounds-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Расширяет область таким образом, чтобы в них входила переданная точка.</td>\n        </tr>\n        <tr>\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Расширяет область таким образом, чтобы в них входили переданные границы другой области.</td>\n        </tr>\n        <tr id=\"latlngbounds-pad\">\n            <td><code><b>pad</b>(\n                <nobr>&lt;Number&gt; <i>bufferRatio</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Возвращает бо́льшую область, увеличенную на заданный процент в каждом из направлений.</td>\n        </tr>\n        <tr id=\"latlngbounds-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает центральную точку области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsouthwest\">\n            <td><code><b>getSouthWest</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает крайнюю юго-западную точку области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnortheast\">\n            <td><code><b>getNorthEast</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает крайнюю северо-восточную точку области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnorthwest\">\n            <td><code><b>getNorthWest</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает крайнюю северо-западную точку области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsoutheast\">\n            <td><code><b>getSouthEast</b>()</code></td>\n\n            <td><code><a href=\"#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает крайнюю юго-восточную точку области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getwest\">\n            <td><code><b>getWest</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает западную границу (долготу) области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getsouth\">\n            <td><code><b>getSouth</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает южную границу (широту) области.</td>\n        </tr>\n        <tr id=\"latlngbounds-geteast\">\n            <td><code><b>getEast</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает восточную границу (долготу) области.</td>\n        </tr>\n        <tr id=\"latlngbounds-getnorth\">\n            <td><code><b>getNorth</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает северную границу (широту) области.</td>\n        </tr>\n        <tr id=\"latlngbounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если область содержит переданные границы.</td>\n        </tr>\n        <tr id=\"latlngbounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n             </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если область содержит переданную точку.</td>\n        </tr>\n        <tr id=\"latlngbounds-intersects\">\n            <td><code><b>intersects</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если границы области пересекают переданные границы хотя бы в одной точке.</td>\n        </tr>\n        <tr id=\"latlngbounds-overlaps\">\n            <td><code><b>overlaps</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если границы области перекрывают переданные границы в некотором пространстве.</td>\n        </tr>\n        <tr id=\"latlngbounds-tobboxstring\">\n            <td><code><b>toBBoxString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Возвращает строку с координатами границ в формате <code>&#39;southwest_lng,southwest_lat,northeast_lng,northeast_lat&#39;</code>.\n                Удобно использовать для отправки запросов к веб-сервисам, возвращающим геоданные.</td>\n        </tr>\n        <tr id=\"latlngbounds-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dglatlngbounds\">LatLngBounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если координаты текущей прямоугольной области эквивалентны переданным\n                (с небольшой погрешностью).</td>\n        </tr>\n        <tr id=\"latlngbounds-isvalid\">\n            <td><code><b>isValid</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если свойства объекта (данные границ) инициализированы должным образом.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Point\n\nТочка с пиксельными координатами x и y.\n\n    var point = DG.point(200, 300);\n\nВсе методы, которые принимают объекты <a href=\"#dgpoint\"><code>Point</code></a>, также принимают\nкоординаты в виде простого массива (если не указано иное), то есть данные записи эквивалентны:\n\n    map.panBy([200, 300]);\n    map.panBy(DG.point(200, 300));\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"point-l-point\">\n            <td><code><b>DG.point</b>(\n                <nobr>&lt;Number&gt; <i>x</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>y</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n            </code></td>\n            <td>Создает объект Point с заданными координатами <code>x</code> и <code>y</code>, при необходимости\n                округляя значения (если <code>round</code> установлен в <code>true</code>).</td>\n        </tr>\n        <tr id=\"point-l-point\">\n            <td><code><b>DG.point</b>(\n                <nobr>&lt;Number[]&gt; <i>coords</i>)</nobr>\n            </code></td>\n            <td>Ожидает массив вида <code>[x, y]</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"point-clone\">\n            <td><code><b>clone</b>()</nobr></code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает копию оригинального объекта.</td>\n        </tr>\n        <tr id=\"point-add\">\n            <td><code><b>add</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает результат сложения координат заданной точки и текущей.</td>\n        </tr>\n        <tr id=\"point-subtract\">\n            <td><code><b>subtract</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает результат вычитания координат заданной точки из текущей.</td>\n        </tr>\n        <tr id=\"point-divideby\">\n            <td><code><b>divideBy</b>(\n                <nobr>&lt;Number&gt; <i>num</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает результат деления координат текущей точки на произвольное число.</td>\n        </tr>\n        <tr id=\"point-multiplyby\">\n            <td><code><b>multiplyBy</b>(\n                <nobr>&lt;Number&gt; <i>num</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает результат умножения координат текущей точки на произвольное число.</td>\n        </tr>\n        <tr id=\"point-scaleby\">\n            <td><code><b>scaleBy</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>scale</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает новую точку, каждая координата которой получена умножением на соответствующую координату\n                <code>scale</code>. В терминах линейной алгебры, данная операция производит умножение на\n                <a href=\"https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation\">матрицу масштабирования</a>,\n                заданную <code>scale</code>.</td>\n        </tr>\n        <tr id=\"point-unscaleby\">\n            <td><code><b>unscaleBy</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>scale</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Обратная операция, относительно <code>scaleBy</code>.</td>\n        </tr>\n        <tr id=\"point-round\">\n            <td><code><b>round</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает копию оригинального объекта с округленными координатами.</td>\n        </tr>\n        <tr id=\"point-floor\">\n            <td><code><b>floor</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает копию оригинального объекта с координатами, округленными вниз.</td>\n        </tr>\n        <tr id=\"point-ceil\">\n            <td><code><b>ceil</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает копию оригинального объекта с координатами, округленными вверх.</td>\n        </tr>\n        <tr id=\"point-distanceto\">\n            <td><code><b>distanceTo</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает декартово расстояние между текущй и заданной точками.</td>\n        </tr>\n        <tr id=\"point-equals\">\n            <td><code><b>equals</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если заданная точка имеет аналогичные координаты.</td>\n        </tr>\n        <tr id=\"point-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>otherPoint</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если обе координаты заданной точки меньше (в абсолютных величинах) координат\n                текущей точки.</td>\n        </tr>\n        <tr id=\"point-tostring\">\n            <td><code><b>toString</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Возвращает строковое представление точки (удобно для отладки).</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>x</b></code></td>\n            <td><code>Number</code></td>\n            <td>Координата x.</td>\n        </tr>\n        <tr>\n            <td><code><b>y</b></code></td>\n            <td><code>Number</code></td>\n            <td>Координата y.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Bounds\n\nОписывает прямоугольную область на карте в пиксельных координатах.\n\n    var p1 = DG.point(10, 10),\n        p2 = DG.point(40, 60),\n        bounds = DG.bounds(p1, p2);\n\nВсе методы, которые принимают объекты <a href=\"#dgpoint\"><code>Point</code></a> также принимают их в виде простого массива\n(если не указано иное), то есть границы могут быть указаны, как в этом примере:\n\n    otherBounds.intersects([[10, 10], [40, 60]]);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-l-bounds\">\n            <td><code><b>DG.bounds</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>topLeft</i>,</nobr>\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>bottomRight</i> )</nobr>\n            </code></td>\n            <td>Создает объект Bounds на основе переданных координат (обычно, координат левого-верхнего и правого-нижнего углов).</td>\n        </tr>\n        <tr id=\"bounds-l-bounds\">\n            <td><code><b>DG.bounds</b>(\n                <nobr>&lt;Point[]&gt; <i>points</i> )</nobr>\n            </code></td>\n            <td>Создает объект Bounds на основе массива координат переданных точек.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Расширяет область таким образом, чтобы в нее входила переданная точка.</td>\n        </tr>\n        <tr id=\"bounds-getcenter\">\n            <td><code><b>getCenter</b>(\n                <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает центральную точку области.</td>\n        </tr>\n        <tr id=\"bounds-getbottomleft\">\n            <td><code><b>getBottomLeft</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает координаты левого-нижнего угла области.</td>\n        </tr>\n        <tr id=\"bounds-gettopright\">\n            <td><code><b>getTopRight</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает координаты правого-верхнего угла области.</td>\n        </tr>\n        <tr id=\"bounds-getsize\">\n            <td><code><b>getSize</b>()</code></td>\n\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Возвращает размер области.</td>\n        </tr>\n        <tr id=\"bounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если область содержит переданные границы.</td>\n        </tr>\n        <tr id=\"bounds-contains\">\n            <td><code><b>contains</b>(\n                <nobr>&lt;<a href=\"#dgpoint\">Point</a>&gt; <i>point</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если область содержит переданную точку.</td>\n        </tr>\n        <tr id=\"bounds-intersects\">\n            <td><code><b>intersects</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если границы области пересекают переданные границы хотя бы в одной точке.</td>\n        </tr>\n        <tr id=\"bounds-overlaps\">\n            <td><code><b>overlaps</b>(\n                <nobr>&lt;<a href=\"#dgbounds\">Bounds</a>&gt; <i>otherBounds</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если границы области перекрывают переданные границы в некотором пространстве.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"bounds-min\">\n            <td><code><b>min</b></code></td>\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Левый верхний угол прямоугольной области.</td>\n        </tr>\n        <tr id=\"bounds-max\">\n            <td><code><b>max</b></code></td>\n            <td><code><a href=\"#dgpoint\">Point</a></code></td>\n            <td>Правый нижний угол прямоугольной области.</td>\n        </tr>\n\t</tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/controls.md",
    "content": "## Элементы управления\n\nЭлементы управления — это компоненты интерфейса, с помощью которых пользователь может взаимодействовать с картой.\n\n{toc}\n\n### DG.Control.Zoom\n\nБазовый элемент управления масштабом с двумя кнопками (приблизить и отдалить). Добавляется на карту по умолчанию,\nесли не передана <a href=\"/doc/maps/ru/manual/map#map-zoomcontrol\">опция <code>zoomControl</code></a> со значением <code>false</code>.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-zoom-l-control-zoom\">\n            <td><code><b>DG.control.zoom</b>(\n                <nobr>&lt;<a href=\"#control-zoom-option\">DG.Control.Zoom options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td>Создает элемент управления масштабом.</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-zoom-zoomintext\">\n            <td><code><b>zoomInText</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;+&#x27;</code></td>\n            <td>Текст кнопки &#39;приблизить&#39;.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomintitle\">\n            <td><code><b>zoomInTitle</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Zoom in&#x27;</code></td>\n            <td>Значение атрибута title для конпки &#39;приблизить&#39;.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomouttext\">\n            <td><code><b>zoomOutText</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;-&#x27;</code></td>\n            <td>Текст кнопки &#39;Отдалить&#39;.</td>\n        </tr>\n        <tr id=\"control-zoom-zoomouttitle\">\n            <td><code><b>zoomOutTitle</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Zoom out&#x27;</code></td>\n            <td>Значение атрибута title для конпки &#39;отдалить&#39;.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Attribution\n\nПозволяет показать информацию об авторстве в небольшом текстовом контейнере на карте. Добавляется на карту по умолчанию,\nесли значение опции <a href=\"/doc/maps/ru/manual/map#map-attributioncontrol\"><code>attributionControl</code></a>\nне выставлено в <code>false</code>. Компонует итоговый текст из слоев, вызывая их метод\n<a href=\"/doc/maps/ru/manual/base-classes#layer-getattribution\"><code>getAttribution</code></a>.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-attribution-l-control-attribution\">\n            <td><code><b>DG.control.attribution</b>(\n                <nobr>&lt;<a href=\"#control-attribution-option\">DG.Control.Attribution options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td>Создает элемент с информацией об авторстве.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-attribution-prefix\">\n            <td><code><b>prefix</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;Leaflet&#x27;</code></td>\n            <td>Текст в формате HTML, который будет отображен перед информацией об авторстве.\n                Для отключения необходимо передать <code>false</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\n<table>\n    <thead>\n\t<tr>\n\t\t<th>Метод</th>\n\t\t<th>Возвращает</th>\n\t\t<th>Описание</th>\n\t</tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"control-attribution-setprefix\">\n            <td><code><b>setPrefix</b>(\n                <nobr>&lt;String&gt; <i>prefix</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет текст перед информацией об авторстве.</td>\n        </tr>\n        <tr id=\"control-attribution-addattribution\">\n            <td><code><b>addAttribution</b>(\n                <nobr>&lt;String&gt; <i>text</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет информацию об авторстве (например, <code>&#39;Картографические данные 2GIS&#39;</code>).</td>\n        </tr>\n        <tr id=\"control-attribution-removeattribution\">\n            <td><code><b>removeAttribution</b>(\n                <nobr>&lt;String&gt; <i>text</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет информацию об авторстве.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Scale\n\nПоказывает масштаб карты в метрической (метры, километры) и английской (мили, футы) системах измерений.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.scale().addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-scale-l-control-scale\">\n            <td><code><b>DG.control.scale</b>(\n                <nobr>&lt;<a href=\"#control-scale-option\">DG.Control.Scale options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает индикатор масштаба.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-scale-maxwidth\">\n            <td><code><b>maxWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>100</code></td>\n            <td>Максимальная ширина элемента в пикселях.</td>\n        </tr>\n        <tr id=\"control-scale-metric\">\n            <td><code><b>metric</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>True</code></td>\n            <td>Включает или отключает метрическую систему измерений (метры, километры).</td>\n        </tr>\n        <tr id=\"control-scale-imperial\">\n            <td><code><b>imperial</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>True</code></td>\n            <td>Включает или отключает английскую систему измерений (мили, футы).</td>\n        </tr>\n        <tr id=\"control-scale-updatewhenidle\">\n            <td><code><b>updateWhenIdle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>При значении <code>true</code>, элемент будет обновляться только при возникновении события\n                <a href=\"/doc/maps/ru/manual/map#map-moveend\"><code>moveend</code></a>, в противном случае, при каждом событии\n                <a href=\"/doc/maps/ru/manual/map#map-move\"><code>move</code></a>.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Ruler\n\nКнопка включения отображения линейки для измерения расстояний на карте.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.ruler().addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-ruler-l-control-ruler\">\n            <td><code><b>DG.control.ruler</b>(\n                <nobr>&lt;<a href=\"#control-ruler-option\">DG.Control.Ruler options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает кнопку включения отображения линейки.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Traffic\n\nКнопка включения отображения слоя пробок на карте.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.traffic().addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-traffic-l-control-traffic\">\n            <td><code><b>DG.control.traffic</b>(\n                <nobr>&lt;<a href=\"#control-traffic-option\">DG.Control.Traffic options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает элемент управления слоем пробок.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.Fullscreen\n\nКнопка включения полноэкранного отображения карты, повторный клик в кнопку\nвосстанавливает исходный размер карты. Добавляется на карту по умолчанию,\nесли не передана опция <code>fullscreenControl</code> со значением <code>false</code>.\nРасширяет <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\"><code>DG.Control</code></a>.\n\n    DG.control.fullscreen().addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-fullscreen-l-control-fullscreen\">\n            <td><code><b>DG.control.fullscreen</b>(\n                <nobr>&lt;<a href=\"#control-fullscreen-option\">DG.Control.Fullscreen options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает элемент управления полноэкранным режимом.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n### DG.Control.LocationControl\n\nЭлемент управление (кнопка), при клике на которую определяется и отображается текущее месторасположение пользователя.\nЕсли API геолокации не поддерживается устройством, тогда элемент управления не выводится.\n\n    DG.control.location().addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-location-l-control-location\">\n            <td><code><b>DG.control.location</b>(\n                <nobr>&lt;<a href=\"#control-location-option\">DG.Control.LocationControl options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает элемент управления геопозиционированием.</td>\n        </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"control-location-drawcircle\">\n            <td><code><b>drawCircle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Будет ли отображаться круг, показывающий точность определения месторасположения.</td>\n        </tr>\n        <tr id=\"control-location-follow\">\n            <td><code><b>follow</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Динамическое обновление месторасположения пользователя, работает, если <code>watch</code> и\n                <code>setView</code> выставлены в <code>true</code>.</td>\n        </tr>\n        <tr id=\"control-location-stopfollowingondrag\">\n            <td><code><b>stopFollowingOnDrag</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Включает или отключает обновление месторасположения пользователя при перетаскивании карты.</td>\n        </tr>\n        <tr id=\"control-location-metric\">\n            <td><code><b>metric</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Использовать метрические или английские единицы измерения.</td>\n        </tr>\n        <tr id=\"control-location-locateoptions\">\n            <td><code><b>locateOptions</b></code></td>\n            <td><code>Object </code></td>\n            <td><code></code></td>\n            <td>См. <a href=\"/doc/maps/ru/manual/map#geolocation-options\">geo-location options</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgcontrol\">Control</a> <!-- TODO: include options -->\n"
  },
  {
    "path": "src/doc/ru/manual/dg-ajax.md",
    "content": "## Асинхронные запросы (AJAX)\n\n{toc}\n\n### DG.ajax\n\nФункция DG.ajax позволяет отправлять кросс-доменные AJAX запросы.\n\n    var promise = DG.ajax('http://www.geonames.org/postalCodeLookupJSON', {\n        type: 'get',\n        data: {\n            postalcode: 10504,\n            country: 'US'\n        },\n        success: function(data) {\n            console.log('success', data);\n        },\n        error: function(error) {\n            console.log('error', error);\n        }\n    });\n\n    // для отмены запроса:\n    // promise.abort();\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Вызов</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.ajax</b>(\n                <nobr>&lt;String&gt; <i>url</i>,</nobr>\n                <nobr>&lt;<a href=\"#опции\">Ajax options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Отправляет запрос на сервер и возвращает объект Promise с методом abort, с помощью\n                которого можно прервать отправку запроса. В качестве входящих параметров принимает URL,\n                на который будет отправлен запрос и необязательный объект опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>data</b></code></td>\n            <td><code>Object</code></td>\n            <td><code>null</code></td>\n            <td>Данные, которые будут переданы на сервер.</td>\n        </tr>\n        <tr>\n            <td><code><b>type</b></code></td>\n            <td><code>String</code></td>\n            <td><code>get</code></td>\n            <td>Тип запроса ('get', 'post' или 'jsonp').</td>\n        </tr>\n        <tr>\n            <td><code><b>success</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>Функция, которая срабатывает в случае успешного ответа сервера.\n                В качестве параметра принимает полученные данные.</td>\n        </tr>\n        <tr>\n            <td><code><b>error</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>Функция, которая срабатывает при возникновении ошибки.\n                В качестве параметра принимает информацию об ошибке.</td>\n        </tr>\n        <tr>\n            <td><code><b>url</b></code></td>\n            <td><code>String</code></td>\n            <td><code>null</code></td>\n            <td>URL, на который будет отправлен запрос.</td>\n        </tr>\n        <tr>\n            <td><code><b>timeout</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>null</code></td>\n            <td>Время ожидания запроса (в миллисекундах).</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-entrance.md",
    "content": "## DG.Entrance\n\nПозволяет отобразить вход в здание. Класс поддерживает простейшую анимацию и отображение сразу нескольких входов. Сами\nобъекты входов представляют собой стрелки, которые изменяют свой масштаб вместе с изменением масштаба карты, но не ниже\n16 уровня, после которого стрелки исчезают с карты (до возвращения приемлемого значения уровня масштабирования).\n\n{toc}\n\n### DG.Entrance\n\n#### Пример использования\n\nСоздание и отображение входов в здание:\n\n    var options = {vectors: [\n        \"LINESTRING(82.897079 54.980906,82.897191 54.980844)\",\n        \"LINESTRING(82.897933 54.980649,82.898045 54.980587)\",\n        \"LINESTRING(82.897071 54.980122,82.897226 54.98013)\",\n        \"LINESTRING(82.897354 54.979515,82.89741 54.979599)\",\n        \"LINESTRING(82.898498 54.979826,82.898386 54.979889)\"\n    ]}\n    DG.entrance(options).addTo(map).show(true);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Entrance</b>(\n                <nobr>&lt;<a href=\"#entrance-options\">Entrance options</a>&gt; <i>options</i> )</nobr>\n            </code></td>\n            <td><code>DG.entrance(&hellip;)</code></td>\n            <td>Создает объект входа на основе переданных опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>vectors</b></code></td>\n            <td><code>Array</td>\n            <td><code>[]</code></td>\n            <td><b>(обязательный параметр)</b>Массив векторов, описывающих входы в здание. В массиве можно передать\n                несколько значений, если существует более одного входа в здание. Каждый элемент должен представлять\n                собой строку в WKT-формате: LINESTRING(lng0 lat0,lng1 lat1[,... lngN latN]), где последняя пара координат\n                должна представлять собой непосредственно точку входа в здание, а предыдущие координаты - маршрут до этой точки.\n                На всем протяжении маршрута не должно быть взаимных пересечений.</td>\n        </tr>\n        <tr>\n            <td><code><b>fillColor</b></code></td>\n            <td><code>String</td>\n            <td><code>#0085a0</code></td>\n            <td>Цвет заполнения стрелок.</td>\n        </tr>\n        <tr>\n            <td><code><b>strokeColor</b></code></td>\n            <td><code>String</td>\n            <td><code>#ffffff</code></td>\n            <td>Цвет обводки стрелок.</td>\n        </tr>\n        <tr>\n            <td><code><b>enableAnimation</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>true</code></td>\n            <td>Анимировать ли отображение стрелок при изменении уровней масштаба карты и начальном показе.</td>\n        </tr>\n        <tr>\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>false</code></td>\n            <td>Если значение false, тогда обработчик действий мыши не вызывается.</td>\n        </tr>\n        <tr>\n            <td><code><b>autoClose</b></code></td>\n            <td><code>Boolean</td>\n            <td><code>true</code></td>\n            <td>Если значение true, то входы пропадут с карты после добавления новых слоев.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"#map\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет объект входов на карту.</td>\n        </tr>\n        <tr>\n            <td><code><b>removeFrom</b>(\n                <nobr>&lt;<a href=\"#map\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет объект входов с карты.</td>\n        </tr>\n        <tr>\n            <td><code><b>show</b>(\n                <nobr>&lt;fitBounds&gt; <i>boolean</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Отображает входы на карте. Если <code>fitBounds</code> установлен в <code>true</code>, тогда границы карты\n                (и уровень масштаба) подстраиваются таким образом, чтобы пользователь увидел все входы на одном экране.</td>\n        </tr>\n        <tr>\n            <td><code><b>hide</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Скрывает входы. Сами объекты не удаляются с карты и входы могут быть повторно отображены путем вызова метода\n                <code>show()</code>.</td>\n        </tr>\n        <tr>\n            <td><code><b>isShown</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если входы в данный момент отображаются на карте.</td>\n        </tr>\n        <tr>\n            <td><code><b>setFillColor</b>()</code></td>\n            <td><code>String</code></td>\n            <td>Изменяет цвет заполнения стрелок.</td>\n        </tr>\n        <tr>\n            <td><code><b>setStrokeColor</b>()</code></td>\n            <td><code>String</code></td>\n            <td>Изменяет цвет обводки стрелок.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-external-modules.md",
    "content": "## Внешние модули\n\nКроме возможности подключить один из <a href=\"/doc/maps/ru/manual/dg-loading#loading-pkg\">пакетов</a> модулей 2ГИС,\nвы можете загружать модули других разработчиков со сторонних серверов. API карт совместим с большинством\n<a target=\"_blank\" href=\"http://leafletjs.com/plugins.html\">модулей библиотеки</a> Leaflet.\nТакже вы можете разработать и подключить\n<a href=\"https://github.com/2gis/maps-api-2.0/blob/master/CONTRIBUTING.md#%D0%9A%D0%B0%D0%BA-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D1%82%D1%8C-%D1%81%D0%BE%D0%B1%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C\" target=\"_blank\">собственный модуль</a>.\n\n{toc}\n\n### Подключение\n\nДля подключения внешних модулей используется функция <code>DG.plugin</code>.\nНиже мы рассмотрим несколько примеров ее использования.\n\nИспользование функции <code>DG.plugin</code> в случае, когда модуль должен быть\nзагружен до начала инициализации карты:\n\n    // загрузка кода API карт\n    DG.then(function() {\n        // загрузка кода модуля\n        return DG.plugin('https://raw.github.com/mlevans/leaflet-hash/master/leaflet-hash.js');\n    })\n    .then(function() {\n        // инициализация карты\n        var map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n        // инициализация модуля\n        L.hash(map);\n    });\n\nЕсли модуль не нужен на начальном этапе работы с картой, тогда можно использовать его отложенную\nзагрузку и инициализацию (например, при клике на кнопку):\n\n    // загрузка кода API карт\n    DG.then(function() {\n        // инициализация карты\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\n    // код, который может быть вызван по требованию\n    DG.then(function() {\n        // загрузка кода модуля\n        return DG.plugin('https://raw.github.com/mlevans/leaflet-hash/master/leaflet-hash.js');\n    }).then(function () {\n        // инициализация модуля\n        L.hash(map);\n    });\n\n### DG.plugin\n\nОтвечает за загрузку внешних модулей. Параметры функции:\n\n<table>\n    <thead>\n        <tr>\n            <th>Вызов</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code>DG.plugin</b>(\n                <nobr>&lt;String&gt; <i>url</i>&nbsp;|&nbsp;</nobr>\n                <nobr>&lt;Array&gt; <i>[&lt;String&gt; url, &lt;String&gt; url, ...]</i></nobr>&nbsp;)\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Загружает модули. В качестве параметров должны быть указкны прямые ссылки на js и css файлы.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-label.md",
    "content": "## Подсказки\n\n{toc}\n\n### DG.Label\n\nКласс <code>DG.Label</code> реализует небольшую подсказку, которая может появляться над определенным объектом на карте\n(над маркером или векторным слоем, например). Также, подсказки могут отображаться не только, при наведении курсора мыши\nна объект, а постоянно, такие подсказки называются статическими.\n\n#### Пример использования\n\nВключить отображение подсказки при наведении курсора мыши на маркер довольно просто:\n\n    DG.marker([54.9502, 82.8380], {\n        label : 'Я подсказка!'\n    }).addTo(map);\n\nДля векторных слоев, подсказку можно указать таким образом, например:\n\n    DG.polyline([\n        [55.02, 83.02],\n        [54.97, 83.03],\n        [54.95, 83.01],\n        [54.98, 82.97]\n    ], {\n        label: 'Я подсказка!'\n    }).addTo(map);\n\nДля добавления подсказки к уже созданному объекту, следует вызвать метод <code>bindLabel</code>:\n\n    var marker = DG.marker([54.9502, 82.8980]).addTo(map);\n    marker.bindLabel('Я статическая подсказка!', { static: true });\n\n<!--\nTODO: JSAPI-3564\nОтображение автономной статической подсказки на карте:\n\n    DG.label('Я автономная подсказка!')\n        .setLatLng([54.9502, 82.8980]);\n        .addTo(map);\n\n#### Создание\n...\n-->\n\n#### Опции\n\nПри вызове метода <code>bindLabel</code>, вы можете задать следующие опции для всплывающей подсказки:\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><b><code>offset</code></b></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td><nobr><code>Point(12, 15)</code></nobr></td>\n            <td>Смещение контейнера всплывающей подсказки относительно позиции курсора (позиции маркера в случае\n                использования с маркером).</td>\n        </tr>\n        <tr>\n            <td><b><code>className</code></b></td>\n            <td><code>String</code></td>\n            <td><code>'dg-label'</code></td>\n            <td>CSS класс который будет присвоен DOM элементу всплывающей подсказки.</td>\n        </tr>\n        <tr id=\"label-static\">\n            <td><b><code>static</code></b></td>\n            <td><code>Boolean</code></td>\n            <td><code>false</code></td>\n            <td>Если задано значение <code>true</code>, тогда всплывающая подсказка будет отображаться постоянно\n                (эта опция доступна только для подсказки у маркера).</td>\n        </tr>\n        <tr id=\"label-textdirection\">\n            <td><code><b>textDirection</b></code></td>\n            <td><code>string</code></td>\n            <td><code>'auto'</code></td>\n            <td>Направление текста подсказки. Может принимать одно из следующих значений: <code>'auto'</code>,\n                <code>'rtl'</code>, <code>'ltr'</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n<!--\nTODO: JSAPI-3564\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>setContent</b>(&lt;String&gt; content)</code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает содержимое всплывающей подсказки.</td>\n        </tr>\n        <tr>\n            <td><code><b>setLatLng</b>(&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; latlng)</code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает географические координаты подсказки.</td>\n        </tr>\n        <tr>\n            <td><code><b>getLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Возвращает географические координаты подсказки.</td>\n        </tr>\n    </tbody>\n</table>\n-->\n"
  },
  {
    "path": "src/doc/ru/manual/dg-loading.md",
    "content": "## Подключение API\n\n{toc}\n\n### Описание\n\nРабота с картой возможна только после того, как в браузер будет загружен код API карт.\nЕсть несколько способов его загрузки.\n\n### Простой способ\n\nСперва подключим API карт, поместив в секцию <code>head</code> HTML-страницы следующий код:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n\nЗатем воспользуемся функцией <code>DG.then</code>, в которую поместим код инициализации карты:\n\n    DG.then(function() {\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\nВнутри себя эта функция добавляет обработчик события загрузки страницы. Именно такой способ\nрассматривался в разделе [«Быстрый старт»](/doc/maps/ru/quickstart).\n\n### npm\n\nAPI карт можно подключить через npm:\n\n    $ npm i 2gis-maps\n\nПосле установки пакета подключим его через <code>require</code>:\n\n    var DG = require('2gis-maps');\n    var map = DG.map('map', {\n        'center': [54.98, 82.89],\n        'zoom': 13\n    });\n\nОбратите внимание, что при использовании npm-пакета использовать <code>DG.then</code> не нужно.\n\n### Загрузка по требованию\n\nВы можете загрузить API карт именно в тот момент, когда карта станет нужна. Для этого в URL\nподключения API необходимо добавить параметр <code>lazy=true</code>:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full&lazy=true\"></script>\n\nЗатем в нужный момент времени (например, при нажатии на кнопку) необходимо вызвать функцию DG.then:\n\n    DG.then(function() {\n        map = DG.map('map', {\n            'center': [54.98, 82.89],\n            'zoom': 13\n        });\n    });\n\n### Опции подключения\n\nНиже описаны все опции, которые может принимать URL загрузки API карт:\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"loading-pkg\">\n            <td><code>pkg</code></td>\n            <td><code>full</code></td>\n            <td>Пакет загружаемых модулей. На данный момент поддерживается 2 пакета:\n                <code>full</code> — все модули API; <code>basic</code> — базовая функциональность\n                (попапы, маркеры, векторные объекты).</td>\n        </tr>\n        <tr>\n            <td><code>skin</code></td>\n            <td><code>dark</code></td>\n            <td>Тема управляющих элементов (светлая или темная). Принимает значение\n                <code>light</code> или <code>dark</code>.</td>\n        </tr>\n        <tr>\n            <td><code>lazy</code></td>\n            <td><code>false</code></td>\n            <td>Если указать значение <code>true</code>, тогда API карт загрузится отложенно,\n                при первом вызове <code>DG.then</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### Функция DG.then\n\nКак было описано ранее, функция <code>DG.then</code> отвечает за отслеживание момента загрузки API карт\nи добавление обработчиков этого действия. Параметры функции:\n\n<table>\n    <thead>\n        <tr>\n            <th>Вызов</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code>DG.then</b>(\n                <nobr>&lt;Function&gt; <i>resolve</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>reject</i></nobr>&nbsp;)\n            </code></td>\n            <td><code>Promise</code></td>\n            <td>Регистрирует обработчики загрузки API. Пареметры: <code>resolve</code> — функция,\n                срабатывающая при успешной загрузке API карт, <code>reject</code> — функция,\n                срабатывающая в случае ошибки сервера.</td>\n        </tr>\n    </tbody>\n</table>\n\nВызов функции <code>DG.then</code> в любой момент после загрузки API мгновенно выполнит обработчик.\n"
  },
  {
    "path": "src/doc/ru/manual/dg-locale.md",
    "content": "## Локализация\n\n{toc}\n\n### Описание\n\nAPI карт предоставляет возможность отображения элементов пользовательского интерфейса на нескольких языках.\n\nПо умолчанию задается такой же язык, как и у корневого тега html:\n\n    <html lang=\"it\">\n        <head></head>\n        <body></body>\n    </html>\n\nЕсли язык в корневом теге не указан, тогда будет использоваться язык по умолчанию — русский.\n\nПолучить или динамически изменить язык можно с помощью соответствующих методов карты\n<a href=\"/doc/maps/ru/manual/map#map-getlang\">getLang</a> и <a href=\"/doc/maps/ru/manual/map#map-setlang\">setLang</a>:\n\n    map.setLang('it');\n    map.getLang(); // вернет 'it'\n\nили проинициализировав карту со следующей опцией <a href=\"/doc/maps/ru/manual/map#map-currentlang\">currentLang</a>.\n\nНа данный момент поддерживаются следующие языки:\n\n* en &mdash; английский;\n* ru &mdash; русский;\n* it &mdash; итальянский;\n* cs &mdash; чешский;\n* es &mdash; испанский;\n* ar &mdash; арабский.\n\n### DG.Locale\n\nОсуществляет <a href=\"/doc/maps/ru/manual/dg-locale\">перевод пользовательского интерфейса</a>.\n\nДобавляет в карту два метода: <a href=\"/doc/maps/ru/manual/map#map-setlang\">setLang</a> и\n<a href=\"/doc/maps/ru/manual/map#map-getlang\">getLang</a>. Также имеется объект DG.Locale, который можно подмешать\nв любой <a href=\"/doc/maps/ru/manual/dg-external-modules\">внешний модуль</a>, после чего в нем появится метод t,\nс помощью которого можно осуществить перевод. Классы модулей, к которым примешивается DG.Locale должны\nсодержать внутри себя свойство <code>_map</code> и статическое свойство <code>Dictionary</code>.\n\nБазовым для всех словарей является словарь <code>DG.Dictionary</code>, в котором хранятся правила перевода слов во\nмножественные формы (plural rules). При создании модуля, использующего свои словари, необходимо их разместить\nв папке lang. К примеру, если вы будете использовать итальянский и русский языки, тогда необходимо создать\nфайлы <code>lang/it.js</code> и <code>lang/ru.js</code>. Примеры создания словарей рассмотрены ниже.\n\n#### Пример использования\n\nПодмешивание (mixin) возможности локализации в модуль:\n\n    DG.LocaleExample = DG.Control.extend({\n        includes: DG.Locale,\n        statics: {\n            Dictionary: {}\n        }\n        ...\n    }\n\nПодписка на событие langchange:\n\n    this._map.on('langchange', this._updateText, this);\n\nПеревод строки на текущий язык карты:\n\n    container.innerHTML = this.t(\"{n} people\", 16700000) + ' ' + this.t(\"regularly use 2GIS\");\n\nСоздание собственных словарей на итальянском и русском языках:\n\nCодержимое файла lang/it.js:\n\n    DG.LocaleExample.Dictionary.it = DG.extend({\n        \"{n} people\" : [\"{n} utente\", \"{n} utenti\"],\n        \"regularly use 2GIS\" : \"utilizzano regolarmente 2GIS\"\n    }, DG.Dictionary.it);\n\nCодержимое файла lang/ru.js:\n\n     DG.LocaleExample.Dictionary.ru = DG.extend({\n        \"{n} people\" : [\"{n} пользователь\", \"{n} пользователя\", \"{n} пользователей\"],\n        \"regularly use 2GIS\" : \"регулярно используют 2GIS\"\n    }, DG.Dictionary.ru);\n"
  },
  {
    "path": "src/doc/ru/manual/dg-metalayers.md",
    "content": "## Слои с мета-информацией\n\nПозволяет создавать дополнительные слои с мета-информацией и добавлять их на карту.\n\n{toc}\n\n### DG.Meta.layer\n\nНаследует от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\"><code>DG.Layer</code></a>.\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Meta.layer</b>(\n                <nobr>&lt;String&gt; <i>source</i>,</nobr>\n                <nobr>&lt;<a href=\"#опции\">DG.Meta.layer options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Meta.layer(&hellip;)</code></td>\n            <td>Создает дополнительный слой с метаинформацией. Принимает в качестве параметра source URL,\n                по которому доступны тайлы допслоя.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>tileSize</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>256</code></td>\n            <td>Размер тайла (ширина и высота в пикселях, предполагается что тайл квадратный).</td>\n        </tr>\n        <tr>\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>0</code></td>\n            <td>Минимальный уровень зума.</td>\n        </tr>\n        <tr>\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>18</code></td>\n            <td>Максимальный уровень зума.</td>\n        </tr>\n        <tr>\n            <td><code><b>zoomOffset</b></code></td>\n            <td><code>Number</code></td>\n            <td><code>0</code></td>\n            <td>Значение, на которое будет смещен уровень масштабирования в адресе тайла.</td>\n        </tr>\n        <tr>\n            <td><code><b>eventBubbling</b></code></td>\n            <td><code>String</code></td>\n            <td><code><span class=\"string\">'transparent'</span>||<span class=\"string\">'layer'</span></td>\n            <td>Способ, которым мета-слой обрабатывает события. Принимает значения <b>layer</b>\n                или <b>transparent</b> (по-умолчанию):<ul><li>transparent &mdash; мета-слой принимает\n                все события и прокидывает их на карту</li><li>layer &mdash; мета-слой принимает\n                события и останавливает их после обработки</li></ul></td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\nВы можете подписаться на следующие события, используя\n<a href=\"/doc/maps/ru/manual/base-classes#dgevented\">эти методы</a>.\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code>\n            <td>Вызывается при наведении курсором мыши на объект допслоя.</td>\n        </tr>\n        <tr>\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code>\n            <td>Вызывается при когда курсор мыши покидает границы объекта допслоя.</td>\n        </tr>\n        <tr>\n          <td><code><b>mousemove</b></code></td>\n          <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Вызывается при движении курсора мыши над объектом допслоя.</td>\n        </tr>\n        <tr>\n          <td><code><b>click</b></code></td>\n          <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Вызывается при клике мыши в допслой.</td>\n        </tr>\n        <tr>\n          <td><code><b>dblclick</b></code></td>\n          <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Вызывается при двойном клике мыши в допслой.</td>\n        </tr>\n        <tr>\n          <td><code><b>mousedown</b></code></td>\n          <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Вызывается при нажатии мыши, когда курсор находится над допслоем.</td>\n        </tr>\n        <tr>\n          <td><code><b>contextmenu</b></code></td>\n          <td><code><a href=\"/doc/maps/ru/manual/base-classes#metaevent\">MetaEvent</a></code></td>\n          <td>Вызывается при клике правой кнопкой мыши в допслой.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>getOrigin</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Возвращает origin-инстанс допслоя.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Meta.origin\n\nРаботает с метаданными слоя, наследует от <a href=\"/doc/maps/ru/manual/base-classes#dgclass\"><code>DG.Class</code></a>.\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Meta.origin</b>(\n                <nobr>&lt;String&gt; <i>source</i>,</nobr>\n                <nobr>&lt;DG.Meta.layer options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Meta.origin(&hellip;)</code></td>\n            <td>Создает инстанс для работы с данными метаслоя. Принимает в качестве параметра source URL,\n                по которому доступны тайлы допслоя.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>subdomains</b></code></td>\n            <td><code>String</code> или <code>String[]</code></td>\n            <td><code>'0123'</code></td>\n            <td>Поддомены тайлового сервиса. Могут передаваться одной строкой (где каждая буква &mdash;\n                имя поддомена) или массивом строк.</td>\n        </tr>\n        <tr>\n            <td><code><b>dataFilter</b></code></td>\n            <td><code>Function</code></td>\n            <td><code>null</code></td>\n            <td>Опциональный параметр, который принимает функцию для фильтрации или преобразования метаданных,\n                полученных от сервера.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>getTileData</b>(\n                <nobr>&lt;Object&gt; <i>coord</i>)</nobr>\n            </code>\n            <td><code>Object</code></td>\n            <td>Возвращает метаданные метаслоя по заданному тайлу.</td>\n        </tr>\n        <tr>\n            <td><code><b>setTileData</b>(\n                <nobr>&lt;String&gt;/&lt;Object&gt; <i>coord</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>data</i>)</nobr>\n            </code>\n            <td><code>this</code></td>\n            <td>Присваевает данные data для тайла с ключем coord.</td>\n        </tr>\n        <tr>\n            <td><code><b>flush</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Полностью очищает закешированные данные по всем тайлам.</td>\n        </tr>\n        <tr>\n            <td><code><b>setURL</b>(\n                <nobr>&lt;String&gt; <i>url</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>flush?</i>)</nobr>\n            </code>\n            <td><code>this</code></td>\n            <td>Устанавливает url, по которому забираются метаданные. Если передан парметр flush=true,\n                закешированные данные будут очищены.</td>\n        </tr>\n        <tr>\n            <td><code><b>getTileKey</b>(\n                <nobr>&lt;Object&gt; <i>coord</i>)</nobr>\n            </code>\n            <td><code>String</code></td>\n            <td>Возвращает ключ тайла в виде строки.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-migration.md",
    "content": "## Руководство по переходу на API 2.0\n\n{toc}\n\n### Описание\n\nРаздел содержит примеры кода основных возможностей, которые помогут вам прейти с API карт\nверсии 1.0 на API карт версии 2.0.\n\n### Подключение API\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/map/#toc-load\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/loading\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code>&lt;script src=\"https://maps.api.2gis.ru/1.0\"&gt;&lt;/script&gt;\n\n                    DG.autoload(function() {\n                        // инициализация карты\n                        ...\n                    });</code>\n            </td>\n            <td>\n                <code>&lt;script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"&gt;&lt;/script&gt;\n                \n                DG.then(function() {\n                    // инициализация карты\n                    ...\n                });</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Инициализация карты\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/map/#toc-init\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/map#dgmap\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code>var map = new DG.Map('map');\n                <nobr>var center = new DG.GeoPoint(82.89, 55.98);</nobr>\n                map.setCenter(center, 13);</code>\n            </td>\n            <td>\n                <code>var map = DG.map('map', {\n                    <nobr>'center': [54.98, 82.89],</nobr>\n                    'zoom': 13\n                });</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Отображение маркера\n\nДобавление на карту маркера с картинкой по умолчанию:\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/markers/#toc-base\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/markers#dgmarker\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>var position = new DG.GeoPoint(82.89, 54.98);</nobr>\n                var marker = new DG.Markers.Common({\n                    geoPoint: position\n                });\n                map.markers.add(marker);</code>\n            </td>\n            <td>\n                <code><nobr>DG.marker([54.98, 82.89]).addTo(map);</nobr></code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\nДобавление на карту маркера с адаптивной пользовательской картинкой:\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/utils/#fun-getAdaptiveAcon\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/markers#dgicon\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>var position = new DG.GeoPoint(82.89, 54.98);</nobr>\n                var desktopParams = [\n                    'desktop-icon.png',\n                    24, 24,\n                    function() {\n                        return new DG.Point(-12, -12)\n                    }\n                ];\n                var mobileParams = [\n                    '{density}-icon.png',\n                    34, 34,\n                    function() {\n                        return new DG.Point(-17, -17)\n                    }\n                ];\n                var myIcon = DG.Utils.getAdaptiveIcon({\n                    desktop: desktopParams,\n                    mobile:  mobileParams\n                });\n                var marker = new DG.Markers.Common({\n                    geoPoint: position,\n                    icon: myIcon\n                });\n                map.markers.add(marker);</code>\n            </td>\n            <td>\n                <code>var myIcon = DG.icon({\n                    iconUrl: 'my-icon.png',\n                    <nobr>iconRetinaUrl: 'my-icon@2x.png',</nobr>\n                    iconSize: [24, 24],\n                    iconAnchor: [-12, -12]\n                });\n                DG.marker([54.98, 82.89], {\n                    icon: myIcon\n                }).addTo(map);</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Отображение группы маркеров\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/markers/#toc-dgmarkersgroup\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/other-layers#dglayergroup\">Версия 2.0</a></td></tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>map.markers.createGroup('myGroup');</nobr>\n                map.markers.add(marker1, 'myGroup');\n                map.markers.add(marker2, 'myGroup');\n                map.markers.add(marker3, 'myGroup');</code>\n            </td>\n            <td>\n                <code><nobr>DG.layerGroup([marker1, marker2])</nobr>\n                .addLayer(marker3).addTo(map);</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Отображение маркера с привязанным попапом\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/markers/#toc-dgmarkersballoon\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/base-classes#layer-bindpopup\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>var position = new DG.GeoPoint(82.89, 54.98);</nobr>\n                var marker = new DG.Markers.MarkerWithBalloon({\n                    geoPoint: position,\n                    balloonOptions: {\n                        contentHtml: 'Я бабочка!'\n                    }\n                });\n                map.markers.add(marker);</code>\n                            </td>\n                            <td>\n                <code>DG.marker([54.98, 82.89])\n                <nobr>.addTo(map).bindPopup('Я бабочка!');</nobr></code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Отображение попапа\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/balloons/#balloon-intro\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/popup#dgpopup\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>var position = new DG.GeoPoint(82.89, 54.98);</nobr>\n                var myBalloon = new DG.Balloons.Common({\n                    geoPoint: position,\n                    contentHtml: 'Привет!'\n                });\n                map.balloons.add(myBalloon);</code>\n            </td>\n            <td>\n                <code>DG.popup()\n                .setLatLng([54.98, 82.89])\n                .setContent('Привет!')\n                .addTo(map);</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n### Отображение элемента управления\n\nОтображение пользовательского элемента управления в правом верхнем углу карты:\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/controls/#toc-intro\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/controls\">Версия 2.0</a></td></tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code>var myControl = new MyControl();\n                var positionOffset = new DG.Point(0, 0);\n                var position = new DG.ControlPosition(DG.ControlPosition.TOP_RIGHT, positionOffset);\n                map.controls.add(myControl, null, position);</code>\n            </td>\n            <td>\n                <code><nobr>DG.control({ position: 'topright' })</nobr>\n                .addTo(map)</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n\n### Подписка на события\n\n<table>\n    <thead>\n        <tr>\n            <td><a href=\"/doc/maps/1.0/manual/events/#toc-intro\">Версия 1.0</a></td>\n            <td><a href=\"/doc/maps/ru/manual/base-classes#events\">Версия 2.0</a></td>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>\n                <code><nobr>var callback = function(e) {</nobr>\n                    console.log(e.getPoint());\n                };\n                map.addEventListener(map.getContainerId(), 'DgClick', callback);</code>\n            </td>\n            <td>\n                <code><nobr>map.on('click', function(e) {</nobr>\n                    console.log(e.latlng);\n                });</code>\n            </td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-project-detector.md",
    "content": "## Модуль определения проекта 2GIS\n\nПроект — это агломерация, включающая крупный город и ближайшие населённые пункты.\nДанный плагин позволяет получить информацию о просматриваемом в текущий момент времени проекте.\n\n{toc}\n\n### Примеры использования\n\nПодписка на событие projectchange:\n\n    map.on('projectchange', function (e) {\n        console.log(e);\n    });\n\nПодписка на событие projectleave:\n\n    map.on('projectleave', function (e) {\n       console.log(e);\n    });\n\n### События\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>projectchange</td>\n            <td>ProjectEvent</td>\n            <td>Возникает, когда пользователь переходит из одного проекта в другой.</td>\n        </tr>\n        <tr>\n            <td>projectleave</td>\n            <td>ProjectEvent</td>\n            <td>Возникает, когда пользователь выходит за пределы текущего проекта.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td>getProjectsList</td>\n            <td>Object</td>\n            <td>Возвращает все доступные проекты.</td>\n        </tr>\n        <tr>\n            <td>getProject</td>\n            <td>Object</td>\n            <td>Возвращает текущий проект.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-ruler.md",
    "content": "## Линейка\n\nОтображает на карте линейку, позволяющую измерять расстояния между географическими точками.\n\n{toc}\n\n### DG.Ruler\n\n#### Пример использования\n\nСоздание и отображение линейки на карте:\n\n    var latLngs = [\n        [51.7314, 36.1938],\n        [51.7307, 36.1894],\n        [51.7297, 36.1926],\n        [51.7299, 36.1968],\n        [51.7307, 36.1968]]\n    DG.ruler(latLngs).addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Ruler</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>[]&gt; <i>latlngs</i>,</nobr>\n                <nobr>&lt;<a href=\"#dgruler-options\">Ruler options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.ruler(&hellip;)</code></td>\n            <td>Создает объект линейки по переданному массиву географических точек и необязательному объекту опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id='dgruler-options'>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>editable</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code><span class=\"string\">'true'</span></td>\n            <td>Возможно ли изменять промежуточные точки линейки.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>addTo</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Добавляет линейку на карту.</td>\n        </tr>\n        <tr>\n            <td><code><b>getTotalDistance</b>()</nobr></code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает расстояние (в метрах) между начальной и конечной точками.</td>\n        </tr>\n        <tr>\n            <td><code><b>addLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Добавляет точку в линейку.</td>\n        </tr>\n        <tr>\n            <td><code><b>setLatLngs</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>[]&gt; <i>latlngs</i> )</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Заменяет все точки линейки массивом переданных географических точек.</td>\n        </tr>\n        <tr>\n            <td><code><b>getLatLngs</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>[]</code></td>\n            <td>Возвращает массив точек линейки.</td>\n        </tr>\n        <tr>\n            <td><code><b>spliceLatLngs</b>(\n                <nobr>&lt;Number&gt; <i>index</i></nobr>,\n                <nobr>&lt;Number&gt; <i>pointsToRemove</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng?</i>, &hellip; )</nobr>\n            </code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>[]</code></td>\n            <td>Позволяет добавлять, удалять или заменять точки в линейке. Синтаксис аналогичен\n                <a target=\"_blank\" href=\"https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice\">Array#splice</a>.\n                Возвращает массив удаленных точек.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-traffic.md",
    "content": "## Информация о пробках\n\nСоздает слой с информацией о пробках. При наведении на участок дороги отображает дополнительную метаинформацию.\n\n{toc}\n\n### DG.Traffic\n\n#### Конструктор\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Traffic</b>(\n                <nobr>&lt;<a href=\"#опции\">DG.Traffic options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td><code>DG.Traffic(&hellip;)</code></td>\n            <td>Создает слой пробок.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>disableLabel</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code><span class=\"string\">false</span></td>\n            <td>Если передать значение true, при наведении на участок дороги дополнительная информация\n                отображаться не будет.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dg-wkt.md",
    "content": "## Well-known text\n\nИспользуется для получения векторных слоев API карт на основе их описания в\n<a target=\"_blank\" href=\"http://en.wikipedia.org/wiki/Well-known_text\">WKT-формате</a>.\n\n{toc}\n\n### DG.Wkt\n\n#### Пример использования\n\nСчитывает описание многоугольника в WKT-формате и отображает его на карте:\n\n    var polygonComponents = 'POLYGON((82.91699 55.042136, 82.917522 55.040187, 82.918063 55.040235, 82.917540 55.042184,82.91699 55.042136))';\n    DG.Wkt.geoJsonLayer(polygonComponents).addTo(map);\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>DG.Wkt.toGeoJSON</b>(\n                <nobr>&lt;String&gt; <i>wkt</i>)</nobr>\n            </code></td>\n            <td><code>geoJSON</code></td>\n            <td>Считывает строку в WKT-формате и проверяет ее корректность.\n                Возвращает <a href=\"http://geojson.org/geojson-spec.html\" target=\"_blank\">GeoJSON</a>.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.Wkt.toLatLngs</b>(\n                <nobr>&lt;String | Array&gt; <i>wkt</i>)</nobr>\n            </code></td>\n            <td><code>Array</code></td>\n            <td>Считывает строку в WKT-формате и возвращает массив точек в формате\n                <a href=\"/doc/maps/ru/manual/basic-types/#dglatlng\">LatLng</a> (ее внутреннее представление).\n                Может принимать массив WKT строк.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.Wkt.geoJsonLayer</b>(\n                <nobr>&lt;String&gt; <i>wkt</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/other-layers#geojson-option\">GeoJSON options</a>&gt; <i>options?</i>)</nobr></code></td>\n            <td><code>Object</code></td>\n            <td>Создает GeoJSON слой. Принимает строку в WKT-формате для отображения данных на карте и объект опций.\n                Формирует векторный слой API карт на основе данных, считанных методом DG.Wkt.toGeoJSON. Этот метод\n                поддерживает все опции конструктора класса <a href=\"/doc/maps/ru/manual/other-layers#dggeojson\">DG.GeoJSON</a>.\n                Например, можно передать параметр <code>DG.Wkt.geoJsonLayer(polygonComponents, {clickable:false})</code>,\n                чтобы сделать слой некликабельным.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/dom-utils.md",
    "content": "## Работа с DOM\n\n{toc}\n\n### DG.DomEvent\n\nКласс для работы с <a href=\"https://developer.mozilla.org/docs/Web/API/Event\">событиями DOM</a>.\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"domevent-on\">\n            <td><code><b>on</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;String&gt; <i>types</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Добавляет метод <code>fn</code> к цепочкам обработчиков событий DOM, привязанных\n                к элементу <code>el</code>. Вы также можете указать (изменить) контекст вызова\n                обработчика (объект, на который ссылается ключевое слово <code>this</code> внутри\n                обработчика). Также, можно указать несколько типов событий, разделив их пробелами\n                (например: <code>&#39;click dblclick&#39;</code>).</td>\n        </tr>\n        <tr>\n            <td><code><b>on</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>eventMap</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет набор пар &#39;тип/обработчик&#39; в качестве обработчиков событий DOM\n                (например:  <code>{click: onClick, mousemove: onMouseMove}</code>).</td>\n        </tr>\n        <tr id=\"domevent-off\">\n            <td><code><b>off</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;String&gt; <i>types</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет метод <code>fn</code> из цепочек обработчиков событий DOM, привязанных\n                к элементу <code>el</code>. Если метод не указан, то удаляются все методы,\n                привязанные на текущий момент. Замечание: если методу <code>on</code> передавался\n                контекстный объект, этот же объект должен быть передан и методу <code>off</code>.</td>\n        </tr>\n        <tr>\n            <td><code><b>off</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>eventMap</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет набор пар &#39;тип/обработчик&#39; из цепочек обработчиков событий DOM.</td>\n        </tr>\n        <tr id=\"domevent-stoppropagation\">\n            <td><code><b>stopPropagation</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Останавливает всплытие события к родительским элементам. Используется внутри\n                функции-обработчика. Пример:\n                <pre><code>DG.DomEvent.on(div, 'click', function (ev) {\n    DG.DomEvent.stopPropagation(ev);\n});</code></pre></td>\n        </tr>\n        <tr id=\"domevent-disablescrollpropagation\">\n            <td><code><b>disableScrollPropagation</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет <code>stopPropagation</code> к событиям элемента <code>&#39;mousewheel&#39;</code>.</td>\n        </tr>\n        <tr id=\"domevent-disableclickpropagation\">\n            <td><code><b>disableClickPropagation</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет <code>stopPropagation</code> к событиям элемента <code>&#39;click&#39;</code>,\n                <code>&#39;doubleclick&#39;</code>, <code>&#39;mousedown&#39;</code> and\n                <code>&#39;touchstart&#39;</code>.</td>\n        </tr>\n        <tr id=\"domevent-preventdefault\">\n            <td><code><b>preventDefault</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Предотвращает поведение DOM элемента по умолчанию (например, переход по ссылке указанной\n                в свойстве <code>href</code> элемента <code>a</code>). Используется внутри функции-обработчика.</td>\n        </tr>\n        <tr id=\"domevent-stop\">\n            <td><code><b>stop</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Вызывает одновременно <code>stopPropagation</code> и <code>preventDefault</code>.\n                Используется внутри функции-обработчика.</td>\n        </tr>\n        <tr id=\"domevent-getmouseposition\">\n            <td><code><b>getMousePosition</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i>,</nobr>\n                <nobr>&lt;HTMLElement&gt; <i>container?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Возвращает нормализованную позицию мыши из события DOM относительно контейнера или\n                относительно всей страницы, если контейнер не указан.</td>\n        </tr>\n        <tr id=\"domevent-getwheeldelta\">\n            <td><code><b>getWheelDelta</b>(\n                <nobr>&lt;DOMEvent&gt; <i>ev</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает нормализованную дельту колесика мыши, в виде вертикального смещения\n                в пикселях (отрицательного, при прокрутке вниз), из события DOM <code>mousewheel</code>.\n                События от устройств, которые не поддерживают точную прокрутку, отображаются на пиксельные\n                координаты так, чтобы дельта прокрутки попадала в диапазон 50-60 пикселей.</td>\n        </tr>\n        <tr id=\"domevent-addlistener\">\n            <td><code><b>addListener</b>(\n                <nobr><i>…</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#domevent-on\"><code>DG.DomEvent.on</code></a></td>\n        </tr>\n        <tr id=\"domevent-removelistener\">\n            <td><code><b>removeListener</b>(\n                <nobr><i>…</i> )</nobr>\n            </code></td>\n\n\t\t    <td><code>this</code></td>\n            <td>Псевдоним для <a href=\"#domevent-off\"><code>DG.DomEvent.off</code></a></td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.DomUtil\n\nКласс для работы с <a href=\"https://developer.mozilla.org/ru/docs/DOM/DOM_Reference\">DOM деревом</a>.\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"domutil-get\">\n    \t\t<td><code><b>get</b>(\n    \t\t    <nobr>&lt;String|HTMLElement&gt; <i>id</i> )</nobr>\n    \t\t</code></td>\n\n\t\t    <td><code>HTMLElement</code></td>\n            <td>Возвращает элемент по его id, если параметром была передана строка, либо возвращает\n                элемент непосредственно, если он был передан в качестве параметра.</td>\n\t    </tr>\n        <tr id=\"domutil-getstyle\">\n    \t\t<td><code><b>getStyle</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>styleAttrib</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>String</code></td>\n            <td>Возвращает значение стилей элемента, установленных через атрибут sytle,\n                включая вычисленные значения или значения, указанные с помощью CSS.</td>\n    \t</tr>\n        <tr id=\"domutil-create\">\n\t\t    <td><code><b>create</b>(\n\t\t        <nobr>&lt;String&gt; <i>tagName</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>className?</i>,</nobr>\n\t\t        <nobr>&lt;HTMLElement&gt; <i>container?</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>HTMLElement</code></td>\n            <td>Создает HTML элемент <code>tagName</code>, устанавливает ему значение класса\n                <code>className</code> и опционально добавляет его в элемент <code>container</code>.</td>\n    \t</tr>\n        <tr id=\"domutil-remove\">\n\t\t    <td><code><b>remove</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Удаляет элемент <code>el</code> из элемента контейнера.</td>\n\t    </tr>\n        <tr id=\"domutil-empty\">\n\t\t    <td><code><b>empty</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n\t\t    <td>Удаляет все дочерние элементы из контейнера <code>el</code>.</td>\n    \t</tr>\n        <tr id=\"domutil-tofront\">\n\t\t    <td><code><b>toFront</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Перемещает элемент <code>el</code> в конец списка дочерних элементов, чтобы он\n    \t\t    отображался поверх остальных дочерних элементов контейнера.</td>\n    \t</tr>\n        <tr id=\"domutil-toback\">\n\t\t    <td><code><b>toBack</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Перемещает элемент <code>el</code> в начало списка дочерних элементов, чтобы он\n\t\t        отображался перед остальными дочерними элементами контейнера.</td>\n\t    </tr>\n        <tr id=\"domutil-hasclass\">\n\t\t    <td><code><b>hasClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если элемент содержит класс <code>name</code>.</td>\n\t    </tr>\n        <tr id=\"domutil-addclass\">\n    \t\t<td><code><b>addClass</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;String&gt; <i>name</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n            <td>Добавляет класс <code>name</code> к элементу.</td>\n    \t</tr>\n        <tr id=\"domutil-removeclass\">\n\t\t    <td><code><b>removeClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n            <td>Удаляет класс <code>name</code> из элемента.</td>\n\t    </tr>\n        <tr id=\"domutil-setclass\">\n\t\t    <td><code><b>setClass</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;String&gt; <i>name</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Устанавливает класс у элемента.</td>\n\t    </tr>\n        <tr id=\"domutil-getclass\">\n    \t\t<td><code><b>getClass</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code>String</code></td>\n    \t\t<td>Возвращает значение класса элемента.</td>\n    \t</tr>\n        <tr id=\"domutil-setopacity\">\n    \t\t<td><code><b>setOpacity</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;Number&gt; <i>opacity</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Устанавливает прозрачность элемента. Значение <code>opacity</code> должно быть\n    \t\t    в диапазоне от <code>0.0</code> до <code>1.0</code>.</td>\n    \t</tr>\n        <tr id=\"domutil-testprop\">\n\t\t    <td><code><b>testProp</b>(\n\t\t        <nobr>&lt;String[]&gt; <i>props</i> )</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code>String|false</code></td>\n\t\t    <td>Перебирает массив наименований стилей элемента и возвращает первое корректное наименование.\n\t\t        Используется с префиксами производителей браузеров и стилями, вроде <code>transform</code>.</td>\n\t    </tr>\n        <tr id=\"domutil-settransform\">\n\t\t    <td><code><b>setTransform</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>scale?</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Устанавливает стиль 3D CSS transform элемента <code>el</code> так, чтобы он был\n    \t\t    смещен на <code>offset</code> пикселей и увеличен/уменьшен в <code>scale</code> раз.\n    \t\t    Метод не работает, если браузер не поддерживает 3D CSS transforms.</td>\n\t    </tr>\n        <tr id=\"domutil-setposition\">\n    \t\t<td><code><b>setPosition</b>(\n    \t\t    <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n    \t\t    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>position</i> )</nobr>\n    \t\t</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Изменяет позиционирование элемента <code>el</code>, используя CSS translate или свойства\n    \t\t    top/left в зависимости от поддержки браузером.</td>\n\t    </tr>\n        <tr id=\"domutil-getposition\">\n\t\t    <td><code><b>getPosition</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code><a href=\"/doc/maps/ru/manual/#dgpoint\">Point</a></code></td>\n\t\t    <td>Возвращает координаты элемента, ранее установленные методом <code>setPosition</code>.</td>\n\t    </tr>\n        <tr id=\"domutil-disabletextselection\">\n    \t\t<td><code><b>disableTextSelection</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Отключает возможность возникновения <code>selectstart</code> событий DOM, обычно сопутствующих\n    \t\t    выделению текстового фрагмента на странице. Влияет на поведение всего документа.</td>\n\t    </tr>\n        <tr id=\"domutil-enabletextselection\">\n\t\t    <td><code><b>enableTextSelection</b>()</code></td>\n\n\t\t    <td><code></code></td>\n\t\t    <td>Включает возможность возникновения событий DOM <code>selectstart</code>, ранее отключенных\n\t\t        <a href=\"#domutil-disabletextselection\"><code>DG.DomUtil.disableTextSelection</code></a>.</td>\n\t    </tr>\n        <tr id=\"domutil-disableimagedrag\">\n\t\t    <td><code><b>disableImageDrag</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Отключает возможность возникновения <code>dragstart</code> событий DOM, обычно сопутствующих\n    \t\t    перемещению изображения по странице.</td>\n\t    </tr>\n\t    <tr id=\"domutil-enableimagedrag\">\n    \t\t<td><code><b>enableImageDrag</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Включает возможность возникновения событий DOM <code>dragstart</code>, ранее отключенных\n    \t\t    <a href=\"#domutil-disableimagedrag\"><code>DG.DomUtil.disableImageDrag</code></a>.</td>\n    \t</tr>\n        <tr id=\"domutil-preventoutline\">\n\t\t    <td><code><b>preventOutline</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Делает <a href=\"https://developer.mozilla.org/ru/docs/Web/CSS/outline\">outline</a>\n    \t\t    элемента <code>el</code> невидимой.</td>\n    \t</tr>\n    \t<tr id=\"domutil-restoreoutline\">\n\t    \t<td><code><b>restoreOutline</b>()</code></td>\n\n    \t\t<td><code></code></td>\n    \t\t<td>Отменяет эффект <a href=\"#domutil-preventoutline\"><code>DG.DomUtil.preventOutline</code></a>.</td>\n    \t</tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>TRANSFORM</b></code></td>\n            <td><code>String</code></td>\n            <td>Название CSS свойства transform с учетом префикса производителя браузера\n                (например, <code>&#39;webkitTransform&#39;</code> для WebKit).</td>\n        </tr>\n        <tr>\n            <td><code><b>TRANSITION</b></code></td>\n            <td><code>String</code></td>\n            <td>Название CSS свойства transition с учетом префикса производителя браузера</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.PosAnimation\n\nИспользуется внутри библиотеки для анимаций перемещения, используя CSS3 transitions для современных\nбраузеров и таймер для IE6-9.\n\n    var fx = new DG.PosAnimation();\n    fx.run(el, [300, 500], 0.5);\n\n#### События\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"posanimation-start\">\n            <td><code><b>start</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается во время старта анимации.</td>\n        </tr>\n        <tr id=\"posanimation-step\">\n            <td><code><b>step</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается (периодически) в процессе анимации.</td>\n        </tr>\n        <tr id=\"posanimation-end\">\n            <td><code><b>end</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается во время окончания анимации.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"posanimation-run\">\n\t\t    <td><code><b>run</b>(\n\t\t        <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>newPos</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>duration?</i>,</nobr>\n\t\t        <nobr>&lt;Number&gt; <i>easeLinearity?</i>)</nobr>\n\t\t    </code></td>\n\n\t\t    <td><code></code></td>\n            <td>Запускает анимацию перемещения элемента, полученного через аргумент метода.\n                Дополнительно можно задать продолжительность анимации в секундах\n                (по умолчанию <code>0.25</code>) и функцию затухания\n                (третий аргумент <a target=\"_blank\" href=\"http://cubic-bezier.com/#0,0,.5,1\">кубической кривой Безье</a>,\n                по умолчанию <code>0.5</code>).</td>\n\t    </tr>\n\t    <tr id=\"posanimation-stop\">\n\t\t    <td><code><b>stop</b>()</code></td>\n\t\t    <td><code></code></td>\n\t\t    <td>Останавливает ранее запущенную анимацию.</td>\n\t    </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Draggable\n\nКласс, с помощью которого можно сделать DOM элемент перетаскиваемым (включая поддержку тач-устройств).\nРаботает только в том случае, если элемент был позиционирован с помошью <a href=\"#domutil-setposition\">DG.DomUtil.setPosition</a>.\n\n    var draggable = new DG.Draggable(elementToDrag);\n    draggable.enable();\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"draggable-clicktolerance\">\n\t\t    <td><code><b>clickTolerance</b></code></td>\n\t\t    <td><code>Number</code></td>\n\t\t    <td><code>3</code></td>\n\t\t    <td>Максимальное количество пикселей, на которое может сдвинуться мышь при нажатой кнопке,\n\t\t        чтобы идентифицировать это событике как нажатие (а не начало перетаскивания).</td>\n    \t</tr>\n    </tbody>\n</table>\n\n#### События\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n    \t<tr id=\"draggable-down\">\n    \t\t<td><code><b>down</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается перед началом перетаскивания.</td>\n    \t</tr>\n    \t<tr id=\"draggable-dragstart\">\n    \t\t<td><code><b>dragstart</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается в момент начала перетаскивания.</td>\n    \t</tr>\n    \t<tr id=\"draggable-predrag\">\n    \t\t<td><code><b>predrag</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается в процессе перетаскивания <i>перед</i> каждым обновлением позиции элемента.</td>\n\t    </tr>\n\t    <tr id=\"draggable-dragend\">\n    \t\t<td><code><b>dragend</b></code></td>\n    \t\t<td><code><a href=\"/doc/maps/ru/manual/events#event\">Event</a></code></td>\n            <td>Вызывается в момент окончания перетаскивания.</td>\n\t    </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"draggable-enable\">\n            <td><code><b>enable</b>()</code></td>\n            <td><code></code></td>\n            <td>Включает возможность перетаскивания.</td>\n        </tr>\n        <tr id=\"draggable-disable\">\n            <td><code><b>disable</b>()</code></td>\n            <td><code></code></td>\n            <td>Отключает возможность перетаскивания.</td>\n        </td>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/manual/map.md",
    "content": "## Карта\n\nВ данном разделе описывается основной класс API карт, который используется для создания и управления картой на странице.\n\n{toc}\n\n### DG.Map\n\n#### Пример использования\n\nИнициализация карты в элементе <code>div</code> с id &quot;map&quot;, с указанием координат центра и коэффициента\nмасштабирования:\n\n    var map = DG.map('map', {\n        center: [54.98, 82.89],\n        zoom: 13\n    });\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-l-map\">\n            <td><code><b>DG.map</b>(\n                <nobr>&lt;String&gt;> <i>id</i>,</nobr>\n                <nobr>&lt;Map options&gt;> <i>options?</i> )</nobr>\n            </code></td>\n            <td>Инициализирует карту в DOM-узле <code>&lt;div&gt;</code> элемента с указанным id с необязательным\n                набором опций, которые описаны ниже.</td>\n        </tr>\n        <tr>\n            <td><code><b>DG.map</b>(\n                <nobr>&lt;HTMLElement&gt; <i>el</i>,</nobr>\n                <nobr>&lt;Map options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Инициализирует карту в переданном DOM-узле <code>&lt;div&gt;</code> элемента с необязательным набором\n                опций, которые описаны ниже.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-prefercanvas\">\n            <td><code><b>preferCanvas</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Должны ли экземпляры <a href=\"/doc/maps/ru/manual/vector-layers#dgpath\"><code>Path</code></a>\n                отрисовываться на <a href=\"/doc/maps/ru/manual/vector-layers#dgcanvas\">\n                <code>Canvas</code></a>. По умолчанию все экземпляры <code>Path</code>\n                отрисовываются с помощью <a href=\"/doc/maps/ru/manual/vector-layers#dgsvg\"><code>SVG</code></a> рендерера.\n            </td>\n        </tr>\n        <tr id=\"map-protocol\">\n            <td><code><b>protocol</b></code></td>\n            <td><code>String </code></td>\n            <td><code>''</code></td>\n            <td>Сетевой протокол, используемый в запросах к тайлам.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции элементов управления\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td><code><b>zoomControl</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Добавлен ли <a href=\"/doc/maps/ru/manual/controls#dgcontrol.zoom\">элемент управления масштабом</a>\n                на карту.\n            </td>\n        </tr>\n        <tr>\n            <td><code><b>fullscreenControl</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Добавлена ли <a href=\"/doc/maps/ru/manual/controls#dgcontrol.fullscreen\">\n                кнопка включения полноэкранного режима</a> на карту.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции взаимодействия\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr>\n            <td><code><b>closePopupOnClick</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Закрывать ли попапы при клике в карту.</td>\n        </tr>\n        <tr id=\"map-zoomsnap\">\n            <td><code><b>zoomSnap</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>Всегда приводит уровень масштабирования к значению кратному данному параметру. Приведение\n                происходит сразу после выполнения <a href=\"#map-fitbounds\"><code>fitBounds()</code></a>\n                или изменения масштаба &quot;щипком&quot; (pinch-zoom). По умолчанию уровень масштабирования\n                приводится к ближайшему целому числу; меньшие значения (например, <code>0.5</code> или\n                <code>0.1</code>) позволяют более точно управлять приведением масшатаба. Значение <code>0</code>\n                говорит о том, что уровень масштабирования не будет приводиться после <code>fitBounds</code>\n                или изменения масштаба &quot;щипком&quot;.\n            </td>\n        </tr>\n        <tr id=\"map-zoomdelta\">\n            <td><code><b>zoomDelta</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>Управляет тем, насколько изменится уровень масштаба после\n                <a href=\"#map-zoomin\"><code>zoomIn()</code></a>,\n                <a href=\"#map-zoomout\"><code>zoomOut()</code></a>, нажатия <code>+</code> или\n                <code>-</code> на клавиатуре или используя\n                <a href=\"/doc/maps/ru/manual/controls#dgcontrol.zoom\">элемент управления масштабом</a>.\n                Значения меньшие чем <code>1</code> (например, <code>0.5</code>) предоставляют большую точность.\n            </td>\n        </tr>\n        <tr id=\"map-trackresize\">\n            <td><code><b>trackResize</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Обновляется ли карта при изменении размера окна браузера.</td>\n        </tr>\n        <tr id=\"map-boxzoom\">\n            <td><code><b>boxZoom</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Может ли масштаб карты быть изменен с помощью box-масштабирования (shift + выделение мышью).</td>\n        </tr>\n        <tr id=\"map-doubleclickzoom\">\n            <td><code><b>doubleClickZoom</b></code></td>\n            <td><code>Boolean|String </code></td>\n            <td><code>true</code></td>\n            <td>Разрешено ли увеличивать масштаб карты двойным кликом мыши (удерживание Shift позволяет уменьшать\n                масштаб). Если передано значение <code>center</code>, карта всегда масштабируется отностиельно центра\n                просматриваемой области, независимо от положения курсора.\n            </td>\n        </tr>\n        <tr id=\"map-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Разрешено ли перетаскивать карту мышью или тачем.</td>\n        </tr>\n        <tr id=\"map-geoclicker\">\n            <td><code><b>geoclicker</b></code></td>\n            <td><code>Boolean | Object</code></td>\n            <td><code>false</code></td>\n            <td>Включено ли геокодирование по клику (геокликер). Если <code>false</code>, тогда при клике в любой объект\n                карты (улицы, дома, остановки) не будет отображаться информация об этом объекте. Если\n                в качестве параметра передан объект с опциями, тогда геокликер будет включен. Опции\n                <code>showPhotos</code> и <code>showBooklet</code> позволяют отключить в балуне организации ссылки на буклеты\n                и фотографии.\n            </td>\n        </tr>\n        <tr id=\"map-projectdetector\">\n            <td><code><b>projectDetector</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Включает или отключает механизм определения проектов 2ГИС. Проект — это агломерация,\n                включающая крупный город и ближайшие населённые пункты.\n            </td>\n        </tr>\n        <tr id=\"map-tilescheck\">\n            <td><code><b>tilesCheck</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Возвращается ли карта к предыдущему состоянию, если на целевом уровне\n                масштабирования нет тайлов.\n            </td>\n        </tr>\n        <tr id=\"map-museum\">\n            <td><code><b>museum</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code></td>\n            <td>Будет ли отображаться сообщение о том, что браузер не поддерживается.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции состояния карты\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-center\">\n            <td><code><b>center</b></code></td>\n            <td><code>LatLng </code></td>\n            <td><code>undefined</code></td>\n            <td>Начальный географический центр карты.</td>\n        </tr>\n        <tr id=\"map-zoom\">\n            <td><code><b>zoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Начальный уровень масштаба.</td>\n        </tr>\n        <tr id=\"map-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Минимальный уровень масштабируемости карты. Переопределяет свойство <code>minZoom</code>\n                используемых слоев.\n            </td>\n        </tr>\n        <tr id=\"map-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Максимальный уровень масштабируемости карты. Переопределяет свойство <code>maxZoom</code>\n                используемых слоев.\n            </td>\n        </tr>\n        <tr id=\"map-layers\">\n            <td><code><b>layers</b></code></td>\n            <td><code>Layer[] </code></td>\n            <td><code>[]</code></td>\n            <td>Массив слоев, которые изначально будут добавлены на карту.</td>\n        </tr>\n        <tr id=\"map-maxbounds\">\n            <td><code><b>maxBounds</b></code></td>\n            <td><code>LatLngBounds </code></td>\n            <td><code>null</code></td>\n            <td>Если свойство установлено, карта ограничивает область просмотра согласно заданным географическим\n                границам, &quot;отбрасывая&quot; пользователя назад, если он пытается выйти за пределы установленных границ,\n                а также не позволяет уменьшить масштаб так, чтобы можно было просмотреть неразрешенные участки\n                карты. Для установки ограничения динамически, используйте метод\n                <a href=\"#map-setmaxbounds\">setMaxBounds</a>.\n            </td>\n        </tr>\n        <tr id=\"map-renderer\">\n            <td><code><b>renderer</b></code></td>\n            <td><code>Renderer </code></td>\n            <td><code>*</code></td>\n            <td>Метод, который используется для отрисовки векторных слоев на карте.\n                По умолчанию устанавливается\n                <a href=\"/doc/maps/ru/manual/vector-layers#dgsvg\"><code>DG.SVG</code></a> или\n                <a href=\"/doc/maps/ru/manual/vector-layers#dgcanvas\"><code>DG.Canvas</code></a>\n                в зависимости от поддержки браузером.\n            </td>\n        </tr>\n        <tr id=\"map-poi\">\n            <td><code><b>poi</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Отображать ли точки интереса на карте.</td>\n        </tr>\n        <tr id=\"map-currentlang\">\n            <td><code><b>currentLang</b></code></td>\n            <td><code>string</code></td>\n            <td><code>''</code></td>\n            <td>Язык пользовательского интерфейса карты (см. <a href=\"/doc/maps/ru/manual/dg-locale/\">Локализация</a>)</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции анимации\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-fadeanimation\">\n            <td><code><b>fadeAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Включена ли анимация затухания тайлов. По умолчанию включена во всех браузерах\n                поддерживающих CSS3 transitions, кроме Android.\n            </td>\n        </tr>\n        <tr id=\"map-markerzoomanimation\">\n            <td><code><b>markerZoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Включена ли анимация масштабирования маркеров при анимации масштабирования карты,\n                если выключена, тогда маркеры пропадают во время анимации карты. По умолчанию включена\n                во всех браузерах поддерживающих CSS3 transitions, кроме Android.\n            </td>\n        </tr>\n        <tr id=\"map-transform3dlimit\">\n            <td><code><b>transform3DLimit</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>2^23</code></td>\n            <td>Определяет максимальное значение CSS translation transform. Значение по умолчанию\n                изменять не стоит, до тех пор пока браузер не начинает позиционировать слои в\n                неправильном месте после большего смещения в результате <code>panBy</code>.\n            </td>\n        </tr>\n        <tr id=\"map-zoomanimation\">\n            <td><code><b>zoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Включена ли анимация масштабирования тайлов. По умолчанию включена во всех браузерах\n                поддерживающих CSS3 transitions, кроме Android.\n            </td>\n        </tr>\n        <tr id=\"map-zoomanimationthreshold\">\n            <td><code><b>zoomAnimationThreshold</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>4</code></td>\n            <td>Порог, начиная с которого будет отключаться анимация масштабирования.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции инерции при перемещении\n\n<table>\n    <thead>\n\t<tr>\n        <th>Опция</th>\n        <th>Тип</th>\n        <th>По умолчанию</th>\n        <th>Описание</th>\n\t</tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-inertia\">\n            <td><code><b>inertia</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>*</code></td>\n            <td>\n                Если опция включена, тогда создается эффект инерции при движении карты &mdash; при\n                перетаскивании карта продолжает движение в том же направлении какое-то время. Полезно\n                для тач-устройств. По умолчанию, эта опция включена везде, за исключением старых\n                Android-устройств.\n            </td>\n        </tr>\n        <tr id=\"map-inertiadeceleration\">\n            <td><code><b>inertiaDeceleration</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>3000</code></td>\n            <td>Величина, на которую замедляется движение карты, указывается в пикселях/секунду<sup>2</sup>.</td>\n        </tr>\n        <tr id=\"map-inertiamaxspeed\">\n            <td><code><b>inertiaMaxSpeed</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>Infinity</code></td>\n            <td>Максимальная скорость инерционного движения, указывается в пикселях/секунду.</td>\n        </tr>\n        <tr id=\"map-easelinearity\">\n            <td><code><b>easeLinearity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.2</code></td>\n            <td></td>\n        </tr>\n        <tr id=\"map-worldcopyjump\">\n            <td><code><b>worldCopyJump</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Опция позволяет зациклить просмотр карты с сохранением слоев и маркеров на ней.</td>\n        </tr>\n        <tr id=\"map-maxboundsviscosity\">\n            <td><code><b>maxBoundsViscosity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.0</code></td>\n            <td>Если установлено свойство <code>maxBounds</code>, эта опция позволяет контролировать\n                &quot;прочность&quot; границ при перемещении карты мышью или тачем. Значение по умолчанию\n                <code>0.0</code> &mdash; позволяет пользователю перемещать карту за ее границы с нормальной\n                скоростью, чем выше значение, тем меньше будет скорость при пермещении за пределы границы карты.\n                При значении <code>0.1</code>, границы становятся полностью &quot;непроницаемы&quot;, предотвращая любое\n                перемещение карты вне их пределов.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции навигации клавишами\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Устанавливает фокус на карту и позволяет перемещаться по карте с помощью\n                кнопок <code>+</code>/<code>-</code> и стрелок клавиатуры.\n            </td>\n        </tr>\n        <tr id=\"map-keyboardpandelta\">\n            <td><code><b>keyboardPanDelta</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>80</code></td>\n            <td>Указывает, на сколько пикселей сдвинется карта, при нажатии стрелки на клавиатуре.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции колеса мыши\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-scrollwheelzoom\">\n            <td><code><b>scrollWheelZoom</b></code></td>\n            <td><code>Boolean | String </code></td>\n            <td><code>true</code></td>\n            <td>Можно ли изменять масштаб карты с помощью колеса мыши. Если в качестве параметра\n                передано значение <code>&#39;center&#39;</code>, изменение масштаба будет происходить\n                относительно центра просматриваемой области, вне зависимости от позиции указателя\n                мыши.\n            </td>\n        </tr>\n        <tr id=\"map-wheeldebouncetime\">\n            <td><code><b>wheelDebounceTime</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>40</code></td>\n            <td>Ограничевает частоту, с которой прокрутка колеса мыши будет отправлять событие на изменение\n                масштаба (в милисекундах). По умолчанию, пользователь не может изменять масштаб карты\n                более чем один раз в 40 мс.\n            </td>\n        </tr>\n        <tr id=\"map-wheelpxperzoomlevel\">\n            <td><code><b>wheelPxPerZoomLevel</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>50</code></td>\n            <td>Какое количество пикселей прокрутки (можно определить через\n                <a href=\"/doc/maps/ru/manual/dom-utils#domevent-getwheeldelta\">DG.DomEvent.getWheelDelta</a>)\n                означает изменение на один уровень масштабирования. Меньшие значения\n                будут изменять масштаб карты, с помощью колеса, быстрей (и наоборот).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Опции взаимодействия на тач-устройствах\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-tap\">\n            <td><code><b>tap</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Активирует поддержку мгновенных тапов (отключение задержки в 200мс в iOS/Android)\n                и долгих тапов (в этом случае посылается событие <code>contextmenu</code>).\n            </td>\n        </tr>\n        <tr id=\"map-taptolerance\">\n            <td><code><b>tapTolerance</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>15</code></td>\n            <td>Максимальное число пикселей, на которое пользователь может сдвинуть свой палец во\n                время тача, для того, чтобы это событие было воспринято как тап.\n            </td>\n        </tr>\n        <tr id=\"map-touchzoom\">\n            <td><code><b>touchZoom</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>*</code></td>\n            <td>Разрешено ли изменять масштаб карты двумя пальцами на тач-устройствах.\n                Если передано значение <code>&#39;center&#39;</code>, карта всегда будет масштабироваться\n                относительно центра просматриваемой области, независимо от того, где на карте произошли\n                события тача. Активируется в веб-браузерах с тач поддержкой, за исключением устройств со\n                старой версией Android.\n            </td>\n        </tr>\n        <tr id=\"map-bounceatzoomlimits\">\n            <td><code><b>bounceAtZoomLimits</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, карта будет возвращаться к допустимому масштабу,\n                когда пользователь будет пытаться выйти за предельный максимальный/минимальный\n                масштаб карты с помощью масштабирования пальцами.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\n##### События слоев\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-layeradd\">\n            <td><code><b>layeradd</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#layerevent\">LayerEvent</a></code></td>\n            <td>Вызывается при добавлении нового слоя на карту.</td>\n        </tr>\n        <tr id=\"map-layerremove\">\n            <td><code><b>layerremove</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#layerevent\">LayerEvent</a></code></td>\n            <td>Вызывается при удалении слоя с карты.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События изменения состояния карты\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-zoomlevelschange\">\n            <td><code><b>zoomlevelschange</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается, если при добавлении или удалении слоя карты изменилось\n                количество доступных уровней масштабирования.\n            </td>\n        </tr>\n        <tr id=\"map-resize\">\n            <td><code><b>resize</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при изменении размера карты.</td>\n        </tr>\n        <tr id=\"map-unload\">\n            <td><code><b>unload</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при удалении карты c помощью метода <a href=\"#map-remove\">remove</a>.</td>\n        </tr>\n        <tr id=\"map-viewreset\">\n            <td><code><b>viewreset</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается, когда нужно перерисовать содержимое карты (обычно при\n                изменении масштаба или загрузке). Полезно при создании дополнительных слоев.\n            </td>\n        </tr>\n        <tr id=\"map-load\">\n            <td><code><b>load</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при инициализации карты (при первой установке ее центра и масштаба).</td>\n        </tr>\n        <tr id=\"map-zoomstart\">\n            <td><code><b>zoomstart</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается в начале изменения масштаба (перед анимацией изменения масштаба).</td>\n        </tr>\n        <tr id=\"map-movestart\">\n            <td><code><b>movestart</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается в начале изменения области просмотра карты (например, когда пользователь\n                начинает перетаскивать карту).\n            </td>\n        </tr>\n        <tr id=\"map-zoom\">\n            <td><code><b>zoom</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается периодически, в течении любого изменения уровня масштаба,\n                включая анимации перелета.\n            </td>\n        </tr>\n        <tr id=\"map-move\">\n            <td><code><b>move</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается периодически, во время любого передвижения карты, включая\n                анимации перелета.\n            </td>\n        </tr>\n        <tr id=\"map-zoomend\">\n            <td><code><b>zoomend</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается после изменения масштаба и анимаций.</td>\n        </tr>\n        <tr id=\"map-moveend\">\n            <td><code><b>moveend</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при окончании передвижения карты (например, когда пользователь\n                прекращает перетаскивать карту).\n            </td>\n        </tr>\n        <tr id=\"map-projectchange\">\n            <td><code><b>projectchange</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#projectevent\">ProjectEvent</a></code></td>\n            <td>Вызывается при перемещении пользователя из одного\n                <a href=\"#map-projectdetector\">проекта 2ГИС</a> в другой.\n            </td>\n        </tr>\n        <tr id=\"map-projectleave\">\n            <td><code><b>projectleave</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#projectevent\">ProjectEvent</a></code></td>\n            <td>Вызывается при выходе пользователя из текущего\n                <a href=\"#map-projectdetector\">проекта 2ГИС</a>.\n            </td>\n        </tr>\n        <tr id=\"map-entranceshow\">\n            <td><code><b>entranceshow</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при отображении входа в здание.</td>\n        </tr>\n        <tr id=\"map-entrancehide\">\n            <td><code><b>entrancehide</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при скрытии входа в здание.</td>\n        </tr>\n        <tr id=\"map-poihover\">\n            <td><code><b>poihover</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#poievent\">MetaEvent</a></code></td>\n            <td>Вызывается при наведении курсора мыши на точку интереса.</td>\n        </tr>\n        <tr id=\"map-poileave\">\n            <td><code><b>poileave</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#poievent\">MetaEvent</a></code></td>\n            <td>Вызывается, когда курсор мыши покидает область точки интереса.</td>\n        </tr>\n        <tr id=\"map-langchange\">\n            <td><code><b>langchange</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#langevent\">LangEvent</a></code></td>\n            <td>Вызывается при изменении языка карты.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События попапа\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается при открытии попапа.</td>\n        </tr>\n        <tr id=\"map-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается при закрытии попапа.</td>\n        </tr>\n        <tr id=\"map-autopanstart\">\n            <td><code><b>autopanstart</b></code></td>\n            <td><code></code></td>\n            <td>Вызывается, когда карта начинает двигаться после появления попапа.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События взаимодействий\n\n<table>\n    <thead>\n        <tr>\n            <th>События</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-click\">\n            <td><code><b>click</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается при клике (или тапе) по карте.</td>\n        </tr>\n        <tr id=\"map-dblclick\">\n            <td><code><b>dblclick</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается при двойном клике (или двойном тапе) по карте.</td>\n        </tr>\n        <tr id=\"map-mousedown\">\n            <td><code><b>mousedown</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается при нажатии кнопки мыши над областью карты.</td>\n        </tr>\n        <tr id=\"map-mouseup\">\n            <td><code><b>mouseup</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается, когда пользователь отпускает кнопку мыши над областью карты.</td>\n        </tr>\n        <tr id=\"map-mouseover\">\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается при наведении курсора мыши на карту.</td>\n        </tr>\n        <tr id=\"map-mouseout\">\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается, когда курсор мыши покидает область карты.</td>\n        </tr>\n        <tr id=\"map-mousemove\">\n            <td><code><b>mousemove</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается, когда курсор мыши перемещается над картой.</td>\n        </tr>\n        <tr id=\"map-contextmenu\">\n            <td><code><b>contextmenu</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается при нажатии правой кнопки мыши на карте, предотвращает появление\n                стандартного контекстного меню браузера, если на это событие подписаны обработчики.\n                Также вызывается на мобильных устройствах, когда пользователь удерживает тач\n                в течение секунды (долгое нажатие).\n            </td>\n        </tr>\n        <tr id=\"map-keypress\">\n            <td><code><b>keypress</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при нажатии клавиш на клавиатуре, когда карта находится в фокусе.</td>\n        </tr>\n        <tr id=\"map-preclick\">\n            <td><code><b>preclick</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n            <td>Вызывается перед кликом мыши на карте (полезно, если нужно выполнить\n                какое-либо действие до вызова обработчика клика).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### События анимаций\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-zoomanim\">\n            <td><code><b>zoomanim</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#zoomanimevent\">ZoomAnimEvent</a></code></td>\n            <td>Вызывается каждый кадр, в процессе изменения масштаба.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События местоположения\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-locationerror\">\n            <td><code><b>locationerror</b></code></td>\n            <td><code><a href=\"#errorevent\">ErrorEvent</a></code></td>\n            <td>Вызывается при возникновении ошибок, во время обнаружения местоположения пользователя\n                (при использовании метода <a href=\"#map-locate\"><code>locate</code></a>).\n            </td>\n        </tr>\n        <tr id=\"map-locationfound\">\n            <td><code><b>locationfound</b></code></td>\n            <td><code><a href=\"#locationevent\">LocationEvent</a></code></td>\n            <td>Вызывается при успешном обнаружении местоположения пользователя (при использовании метода\n                <a href=\"#map-locate\">locate</a>).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getrenderer\">\n            <td>\n                <code>\n                    <b>getRenderer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/vector-layers#dgpath\">Path</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\">Renderer</a></code></td>\n            <td>Возвращает экземпляр <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\"><code>Renderer</code></a>,\n                который должен быть использован для отрисовки необходимого\n                <a href=\"/doc/maps/ru/manual/vector-layers#dgpath\"><code>векторного слоя</code></a>. Метод гарантирует, что опции\n                <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\"><code>движка отображения</code></a> карты и векторных слоев\n                будут учитываться, и что необходимые движки отображения действительно существуют на карте.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы слоев и элементов управления\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-addlayer\">\n            <td>\n                <code>\n                    <b>addLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Добавляет слой на карту.</td>\n        </tr>\n        <tr id=\"map-removelayer\">\n            <td>\n                <code>\n                    <b>removeLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Удаляет указанные слои с карты.</td>\n        </tr>\n        <tr id=\"map-haslayer\">\n            <td>\n                <code>\n                    <b>hasLayer</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если слой, на данный момент, добавлен на карту.</td>\n        </tr>\n        <tr id=\"map-eachlayer\">\n            <td>\n                <code>\n                    <b>eachLayer</b>(\n                    <nobr>&lt;Function&gt; <i>fn</i></nobr>,\n                    <nobr>&lt;Object&gt; <i>context?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>\n                Выполняет заданную функцию для каждого слоя карты. Дополнительно можно\n                указать контекст выполнения функции.\n<pre><code>map.eachLayer(function(layer){\n    layer.bindPopup(&#39;Hello&#39;);\n});\n</code></pre>\n            </td>\n        </tr>\n        <tr id=\"map-openpopup\">\n            <td>\n                <code>\n                    <b>openPopup</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/popup#dgpopup\">Popup</a>&gt; <i>popup</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Показывает указанный попап, предварительно закрыв все открытые.</td>\n        </tr>\n        <tr id=\"map-openpopup\">\n            <td>\n                <code>\n                    <b>openPopup</b>(\n                    <nobr>&lt;String|HTMLElement&gt; <i>content</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/popup#popup-option\">Popup options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Создает попап с переданными опциями и содержимым и открывает его в определенной точке на карте.</td>\n        </tr>\n        <tr id=\"map-closepopup\">\n            <td>\n                <code>\n                    <b>closePopup</b>(<nobr>&lt;<a href=\"/doc/maps/ru/manual/popup#dgpopup\">Popup</a>&gt; <i>popup?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Закрывает попап, открытый с помощью <a href=\"/doc/maps/ru/manual/popup#map-openpopup\">openPopup</a>.</td>\n        </tr>\n        <tr id=\"map-addcontrol\">\n            <td>\n                <code>\n                    <b>addControl</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/controls#dgcontrol\">Control</a>&gt; <i>control</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Добавляет элемент управления на карту.</td>\n        </tr>\n        <tr id=\"map-removecontrol\">\n            <td>\n                <code>\n                    <b>removeControl</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/controls#dgcontrol\">Control</a>&gt; <i>control</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Удаляет элемент управления с карты.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы модификации состояния карты\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-setview\">\n            <td>\n                <code>\n                    <b>setView</b>(\n                    <nobr>&lt;LatLnt&gt; <i>center</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает область просмотра карты (географический центр и масштаб).\n                Дополнительно можно указать опции анимации.\n            </td>\n        </tr>\n        <tr id=\"map-setzoom\">\n            <td>\n                <code>\n                    <b>setZoom</b>(\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает уровень масштаба.</td>\n        </tr>\n        <tr id=\"map-zoomin\">\n            <td>\n                <code>\n                    <b>zoomIn</b>(\n                    <nobr>&lt;Number&gt; <i>delta?</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-масштабирования\">Zoom options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Увеличивает масштаб карты на величину <code>delta</code>\n                (по умолчанию <a href=\"#map-zoomdelta\"><code>zoomDelta</code></a>).\n            </td>\n        </tr>\n        <tr id=\"map-zoomout\">\n            <td>\n                <code>\n                    <b>zoomOut</b>(\n                    <nobr>&lt;Number&gt; <i>delta?</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-масштабирования\">Zoom options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Уменьшает масштаб карты на величину <code>delta</code>\n                (по умолчанию <a href=\"#map-zoomdelta\"><code>zoomDelta</code></a>).\n            </td>\n        </tr>\n        <tr id=\"map-setzoomaround\">\n            <td>\n                <code>\n                    <b>setZoomAround</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-масштабирования\">Zoom options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Масштабирует карту, сохраняя при этом указанную точку в неподвижном состоянии\n                (например, используется для масштабировании при помощи колесика мыши и двойного клика).\n            </td>\n        </tr>\n        <tr id=\"map-setzoomaround\">\n            <td>\n                <code>\n                    <b>setZoomAround</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-масштабирования\">Zoom options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Масштабирует карту, сохраняя при этом указанную точку в пикселях в неподвижном состоянии\n                (относительно левого верхнего угла).\n            </td>\n        </tr>\n        <tr id=\"map-fitbounds\">\n            <td>\n                <code>\n                    <b>fitBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-соответствия-границам\">fitBounds options</a>&gt; <i>options</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает область просмотра карты так, чтобы она содержала заданные границы,\n                на максимально возможном уровне масштаба.\n            </td>\n        </tr>\n        <tr id=\"map-fitworld\">\n            <td>\n                <code>\n                    <b>fitWorld</b>(\n                    <nobr>&lt;<a href=\"#опции-соответствия-границам\">fitBounds options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает область просмотра карты так, чтобы та отображала весь мир,\n                на максимально возможном уровне масштаба.\n            </td>\n        </tr>\n        <tr id=\"map-panto\">\n            <td>\n                <code>\n                    <b>panTo</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-перемещения\">Pan options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Передвигает карту к указанному центру.\n            </td>\n        </tr>\n        <tr id=\"map-panby\">\n            <td>\n                <code>\n                    <b>panBy</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>offset</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Перемещает карту на заданное количество пикселей (анимировано).</td>\n        </tr>\n        <tr id=\"map-setmaxbounds\">\n            <td>\n                <code>\n                    <b>setMaxBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgbounds\">Bounds</a>&gt; <i>bounds</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Ограничивает область просмотра карты заданными границами (см. опцию\n                <a href=\"#map-maxbounds\">maxBounds</a>).\n            </td>\n        </tr>\n        <tr id=\"map-setminzoom\">\n            <td><code><b>setMinZoom</b>(<nobr>&lt;Number&gt; <i>zoom</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает нижний предел уровней масштабирования\n                (см. опцию <a href=\"#map-minzoom\">minZoom</a>).\n            </td>\n        </tr>\n        <tr id=\"map-setmaxzoom\">\n            <td><code><b>setMaxZoom</b>(<nobr>&lt;Number&gt; <i>zoom</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает верхний предел уровней масштабирования\n                (см. опцию <a href=\"#map-minzoom\">maxZoom</a>).\n            </td>\n        </tr>\n        <tr id=\"map-paninsidebounds\">\n            <td>\n                <code>\n                    <b>panInsideBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-перемещения\">Pan options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Перемещает карту в ближайшую область просмотра, лежащую в пределах заданных границ.\n                Можно контролировать анимацию, передав объект опций вторым параметром.\n            </td>\n        </tr>\n        <tr id=\"map-invalidatesize\">\n            <td><code><b>invalidateSize</b>(<nobr>&lt;Zoom/Pan options&gt; <i>options</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Обновляет карту при изменении размера ее контейнера. Этот метод необходимо вызывать,\n                если размер контейнера изменяется динамически (по умолчанию, также будет происходить\n                анимация переимещения). Если параметр <code>options.pan</code> установлен в <code>false</code>,\n                то карта не будет перемещаться. Если параметр <code>options.debounceMoveend</code> установлен в\n                <code>true</code>, то событие <code>moveend</code> не будет вызываться часто, даже\n                если метод будет вызываться много раз подряд.\n            </td>\n        </tr>\n        <tr id=\"map-invalidatesize\">\n            <td><code><b>invalidateSize</b>(<nobr>&lt;Boolean&gt; <i>animate</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Обновляет карту при изменении размера ее контейнера. Этот метод необходимо вызывать,\n                если размер контейнера изменяется динамически (по умолчанию, также будет происходить\n                анимация переимещения).\n            </td>\n        </tr>\n        <tr id=\"map-stop\">\n            <td><code><b>stop</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Останавливает текущие запущенные анимации <code>panTo</code> или <code>flyTo</code>.\n            </td>\n        </tr>\n        <tr id=\"map-flyto\">\n            <td>\n                <code>\n                    <b>flyTo</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom?</i></nobr>,\n                    <nobr>&lt;Zoom/Pan options&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает область просмотра карты (гегорафический центр и масштаб), выполняя\n                плавную анимацию изменения масштаба и перемещения.\n            </td>\n        </tr>\n        <tr id=\"map-flytobounds\">\n            <td>\n                <code>\n                    <b>flyToBounds</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;<a href=\"#опции-соответствия-границам\">fitBounds options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Устанавливает область просмотра карты с плавной анимацией изменения масштаба и перемещения, как\n                <a href=\"#map-flyto\"><code>flyTo</code></a>, но примнимает в качестве параметра границы, как\n                <a href=\"#map-fitbounds\"><code>fitBounds</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-setlang\">\n            <td><code><b>setLang</b>( <nobr>&lt;String&gt; <i>lang</i> )</nobr></code></td>\n            <td><code>String</code></td>\n            <td>Устанавливает <a href=\"/doc/maps/ru/manual/dg-locale\">язык карты</a>. В качестве параметра\n                принимает код языка (например, 'en').\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Другие методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-addhandler\">\n            <td>\n                <code>\n                    <b>addHandler</b>(\n                    <nobr>&lt;String&gt; <i>name</i></nobr>,\n                    <nobr>&lt;Function&gt; <i>HandlerClass</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Добавляет новый <a href=\"/doc/maps/ru/manual/base-classes#dghandler\"><code>Handler</code></a> на карту,\n                c переданным именем и функцией-конструктором.\n            </td>\n        </tr>\n        <tr id=\"map-remove\">\n            <td><code><b>remove</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Удаляет карту и все обработчики, связанные с ней.</td>\n        </td>\n        </tr>\n        <tr id=\"map-createpane\">\n            <td>\n                <code>\n                    <b>createPane</b>(\n                    <nobr>&lt;String&gt; <i>name</i></nobr>,\n                    <nobr>&lt;HTMLElement&gt; <i>container?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>HTMLElement</code></td>\n            <td>Создает новую панель карты с данным именем, если она еще не существует, и затем\n                возвращает ее. Панель создается как ребенок <code>container</code>,\n                или как дочерний элемент главной панели карты, если <code>container</code> не установлен.\n            </td>\n        </tr>\n        <tr id=\"map-getpane\">\n            <td><code><b>getPane</b>(<nobr>&lt;String | HTMLElement&gt; <i>pane</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Возвращает панель карты по ее имени или по ее HTML-элементу</td>\n        </tr>\n        <tr id=\"map-getpanes\">\n            <td><code><b>getPanes</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Возвращает объект, содержащий имена всех панелей как ключи и сами панели, как значения\n            </td>\n        </tr>\n        <tr id=\"map-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Возвращает контейнер карты (HTML-элемент).</td>\n        </tr>\n        <tr id=\"map-whenready\">\n            <td>\n                <code>\n                    <b>whenReady</b>(\n                    <nobr>&lt;Function&gt; <i>fn</i></nobr>,\n                    <nobr>&lt;Object&gt; <i>context?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Выполняет функцию <code>fn</code> после инициализации карты (когда установлен\n                центр и масштаб) и, по крайней мере, одним слоем, или сразу, если она\n                была инициализирована ранее. Опционально можно передать контекст выполнения.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы получения состояния карты\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает географический центр области просмотра карты.</td>\n        </tr>\n        <tr id=\"map-getzoom\">\n            <td><code><b>getZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает текущий уровень масштабирования.</td>\n        </tr>\n        <tr id=\"map-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Возвращает географические прямоугольные границы текущей области просмотра карты.</td>\n        </tr>\n        <tr id=\"map-getminzoom\">\n            <td><code><b>getMinZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает минимальный уровень масштабирования карты (если установлена опция\n                <code>minZoom</code> у карты или любого слоя) или <code>0</code>, по умолчанию.\n            </td>\n        </tr>\n        <tr id=\"map-getmaxzoom\">\n            <td><code><b>getMaxZoom</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает максимальный уровень масштабирования карты (если установлена опция\n                <code>maxZoom</code> у карты или любого слоя).\n            </td>\n        </tr>\n        <tr id=\"map-getboundszoom\">\n            <td>\n                <code>\n                    <b>getBoundsZoom</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                    <nobr>&lt;Boolean&gt; <i>inside?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Возвращает максимальный уровень масштабирования, при котором заданные границы полностью\n                входят в область просмотра. Если опция <code>inside</code> установлена в <code>true</code>,\n                тогда метод возвращает минимальный уровень зума, с теми же условиями.\n            </td>\n        </tr>\n        <tr id=\"map-getsize\">\n            <td><code><b>getSize</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Возвращает текущий размер контейнера карты (в пикселях).</td>\n        </tr>\n        <tr id=\"map-getpixelbounds\">\n            <td><code><b>getPixelBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgbounds\">Bounds</a></code></td>\n            <td>Возвращает прямоугольные границы области просмотра карты, спроецированные на пиксельные\n                координаты (иногда полезно в реализациях слоев и оверлеев).\n            </td>\n        </tr>\n        <tr id=\"map-getpixelorigin\">\n            <td><code><b>getPixelOrigin</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Возвращает спроецированные пиксельные координаты левой верхней точки слоя карты.\n                Полезно при реализации дополнительных слоев и оверлеев.\n            </td>\n        </tr>\n        <tr id=\"map-getpixelworldbounds\">\n            <td>\n                <code>\n                    <b>getPixelWorldBounds</b>(\n                    <nobr>&lt;Number&gt; <i>zoom?</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgbounds\">Bounds</a></code></td>\n            <td>Возвращает пиксельные координаты границ мира для заданного уровня масштабирования\n                <code>zoom</code>. Если <code>zoom</code> пропущен, используется текущий уровень масштаба\n                карты.\n            </td>\n        </tr>\n        <tr id=\"map-getlang\">\n            <td><code><b>getLang</b>()</code></td>\n            <td><code>String</code></td>\n            <td>Возвращает текущий <a href=\"/doc/maps/ru/manual/dg-locale\">язык карты</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы преобразования\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-getzoomscale\">\n            <td>\n                <code>\n                    <b>getZoomScale</b>(\n                    <nobr>&lt;Number&gt; <i>toZoom</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>fromZoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Возвращает коэффициент масштабирования, который будет применен к переходу с уровня\n                <code>fromZoom</code> до <code>toZoom</code>. Используется внутри библиотеки в анимациях\n                изменения масштаба.\n            </td>\n        </tr>\n        <tr id=\"map-getscalezoom\">\n            <td>\n                <code><b>getScaleZoom</b>(\n                <nobr>&lt;Number&gt; <i>scale</i></nobr>,\n                <nobr>&lt;Number&gt; <i>fromZoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Возвращает уровень масштаба, на котором окажется карта, если ее текущий уровень масштабирования\n                <code>fromZoom</code> и коэффициент масштабирования <code>scale</code>. Метод обратный\n                <a href=\"#map-getZoomScale\"><code>getZoomScale</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-project\">\n            <td>\n                <code>\n                    <b>project</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Проецирует географические координаты\n                <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a>\n                в соответствии с типом проекции карты (CRS), затем масштабирует их в соответствии с\n                параметром zoom и CRS <a href=\"#transformation\"><code>Transformation</code></a>\n                Результат - пиксельные координаты относительно основания CRS.\n            </td>\n        </tr>\n        <tr id=\"map-unproject\">\n            <td>\n                <code>\n                    <b>unproject</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i></nobr>,\n                    <nobr>&lt;Number&gt; <i>zoom</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Метод обратный <a href=\"#map-project\"><code>project</code></a>.\n            </td>\n        </tr>\n        <tr id=\"map-layerpointtolatlng\">\n            <td>\n                <code>\n                    <b>layerPointToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>По переданным пиксельным координатам относительно <a href=\"#map-getpixelorigin\">origin pixel</a>\n                возвращает соответствующие географические координаты (для текущего уровня масштабирования).\n            </td>\n        </tr>\n        <tr id=\"map-latlngtolayerpoint\">\n            <td>\n                <code>\n                    <b>latLngToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданным географическим координатам возвращает соответствующие пиксельные\n                координаты относительно <a href=\"#map-getpixelorigin\">origin pixel</a>.\n            </td>\n        </tr>\n        <tr id=\"map-wraplatlng\">\n            <td>\n                <code>\n                    <b>wrapLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a>, где <code>lat</code>\n                и <code>lng</code> &quot;зацикливаются&quot; в соответствии с CRS-свойствами <code>wrapLat</code> и\n                <code>wrapLng</code>, если они выходят за  CRS-границы. По умолчанию\n                это значит, что долгота переносится относительно линии перемены даты. Таким\n                образом, ее значение всегда будет находиться между -180 и +180 градусами.\n            </td>\n        </tr>\n        <tr id=\"map-distance\">\n            <td>\n                <code>\n                    <b>distance</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng1</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng2</i>)</nobr>\n                </code>\n            </td>\n            <td><code>Number</code></td>\n            <td>Возвращает расстояние между двумя географическими координатами в соответствии\n                с CRS карты. По умолчанию расстояние измеряется в метрах.\n            </td>\n        </tr>\n        <tr id=\"map-containerpointtolayerpoint\">\n            <td>\n                <code>\n                    <b>containerPointToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданным пиксельным координатам, относительно контейнера карты, возвращает\n                соответствующие пиксельные координаты, относительно <a href=\"#map-getpixelorigin\">origin pixel</a>.\n            </td>\n        </tr>\n        <tr id=\"map-layerpointtocontainerpoint\">\n            <td>\n                <code>\n                    <b>layerPointToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданным пиксельным координатам, относительно <a href=\"#map-getpixelorigin\">origin pixel</a>,\n                возвращает соответствующие пиксельные координаты, относительно контейнера карты.\n            </td>\n        </tr>\n        <tr id=\"map-containerpointtolatlng\">\n            <td>\n                <code>\n                    <b>containerPointToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>point</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданным пиксельным координатам, относительно контейнера карты,\n                возвращает географические координаты (для текущего уровня масштабирования).\n            </td>\n        </tr>\n        <tr id=\"map-latlngtocontainerpoint\">\n            <td>\n                <code>\n                    <b>latLngToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданным географическим координатам, возвращает пиксельные координаты,\n                относительно контейнера карты.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtocontainerpoint\">\n            <td>\n                <code>\n                    <b>mouseEventToContainerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданному объекту MouseEvent, возвращает пиксельную координату места, где произошло событие,\n                относительно левого верхнего угла контейнера карты.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtolayerpoint\">\n            <td>\n                <code>\n                    <b>mouseEventToLayerPoint</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>По переданному объекту MouseEvent, возвращает пиксельную координату, где произошло\n                событие, относительно <a href=\"#map-getpixelorigin\">origin pixel</a>.\n            </td>\n        </tr>\n        <tr id=\"map-mouseeventtolatlng\">\n            <td>\n                <code>\n                    <b>mouseEventToLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a>&gt; <i>ev</i>)</nobr>\n                </code>\n            </td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>По переданному объекту MouseEvent, возвращает географическую координату, где\n                произошло событие.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы геолокации\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead\n    ><tbody>\n        <tr id=\"map-locate\">\n            <td>\n                <code>\n                    <b>locate</b>(\n                    <nobr>&lt;<a href=\"#опции-определения-местоположения\">Locate options</a>&gt; <i>options?</i>)</nobr>\n                </code>\n            </td>\n            <td><code>this</code></td>\n            <td>Пытается определить местоположение пользователя используя\n                <a href=\"https://en.wikipedia.org/wiki/W3C_Geolocation_API\" target=\"_blank\">Geolocation API</a>.\n                При успешном определении вызывается событие <code>locationfound</code> с данными о местоположении,\n                в случае ошибки будет вызвано событие <code>locationerror</code>. Опционально устанавливает\n                область просмотра карты согласно местоположению пользователя (или отображает карту\n                мира, если возникла ошибка геолокации).\n                Для дополнительной информации см.\n                <a href=\"#Опции определения местоположения\">опции определения местоположения</a>.\n            </td>\n        </tr>\n        <tr id=\"map-stoplocate\">\n            <td><code><b>stopLocate</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Останавливает отслеживание местоположения, предварительно инициированное методом\n                <code>map.locate({watch: true})</code>, и предотвращает сброс карты, если map.locate\n                был вызван с <code>({setView: true})</code>.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы, унаследованные от Evented\n\nМетоды, унаследованные от Evented, смотрите <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">здесь</a>.\n\n#### Свойства\n\nСвойства карты включают в себя обработчики взаимодействия, которые позволяют контролировать интерактивное поведение,\nподключение и отключение определенных возможностей карты, таких как перетаскивание и масштабирование тачем\n(см. методы <a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a>). Например:\n\n    map.doubleClickZoom.disable();\n\nВы также можете получить доступ к элементам управления картой, которые включены по умолчанию, например,\nк элементу управления масштабом:\n\n    map.zoomControl.setPosition('topright');\n\n##### Обработчики\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-boxzoom\">\n            <td><code><b>boxZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик box-масштабирования (shift + выделение мышью).</td>\n        </tr>\n        <tr id=\"map-doubleclickzoom\">\n            <td><code><b>doubleClickZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик масштабирования по двойному клику.</td>\n        </tr>\n        <tr id=\"map-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик перетаскивания карты (мышью и тачем).</td>\n        </tr>\n        <tr id=\"map-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик навигации с помощью клавиатуры.</td>\n        </tr>\n        <tr id=\"map-scrollwheelzoom\">\n            <td><code><b>scrollWheelZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик масштабирования по скроллу.</td>\n        </tr>\n        <tr id=\"map-tap\">\n            <td><code><b>tap</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчики мобильных тач хаков (быстрый тап и удерживание тача).</td>\n        </tr>\n        <tr id=\"map-touchzoom\">\n            <td><code><b>touchZoom</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dghandler\">Handler</a></code></td>\n            <td>Обработчик масштабирования с помощью тача.</td>\n        </tr>\n        <tr id=\"map-geoclicker\">\n            <td><code><b>geoclicker</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/base-classes#dghandler\"><code>Handler</code></a></td>\n            <td>Обработчик геокодирования по клику.</td>\n        </tr>\n        <tr id=\"map-projectDetector\">\n            <td><code><b>projectDetector</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/base-classes#dghandler\"><code>Handler</code></a></td>\n            <td>Обработчик определения <a href=\"#map-projectdetector\">проекта 2ГИС</a>.</td>\n        </tr>\n        <tr id=\"map-zoomcontrol\">\n            <td><code><b>zoomControl</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/controls#dgcontrol.zoom\"><code>Control.Zoom</code></a></td>\n            <td>Элемент управления масштабом.</td>\n        </tr>\n        <tr id=\"map-fullscreenControl\">\n            <td><code><b>fullscreenControl</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/controls#dgcontrol.fullscreen\"><code>Control.FullScreen</code></a></td>\n            <td>Кнопка включения полноэкранного режима.</td>\n        </tr>\n        <tr id=\"map-rulerControl\">\n            <td><code><b>rulerControl</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/controls#dgcontrol.ruler\"><code>Control.Ruler</code></a></td>\n            <td>Кнопка включения линейки.</td>\n        </tr>\n        <tr id=\"map-trafficControl\">\n            <td><code><b>trafficControl</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/controls#dgcontrol.traffic\"><code>Control.Traffic</code></a></td>\n            <td>Кнопка включения слоя с пробками.</td>\n        </tr>\n        <tr id=\"map-baseLayer\">\n            <td><code><b>baseLayer</b></code></td>\n            <td><a href=\"/doc/maps/ru/manual/raster-layers#dgtilelayer\"><code>TileLayer</code></a></td>\n            <td>Слой с тайлами 2ГИС, автоматически добавляемый на карту при её создании.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Панели карты\n\nПанели - это DOM-элементы, которые используются для контроля очередности отображения слоев на карте.\nПолучить панели можно с помощью методов <a href=\"#map-getpane\"><code>map.getPane</code></a>\nили <a href=\"#map-getpanes\"><code>map.getPanes</code></a>. Новые панели можно создать\nс помощью метода <a href=\"#map-createpane\"><code>map.createPane</code></a>. У каждой карты\nпо умолчанию есть следующий набор панелей, которые отличаются только zIndex.\n\n<table>\n    <thead>\n        <tr>\n            <th>Панель</th>\n            <th>Тип</th>\n            <th>Z-index</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"map-mappane\">\n            <td><code><b>mapPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>&#x27;auto&#x27;</code></td>\n            <td>Панель, содержащая в себе все другие панели</td>\n        </tr>\n        <tr id=\"map-tilepane\">\n            <td><code><b>tilePane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>2</code></td>\n            <td>Панель для тайловых слоев</td>\n        </tr>\n        <tr id=\"map-overlaypane\">\n            <td><code><b>overlayPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>4</code></td>\n            <td>Панель для векторных слоев, таких как ломаные и многоугольники.</td>\n        </tr>\n        <tr id=\"map-shadowpane\">\n            <td><code><b>shadowPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>5</code></td>\n            <td>Панель для наложения теней (например, тени от маркеров).</td>\n        </tr>\n        <tr id=\"map-markerpane\">\n            <td><code><b>markerPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>6</code></td>\n            <td>Панель маркеров.</td>\n        </tr>\n        <tr id=\"map-popuppane\">\n            <td><code><b>popupPane</b></code></td>\n            <td><code>HTMLElement </code></td>\n            <td><code>7</code></td>\n            <td>Панель попапов.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции определения местоположения\n\nНекоторые методы геолокации объекта <a href=\"#dgmap\"><code>Map</code></a> принимают параметр\n<code>options</code>. Это обычный JavaScript-объект со следующими опциональными компонентами:\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"locate-options-watch\">\n            <td><code><b>watch</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, то местоположение будет отслеживаться постоянно (вместо определения\n                местоположения один раз) используя W3C метод <code>watchPosition</code>. Можно остановить\n                отслеживание, вызвав метод <code><b>map.stopLocate</b>()</code>.</td>\n            </td>\n        </tr>\n        <tr id=\"locate-options-setview\">\n            <td><code><b>setView</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, то автоматически устанавливает область просмотра карты в\n                точку местоположения пользователя, в соответствии с точностью определения.\n                В случае ошибки поиска, отображаетcя карта мира.\n            </td>\n        </tr>\n        <tr id=\"locate-options-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>Infinity</code></td>\n            <td>Задает максимальный уровень масштабирования при автоматическом перемещения карты,\n                когда включена опция <code>setView</code>.\n            </td>\n        </tr>\n        <tr id=\"locate-options-timeout\">\n            <td><code><b>timeout</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>10000</code></td>\n            <td>Количество миллисекунд ожидания ответа геолокации, перед тем как произойдет вызов\n                события <code>locationerror</code>.\n            </td>\n        </tr>\n        <tr id=\"locate-options-maximumage\">\n            <td><code><b>maximumAge</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Максимальное время жизни данных о местоположении. Если с момента последнего поиска\n                прошло меньше времени, чем указанно в данной опции, <code>locate</code> вернет\n                данные из кэша.\n            </td>\n        </tr>\n        <tr id=\"locate-options-enablehighaccuracy\">\n            <td><code><b>enableHighAccuracy</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Включает функцию повышения точности, см.\n                <a target=\"_blank\" href=\"http://dev.w3.org/geo/api/spec-source.html#high-accuracy\">\n                описание в W3C спецификации</a>.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n\n#### Опции масштабирования\n\nНекоторые методы объекта <a href=\"#dgmap\"><code>Map</code></a>, которые изменяют масштаб,\nпринимают параметр <code>options</code>. Это обычный JavaScript-объект со следующими\nнеобязательными компонентами:\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"zoom-options-animate\">\n            <td><code><b>animate</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code></code></td>\n            <td>Если не указано, то масштабирование будет анимироваться, если точка, относительно\n                которой происходит масштабирование, находится в пределах просматриваемой области карты.\n                Если <code>true</code>, всегда будет производиться попытка анимировать масштабирование,\n                вне зависимости от положения источника масштабирования. Если <code>false</code>,\n                то масштабирование будет происходить без анимации.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции перемещения\n\nНекоторые методы объекта <a href=\"#dgmap\"><code>Map</code></a>, которые меняют центр карты,\nпринимают параметр <code>options</code>. Это обычный JavaScript-объект со следующими\nнеобязательными компонентами:\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"pan-options-animate\">\n            <td><code><b>animate</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code></code></td>\n            <td>Если <code>true</code>, то перемещения будут анимироваться всегда. Если <code>false</code>,\n                перемещения не будут анимироваться при сбросе карты в исходное положение, если она была\n                передвинута более чем на один экран; перемещения также не будут анимироваться при установке\n                нового смещения панели карты (за исключением использования метода <code>panBy</code>).\n            </td>\n        </tr>\n        <tr id=\"pan-options-duration\">\n            <td><code><b>duration</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.25</code></td>\n            <td>Продолжительность анимации перемещения.</td>\n        </tr>\n        <tr id=\"pan-options-easelinearity\">\n            <td><code><b>easeLinearity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.25</code></td>\n            <td>Коэффициент кривизны затухания анимации (третий параметр\n                <a target=\"_blank\" href=\"http://cubic-bezier.com/\">Кривой Безье</a>). Значение 1.0 означает\n                линейную анимацию; чем меньше значение, тем больше кривизна.\n            </td>\n        </tr>\n        <tr id=\"pan-options-nomovestart\">\n            <td><code><b>noMoveStart</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, тогда при перемещении не будет инициироваться событие\n                <code>movestart</code> (используется внутри библиотеки при реализации\n                инерции перемещения).\n            </td>\n        </tr>\n    </tbody>\n</table>\n\n#### Дополнительные опции масштабирования/перемещения\n\nДополнительные опции наследуются от <a href=\"#zoom-options\">Zoom options</a> и\n<a href=\"#pan-options\">Pan options</a>\n\n#### Опции соответствия границам\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n\t<tr id=\"fitbounds-options-paddingtopleft\">\n\t\t<td><code><b>paddingTopLeft</b></code></td>\n\t\t<td><code>Point </code></td>\n\t\t<td><code>[0, 0]</code></td>\n        <td>Задает отступ от верхнего левого угла контейнера карты, который не должен учитываться\n            при подстройке центра и масштаба. Удобно использовать, например, если на карте приложения\n            имеется левая панель и вы не хотите, чтобы при масштабировании под ней скрывались объекты.\n        </td>\n        </tr>\n        <tr id=\"fitbounds-options-paddingbottomright\">\n            <td><code><b>paddingBottomRight</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>То же самое, но для нижнего правого угла карты.</td>\n        </tr>\n        <tr id=\"fitbounds-options-padding\">\n            <td><code><b>padding</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>Эквивалентно установке и верхнего левого, и нижнего правого отступов в одинаковые значения.</td>\n        </tr>\n        <tr id=\"fitbounds-options-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>Максимальный возможный уровень зума.</td>\n        </tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/markers.md",
    "content": "## Маркеры\n\n{toc}\n\n### DG.Marker\n\nМаркер представляет собой маленькую картинку, которая связана с определенным местом на карте.\n\n    DG.marker([54.98, 82.89]).addTo(map);\n\n#### Создание\n\n<table>\n\t<thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n\t\t<tr>\n\t\t\t<td><code><b>DG.Marker</b>(\n\t\t\t\t<nobr>&lt;<a href=\"/doc/maps/ru/manual/base-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>,</nobr>\n\t\t\t\t<nobr>&lt;<a href=\"#опции\">Marker options</a>&gt; <i>options?</i> )</nobr>\n\t\t\t</code></td>\n\t\t\t<td>Создает объект маркера с переданными географическими координатами и необязательными опциями.</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-icon\">\n            <td><code><b>icon</b></code></td>\n            <td><code><a href=\"#dgicon\">Icon</a></code></td>\n            <td><code>*</code></td>\n\t\t\t<td>Иконка, используемая для отображения маркера. Смотрите <a href=\"#dgicon\">документацию по иконкам</a>,\n\t\t\t    для информации о настройке внешнего вида маркеров. Новые маркеры по умолчанию принимают стиль\n\t\t\t    <code>DG.Icon.Default()</code>.</td>\n        </tr>\n        <tr id=\"marker-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n\t\t\t<td>Если значение <code>false</code>, тогда обработчик клика по маркеру не вызывается.\n                Маркер ведет себя как часть нижележащего слоя карты.</td>\n        </tr>\n        <tr id=\"marker-draggable\">\n            <td><code><b>draggable</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n\t\t\t<td>Можно ли перетаскивать маркер или нет.</td>\n        </tr>\n        <tr id=\"marker-keyboard\">\n            <td><code><b>keyboard</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Можно ли переходить к маркеру по нажатию на кнопку <code>Tab</code> и имитировать клик при\n                нажатиии <code>Enter</code>.</td>\n        </tr>\n        <tr id=\"marker-title\">\n            <td><code><b>title</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n\t\t\t<td>Текст подсказки при наведении курсора на маркер (по умолчанию не отображается).</td>\n        </tr>\n        <tr id=\"marker-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n\t\t\t<td>Текст для <code>alt</code> атрибута иконки (полезно для accessibility).</td>\n        </tr>\n        <tr id=\"marker-zindexoffset\">\n            <td><code><b>zIndexOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n\t\t\t<td>По умолчанию, свойство z-index изображения маркера устанавливается автоматически, в зависимости\n                от его географического положения (широты). Используйте эту опцию, если необходимо разместить\n                маркер поверх (или под) другим элементом, указав большее, например <code>1000</code>,\n                (или меньшее) значение.</td>\n        </tr>\n        <tr id=\"marker-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n\t\t\t<td>Прозрачность маркера.</td>\n        </tr>\n        <tr id=\"marker-riseonhover\">\n            <td><code><b>riseOnHover</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n\t\t\t<td>Если значение <code>true</code>, тогда маркер отобразится поверх остальных при наведении\n                на него мышью.</td>\n        </tr>\n        <tr id=\"marker-riseoffset\">\n            <td><code><b>riseOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>250</code></td>\n\t\t\t<td>Позволяет задать шаг z-index при использовании <code>riseOnHover</code>.</td>\n        </tr>\n        <tr id=\"marker-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;markerPane&#x27;</code></td>\n            <td>Панель карты, на которую будет добавлен маркер.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Событие</th>\n\t\t\t<th>Данные</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-click\">\n            <td><code><b>click</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается при клике (или тапу) по маркеру.</td>\n        </tr>\n        <tr id=\"marker-dblclick\">\n            <td><code><b>dblclick</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается при двойном клике (или двойному тапу) по маркеру.</td>\n        </tr>\n        <tr id=\"marker-mousedown\">\n            <td><code><b>mousedown</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается при нажатии кнопки мыши над маркером.</td>\n        </tr>\n        <tr id=\"marker-mouseover\">\n            <td><code><b>mouseover</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается при наведении курсора мыши на маркер.</td>\n        </tr>\n        <tr id=\"marker-mouseout\">\n            <td><code><b>mouseout</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается, когда курсор мыши покидает область маркера.</td>\n        </tr>\n        <tr id=\"marker-contextmenu\">\n            <td><code><b>contextmenu</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#mouseevent\">MouseEvent</a></code></td>\n\t\t\t<td>Вызывается при нажатии правой кнопки мыши над маркером.</td>\n        </tr>\n        <tr id=\"marker-move\">\n            <td><code><b>move</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается, когда маркер перемещается с помощью метода\n                <a href=\"#marker-setlatlng\"><code>setLatLng</code></a> или обычным\n                <a href=\"#marker-dragging\">перетаскиванием</a>. Старые и новые координаты попадают в\n                аргументы события как <code>oldLatLng</code> и <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>latlng</code></a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### События перетаскивания\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Событие</th>\n\t\t\t<th>Данные</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-dragstart\">\n            <td><code><b>dragstart</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n\t\t\t<td>Вызывается, когда пользователь начинает перетаскивать маркер.</td>\n        </tr>\n        <tr id=\"marker-movestart\">\n            <td><code><b>movestart</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n\t\t\t<td>Вызывается, когда маркер фактически начинает перемещаться во время перетаскивания.</td>\n        </tr>\n        <tr id=\"marker-drag\">\n            <td><code><b>drag</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n\t\t\t<td>Вызывается периодически, во время перетаскивания маркера.</td>\n        </tr>\n        <tr id=\"marker-dragend\">\n            <td><code><b>dragend</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dragendevent\">DragEndEvent</a></code></td>\n\t\t\t<td>Вызывается, когда пользователь прекращает перетаскивание маркера.</td>\n        </tr>\n        <tr id=\"marker-moveend\">\n            <td><code><b>moveend</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n\t\t\t<td>Вызывается, когда маркер фактически прекращает перемещаться во время перетаскивания.</td>\n        </tr>\n    </tbody>\n</table>\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Событие</th>\n\t\t\t<th>Данные</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается, когда слой (маркер) добавляется на карту</td>\n        </tr>\n        <tr id=\"marker-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается, когда слой (маркер) удаляется с карты</td>\n        </tr>\n    </tbody>\n</table>\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Событие</th>\n\t\t\t<th>Данные</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается, когда открывается попап, привязанный к данному слою (маркеру).</td>\n        </tr>\n        <tr id=\"marker-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается, когда закрываетс попап, привязанный к данному слою (маркеру).</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-getlatlng\">\n            <td><code><b>getLatLng</b>()</nobr></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает текущую географическую позицию маркера.</td>\n        </tr>\n        <tr id=\"marker-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Устанавилвает позицию маркера по переданным географическим координатам.</td>\n        </tr>\n        <tr id=\"marker-setzindexoffset\">\n            <td><code><b>setZIndexOffset</b>(\n                    <nobr>&lt;Number&gt; <i>offset</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Изменяет <a href=\"#marker-zindexoffset\">смещение zIndex</a> маркера.</td>\n        </tr>\n        <tr id=\"marker-seticon\">\n            <td><code><b>setIcon</b>(\n                    <nobr>&lt;<a href=\"#dgicon\">Icon</a>&gt; <i>icon</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает иконку маркера</td>\n        </tr>\n        <tr id=\"marker-setopacity\">\n            <td><code><b>setOpacity</b>(\n                    <nobr>&lt;Number&gt; <i>opacity</i>)</nobr>\n                </code></td>\n            <td><code>this</code></td>\n            <td>Изменяет уровень прозрачности маркера. </td>\n        </tr>\n\t    <tr id=\"marker-bindlabel\">\n\t        <td><code><b>bindLabel</b>(&lt;String&gt; content, &lt;<a href=\"/doc/maps/ru/manual/dg-label#опции\">Label options</a>&gt; options?)</code></td>\n            <td><code>this</code></td>\n            <td>Добавляет всплывающую подсказку для маркера или обновляет содержимое уже созданной.</td>\n\t    </tr>\n\t    <tr id=\"marker-unbindlabel\">\n\t        <td><code><b>unbindLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td>Отвязывает всплывающую подсказку от маркера.</td>\n\t    </tr>\n\t    <tr id=\"marker-showLabel\">\n\t        <td><code><b>showLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td>Показывает всплывающую подсказку (в случае использования опции\n            <code><a href=\"/doc/maps/ru/manual/dg-label#label-static\">static</a></code>).</td>\n\t    </tr>\n\t    <tr id=\"marker-hideLabel\">\n\t        <td><code><b>hideLabel</b>()</code></td>\n\t        <td><code>this</code></td>\n            <td>Скрывает всплывающую подсказку (в случае использования опции <code>static</code>).</td>\n\t    </tr>\n    </tbody>\n</table>\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n#### Обработчики взаимодействия\n\nСвойства маркера включают в себя обработчики взаимодействия, которые позволяют контролировать\nинтерактивное поведение маркера, а также подключение и отключение определенных возможностей,\nтаких как перетаскивание (см. методы Handler). Например:\n\n    marker.dragging.disable();\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Свойство</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"marker-dragging\">\n            <td><code><b>dragging</b></code></td>\n            <td><code><a href=\"/doc/maps/manual/base-classes#dghandler\">Handler</a></code></td>\n\t\t\t<td>Обработчик перетаскивания маркера (мышью и тачем).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Icon\n\nИконка, которую можно использовать при создании маркера. Например:\n\n    var myIcon = DG.icon({\n        iconUrl: 'my-icon.png',\n        iconRetinaUrl: 'my-icon@2x.png',\n        iconSize: [38, 95],\n        iconAnchor: [22, 94],\n        popupAnchor: [-3, -76],\n        shadowUrl: 'my-icon-shadow.png',\n        shadowRetinaUrl: 'my-icon-shadow@2x.png',\n        shadowSize: [68, 95],\n        shadowAnchor: [22, 94]\n    });\n\n    DG.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n\n#### Создание\n\n<table>\n\t<thead>\n\t    <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n\t    <tr>\n            <td><code><b>DG.icon</b>(\n                <nobr>&lt;<a href=\"#icon-option\">Icon options</a>&gt; <i>options</i>)</nobr>\n            </code></td>\n\t        <td>Создает объект иконки, на основании переданных опций.</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table id=\"dgicon-options\">\n    <thead>\n        <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"icon-iconurl\">\n            <td><code><b>iconUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n\t        <td>Обязательный URL к изображению иконки (абсолютный или относительный).</td>\n        </tr>\n        <tr id=\"icon-iconretinaurl\">\n            <td><code><b>iconRetinaUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n\t        <td>URL к изображению иконки для устройств с Retina экраном (абсолютный или относительный).</td>\n        </tr>\n        <tr id=\"icon-iconsize\">\n            <td><code><b>iconSize</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-types#dgpoint\">Point</a></code></td>\n            <td><code>null</code></td>\n\t        <td>Размер изображения иконки в пикселях.</td>\n        </tr>\n        <tr id=\"icon-iconanchor\">\n            <td><code><b>iconAnchor</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-types#dgpoint\">Point</a></code></td>\n            <td><code>null</code></td>\n\t        <td>Координаты \"ножки\" иконки (относительно ее левого верхнего угла).\n\t            Иконка будет установлена так, чтобы эта точка соответствовала географическому положению маркера.\n                По умолчанию \"ножка\" располагается по центру иконки; дополнительно положение может быть настроено\n                через отрицательные значения CSS-свойства margin.</td>\n        </tr>\n        <tr id=\"icon-popupanchor\">\n            <td><code><b>popupAnchor</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n\t        <td>Координаты точки, из которой будет открываться попап (относительно <code>iconAnchor</code>).</td>\n        </tr>\n        <tr id=\"icon-shadowurl\">\n            <td><code><b>shadowUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n\t        <td>URL к изображению тени иконки. Если не указан, тогда тени не будет.</td>\n        </tr>\n        <tr id=\"icon-shadowretinaurl\">\n            <td><code><b>shadowRetinaUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n\t        <td>URL к изображению тени иконки для устройств с Retina экраном.\n                Если не указан, тогда тени не будет.</td>\n        </tr>\n        <tr id=\"icon-shadowsize\">\n            <td><code><b>shadowSize</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n\t        <td>Размер изображения тени в пикселях.</td>\n        </tr>\n        <tr id=\"icon-shadowanchor\">\n            <td><code><b>shadowAnchor</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n\t        <td>Координаты \"ножки\" тени (относительно ее левого верхнего угла).\n                Значение по умолчанию такое же, как у <code>iconAnchor</code>.</td>\n        </tr>\n        <tr id=\"icon-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n\t        <td>Значение класса, которое будет присвоено изображениям иконки и тени. По умолчанию пустое.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table id=\"dgicon-methods\">\n    <thead>\n        <tr>\n\t\t\t<th>Метод</th>\n\t\t\t<th>Возвращает</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"icon-createicon\">\n            <td><code><b>createIcon</b>(<nobr>&lt;HTMLElement&gt; <i>oldIcon?</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Вызывается внутри библиотеки, когда должна быть показана иконка, возвращает\n                HTML-элемент <code>&lt;img&gt;</code> со стилями, соответсвующими переданным опциям.</td>\n        </tr>\n        <tr id=\"icon-createshadow\">\n            <td><code><b>createShadow</b>(<nobr>&lt;HTMLElement&gt; <i>oldIcon?</i>)</nobr></code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Тоже что и <code>createIcon</code>, но с тенью за иконкой.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.DivIcon\n\nИконка для маркеров, которые используют простой элемент <code>&lt;div&gt;</code> вместо изображения.\nНаследуется от <a href=\"#dgicon\"><code>Icon</code></a>, но игнорирует опции теней и <code>iconUrl</code>.\n\n    // вы можете установить стиль класса .my-div-icon в CSS\n    var myIcon = DG.divIcon({className: 'my-div-icon'});\n\n    DG.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n\n#### Создание\n\n<table>\n\t<thead>\n\t    <tr>\n\t        <th>Конструктор</th>\n\t        <th>Описание</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n\t    <tr>\n\t        <td><code><b>DG.DivIcon</b>(\n\t            <nobr>&lt;<a href=\"#divicon-options\">DivIcon options</a>&gt; <i>options</i> )</nobr>\n\t        </code></td>\n\t        <td>Создает объект <code>DG.DivIcon</code>, на основании переданных опций.</td>\n\t    </tr>\n\t</tbody>\n</table>\n\n#### Опции\n\n<table>\n\t<thead>\n\t    <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n\t    </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"divicon-html\">\n            <td><code><b>html</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n\t        <td>HTML код, который будет установлен как содержимое иконки. По умолчанию пустой.</td>\n        </tr>\n        <tr id=\"divicon-bgpos\">\n            <td><code><b>bgPos</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>[0, 0]</code></td>\n            <td>Опциональное относительное позиционирование фона в пикселях</td>\n        </tr>\n\t</tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#dgicon-options\">Icon</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"#dgicon-methods\">Icon</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/manual/other-layers.md",
    "content": "## Дополнительные слои\n\n{toc}\n\n### DG.LayerGroup\n\nИспользуется для группировки нескольких слоев, чтобы обрабатывать их как один. При добавлении\nгруппового слоя на карту, все другие слои, добавляемые и удаляемые из группы, также будут\nдобавлены или удалены с карты. Расширяет <a href=\"/doc/maps/ru/manual/base-classes#dglayer\"><code>DG.Layer</code></a>.\n\n    DG.layerGroup([marker1, marker2])\n        .addLayer(polyline)\n        .addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"layergroup-l-layergroup\">\n            <td><code><b>DG.layerGroup</b>(\n                <nobr>&lt;Layer[]&gt; <i>layers</i> )</nobr>\n            </code></td>\n            <td>Создает объект группы, принимает начальный набор слоев для группировки (опционально).</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"layergroup-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n\n            <td><code>Object</code></td>\n            <td>Возвращает <a href=\"http://en.wikipedia.org/wiki/GeoJSON\">\n                <code>GeoJSON</code></a> объект, описывающий группу слоев, как <code>GeometryCollection</code>.</td>\n        </tr>\n        <tr id=\"layergroup-addlayer\">\n            <td><code><b>addLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Добавляет указанный слой в группу.</td>\n        </tr>\n        <tr id=\"layergroup-removelayer\">\n            <td><code><b>removeLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет указанный слой из группы.</td>\n        </tr>\n        <tr>\n            <td><code><b>removeLayer</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет из группы слой, с указанным ID.</td>\n        </tr>\n        <tr id=\"layergroup-haslayer\">\n            <td><code><b>hasLayer</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если указанный слой уже добавлен в группу.</td>\n        </tr>\n        <tr id=\"layergroup-clearlayers\">\n            <td><code><b>clearLayers</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Удаляет все слои из группы.</td>\n        </tr>\n        <tr id=\"layergroup-invoke\">\n            <td><code><b>invoke</b>(\n                <nobr>&lt;string&gt; <i>methodName</i>, <i>…</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Вызывает метод <code>methodName</code> у каждого слоя из группы. Возможна передача\n                дополнительных параметров. Пропускает слои, у которых не реализован <code>methodName</code>.</td>\n        </tr>\n        <tr id=\"layergroup-eachlayer\">\n            <td><code><b>eachLayer</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Итерационно обходит все слои группы. Возможна передача контекстного объекта в функцию итератор.\n                <code class=\"lang-js\">group.eachLayer(function (layer) {\n                    layer.bindPopup(&#39;Hello&#39;);\n                });</code></td>\n        </tr>\n        <tr id=\"layergroup-getlayer\">\n            <td><code><b>getLayer</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a></code></td>\n            <td>Возвращает слой с указанным ID.</td>\n        </tr>\n        <tr id=\"layergroup-getlayers\">\n            <td><code><b>getLayers</b>()</code></td>\n\n            <td><code>Layer[]</code></td>\n            <td>Возвращает массив всех слоев группы.</td>\n        </tr>\n        <tr id=\"layergroup-setzindex\">\n            <td><code><b>setZIndex</b>(\n                <nobr>&lt;Number&gt; <i>zIndex</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Вызывает метод <code>setZIndex</code> у каждого слоя из группы, передавая аргумент z-index.</td>\n        </tr>\n        <tr id=\"layergroup-getlayerid\">\n            <td><code><b>getLayerId</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>layer</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает ID для указанного слоя.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.FeatureGroup\n\nРасширяет <a href=\"#dglayergroup\"><code>DG.LayerGroup</code></a>, добавляя обработку событий мыши\n(получаемых от членов группы) и общий метод bindPopup.\n\n    DG.featureGroup([marker1, marker2, polyline])\n        .bindPopup('Привет, Мир!')\n        .on('click', function() { alert('Вы щелкнули по группе!'); })\n        .addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"featuregroup-l-featuregroup\">\n            <td><code><b>DG.featureGroup</b>(\n                <nobr>&lt;Layer[]&gt; <i>layers</i> )</nobr>\n            </code></td>\n            <td>Создает объект группы, принимает начальный набор слоев для группировки (опционально).</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"featuregroup-setstyle\">\n            <td><code><b>setStyle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/vector-layers#dgpath-options\">Path options</a>&gt; <i>style</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Устанавливает указанные опции векторного объекта для каждого слоя из группы, у которого реализован\n                метод <code>setStyle</code>.</td>\n        </tr>\n        <tr id=\"featuregroup-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Позиционирует слой группы поверх остальных слоев.</td>\n        </tr>\n        <tr id=\"featuregroup-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Позиционирует слой группы под остальными слоями.</td>\n        </tr>\n        <tr id=\"featuregroup-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Возвращает прямоугольные границы LatLngBounds объекта Feature Group (для корректной работы метода\n                слои в группе должны возвращать подобную информацию о себе).</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"#dglayergroup\">LayerGroup</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n### DG.GeoJSON\n\nОписывает объект GeoJSON или массив объектов GeoJSON. Позволяет корректно интерпретировать данные\nGeoJSON и отобразить их на карте. Расширяет <a href=\"#dgfeaturegroup\"><code>DG.FeatureGroup</code></a>.\n\n    DG.geoJson(data, {\n        style: function (feature) {\n            return {color: feature.properties.color};\n        }\n    }).bindPopup(function (layer) {\n        return layer.feature.properties.description;\n    }).addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-l-geojson\">\n            <td><code><b>DG.geoJSON</b>(\n                <nobr>&lt;Object&gt; <i>geojson?</i>,</nobr>\n                <nobr>&lt;<a href=\"#geojson-option\">GeoJSON options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает слой GeoJSON. Опционально принимает объект в формате\n                <a href=\"http://geojson.org/geojson-spec.html\">GeoJSON</a> (возможна передача этого объекта позже,\n                 используя метод <code>addData</code>) и объект с <code>опциями</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id=\"geojson-option\">\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-pointtolayer\">\n            <td><code><b>pointToLayer</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td><code>Функция</code>, определяющая, как точки GeoJSON будут создавать слои API карт.\n                API карт вызывает метод, если он реализован, передавая объекты точек GeoJSON и\n                <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a>.\n                По умолчанию, будут создаваться обычные <a href=\"/doc/maps/ru/manual/markers#dgmarker\"><code>Маркеры</code></a>:\n                <code class=\"lang-js\">function(geoJsonPoint, latlng) {\n                    return DG.marker(latlng);\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-style\">\n            <td><code><b>style</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td><code>Функция</code>, определяющая\n                <a href=\"/doc/maps/ru/manual/vector-layers#dgpath-options\"><code>Path options</code></a>\n                для стилизации отображения GeoJSON линий и полигонов. API карт вызывает метод, если он реализован,\n                при каждом добавлении данных. По умолчанию, стили никак не изменяются:\n                <code class=\"lang-js\">function (geoJsonFeature) {\n                    return {}\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-oneachfeature\">\n            <td><code><b>onEachFeature</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td><code>Функция</code>, которая будет вызвана после каждого создания и стилизации нового\n                <a href=\"/doc/maps/ru/manual/base-classes#dglayer\"><code>слоя</code></a>.\n                Удобно использовать для подключения обработчиков событий и попапов.\n                По умолчанию, никаких дополнительных действий не происходит:\n                <code class=\"lang-js\">function (layer) {}\n                </code></td>\n        </tr>\n        <tr id=\"geojson-filter\">\n            <td><code><b>filter</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td><code>Функция</code>, которая определяет, должен ли отображаться указанный объект или нет.\n                По умолчанию, отображаются все объекты:\n                <code class=\"lang-js\">function (geoJsonFeature) {\n                    return true;\n                }\n                </code></td>\n        </tr>\n        <tr id=\"geojson-coordstolatlng\">\n            <td><code><b>coordsToLatLng</b></code></td>\n            <td><code>Function </code></td>\n            <td><code>*</code></td>\n            <td><code>Функция</code>, которая будет использоваться для преобразования координат GeoJSON\n                в координаты <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a>s.\n                По умолчанию будет использован статический метод <code>coordsToLatLng</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Методы\n\nМетоды, унаследованные от <a href=\"#dgfeaturegroup\">FeatureGroup</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"#dglayergroup\">LayerGroup</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n\n#### Статические функции\n\nЕсть несколько статических функций, которые можно использовать без создания экземпляров класса DG.GeoJSON:\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"geojson-geometrytolayer\">\n            <td><code><b>geometryToLayer</b>(\n                <nobr>&lt;Object&gt; <i>featureData</i>,</nobr>\n                <nobr>&lt;<a href=\"#geojson-option\">GeoJSON options</a>&gt; <i>options?</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a></code></td>\n            <td>Создает <a href=\"/doc/maps/ru/manual/base-classes#dglayer\"><code>Слой</code></a> на основе переданного\n                GeoJSON объекта. Может использовать собственные функции <a href=\"#geojson-pointtolayer\"><code>pointToLayer</code></a>\n                и/или <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a>, если они переданы в объекте опций.</td>\n        </tr>\n        <tr id=\"geojson-coordstolatlng\">\n            <td><code><b>coordsToLatLng</b>(\n                <nobr>&lt;Array&gt; <i>coords</i> )</nobr>\n            </code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Создает объект <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a> из массива\n                двух чисел, переданных в формате (longitude, latitude), или трех чисел, в формате (longitude, latitude, altitude),\n                которые используются в GeoJSON для представления точек.</td>\n        </tr>\n        <tr>\n            <td><code><b>coordsToLatLngs</b>(\n                <nobr>&lt;Array&gt; <i>coords</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>levelsDeep?</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>coordsToLatLng?</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Создает многомерный массив объектов <a href=\"/doc/maps/ru/manual/basic-types#dglatlng\"><code>LatLng</code></a>\n                из массива GeoJSON координат. <code>levelsDeep</code> определяет уровень вложенности (0 для массива точек,\n                1 для массива массивов точек, и т.д., по умолчанию 0). Может использовать собственную функцию\n                <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a> для преобразования.</td>\n        </tr>\n        <tr id=\"geojson-latlngtocoords\">\n            <td><code><b>latLngToCoords</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Обратная операция для <a href=\"#geojson-coordstolatlng\"><code>coordsToLatLng</code></a></td>\n        </tr>\n        <tr id=\"geojson-latlngstocoords\">\n            <td><code><b>latLngsToCoords</b>(\n                <nobr>&lt;Array&gt; <i>latlngs</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>levelsDeep?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>closed?</i> )</nobr>\n            </code></td>\n\n            <td><code>Array</code></td>\n            <td>Обратная операция для <a href=\"#geojson-coordstolatlngs\"><code>coordsToLatLngs</code></a>\n                Опция <code>closed</code> определяет, нужно ли добавлять первую точку в конец массива и используется\n                только в случае, если <code>levelsDeep</code> равен 0.</td>\n        </tr>\n        <tr id=\"geojson-asfeature\">\n            <td><code><b>asFeature</b>(\n                <nobr>&lt;Object&gt; <i>geojson</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Нормализует геометрические примитивы GeoJSON в объекты GeoJSON.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.GridLayer\n\nУниверсальный класс для обработки тайловой сетки из HTML элементов. Это базовый класс, от которого наследуются\nвсе тайловые слои. Поддерживает создание, анимацию и другие действия с элементами, представляющими тайл, такими\nкак <code>&lt;canvas&gt;</code>, <code>&lt;img&gt;</code> или <code>&lt;div&gt;</code>.\n\n#### Использование в синхронном коде\n\nДля того, чтобы создать собственный слой, нужно произвести наследование от GridLayer и реализовать метод\n<code>create()</code>, которому будет передан объект <a href=\"/doc/maps/ru/manual/basic-types#dgpoint\"><code>Point</code></a>\nс <code>x</code>, <code>y</code> и <code>z</code> (уровень увеличения) координатами для отображения тайла.\n\n    var CanvasLayer = DG.GridLayer.extend({\n        createTile: function(coords){\n            // создаем элемент <canvas>\n            var tile = DG.DomUtil.create('canvas', 'leaflet-tile');\n            // устанавливаем размер тайла\n            var size = this.getTileSize();\n            tile.width = size.x;\n            tile.height = size.y;\n            // получаем объект контекста и рисуем что-нибудь на нем, используя coords.x, coords.y и coords.z\n            var ctx = canvas.getContext('2d');\n            // возвращаем получившийся объект, чтобы его можно было отобразить на экране\n            return tile;\n        }\n    });\n\n#### Использование в асинхронном коде\n\nСоздавать объекты тайлов можно и асинхронно. Когда объект тайла полностью создан, его можно вернуть в API карт,\nиспользуя функцию обратного вызова done().\n\n    var CanvasLayer = DG.GridLayer.extend({\n        createTile: function(coords, done){\n            var error;\n            // создаем элемент <canvas>\n            var tile = DG.DomUtil.create('canvas', 'leaflet-tile');\n            // устанавливаем размер тайла\n            var size = this.getTileSize();\n            tile.width = size.x;\n            tile.height = size.y;\n            // рисуем что-нибудь и возвращаем итоговый тайл, используя функцию обратного вызова done()\n            done(error, tile);\n        }\n    });\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"gridlayer-l-gridlayer\">\n            <td><code><b>DG.gridLayer</b>(\n                <nobr>&lt;GridLayer options&gt; <i>options?</i> )</nobr>\n            </code></td>\n            <td>Создает новый объект GridLayer.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id='gridlayer-options'>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>Значение<br>по умолчанию</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-tilesize\">\n            <td><code><b>tileSize</b></code></td>\n            <td><code>Number|Point </code></td>\n            <td><code>256</code></td>\n            <td>Ширина и высота тайлов. Используйте число, если ширина и высота одинаковые,\n                или объект <code>DG.point(ширина, высота)</code> в противном случае.</td>\n        </tr>\n        <tr id=\"gridlayer-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>Уровень полупрозрачности тайлов. Может использоваться в функции <code>createTile()</code>.</td>\n        </tr>\n        <tr id=\"gridlayer-updatewhenidle\">\n            <td><code><b>updateWhenIdle</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>depends</code></td>\n            <td>Если значение <code>false</code>, новые тайлы подгружаются в процессе перемещения карты, в противном случае,\n                только после окончания перемещения карты по экрану (можно использовать для лучшей производительности).\n                <code>true</code> по умолчанию на мобильных устройствах, и <code>false</code> в остальных случаях.</td>\n        </tr>\n        <tr id=\"gridlayer-updateinterval\">\n            <td><code><b>updateInterval</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>200</code></td>\n            <td>Тайлы не будут обновляться чаще, чем раз в <code>updateInterval</code> миллисекунд.</td>\n        </tr>\n        <tr id=\"gridlayer-attribution\">\n            <td><code><b>attribution</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>Информация, которая будет отображаться в строке об авторстве, например &quot;© 2GIS&quot;.</td>\n        </tr>\n        <tr id=\"gridlayer-zindex\">\n            <td><code><b>zIndex</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1</code></td>\n            <td>zIndex для тайлового слоя.</td>\n        </tr>\n        <tr id=\"gridlayer-bounds\">\n            <td><code><b>bounds</b></code></td>\n            <td><code>LatLngBounds </code></td>\n            <td><code>undefined</code></td>\n            <td>Если задан, тайлы будут загружаться только для указанного региона, заданного\n                <a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\"><code>LatLngBounds</code></a>.</td>\n        </tr>\n        <tr id=\"gridlayer-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Минимальный уровень масштабирования, при котором будут загружаться тайлы. По умолчанию - вся карта.</td>\n        </tr>\n        <tr id=\"gridlayer-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>undefined</code></td>\n            <td>Максимальный уровень масштабирования, при котором будут загружаться тайлы. По умолчанию не задан.</td>\n        </tr>\n        <tr id=\"gridlayer-nowrap\">\n            <td><code><b>noWrap</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Будет ли зацикливаться отображение слоя при малом масштабе. Если параметр <code>true</code>, слой\n                будет отображен только один раз.</td>\n        </tr>\n        <tr id=\"gridlayer-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;tilePane&#x27;</code></td>\n            <td><code>Панель карты</code>, на которую будет добавлен слой.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\n<table id='gridlayer-events'>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-loading\">\n            <td><code><b>loading</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Возникает, когда GridLayer начинает загружать тайлы.</td>\n        </tr>\n        <tr id=\"gridlayer-tileunload\">\n            <td><code><b>tileunload</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Возникает, когда тайл удаляется с карты (например, при выходе его за пределы экрана).</td>\n        </tr>\n        <tr id=\"gridlayer-tileloadstart\">\n            <td><code><b>tileloadstart</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Возникает, когда запрашивается тайл.</td>\n        </tr>\n        <tr id=\"gridlayer-tileerror\">\n            <td><code><b>tileerror</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Возникает при ошибке загрузки тайла.</td>\n        </tr>\n        <tr id=\"gridlayer-tileload\">\n            <td><code><b>tileload</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Возникает, когда тайл загружен.</td>\n        </tr>\n        <tr id=\"gridlayer-load\">\n            <td><code><b>load</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#tileevent\">TileEvent</a></code></td>\n            <td>Возникает, когда GridLayer загрузил все видимые тайлы.</td>\n        </tr>\n    </tbody>\n</table>\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include events -->\n\n#### Методы\n\n<table id='gridlayer-methods'>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"gridlayer-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Позиционирует тайловый слой поверх остальных тайловых слоев.</td>\n        </tr>\n        <tr id=\"gridlayer-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Позиционирует тайловый слой под остальными тайловыми слоями.</td>\n        </tr>\n        <tr id=\"gridlayer-getattribution\">\n            <td><code><b>getAttribution</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Используется элементом управления об авторстве, и возвращает соответствующие\n                <a href=\"#gridlayer-attribution\">свойства</a>.</td>\n        </tr>\n        <tr id=\"gridlayer-getcontainer\">\n            <td><code><b>getContainer</b>()</code></td>\n\n            <td><code>String</code></td>\n            <td>Возвращает HTML элемент, который содержит тайлы для данного слоя.</td>\n        </tr>\n        <tr id=\"gridlayer-setopacity\">\n            <td><code><b>setOpacity</b>(\n                <nobr>&lt;Number&gt; <i>opacity</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Меняет значение <a href=\"#gridlayer-opacity\">opacity</a> слоя.</td>\n        </tr>\n        <tr id=\"gridlayer-setzindex\">\n            <td><code><b>setZIndex</b>(\n                <nobr>&lt;Number&gt; <i>zIndex</i> )</nobr>\n            </code></td>\n\n            <td><code>this</code></td>\n            <td>Меняет значение <a href=\"#gridlayer-zindex\">zIndex</a> слоя.</td>\n        </tr>\n        <tr id=\"gridlayer-isloading\">\n            <td><code><b>isLoading</b>()</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если хотя бы один тайл загружен не до конца.</td>\n        </tr>\n        <tr id=\"gridlayer-redraw\">\n            <td><code><b>redraw</b>()</code></td>\n\n            <td><code>this</code></td>\n            <td>Перересовывает все тайлы, запрашивая их повторно.</td>\n        </tr>\n        <tr id=\"gridlayer-gettilesize\">\n            <td><code><b>getTileSize</b>()</code></td>\n\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a></code></td>\n            <td>Возвращает значение опции <a href=\"#gridlayer-tilesize\">tileSize</a> приведенное к объекту\n                DG.Point. Используется методом <code>createTile()</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы, используемые при наследовании\n\nСлои, наследующие от <a href=\"#dggridlayer\"><code>DG.GridLayer</code></a> должны поддерживать следующие методы:\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n\t<tbody>\n        <tr id=\"gridlayer-createtile\">\n            <td><code><b>createTile</b>(\n                <nobr>&lt;Object&gt; <i>coords</i>,</nobr>\n                <nobr>&lt;Function&gt; <i>done?</i> )</nobr>\n            </code></td>\n\n            <td><code>HTMLElement</code></td>\n            <td>Вызывается только из API карт. Метод должен быть переопределен теми классами, которые расширяют\n                <a href=\"#dggridlayer\"><code>GridLayer</code></a>.\n                Метод должен возвращать <code>HTMLElement</code> для позиции, координаты которой передаются в\n                <code>coords</code>. Если указана функция обратного вызова <code>done</code>, она должна быть вызвана\n                после загрузки и отрисовки тайла.\n            </td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/manual/popup.md",
    "content": "## Попапы\n\nПопап — это всплывающее окно, в котором можно отобразить произвольный HTML-код.\nПопап связан с определенным местом на карте.\n\n{toc}\n\n### DG.Popup\n\nИспользуется для создания и открытия попапов в определенных местах на карте.\n\nДля открытия попапа можно использовать метод карты\n<a href=\"/doc/maps/ru/manual/map#map-openpopup\">Map.openPopup</a>, в таком случае\nодновременно может быть открыт лишь один попап, либо метод\n<a href=\"/doc/maps/ru/manual/map#map-addlayer\">Map.addLayer</a> для отображения\nлюбого количества попапов.\n\n#### Пример использования\n\nВключить отображение попапа по клику на маркер довольно просто:\n\n\tmarker.bindPopup(popupContent).openPopup();\n\nУ дополнительных слоев, таких как ломаные, также есть метод bindPopup.\nВот более сложный пример отображения попапа:\n\n\tvar popup = DG.popup()\n\t\t.setLatLng(latlng)\n\t\t.setContent('<p>Привет мир!<br />Это попап.</p>')\n\t\t.openOn(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-dg-popup\">\n            <td><code><b>DG.popup</b>(\n                    <nobr>&lt;<a href=\"#опции\">Popup options</a>&gt; <i>options?</i></nobr>,\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>&gt; <i>source?</i>)</nobr>\n                </code></td>\n            <td>Создает объект Popup с переданными опциями, описывающими внешний вид и расположение попапа.\n                Также вторым параметром можно передать объект <code>source</code>, указывающий привязку\n                попапа к определенному объекту типа Layer.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-maxwidth\">\n            <td><code><b>maxWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>300</code></td>\n            <td>Максимальная ширина попапа в пикселях.</td>\n        </tr>\n        <tr id=\"popup-minwidth\">\n            <td><code><b>minWidth</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>50</code></td>\n            <td>Минимальная ширина попапа в пикселях.</td>\n        </tr>\n        <tr id=\"popup-maxheight\">\n            <td><code><b>maxHeight</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>Если значение установлено и содержимое попапа превышает заданную высоту,\n                создается контейнер указанной высоты со скроллом.</td>\n        </tr>\n        <tr id=\"popup-autopan\">\n            <td><code><b>autoPan</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Установите значение в false, если не хотите, чтобы карта автоматически сдвигалась\n                для полного отображения попапа.</td>\n        </tr>\n        <tr id=\"popup-autopanpaddingtopleft\">\n            <td><code><b>autoPanPaddingTopLeft</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>Задает расстояние от края попапа до левого верхнего угла карты при автоматическом сдвиге.</td>\n        </tr>\n        <tr id=\"popup-autopanpaddingbottomright\">\n            <td><code><b>autoPanPaddingBottomRight</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>null</code></td>\n            <td>Задает расстояние от края попапа до правого нижнего угла карты при автоматическом сдвиге.</td>\n        </tr>\n        <tr id=\"popup-autopanpadding\">\n            <td><code><b>autoPanPadding</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>Point(5, 5)</code></td>\n            <td>Задает расстояние от края попапа до границы карты при автоматическом сдвиге,\n                устанавливает одинаковые значения для <code>autoPanPaddingBottomRight</code> и <code>autoPanPaddingTopLeft</code>.</td>\n        </tr>\n        <tr id=\"popup-keepinview\">\n            <td><code><b>keepInView</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Установите в <code>true</code>, если необходимо предотвратить вероятность перемещения\n                попапа за пределы видимой области карты пока он открыт.</td>\n        </tr>\n        <tr id=\"popup-closebutton\">\n            <td><code><b>closeButton</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Отвечает за отображение кнопки закрытия попапа.</td>\n        </tr>\n        <tr id=\"popup-offset\">\n            <td><code><b>offset</b></code></td>\n            <td><code>Point </code></td>\n            <td><code>Point(0, 7)</code></td>\n            <td>Устанавливает отступ позиции попапа. Удобно для управления \"ножкой\" попапа.</td>\n        </tr>\n        <tr id=\"popup-autoclose\">\n            <td><code><b>autoClose</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Установите эту опцию в <code>false</code>, если хотите изменить стандартное\n                поведение, когда попап закрывается при кликах в область карты (устанавливается глобально\n                с помощью метода карты\n                <a href=\"/doc/maps/ru/manual/map#map-closepopuponclick\">closePopupOnClick</a>)</td>\n        </tr>\n        <tr id=\"popup-zoomanimation\">\n            <td><code><b>zoomAnimation</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Анимировать ли попап при масштабировании. Отключите, если есть проблемы с\n                отображением Flash содержимого внутри попапа.</td>\n        </tr>\n        <tr id=\"popup-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Имя CSS-класса, которое будет назначено попапу.</td>\n        </tr>\n        <tr id=\"popup-pane\">\n            <td><code><b>pane</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;popupPane&#x27;</code></td>\n            <td>Панель карты, на которую будет добавлен попап.</td>\n        </tr>\n        <tr id=\"popup-sprawling\">\n            <td><code><b>sprawling</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>false</code></td>\n            <td>По умолчанию, ширина попапа подстраивается под ширину его контента и под ширину карты.\n                Выставьте значение <code>true</code>, если хотите, чтобы выбиралась максимальная ширина,\n                ограниченная только шириной карты.</td>\n        </tr>\n        <tr id=\"label-textdirection\">\n            <td><code><b>textDirection</b></code></td>\n            <td><code>string</code></td>\n            <td><code>'auto'</code></td>\n            <td>Направление текста контента попапа. Может принимать одно из следующих значений: <code>'auto'</code>,\n                <code>'rtl'</code>, <code>'ltr'</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-add\">\n            <td><code><b>add</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при добавлении нового слоя на карту.</td>\n        </tr>\n        <tr id=\"popup-remove\">\n            <td><code><b>remove</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#event\">Event</a></code></td>\n            <td>Вызывается при удалении слоя с карты.</td>\n        </tr>\n    </tbody>\n</table>\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n<table>\n    <thead>\n        <tr>\n            <th>Событие</th>\n            <th>Данные</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-popupopen\">\n            <td><code><b>popupopen</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается при открытии попапа.</td>\n        </tr>\n        <tr id=\"popup-popupclose\">\n            <td><code><b>popupclose</b></code></td>\n            <td><code>PopupEvent</code></td>\n            <td>Вызывается при закрытии попапа.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"popup-openon\">\n            <td><code><b>openOn</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/map#dgmap\">Map</a>&gt; <i>map</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Добавляет попап на карту, предварительно закрыв другие попапы. Аналогично map.openPopup(popup).</td>\n        </tr>\n        <tr id=\"popup-getlatlng\">\n            <td><code><b>getLatLng</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает географические координаты точки открытия попапа.</td>\n        </tr>\n        <tr id=\"popup-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает географические координаты точки открытия попапа.</td>\n        </tr>\n        <tr id=\"popup-getcontent\">\n            <td><code><b>getContent</b>()</code></td>\n            <td><code>String|HTMLElement</code></td>\n            <td>Возвращает содержимое основной части попапа.</td>\n        </tr>\n        <tr id=\"popup-setcontent\">\n            <td><code><b>setContent</b>(\n                <nobr>&lt;String | HTMLElement | Function&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Задает содержимое основной части попапа. Может принимать HTML строку или DOM-элемент.\n                Если метод получает функцию, данной функции будет передан исходный слой. Функция должна возвращать\n                <code>String</code> или <code>HTMLElement</code></td>\n        </tr>\n        <tr id=\"popup-getheadercontent\">\n            <td><code><b>getHeaderContent</b>()</code></td>\n            <td><code>String | HTMLElement</code></td>\n            <td>Возвращает содержимое секции <code>header</code> попапа.</td>\n        </tr>\n        <tr id=\"popup-setheadercontent\">\n            <td><code><b>setHeaderContent</b>(\n                <nobr>&lt;String | HTMLElement&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Задает содержимое секции <code>header</code> попапа. Может принимать HTML строку или DOM-элемент.</td>\n        </tr>\n        <tr id=\"popup-getfootercontent\">\n            <td><code><b>getFooterContent</b>()</code></td>\n            <td><code>String|HTMLElement</code></td>\n            <td>Возвращает содержимое секции <code>footer</code> попапа.</td>\n        </tr>\n        <tr id=\"popup-setfootercontent\">\n            <td><code><b>setFooterContent</b>(\n                <nobr>&lt;String|HTMLElement&gt; <i>htmlContent</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Задает содержимое секции <code>footer</code> попапа. Может принимать HTML строку или DOM-элемент.</td>\n        </tr>\n        <tr id=\"popup-getelement\">\n            <td><code><b>getElement</b>()</code></td>\n            <td><code>String|HTMLElement</code></td>\n            <td>Алиас для <a href=\"#popup-getcontent\">getContent()</a></td>\n        </tr>\n        <tr id=\"popup-update\">\n            <td><code><b>update</b>()</code></td>\n            <td><code>null</code></td>\n            <td>Обновляет содержимое попапа, разметку и позиционирование. Полезно при обновлении\n                попапа, когда внутри него что-то изменилось, например, загрузилось изображение.</td>\n        </tr>\n        <tr id=\"popup-isopen\">\n            <td><code><b>isOpen</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, когда попап отображается на карте.</td>\n        </tr>\n        <tr id=\"popup-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Помещает данный попап выше других попапов (в пределах одной панели карты)</td>\n        </tr>\n        <tr id=\"popup-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Помещает данный попап под другими попапами (в пределах одной панели карты)</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/manual/raster-layers.md",
    "content": "## Растровые слои\n\nВ данном разделе рассматривается работа с растровыми слоями, которые могут представлять собой тайловые слои\nили изображения привязанные к географическим границам.\n\n{toc}\n\n### DG.TileLayer\n\nИспользуется для загрузки и отображения тайловых слоев на карте.\nРасширяет <a href=\"/doc/maps/ru/manual/other-layers#dggridlayer\">GridLayer</a>.\n\n#### Пример использования\n\n    DG.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);\n\n##### Шаблон URL\n\nСтрока, представленная в следующем виде:\n\n    'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\n\nВы можете использовать свои ключи в шаблоне, которые будут подставлены из опций TileLayer:\n\n    DG.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-dg-tilelayer\">\n            <td><code>\n                    <b>DG.tilelayer</b>(\n                    <nobr>&lt;String&gt;</nobr> <i>urlTemplate</i>,\n                    <nobr><i>options</i></nobr>)\n                </code></td>\n            <td>Создает экземпляр объекта тайлового слоя с данным шаблоном URL и необязательным объектом опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id=\"tilelayer-options\">\n    <thead>\n        <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-minzoom\">\n            <td><code><b>minZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Минимальный уровень масштаба.</td>\n        </tr>\n        <tr id=\"tilelayer-maxzoom\">\n            <td><code><b>maxZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>18</code></td>\n            <td>Максимальный уровень масштаба.</td>\n        </tr>\n        <tr id=\"tilelayer-maxnativezoom\">\n            <td><code><b>maxNativeZoom</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>null</code></td>\n            <td>Максимальный уровень масштаба, который есть у тайлов. Если этот параметр установлен,\n                тайлы всех уровней увеличения, выше чем <code>maxNativeZoom</code>, будут загружены\n                из уровня <code>maxNativeZoom</code> и автоматически отмасштабированы.</td>\n        </tr>\n        <tr id=\"tilelayer-subdomains\">\n            <td><code><b>subdomains</b></code></td>\n            <td><code>String|String[] </code></td>\n            <td><code>&#x27;abc&#x27;</code></td>\n            <td>Под-домены тайловой службы. Могут быть переданы в форме строки (где каждая буква, это имя\n                под-домена) или в форме массива строк.</td>\n        </tr>\n        <tr id=\"tilelayer-errortileurl\">\n            <td><code><b>errorTileUrl</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>URL на тайл изображения, который надо показывать, если загрузка тайла не удалась.</td>\n        </tr>\n        <tr id=\"tilelayer-zoomoffset\">\n            <td><code><b>zoomOffset</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0</code></td>\n            <td>Уровень масштаба, который используется в URL тайлов, будет скорректирован\n                с учетом данного смещения.</td>\n        </tr>\n        <tr id=\"tilelayer-tms\">\n            <td><code><b>tms</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, инвертирует ось Y нумерации тайлов (включите эту опцию\n                для <a href=\"https://en.wikipedia.org/wiki/Tile_Map_Service\">TMS</a> сервисов).</td>\n        </tr>\n        <tr id=\"tilelayer-zoomreverse\">\n            <td><code><b>zoomReverse</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, уровень масштаба используемый в URL тайлов будет\n                инвертировано (<code>maxZoom - zoom</code> вместо <code>zoom</code>) </td>\n        </tr>\n        <tr id=\"tilelayer-detectretina\">\n            <td><code><b>detectRetina</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code> и пользователь использует retina дисплей, тогда будет запрошено\n                четыре тайла вместо одного. Эти тайлы будут в два раза меньше стандартного размера и на\n                один уровень масштабирования больше, для того чтобы адаптироваться под более\n                высокую плотность пикселей.</td>\n        </tr>\n        <tr id=\"tilelayer-crossorigin\">\n            <td><code><b>crossOrigin</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, у всех тайлов атрибут crossOrigin будет установлен в &#39;&#39;.\n                Это необходимое условие, если вы хотите получить доступ к исходным тайлам на уровне пикселей.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-options\">GridLayer</a> <!-- TODO: include options -->\n\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-events\">GridLayer</a> <!-- TODO: include events -->\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table id=\"tilelayer-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-seturl\">\n            <td><code><b>setUrl</b>(\n                <nobr>&lt;String&gt; <i>url</i></nobr>\n                <nobr>&lt;Boolean&gt; <i>noRedraw?</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Обновляет URL шаблон слоя и перерисовывает его (если параметр <code>noRedraw</code>\n                не установлен в <code>true</code>). </td>\n        </tr>\n        <tr id=\"tilelayer-createtile\">\n            <td><code><b>createTile</b>(\n                <nobr>&lt;Object&gt;</nobr> <i>coords</i>,\n                <nobr>&lt;Function&gt;</nobr> <i>done?</i>)</nobr>\n            </code></td>\n            <td><code>HTMLElement</code></td>\n            <td>Вызывается только внутри библиотеки. Перегружает метод\n                <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-createtile\"><code>createTile()</code></a>\n                класса GridLayer. Метод возвращает HTML-элемент <code>&lt;img&gt;</code> с соответствующим\n                изображением по переданному аргументу <code>coords</code>. Функция обратного вызова\n                <code>done</code> будет вызван, когда тайл будет загружен.</td>\n        </tr>\n    </tbody>\n</table>\n\n##### Методы расширения\n\nСлои, расширяющие <a href=\"#dgtilelayer\">TileLayer</a>, могут реализовать следующий метод:\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-gettileurl\">\n            <td><code><b>getTileUrl</b>(<nobr>&lt;Object&gt; <i>coords</i>)</nobr></code></td>\n            <td><code>String</code></td>\n            <td>Вызывается только внутри библиотеки, возвращает URL для тайла, расположенного по\n                переданным координатам. Классы, расширяющие <a href=\"#dgtilelayer\"><code>TileLayer</code></a>,\n                могут перегружать эту функцию, для того чтобы предоставить собственные схемы\n                именования URL тайлов.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от GridLayer <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-methods\">GridLayer</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.TileLayer.wms\n\nИспользуется для отображения WMS сервисов как тайловых слоев на карте. Расширяет <a href=\"#dgtilelayer\">TileLayer</a>.\n\n#### Пример использования\n\n    var nexrad = DG.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\n        layers: 'nexrad-n0r-900913',\n        format: 'image/png',\n        transparent: true,\n        attribution: \"Погодные данные © 2012 IEM Nexrad\"\n    });\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-dg-tilelayer-wms\">\n            <td><code><b>DG.tileLayer.wms</b>(\n                <nobr>&lt;String&gt; <i>baseUrl</i></nobr>,\n                <nobr>&lt;<a href=\"#tilelayer-wms-options\">TileLayer.WMS options</a>&gt; <i>options</i>)</nobr>\n            </code></td>\n            <td>Создает экземпляр объекта WMS тайлового слоя по переданному URL WMS-сервиса и объекту WMS-опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id=\"tilelayer-wms-options\">\n    <thead>\n        <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-layers\">\n            <td><code><b>layers</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td><strong>(требуется)</strong> Разделенный запятыми список WMS-слоев для отображения.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-styles\">\n            <td><code><b>styles</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Разделенный запятыми список WMS-стилей.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-format\">\n            <td><code><b>format</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;image/jpeg&#x27;</code></td>\n            <td>Формат изображений WMS (используйте <code>&#39;image/png&#39;</code> для слоев с прозрачностью).</td>\n        </tr>\n        <tr id=\"tilelayer-wms-transparent\">\n            <td><code><b>transparent</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, WMS-сервис вернет изображения с прозрачностью.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-version\">\n            <td><code><b>version</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;1.1.1&#x27;</code></td>\n            <td>Версия WMS сервиса, которую следует использовать</td>\n        </tr>\n        <tr id=\"tilelayer-wms-crs\">\n            <td><code><b>crs</b></code></td>\n            <td><code>CRS </code></td>\n            <td><code>null</code></td>\n            <td>Система координат (CRS), котрую следует использовать при WMS-запросах, по умолчанию\n                установлена в CRS карты. Не изменяйте эту настройку, если вы не уверены в том, что\n                она означает.</td>\n        </tr>\n        <tr id=\"tilelayer-wms-uppercase\">\n            <td><code><b>uppercase</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, ключи параетров WMS запросов будут переведены в верхний регистр.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#tilelayer-options\">TileLayer</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-options\">GridLayer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-events\">GridLayer</a> <!-- TODO: include events -->\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"tilelayer-wms-setparams\">\n            <td><code><b>setParams</b>(\n                <nobr>&lt;Object&gt; <i>params</i></nobr>,\n                <nobr>&lt;Boolean&gt; <i>noRedraw?</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Расширяет объект новыми параметрами и заново запрашивает тайлы для текущего экрана\n                (если <code>noRedraw</code> не был установлен в true).</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от  TileLayer <a href=\"#tilelayer-methods\">TileLayer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от GridLayer <a href=\"/doc/maps/ru/manual/other-layers#gridlayer-methods\">GridLayer</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.ImageOverlay\n\nИспользуется для загрузки и отображения указанного изображения в определенной области карты. Расширяет Layer.\n\n#### Пример использования\n\n    var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\n        imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\n    DG.imageOverlay(imageUrl, imageBounds).addTo(map);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-dg-imageoverlay\">\n            <td><code><b>DG.imageOverlay</b>(\n                <nobr>&lt;String&gt; <i>imageUrl</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>bounds</i></nobr>,\n                <nobr>&lt;ImageOverlay options&gt; <i>options?</i></nobr>)\n            </code></td>\n            <td>Создает экземпляр слоя с изображением по переданному URL изображения и\n                географическим координатам, к которым оно привязано.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n\t\t\t<th>Опция</th>\n\t\t\t<th>Тип</th>\n\t\t\t<th>По умолчанию</th>\n\t\t\t<th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>Прозрачность слоя с изображением.</td>\n        </tr>\n        <tr id=\"imageoverlay-alt\">\n            <td><code><b>alt</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;&#x27;</code></td>\n            <td>Текст для атрибута <code>alt</code> изобаржения.</td>\n        </tr>\n        <tr id=\"imageoverlay-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, слой изображения будет генерировать события мыши при кликах или наведении курсора.</td>\n        </tr>\n        <tr id=\"imageoverlay-crossorigin\">\n            <td><code><b>crossOrigin</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>false</code></td>\n            <td>Если <code>true</code>, атрибут изображения <code>crossOrigin</code> будет установлен в &#39;&#39;.\n                Это необходимое условие, если вы хотите получить доступ к изображению на уровне пикселей.</td>\n        </tr>\n    </tbody>\n</table>\n\nОцпии, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"imageoverlay-setopacity\">\n            <td><code><b>setOpacity</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает прозрачность слоя.</td>\n        </tr>\n        <tr id=\"imageoverlay-bringtofront\">\n            <td><code><b>bringToFront</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Перемещает слой выше других слоев.</td>\n        </tr>\n        <tr id=\"imageoverlay-bringtoback\">\n            <td><code><b>bringToBack</b>()</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Перемещает слой ниже других слоев.</td>\n        </tr>\n        <tr id=\"imageoverlay-seturl\">\n            <td><code><b>setUrl</b>(<nobr>&lt;String&gt; <i>url</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Изменяет URL изображения.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/manual/utils.md",
    "content": "## Вспомогательные классы\n\n{toc}\n\n### DG.Browser\n\nОбъект со статическими свойствами, описывающими браузер пользователя, например:\n\n    if (DG.Browser.ie6) {\n        alert('Вам срочно нужно обновить свой браузер!');\n    }\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"browser-ie\">\n            <td><code><b>ie</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех версий Internet Explorer (не Edge).</td>\n        </tr>\n        <tr id=\"browser-ielt9\">\n            <td><code><b>ielt9</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех версий Internet Explorer ниже версии 9.</td>\n        </tr>\n        <tr id=\"browser-edge\">\n            <td><code><b>edge</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузера Edge.</td>\n        </tr>\n        <tr id=\"browser-webkit\">\n            <td><code><b>webkit</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров на основе WebKit, таких как Chrome и Safari (включая мобильные версии).</td>\n        </tr>\n        <tr id=\"browser-gecko\">\n            <td><code><b>gecko</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров на основе gecko, таких как Firefox.</td>\n        </tr>\n        <tr id=\"browser-android\">\n            <td><code><b>android</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильных браузеров работающих на базе платформы Android.</td>\n        </tr>\n        <tr id=\"browser-android23\">\n            <td><code><b>android23</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильных браузеров на старых версиях Android устройств (2 и 3).</td>\n        </tr>\n        <tr id=\"browser-chrome\">\n            <td><code><b>chrome</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузера Chrome.</td>\n        </tr>\n        <tr id=\"browser-safari\">\n            <td><code><b>safari</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузера Safari.</td>\n        </tr>\n        <tr id=\"browser-ie3d\">\n            <td><code><b>ie3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех версий Internet Explorer, поддерживающих CSS transform.</td>\n        </tr>\n        <tr id=\"browser-webkit3d\">\n            <td><code><b>webkit3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех браузеров на основе WebKit, поддерживающих CSS transform.</td>\n        </tr>\n        <tr id=\"browser-gecko3d\">\n            <td><code><b>gecko3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех браузеров на основе gecko, поддерживающих CSS transform.</td>\n        </tr>\n        <tr id=\"browser-opera12\">\n            <td><code><b>opera12</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех версий Opera, поддерживающих CSS transform (версия 12+).</td>\n        </tr>\n        <tr id=\"browser-any3d\">\n            <td><code><b>any3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех браузеров, поддерживающих CSS transform.</td>\n        </tr>\n        <tr id=\"browser-mobile\">\n            <td><code><b>mobile</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, работающих на современных мобильных устройствах.</td>\n        </tr>\n        <tr id=\"browser-mobilewebkit\">\n            <td><code><b>mobileWebkit</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильных браузеров на основе WebKit.</td>\n        </tr>\n        <tr id=\"browser-mobilewebkit3d\">\n            <td><code><b>mobileWebkit3d</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильных браузеров на основе WebKit, поддерживающих CSS transform.</td>\n        </tr>\n        <tr id=\"browser-mobileopera\">\n            <td><code><b>mobileOpera</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильной версии Opera.</td>\n        </tr>\n        <tr id=\"browser-mobilegecko\">\n            <td><code><b>mobileGecko</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для мобильных браузеров на основе gecko.</td>\n        </tr>\n        <tr id=\"browser-touch\">\n            <td><code><b>touch</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех браузеров, поддерживающих <a href=\"https://developer.mozilla.org/docs/Web/API/Touch_events\">touch events</a>.</td>\n        </tr>\n        <tr id=\"browser-mspointer\">\n            <td><code><b>msPointer</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, поддерживающих touch events модель от Microsoft (например, IE10).</td>\n        </tr>\n        <tr id=\"browser-pointer\">\n            <td><code><b>pointer</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для всех браузеров, поддерживающих <a href=\"https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx\">pointer events</a>.</td>\n        </tr>\n        <tr id=\"browser-retina\">\n            <td><code><b>retina</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, работающих на устройствах с Retina экраном.</td>\n        </tr>\n        <tr id=\"browser-canvas\">\n            <td><code><b>canvas</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, поддерживающих <a href=\"https://developer.mozilla.org/docs/Web/API/Canvas_API\"><code>&lt;canvas&gt;</code></a>.</td>\n        </tr>\n        <tr id=\"browser-vml\">\n            <td><code><b>vml</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, поддерживающих <a href=\"https://ru.wikipedia.org/wiki/VML\">VML</a>.</td>\n        </tr>\n        <tr id=\"browser-svg\">\n            <td><code><b>svg</b></code></td>\n            <td><code>Boolean</code></td>\n            <td><code>true</code> для браузеров, поддерживающих <a href=\"https://developer.mozilla.org/docs/Web/SVG\">SVG</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Util\n\nОбщие служебные методы и свойства.\n\n#### Функции\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"util-extend\">\n            <td><code><b>extend</b>(\n                <nobr>&lt;Object&gt; <i>dest</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>src?</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Объединяет свойства объекта <code>src</code> (или нескольких объектов) и свойства объекта\n                <code>dest</code> и возвращает последний. Также доступен под псевдонимом <code>DG.extend</code>.</td>\n        </tr>\n        <tr id=\"util-create\">\n            <td><code><b>create</b>(\n                <nobr>&lt;Object&gt; <i>proto</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>properties?</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Полифил для <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create\">Object.create</a></td>\n        </tr>\n        <tr id=\"util-bind\">\n            <td><code><b>bind</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>, <i>…</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td>Возвращает функцию, которая выполняет функцию <code>fn</code> с определенным объектом контекста\n                <code>obj</code> (так, чтобы ключевое слово <code>this</code> внутри функции указывало на\n                <code>obj</code>). Также доступно под псевдонимом <code>DG.bind</code>.</td>\n        </tr>\n        <tr id=\"util-stamp\">\n            <td><code><b>stamp</b>(\n                <nobr>&lt;Object&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает уникальный ID объекта, создавая его при необходимости. Полезно для получения быстрого\n                доступа к объекту, находящемуся в группе.</td>\n        </tr>\n        <tr id=\"util-throttle\">\n            <td><code><b>throttle</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>time</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context</i> )</nobr>\n            </code></td>\n\n            <td><code>Function</code></td>\n            <td>Возвращает обертку над функцией <code>fn</code>, которая гарантирует, что функция не будет\n                вызвана более чем один раз в заданный интервал времени <code>time</code>\n                (например, используется при запросах к тайлам во время перетаскивания карты), опционально\n                можно передать контекст (<code>context</code>), с которым будет вызываться функция.</td>\n        </tr>\n        <tr id=\"util-wrapnum\">\n            <td><code><b>wrapNum</b>(\n                <nobr>&lt;Number&gt; <i>num</i>,</nobr>\n                <nobr>&lt;Number[]&gt; <i>range</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>includeMax?</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает число <code>num</code> приведенное к диапазону <code>range</code> (modulo).\n                Получившееся значение будет всегда меньше <code>range[1]</code>, если только опция\n                <code>includeMax</code> не выставлена в <code>true</code>.</td>\n        </tr>\n        <tr id=\"util-falsefn\">\n            <td><code><b>falseFn</b>()</code></td>\n\n            <td><code>Function</code></td>\n            <td>Возвращает функцию, вызов которой всегда будет давать результат <code>false</code>.</td>\n        </tr>\n        <tr id=\"util-formatnum\">\n            <td><code><b>formatNum</b>(\n                <nobr>&lt;Number&gt; <i>num</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>digits?</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает число <code>num</code>, округленное до <code>digits</code> десятичных знаков\n                (5 знаков по умолчанию).</td>\n        </tr>\n        <tr id=\"util-trim\">\n            <td><code><b>trim</b>(\n                <nobr>&lt;String&gt; <i>str</i> )</nobr>\n            </code></td>\n\n            <td><code>String</code></td>\n            <td>Полифил для <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim\">String.prototype.trim</a></td>\n        </tr>\n        <tr id=\"util-splitwords\">\n            <td><code><b>splitWords</b>(\n                <nobr>&lt;String&gt; <i>str</i> )</nobr>\n            </code></td>\n\n            <td><code>String[]</code></td>\n            <td>Обрезает и разделяет строку на части, используя в качестве разделителя пробел, возвращает массив с этими частями.</code></td>\n        </tr>\n        <tr id=\"util-setoptions\">\n            <td><code><b>setOptions</b>(\n                <nobr>&lt;Object: options: Object&gt; <i>obj</i> )</nobr>\n            </code></td>\n\n            <td><code>Object</code></td>\n            <td>Объединяет свойства <code>options</code> со свойствами объекта <code>obj</code>, возвращая\n                получившийся объект. См. <code>Class options</code>. Также доступен под псевдонимом <code>DG.setOptions</code>.</td>\n        </tr>\n        <tr id=\"util-getparamstring\">\n            <td><code><b>getParamString</b>(\n                <nobr>&lt;Object&gt; <i>obj</i>,</nobr>\n                <nobr>&lt;String&gt; <i>existingUrl?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>uppercase?</i> )</nobr>\n            </code></td>\n\n            <td><code>String</code></td>\n            <td>Преобразует объект в URL-строку, например, <nobr><code>{a: &quot;foo&quot;, b: &quot;bar&quot;}</code></nobr>\n                будет преобразован в <code>&#39;?a=foo&amp;b=bar&#39;</code>. Если задан параметр <code>existingUrl</code>\n                результирующая строка будет подготовлена для добавления в конец переданного URL. Также возможно приведение названий\n                свойств к верхнему регистру (параметр <code>uppercase</code>). Простейший шаблонизатор также воспринимает\n                строки в формате <code>&#39;Hello {a}, {b}&#39;</code> и объект вида <code>{a: &#39;foo&#39;, b: &#39;bar&#39;}</code>.\n                При таком вызове метод возвращает строку <code>(&#39;Hello foo, bar&#39;)</code>.</td>\n        </tr>\n        <tr id=\"util-isarray\">\n            <td><code><b>isArray</b>(<i>obj</i>)</code></td>\n\n            <td><code>Boolean</code></td>\n            <td>Полифил для <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray\">Array.isArray</a></td>\n        </tr>\n        <tr id=\"util-indexof\">\n            <td><code><b>indexOf</b>()</code></td>\n\n            <td><code>Number</code></td>\n            <td>Полифил для <a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf\">Array.prototype.indexOf</a></td>\n        </tr>\n        <tr id=\"util-requestanimframe\">\n            <td><code><b>requestAnimFrame</b>(\n                <nobr>&lt;Function&gt; <i>fn</i>,</nobr>\n                <nobr>&lt;Object&gt; <i>context?</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>immediate?</i> )</nobr>\n            </code></td>\n\n            <td><code>requestId: Number</code></td>\n            <td>Использует планировщик для вызова функции <code>fn</code> при событии обновлении окна браузера (repaint).\n                Функция <code>fn</code> вызывается с контекстом <code>context</code>, если он задан. Когда задан параметр\n                <code>immediate</code>, <code>fn</code> функция вызывается сразу же, если браузер не поддерживает нативно\n                <a href=\"https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame\"><code>window.requestAnimationFrame</code></a>,\n                в противном случае вызов откладывается, до возникновения события перерисовки. Возвращает id, который может\n                быть использован для отмены задания планировщика.</td>\n        </tr>\n        <tr id=\"util-cancelanimframe\">\n            <td><code><b>cancelAnimFrame</b>(\n                <nobr>&lt;Number&gt; <i>id</i> )</nobr>\n            </code></td>\n            <td><code></code></td>\n            <td>Отменяет предыдущий <code>requestAnimFrame</code>. См. также <a href=\"https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame\">window.cancelAnimationFrame</a>.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Свойства\n\n<table>\n    <thead>\n        <tr>\n            <th>Свойство</th>\n            <th>Тип</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"util-lastid\">\n            <td><code><b>lastId</b></code></td>\n            <td><code>Number</code></td>\n            <td>Последний уникальный ID, используемый <a href=\"#util-stamp\"><code>stamp()</code></a></td>\n        </tr>\n        <tr id=\"util-emptyimageurl\">\n            <td><code><b>emptyImageUrl</b></code></td>\n            <td><code>String</code></td>\n            <td>URI, содержащий пустое GIF изображение, закодированное в base64. Используется для освобождения памяти\n                неиспользуемых картинок в мобильных WebKit браузерах (память освобождается установкой свойства\n                <code>src</code> в данное значение).</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.LineUtil\n\nНабор методов для обработки ломаных.\n\n#### Функции\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"lineutil-simplify\">\n            <td><code><b>simplify</b>(\n                <nobr>&lt;Point[]&gt; <i>points</i>,</nobr>\n                <nobr>&lt;Number&gt; <i>tolerance</i> )</nobr>\n            </code></td>\n\n            <td><code>Point[]</code></td>\n            <td>Уменьшает количество точек в ломаной и возвращает новую упрощенную ломаную. Позволяет увеличить\n                производительность обработки/отображения ломаных на карте. Параметр <code>tolerance</code> влияет\n                на величину упрощения (чем меньше значение, тем лучше качество геометрии и ниже производительность).</td>\n        </tr>\n        <tr id=\"lineutil-pointtosegmentdistance\">\n            <td><code><b>pointToSegmentDistance</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p1</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p2</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает расстояние между точкой <code>p</code> и сегментом между точками <code>p1</code> и <code>p2</code>.</td>\n        </tr>\n        <tr id=\"lineutil-closestpointonsegment\">\n            <td><code><b>closestPointOnSegment</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p1</i></nobr>,\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgpoint\">Point</a>&gt; <i>p2</i> )</nobr>\n            </code></td>\n\n            <td><code>Number</code></td>\n            <td>Возвращает ближайшую точку на сегменте <code>p1</code> <code>p2</code> до точки <code>p</code>.</td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.PolyUtil\n\nНабор служебных функций для работы с многоугольниками.\n\n#### Функции\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr id=\"polyutil-clippolygon\">\n\t\t    <td><code><b>clipPolygon</b>(\n\t\t        <nobr>&lt;Point[]&gt; <i>points</i>,</nobr>\n\t\t        <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dgbounds\">Bounds</a>&gt; <i>bounds</i>,</nobr>\n\t\t        <nobr>&lt;Boolean&gt; <i>round?</i> )</nobr>\n\t\t    </code></td>\n\n    \t\t<td><code>Point[]</code></td>\n    \t\t<td>Обрезает многоугольник, заданный координатами <code>points</code> по заданным границам\n    \t\t    (используя алгоритм <a href=\"https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm\">Sutherland-Hodgeman</a>а).</td>\n    \t</tr>\n    </tbody>\n</table>\n"
  },
  {
    "path": "src/doc/ru/manual/vector-layers.md",
    "content": "## Векторные слои\n\nВ данном разделе рассматривается работа с векторными слоями, представляющие собой геометрические\nобъекты на карте: окружности, ломаные линии, многоугольники.\n\n{toc}\n\n### DG.Path\n\nАбстрактный класс, содержащий базовые опции и константы векторных слоев (Polygon, Polyline, Circle).\nНе используйте этот класс напрямую. Расширяет <a href=\"/doc/maps/ru/manual/base-classes#dglayer\">Layer</a>.\n\n#### Опции\n\n<table id=\"dgpath-options\">\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"path-stroke\">\n            <td><code><b>stroke</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Нужно ли рисовать границу фигуры. Установите значение в <code>false</code>,\n                чтобы отключить границы многоугольников или окружностей.</td>\n        </tr>\n        <tr id=\"path-color\">\n            <td><code><b>color</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;#3388ff&#x27;</code></td>\n            <td>Цвет границы.</td>\n        </tr>\n        <tr id=\"path-weight\">\n            <td><code><b>weight</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>3</code></td>\n            <td>Ширина границы в пикселях.</td>\n        </tr>\n        <tr id=\"path-opacity\">\n            <td><code><b>opacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>1.0</code></td>\n            <td>Прозрачность границы.</td>\n        </tr>\n        <tr id=\"path-linecap\">\n            <td><code><b>lineCap</b></code></td>\n            <td><code>String</code></td>\n            <td><code>&#x27;round&#x27;</code></td>\n            <td>Строка, которая определяет вид границы,\n                <a target=\"_blank\" href=\"https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap\">\n                на концах ломаной</a>.</td>\n        </tr>\n        <tr id=\"path-linejoin\">\n            <td><code><b>lineJoin</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;round&#x27;</code></td>\n            <td>Строка, которая определяет вид границы,\n                <a target=\"_blank\" href=\"https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linejoin\">\n                на изгибах</a> ломаной.</td>\n        </tr>\n        <tr id=\"path-dasharray\">\n            <td><code><b>dashArray</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>Строка <a target=\"_blank\" href=\"https://developer.mozilla.org/en/SVG/Attribute/stroke-dasharray\">шаблона границы</a>.\n                Не работает на canvas слоях (например, Android 2).</td>\n        </tr>\n        <tr id=\"path-dashoffset\">\n            <td><code><b>dashOffset</b></code></td>\n            <td><code>String </code></td>\n            <td><code>null</code></td>\n            <td>Строка, которая определяет\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset\">расстояние,\n                через которое начинается штриховка</a>. Не работает на canvas слоях (например, Android 2).</td>\n        </tr>\n        <tr id=\"path-fill\">\n            <td><code><b>fill</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>depends</code></td>\n            <td>Заполнять ли фигуру цветом. Установите значение в <code>false</code>,\n                чтобы отключить заполнение многоугольников или окружностей.</td>\n        </tr>\n        <tr id=\"path-fillcolor\">\n            <td><code><b>fillColor</b></code></td>\n            <td><code>String </code></td>\n            <td><code>*</code></td>\n            <td>Цвет заливки. Цвет по умолчанию определяется опцией <a href=\"#path-color\"><code>color</code></a>.</td>\n        </tr>\n        <tr id=\"path-fillopacity\">\n            <td><code><b>fillOpacity</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>0.2</code></td>\n            <td>Прозрачность заливки.</td>\n        </tr>\n        <tr id=\"path-fillrule\">\n            <td><code><b>fillRule</b></code></td>\n            <td><code>String </code></td>\n            <td><code>&#x27;evenodd&#x27;</code></td>\n            <td>Строка, которая задает,\n                <a href=\"https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule\">как определяется\n                внутренняя область фигуры</a>.</td>\n        </tr>\n        <tr id=\"path-interactive\">\n            <td><code><b>interactive</b></code></td>\n            <td><code>Boolean </code></td>\n            <td><code>true</code></td>\n            <td>Если <code>false</code>, векторный слой не будет генерировать события мыши и будет\n                вести себя, как часть нижележащего слоя карты.</td>\n        </tr>\n        <tr id=\"path-renderer\">\n            <td><code><b>renderer</b></code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\">Renderer</a></code></td>\n            <td><code></code></td>\n            <td>Использовать этот экземпляр <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\"><code>Renderer</code></a>\n                для данного векторного объекта. Переопределяет\n                <a href=\"/doc/maps/ru/manual/map#map-renderer\">renderer карты</a>, установленный по умолчанию.</td>\n        </tr>\n        <tr id=\"path-classname\">\n            <td><code><b>className</b></code></td>\n            <td><code>string </code></td>\n            <td><code>null</code></td>\n            <td>Добавляет класс в соотвествующий атрибут элемента (только для SVG).</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table id=\"dgpath-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"path-redraw\">\n            <td><code><b>redraw</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Перерисовывает слой. Удобно при изменении его координат.</td>\n        </tr>\n        <tr id=\"path-setstyle\">\n            <td><code>\n                <b>setStyle</b>(\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>style</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Изменяет внешний вид объекта с помощью <a href=\"#dgpath-options\">опций класса Path</a>.</td>\n        </tr>\n        <tr id=\"path-bringtofront\">\n            <td><code><b>bringToFront</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Позиционирует слой поверх всех остальных.</td>\n        </tr>\n        <tr id=\"path-bringtoback\">\n            <td><code><b>bringToBack</b>()</code></td>\n            <td><code>this</code></td>\n            <td>Позиционирует слой под остальными.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Polyline\n\nКласс для отрисовки ломаных линий на карте. Расширяет <a href=\"#dgpath\">Path</a>.\n\n#### Пример использования\n\n    // создает ломаную красного цвета из массива точек LatLng\n    var latlngs = [\n        [-122.68, 45.51],\n        [-122.43, 37.77],\n        [-118.2, 34.04]\n    ];\n    var polyline = DG.polyline(latlngs, {color: 'red'}).addTo(map);\n    // увеличиваем масштаб так, чтобы было видно всю ломаную\n    map.fitBounds(polyline.getBounds());\n\nВы также можете передать многомерный массиив, который представляет собой фигуру MultiPolyline:\n\n    // создает красную ломаную из массива массивов точек LatLng\n    var latlngs = [\n        [[-122.68, 45.51],\n         [-122.43, 37.77],\n         [-118.2, 34.04]],\n        [[-73.91, 40.78],\n         [-87.62, 41.83],\n         [-96.72, 32.76]]\n    ];\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Использование</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-dg-polyline\">\n            <td><code><b>DG.polyline</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i></nobr>,\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Создает объект ломаной по переданному массиву географических точек и необязательному объекту опций.\n                Вы можете создать объект <a href=\"#dgpolyline\"><code>Polyline</code></a>, состоящий из\n                множества линий (так называемый <code>MultiPolyline</code>), передав массив массивов\n                географических точек.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table id=\"dgpolyline-options\">\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-smoothfactor\">\n            <td><code><b>smoothFactor</b></code></td>\n            <td><code>Number </code>\n            <td><code>1.0</code></td>\n            <td>Степень упрощения ломаной на каждом уровне масштаба. Большее значение означает более высокую\n                производительность, но худшее качество, меньшее же значение &mdash; наоборот.</td>\n        </tr>\n        <tr id=\"polyline-noclip\">\n            <td><code><b>noClip</b></code></td>\n            <td><code>Boolean: false</code>\n            <td><code></code></td>\n            <td>Отключает отсечение ломаной.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапов, унаследованные <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table id=\"dgpolyline-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polyline-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Возвращает <a href=\"http://en.wikipedia.org/wiki/GeoJSON\">GeoJSON</a>\n                представление ломаной (GeoJSON LineString или <code>MultiLineString</code>).</td>\n        </tr>\n        <tr id=\"polyline-getlatlngs\">\n            <td><code><b>getLatLngs</b>()</code></td>\n            <td><code>LatLng[]</code></td>\n            <td>Возвращает массив точек объекта или массив массивов точек, в случае мультиломаной.</td>\n        </tr>\n        <tr id=\"polyline-setlatlngs\">\n            <td><code><b>setLatLngs</b>(<nobr>&lt;LatLng[]&gt; <i>latlngs</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Заменяет все точки ломаной данными из переданного массива.</td>\n        </tr>\n        <tr id=\"polyline-isempty\">\n            <td><code><b>isEmpty</b>()</code></td>\n            <td><code>Boolean</code></td>\n            <td>Возвращает <code>true</code>, если у Polyline нет точек LatLngs.</td>\n        </tr>\n        <tr id=\"polyline-getcenter\">\n            <td><code><b>getCenter</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает центр (<a href=\"http://en.wikipedia.org/wiki/Centroid\">centroid</a>) ломаной.</td>\n        </tr>\n        <tr id=\"polyline-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Возвращает границы ломаной.</td>\n        </tr>\n        <tr id=\"polyline-addlatlng\">\n            <td><code><b>addLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i>)</nobr>\n                <nobr>&lt;LatLng[]&gt; <i>latlngs?</i></nobr>,\n            </code></td>\n            <td><code>this</code></td>\n            <td>Добавляет точку в ломаную. По умолчанию, добавляет точку в первое звено\n                списка ломаных в случае мультиломаной. Это поведение может быть переопределено передачей\n                определенного звена, как массива элементов LatLng (к которому вы могли получить\n                доступ ранее, с помощью метода <a href=\"#polyline-getlatlngs\">getlatlngs</a>).</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Polygon\n\nКласс для отрисовки многоугольников на карте. Расширяет <a href=\"#dgpolyline\">Polyline</a>.\n\nОбратите внимание на то, что среди точек, которые передаются для создания многоугольника, не должно быть\nдополнительной точки, совпадающей с первой - такие точки лучше предварительно отфильтровать.\n\n#### Пример использования\n\n    // создает красный многоугольник из массива точек LatLng\n    var latlngs = [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]];\n    var polygon = DG.polygon(latlngs, {color: 'red'}).addTo(map);\n\n    // увеличивает масштаб карты до максимального значения, при котором виден весь многоугольник\n    map.fitBounds(polygon.getBounds());\n\nВозможно также создать многоугольник с дырами, передав массив массивов latlngs,\nпервый latlngs массив отвечает за внешние границы, остальные описывают области внутри.\n\n    var latlngs = [\n      [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // внешняя граница\n      [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // дыра\n    ];\n\nТакже, вы можете передать многомерный массив, который представляет собой мульти-многоугольник (MultiPolygon).\n\n    var latlngs = [\n      [ // первый многоугольник\n        [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // внешняя граница\n        [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // дыра\n      ],\n      [ // второй многоугольник\n        [[-109.05, 37],[-109.03, 41],[-102.05, 41],[-102.04, 37],[-109.05, 38]]\n      ]\n    ];\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"polygon-dg-polygon\">\n            <td><code>\n                <b>DG.polygon</b>(\n                <nobr>&lt;LatLng[]&gt; <i>latlngs</i></nobr>,\n                <nobr>&lt;Polyline options&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td></td>\n        </tr>\n    </tbody>\n</table>\n\n\n#### Опции\n\nОпции, унаследованные от <a href=\"#dgpolyline-options\">Polyline</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапов, унаследованные <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<span id=\"#dgpolygon-methods\"></span>\n\nМетоды, унаследованные от <a href=\"#dgpolyline-methods\">Polyline</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Rectangle\n\nКласс для отрисовки прямоугольников на карте. Расширяет <a href=\"#dgpolygon\">Polygon</a>.\n\n#### Пример использования\n\n    // создаем географические границы прямоугольника\n    var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n\n    // создаем оранжевый прямоугольник\n    DG.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n\n    // подстраиваем центр карты и масштаб так, чтобы прямоугольник было видно\n    map.fitBounds(bounds);\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"rectangle-dg-rectangle\">\n            <td><code>\n                <b>DG.rectangle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>latLngBounds</i></nobr>,\n                <nobr>&lt;Polyline options&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td></td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"#dgpolyline-options\">Polyline</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапов, унаследованные <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"rectangle-setbounds\">\n            <td><code><b>setBounds</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a>&gt; <i>latLngBounds</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Перерисовывает прямоугольник с новыми границами.</td>\n        </tr>\n    </tbody>\n</table>\n\n\nМетоды, унаследованные от <a href=\"#dgpolygon-method\">Polygon</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Circle\n\nКласс для отрисовки окружности на карте. Расширяет <a href=\"#dgpath\">Path</a>. Это аппроксимация, которая начинает\nотличаться от настоящей окружности ближе к полюсам (из-за искажений проекции).\n\n#### Пример использование\n\n    DG.circle([50.5, 30.5], 200).addTo(map);\n\n#### Создние\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-dg-circle\">\n            <td><code>\n                <b>DG.circle</b>(\n                    <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                    <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Создает объект круга по переданной географической точке и\n                объекту опций, в котором содежится радиус круга.</td>\n        </tr>\n        <tr id=\"circle-dg-circle-2\">\n            <td><code><b>DG.circle</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                <nobr>&lt;Number&gt; <i>radius</i></nobr>,\n                <nobr>&lt;<a href=\"#dgpath-options\">Path options</a>&gt; <i>options?</i>)</nobr>\n            </code></td>\n            <td>Устаревший способ создания круга, только для совместимости со старым кодом.\n                Не используйте его в своих новых приложениях и плагинах.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-radius\">\n            <td><code><b>radius</b></code></td>\n            <td><code>Number</code>\n            <td><code></code></td>\n            <td>Радиус круга в метрах.</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапов, унаследованные <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table>\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circle-setradius\">\n            <td><code>\n                <b>setRadius</b>(\n                <nobr>&lt;Number&gt; <i>radius</i>)</nobr>\n            </code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает радиус окружности в метрах</td>\n        </tr>\n        <tr id=\"circle-getradius\">\n            <td><code><b>getRadius</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает текущий радиус окружности в метрах</td>\n        </tr>\n        <tr id=\"circle-getbounds\">\n            <td><code><b>getBounds</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\">LatLngBounds</a></code></td>\n            <td>Возвращает <a href=\"/doc/maps/ru/manual/basic-types#dglatlngbounds\"><code>LatLngBounds</code></a>\n                объекта.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"#dgcirclemarker-methods\">CircleMarker</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.CircleMarker\n\nОкружность фиксированного размера с радиусом указанным в пикселях. Расширяет <a href=\"#класс-dgpath\">Path</a>.\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-dg-circlemarker\">\n            <td><code>\n                <b>DG.circleMarker</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latlng</i></nobr>,\n                <i>options</i>)</code></td>\n            <td>Создает объект круглого маркера по переданной географической точке и необязательному объекту опций.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\n<table>\n    <thead>\n        <tr>\n            <th>Опция</th>\n            <th>Тип</th>\n            <th>По умолчанию</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-radius\">\n            <td><code><b>radius</b></code></td>\n            <td><code>Number </code></td>\n            <td><code>10</code></td>\n            <td>Радиус маркера в пикселях</td>\n        </tr>\n    </tbody>\n</table>\n\nОпции, унаследованные от <a href=\"#dgpath-options\">Path</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\n<table id=\"dgcirclemarker-methods\">\n    <thead>\n        <tr>\n            <th>Метод</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"circlemarker-togeojson\">\n            <td><code><b>toGeoJSON</b>()</code></td>\n            <td><code>Object</code></td>\n            <td>Возвращает <a href=\"http://en.wikipedia.org/wiki/GeoJSON\">GeoJSON</a> представление круглого маркера\n                (GeoJSON Point).</td>\n        </tr>\n        <tr id=\"circlemarker-setlatlng\">\n            <td><code><b>setLatLng</b>(\n                <nobr>&lt;<a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a>&gt; <i>latLng</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает географическую позицию круглого маркера.</td>\n        </tr>\n        <tr id=\"circlemarker-getlatlng\">\n            <td><code><b>getLatLng</b>()</code></td>\n            <td><code><a href=\"/doc/maps/ru/manual/basic-types#dglatlng\">LatLng</a></code></td>\n            <td>Возвращает текущую географическую позицию круглого маркера.</td>\n        </tr>\n        <tr id=\"circlemarker-setradius\">\n            <td><code><b>setRadius</b>(<nobr>&lt;Number&gt; <i>radius</i>)</nobr></code></td>\n            <td><code>this</code></td>\n            <td>Устанавливает радиус окружности, значение в пикселях.</td>\n        </tr>\n        <tr id=\"circlemarker-getradius\">\n            <td><code><b>getRadius</b>()</code></td>\n            <td><code>Number</code></td>\n            <td>Возвращает текущее значение радиуса окружности.</td>\n        </tr>\n    </tbody>\n</table>\n\nМетоды, унаследованные от <a href=\"#dgpath-methods\">Path</a> <!-- TODO: include methods -->\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n### DG.Svg\n\nДанный класс позволяет отображать векторные слои с помощью <a href=\"https://developer.mozilla.org/docs/Web/SVG\">SVG</a>.\nНаследуется от <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\">Renderer</a>.\n\nИз-за <a href=\"http://caniuse.com/#search=svg\">технических ограничений</a>, SVG доступен не во всех браузерах\n(например, Android версий 2.x и 3.x не поддерживает SVG).\n\nSVG не доступен в IE8, но в этом браузере есть поддержка устаревшей технологии\n<a href=\"https://en.wikipedia.org/wiki/Vector_Markup_Language\">VML</a>, и SVG renderer переключится на использование\nVML, в случае работы под IE8. Поддержка VML в библиотеке существует только для обратной совместимости со старой версией\nInternet Explorer.\n\n#### Пример использования\n\nИспользование SVG по умолчанию для всех векторных объектов на карте:\n\n    var map = DG.map(\"map\", {\n        renderer: DG.svg();\n    });\n\nИспользование SVG rendrer с дополнительными отступами для определенных векторных объектов:\n\n    var map = DG.map(\"map\");\n    var myRenderer = DG.svg({ padding: 0.5 });\n    var line = DG.polyline( coordinates, { renderer: myRenderer } );\n    var circle = DG.circle( center, { renderer: myRenderer } );\n\n#### Создание\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"svg-dg-svg\">\n            <td><code><b>DG.svg</b>(<nobr>&lt;SVG options&gt; <i>options?</i>)</nobr></code></td>\n            <td>Создает SVG renderer, используя указанные опции.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer-options\">Renderer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n\n#### Функции\n\nЕсть несколько статических функций, которые могут быть вызваны без создания объекта DG.SVG:\n\n<table>\n    <thead>\n        <tr>\n            <th>Функция</th>\n            <th>Возвращает</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"svg-create\">\n            <td><code><b>create</b>(<nobr>&lt;String&gt; <i>name</i>)</nobr></code></td>\n            <td><code>SVGElement</code></td>\n            <td>Возвращает экземпляр <a href=\"https://developer.mozilla.org/docs/Web/API/SVGElement\">SVGElement</a>,\n                соответствуйщий имени класса, переданному как аргумент. Например, использование &#39;line&#39; вернет\n                экземпляр <a href=\"https://developer.mozilla.org/docs/Web/API/SVGLineElement\">SVGLineElement</a>.</td>\n        </tr>\n        <tr id=\"svg-pointstopath\">\n            <td><code>\n                <b>pointsToPath</b>(\n                <nobr>&lt;[]&gt; <i>rings</i>,</nobr>\n                <nobr>&lt;Boolean&gt; <i>closed</i>)</nobr>\n            </code></td>\n            <td><code>String</code></td>\n            <td>Генерирует строку SVG path для множества звеньев, каждое звено превращается\n                в &quot;M..L..L..&quot;-инструкции </td>\n        </tr>\n    </tbody>\n</table>\n\n### DG.Canvas\n\nПозволяет отрисовывать векторные слои с помощью <a href=\"https://developer.mozilla.org/docs/Web/API/Canvas_API\">canvas</a>.\nНаследуется от <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer\">Renderer</a>.\nВ виду <a href=\"http://caniuse.com/#search=canvas\">технических ограничений</a>, Canvas доступен\nне во всех браузерах (например, в IE8) и пересекающиеся объекты могут отображаться некорректно,\nв некоторых крайних случаях.\n\n#### Пример использована\n\nИспользование Canvas по умолчанию для всех векторных объектов на карте:\n\n    var map = DG.map('map', {\n        renderer: DG.canvas();\n    });\n\nИспользование Canvas с дополнительными отступами, для определенных векторных объектов:\n\n    var map = DG.map('map');\n    var myRenderer = DG.canvas({ padding: 0.5 });\n    var line = DG.polyline( coordinates, { renderer: myRenderer } );\n    var circle = DG.circle( center, { renderer: myRenderer } );\n\n#### Создание Canvas\n\n<table>\n    <thead>\n        <tr>\n            <th>Конструктор</th>\n            <th>Описание</th>\n        </tr>\n\t</thead>\n    <tbody>\n        <tr id=\"canvas-dg-canvas\">\n            <td><code><b>DG.canvas</b>(<nobr>&lt;Canvas options&gt; <i>options?</i>)</nobr></code></td>\n            <td>Создает Canvas renderer, используя переданные опции.</td>\n        </tr>\n    </tbody>\n</table>\n\n#### Опции\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgrenderer-options\">Renderer</a> <!-- TODO: include options -->\n\nОпции, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-options\">Layer</a> <!-- TODO: include options -->\n\n#### События\n\nСобытия, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-events\">Layer</a> <!-- TODO: include events -->\n\nСобытия попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-events\">Layer</a> <!-- TODO: include popup events -->\n\n#### Методы\n\nМетоды попапа, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-popup-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dglayer-methods\">Layer</a> <!-- TODO: include methods -->\n\nМетоды, унаследованные от <a href=\"/doc/maps/ru/manual/base-classes#dgevented-methods\">Evented</a> <!-- TODO: include methods -->\n"
  },
  {
    "path": "src/doc/ru/quickstart/quickstart.md",
    "content": "## Все возможности API&SDK 2ГИС\n[dev.2gis.ru](https://dev.2gis.ru)\n\n## Полная обновлённая документация\n[docs.2gis.com/ru](https://docs.2gis.com/ru)\n\n\n\n## Общие сведения\n\nПри помощи API карт вы сможете:\n\n* <span style=\"color:323232\">создавать интерактивные карты на веб-странице;</span>\n* <span style=\"color:323232\">показывать на карте различные объекты (маркеры, попапы, геометрические объекты);</span>\n* <span style=\"color:323232\">производить поиск на карте: определять координаты геообъектов по их названиям и названия по координатам.</span>\n\nИсходный код API карт доступен на [GitHub](https://github.com/2gis/mapsapi), проект открыт к предложениям и пулл-реквестам.\n\n### Начало работы\n\nНиже приведен простой пример создания карты.\n\n#### Подключите API\n\nДля подключения JavaScript кода API добавьте в секцию head HTML-страницы следующий код:\n\n    <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n\nЕсли вас интересует подключение кода API с помощью npm, перейдите в раздел [Подключение API](/doc/maps/ru/manual/dg-loading#npm).\n\n#### Создайте контейнер карты\n\nДля создания контейнера, в котором будет отображаться карта, необходимо добавить блочный HTML-элемент необходимого вам размера:\n\n    <body>\n        <div id=\"map\" style=\"width:500px; height:400px\"></div>\n    </body>\n\n#### Создайте карту\n\nТеперь все готово к тому, чтобы создать карту. Для этого добавьте следующий код в секцию head:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n        });\n    </script>\n\nВ данном примере карта принимает два параметра:\n\n* <span style=\"color:323232\">center - координаты центра карты в формате [широта, долгота];</span>\n* <span style=\"color:323232\">zoom - коэффициент масштабирования в диапазоне от 1 до 18.</span>\n\n#### Добавьте маркер на карту\n\nПосле создания карты вы можете отобразить на ней маркер, добавив одну строку кода в написанный ранее код:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n\n            DG.marker([54.98, 82.89]).addTo(map);\n        });\n    </script>\n\n#### Покажите попап с информацией\n\nЕсли немного расширить добавленную выше строку кода с маркером, тогда при клике в маркер будет отображаться попап\n(всплывающий блок) с необходимой вам информацией:\n\n    <script type=\"text/javascript\">\n        var map;\n\n        DG.then(function () {\n            map = DG.map('map', {\n                center: [54.98, 82.89],\n                zoom: 13\n            });\n\n            DG.marker([54.98, 82.89]).addTo(map).bindPopup('Вы кликнули по мне!');\n        });\n    </script>\n\n#### Всё вместе\n\nРезультирующий код:\n\n    <!DOCTYPE html>\n    <html>\n        <head>\n            <title>API карт 2ГИС</title>\n            <script src=\"https://maps.api.2gis.ru/2.0/loader.js?pkg=full\"></script>\n            <script type=\"text/javascript\">\n                var map;\n\n                DG.then(function () {\n                    map = DG.map('map', {\n                        center: [54.98, 82.89],\n                        zoom: 13\n                    });\n\n                    DG.marker([54.98, 82.89]).addTo(map).bindPopup('Вы кликнули по мне!');\n                });\n            </script>\n        </head>\n        <body>\n            <div id=\"map\" style=\"width:500px; height:400px\"></div>\n        </body>\n    </html>\n\n### Дальнейшие шаги\n\nВсё получилось? Теперь можно ознакомиться с <a href=\"/doc/maps/ru/manual/dg-loading\">руководством для разработчиков</a>\nи <a href=\"/doc/maps/ru/examples/base\">примерами использования</a>.\n\n### Техническая поддержка\n\nЕсли у вас возникли сложности в работе с API карт &mdash; <a href=\"mailto:api@2gis.ru\">напишите нам письмо</a>\nи мы обязательно поможем вам разобраться.\n\n### Порядок определения стоимости\n\nПорядок определения стоимости программного обеспечения вы можете найти по адресу https://docs.2gis.com/ru/prices.\n"
  },
  {
    "path": "src/less/images-usage-statistics.less",
    "content": "stats {\n    .repeatableBg;\n    .notRepeatableBg;\n    repeatable: '@{repeatableBgNames}';\n    notRepeatableSprited: '@{notRepeatableBgNamesSprited}';\n    notRepeatableNotSprited: '@{notRepeatableBgNamesNotSprited}';\n}\n"
  },
  {
    "path": "src/less/mixins.ie8.less",
    "content": ".opacity(@value) when (isnumber(@value)) and (@value < 1) {\n    @percentValue: @value * 100;\n\n    -ms-filter: \"progid:DXImageTransform.Microsoft.Alpha(Opacity=@{percentValue})\";\n    filter: e(\"alpha(opacity=@{percentValue})\");\n}\n\n.gradient(@from; @to; @type: 0) when (iscolor(@from)) and (iscolor(@to)) {\n    @argbFrom: argb(@from);\n    @argbTo: argb(@to);\n\n    filter: e(\"progid:DXImageTransform.Microsoft.gradient(GradientType=@{type},startColorstr='@{argbFrom}',endColorstr='@{argbTo}')\");\n}\n\n.alphaImage(@name; @sizingMethod: scale) {\n    filter: e(\"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='@{spritesURL}/img/@{name}.png',sizingMethod='@{sizingMethod}')\");\n}\n"
  },
  {
    "path": "src/less/mixins.images-usage-statistics.less",
    "content": "@addToRepeatables: ~`addToRepeatables =\n    (function () {\n        var names = '';\n        return function (name) {\n            if (typeof name == 'string' && name.length) {\n                names = names + (names.length ? ',' : '') + name;\n            }\n\n            return names;\n        }\n    })()`;\n\n.repeatableBg(@name: '') {\n    @repeatableBgNames: ~`addToRepeatables(@{name})`;\n}\n\n@addToNotRepeatablesSprited: ~`addToNotRepeatablesSprited =\n    (function () {\n        var names = '';\n        return function (name) {\n            if (typeof name == 'string' && name.length) {\n                names = names + (names.length ? ',' : '') + name;\n            }\n\n            return names;\n        }\n    })()`;\n\n@addToNotRepeatablesNotSprited: ~`addToNotRepeatablesNotSprited =\n    (function () {\n        var names = '';\n        return function (name) {\n            if (typeof name == 'string' && name.length) {\n                names = names + (names.length ? ',' : '') + name;\n            }\n\n            return names;\n        }\n    })()`;\n\n.notRepeatableBg(@name: ''; @newerNotUseSprite: false) {\n    @notRepeatableBgNamesSprited: ~`addToNotRepeatablesSprited()`;\n    @notRepeatableBgNamesNotSprited: ~`addToNotRepeatablesNotSprited()`;\n\n    & when not (@newerNotUseSprite) {\n        @notRepeatableBgNamesSprited: ~`addToNotRepeatablesSprited(@{name})`;\n    }\n    & when (@newerNotUseSprite) {\n        @notRepeatableBgNamesNotSprited: ~`addToNotRepeatablesNotSprited(@{name})`;\n    }\n}\n\n.notRepeatableBgWithSizes(@name; @newerNotUseSprite: false) {\n    .notRepeatableBg(@name: ''; @newerNotUseSprite: false);\n}\n\n.alphaImage(@name: '') {\n    @notRepeatableBgNamesNotSprited: ~`addToNotRepeatablesNotSprited(@{name})`;\n}\n"
  },
  {
    "path": "src/less/mixins.less",
    "content": "/*\n    Variables:\n        @baseURL\n        @ie8\n        @skinName\n        @imagesBasePath\n\n    Mixins:\n        .imageData\n        .spriteData\n        .isSprited\n*/\n\n.imageData(@name) when (default()) {\n    @filename: '';\n    @extension: '';\n    @hasVectorVersion: false;\n    @width: 0;\n    @height: 0;\n    @originalWidth: 0;\n    @originalHeight: 0;\n}\n\n.isSprited(@name) when (default()) {\n    @isSprited: false;\n}\n\n.dataURIImage(@name) {\n    .imageData(@name);\n\n    & when (@hasVectorVersion) {\n        background-image: data-uri('@{imagesBasePath}/@{filename}.svg');\n    }\n\n    & when not (@hasVectorVersion) {\n        background-image: data-uri('@{imagesBasePath}/@{filename}.@{extension}');\n    }\n}\n\n.directImage(@name) {\n    .imageData(@name);\n\n    background-image: url('@{baseURL}/img/@{filename}.@{extension}');\n    background-size: @originalWidth @originalHeight;\n\n    .leaflet-retina & when not (@extension = 'gif') {\n        background-image: url('@{baseURL}/img/@{filename}@2x.@{extension}');\n    }\n}\n\n.spriteImage(@name) {\n    .spriteData(@name);\n\n    width: @width;\n    height: @height;\n    background-image: url('@{baseURL}/img/@{backgroundImage}');\n    background-position: @backgroundPosition;\n    background-size: @totalWidth @totalHeight;\n\n    .leaflet-retina & {\n        .spriteData('@{name}@2x');\n        background-image: url('@{baseURL}/img/@{backgroundImage}');\n        // Spritesmith при формировании 2x-спрайтов часто располагает изображения в другой последовательности,\n        // поэтому размеры проставляем заново, определённые выше скорей всего не подходят.\n        background-position: @backgroundPositionLeft / 2 @backgroundPositionTop / 2;\n        background-size: @totalWidth / 2 @totalHeight / 2;\n    }\n}\n\n.repeatableBg(@name) {\n    .imageData(@name);\n\n    & when not (@ie8) and (@hasVectorVersion) {\n        .dataURIImage(@name);\n    }\n\n    & when (@ie8), not (@hasVectorVersion) {\n        .directImage(@name);\n    }\n}\n\n.notRepeatableBg(@name; @newerNotUseSprite: false) {\n    background-repeat: no-repeat;\n\n    .imageData(@name);\n\n    & when not (@ie8) and (@hasVectorVersion) {\n        .dataURIImage(@name);\n    }\n\n    & when (@ie8), not (@hasVectorVersion) {\n        .isSprited(@name);\n\n        & when (@isSprited) and not (@newerNotUseSprite) {\n            .spriteImage(@name);\n        }\n\n        & when not (@isSprited), (@newerNotUseSprite) {\n            .directImage(@name);\n        }\n    }\n}\n\n.notRepeatableBgWithSizes(@name; @newerNotUseSprite: false) {\n    .imageData(@name);\n    .isSprited(@name);\n    .notRepeatableBg(@name, @newerNotUseSprite);\n\n    & when not (@ie8) and (@hasVectorVersion) {\n        width: @width;\n        height: @height;\n        background-size: @originalWidth @originalHeight;\n    }\n\n    & when (@ie8), not (@hasVectorVersion) {\n        .isSprited(@name);\n\n        & when not (@isSprited), (@newerNotUseSprite) {\n            width: @width;\n            height: @height;\n        }\n    }\n}\n"
  },
  {
    "path": "src/menu.json",
    "content": "{\n    \"mapsapi\": {\n        \"content\": {\n            \"ru\": {\n                \"title\": \"API карт\",\n                \"uri\": \"maps/ru/quickstart\",\n                \"_src\":\"ru/quickstart/quickstart.md\",\n                \"hide\": false\n            },\n            \"en\": {\n                \"title\": \"Maps API\",\n                \"uri\": \"maps/en/quickstart\",\n                \"_src\":\"en/quickstart/quickstart.md\",\n                \"hide\": false\n            }\n        },\n        \"children\": [\n            {\n                \"content\": {\n                    \"ru\": {\n                        \"title\": \"Быстрый старт\",\n                        \"uri\": \"maps/ru/quickstart\",\n                        \"_src\":\"ru/quickstart/quickstart.md\",\n                        \"hide\": false\n                    },\n                    \"en\": {\n                        \"title\": \"Quick Start\",\n                        \"uri\": \"maps/en/quickstart\",\n                        \"_src\":\"en/quickstart/quickstart.md\",\n                        \"hide\": false\n                    }\n                },\n                \"children\": null\n            },\n            {\n                \"content\": {\n                    \"ru\": {\n                        \"title\": \"Руководство\",\n                        \"uri\": \"maps/ru/manual/dg-loading\",\n                        \"_src\":\"ru/manual/dg-loading.md\",\n                        \"hide\": false\n                    },\n                    \"en\": {\n                        \"title\": \"Manual\",\n                        \"uri\": \"maps/en/manual/dg-loading\",\n                        \"_src\":\"en/manual/dg-loading.md\",\n                        \"hide\": false\n                    }\n                },\n                \"children\": [\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Подключение API\",\n                                \"uri\": \"maps/ru/manual/dg-loading\",\n                                \"_src\":\"ru/manual/dg-loading.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Loading API\",\n                                \"uri\": \"maps/en/manual/dg-loading\",\n                                \"_src\":\"en/manual/dg-loading.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Базовые типы\",\n                                \"uri\": \"maps/ru/manual/basic-types\",\n                                \"_src\":\"ru/manual/basic-types.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Basic Types\",\n                                \"uri\": \"maps/en/manual/basic-types\",\n                                \"_src\":\"en/manual/basic-types.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Базовые классы\",\n                                \"uri\": \"maps/ru/manual/base-classes\",\n                                \"_src\":\"ru/manual/base-classes.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Base Classes\",\n                                \"uri\": \"maps/en/manual/base-classes\",\n                                \"_src\":\"en/manual/base-classes.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Карта\",\n                                \"uri\": \"maps/ru/manual/map\",\n                                \"_src\":\"ru/manual/map.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Map\",\n                                \"uri\": \"maps/en/manual/map\",\n                                \"_src\":\"en/manual/map.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Маркеры\",\n                                \"uri\": \"maps/ru/manual/markers\",\n                                \"_src\":\"ru/manual/markers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Markers\",\n                                \"uri\": \"maps/en/manual/markers\",\n                                \"_src\":\"en/manual/markers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Попапы\",\n                                \"uri\": \"maps/ru/manual/popup\",\n                                \"_src\":\"ru/manual/popup.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Popups\",\n                                \"uri\": \"maps/en/manual/popup\",\n                                \"_src\":\"en/manual/popup.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Подсказки\",\n                                \"uri\": \"maps/ru/manual/dg-label\",\n                                \"_src\":\"ru/manual/dg-label.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Labels\",\n                                \"uri\": \"maps/en/manual/dg-label\",\n                                \"_src\":\"en/manual/dg-label.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Элементы управления\",\n                                \"uri\": \"maps/ru/manual/controls\",\n                                \"_src\":\"ru/manual/controls.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Controls\",\n                                \"uri\": \"maps/en/manual/controls\",\n                                \"_src\":\"en/manual/controls.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Векторные слои\",\n                                \"uri\": \"maps/ru/manual/vector-layers\",\n                                \"_src\":\"ru/manual/vector-layers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Vector Layers\",\n                                \"uri\": \"maps/en/manual/vector-layers\",\n                                \"_src\":\"en/manual/vector-layers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Растровые слои\",\n                                \"uri\": \"maps/ru/manual/raster-layers\",\n                                \"_src\":\"ru/manual/raster-layers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Raster Layers\",\n                                \"uri\": \"maps/en/manual/raster-layers\",\n                                \"_src\":\"en/manual/raster-layers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Прочие слои\",\n                                \"uri\": \"maps/ru/manual/other-layers\",\n                                \"_src\":\"ru/manual/other-layers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Other Layers\",\n                                \"uri\": \"maps/en/manual/other-layers\",\n                                \"_src\":\"en/manual/other-layers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Внешние модули\",\n                                \"uri\": \"maps/ru/manual/dg-external-modules\",\n                                \"_src\":\"ru/manual/dg-external-modules.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"External Modules\",\n                                \"uri\": \"maps/en/manual/dg-external-modules\",\n                                \"_src\":\"en/manual/dg-external-modules.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Линейка\",\n                                \"uri\": \"maps/ru/manual/dg-ruler\",\n                                \"_src\":\"ru/manual/dg-ruler.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Ruler\",\n                                \"uri\": \"maps/en/manual/dg-ruler\",\n                                \"_src\":\"en/manual/dg-ruler.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Метаслои\",\n                                \"uri\": \"maps/ru/manual/dg-metalayers\",\n                                \"_src\":\"ru/manual/dg-metalayers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Meta Layers\",\n                                \"uri\": \"maps/en/manual/dg-metalayers\",\n                                \"_src\":\"en/manual/dg-metalayers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Слой пробок\",\n                                \"uri\": \"maps/ru/manual/dg-traffic\",\n                                \"_src\":\"ru/manual/dg-traffic.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Traffic\",\n                                \"uri\": \"maps/en/manual/dg-traffic\",\n                                \"_src\":\"en/manual/dg-traffic.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Входы в здания\",\n                                \"uri\": \"maps/ru/manual/dg-entrance\",\n                                \"_src\":\"ru/manual/dg-entrance.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Entrances\",\n                                \"uri\": \"maps/en/manual/dg-entrance\",\n                                \"_src\":\"en/manual/dg-entrance.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Определение проекта\",\n                                \"uri\": \"maps/ru/manual/dg-project-detector\",\n                                \"_src\":\"ru/manual/dg-project-detector.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Project Detector\",\n                                \"uri\": \"maps/en/manual/dg-project-detector\",\n                                \"_src\":\"en/manual/dg-project-detector.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Асинхронные запросы\",\n                                \"uri\": \"maps/ru/manual/dg-ajax\",\n                                \"_src\":\"ru/manual/dg-ajax.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Asynchronous Requests\",\n                                \"uri\": \"maps/en/manual/dg-ajax\",\n                                \"_src\":\"en/manual/dg-ajax.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"WKT-формат\",\n                                \"uri\": \"maps/ru/manual/dg-wkt\",\n                                \"_src\":\"ru/manual/dg-wkt.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"WKT\",\n                                \"uri\": \"maps/en/manual/dg-wkt\",\n                                \"_src\":\"en/manual/dg-wkt.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Локализация\",\n                                \"uri\": \"maps/ru/manual/dg-locale\",\n                                \"_src\":\"ru/manual/dg-locale.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Localization\",\n                                \"uri\": \"maps/en/manual/dg-locale\",\n                                \"_src\":\"en/manual/dg-locale.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Вспомогательные классы\",\n                                \"uri\": \"maps/ru/manual/utils\",\n                                \"_src\":\"ru/manual/utils.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Utility\",\n                                \"uri\": \"maps/en/manual/utils\",\n                                \"_src\":\"en/manual/utils.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с DOM\",\n                                \"uri\": \"maps/ru/manual/dom-utils\",\n                                \"_src\":\"ru/manual/dom-utils.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Working with DOM\",\n                                \"uri\": \"maps/en/manual/dom-utils\",\n                                \"_src\":\"en/manual/dom-utils.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Переход на версию 2.0\",\n                                \"uri\": \"maps/ru/manual/dg-migration\",\n                                \"_src\":\"ru/manual/dg-migration.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    }\n                ]\n            },\n            {\n                \"content\": {\n                    \"ru\": {\n                        \"title\": \"Примеры\",\n                        \"uri\": \"maps/ru/examples/base\",\n                        \"_src\":\"ru/examples/base.md\",\n                        \"hide\": false\n                    },\n                    \"en\": {\n                        \"title\": \"Examples\",\n                        \"uri\": \"maps/en/examples/base\",\n                        \"_src\":\"en/examples/base.md\",\n                        \"hide\": false\n                    }\n                },\n                \"children\": [\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Базовое использование\",\n                                \"uri\": \"maps/ru/examples/base\",\n                                \"_src\":\"ru/examples/base.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Basic Usage\",\n                                \"uri\": \"maps/en/examples/base\",\n                                \"_src\":\"en/examples/base.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с маркерами\",\n                                \"uri\": \"maps/ru/examples/markers\",\n                                \"_src\":\"ru/examples/markers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with Markers\",\n                                \"uri\": \"maps/en/examples/markers\",\n                                \"_src\":\"en/examples/markers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с попапами\",\n                                \"uri\": \"maps/ru/examples/popups\",\n                                \"_src\":\"ru/examples/popups.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with Popups\",\n                                \"uri\": \"maps/en/examples/popups\",\n                                \"_src\":\"en/examples/popups.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с границами\",\n                                \"uri\": \"maps/ru/examples/bounds\",\n                                \"_src\":\"ru/examples/bounds.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with Map Bounds\",\n                                \"uri\": \"maps/en/examples/bounds\",\n                                \"_src\":\"en/examples/bounds.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с векторными слоями\",\n                                \"uri\": \"maps/ru/examples/vector-layers\",\n                                \"_src\":\"ru/examples/vector-layers.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with Vector Layers\",\n                                \"uri\": \"maps/en/examples/vector-layers\",\n                                \"_src\":\"en/examples/vector-layers.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Элементы управления\",\n                                \"uri\": \"maps/ru/examples/controls\",\n                                \"_src\":\"ru/examples/controls.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Control Elements\",\n                                \"uri\": \"maps/en/examples/controls\",\n                                \"_src\":\"en/examples/controls.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с GeoJSON\",\n                                \"uri\": \"maps/ru/examples/geojson\",\n                                \"_src\":\"ru/examples/geojson.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with GeoJSON\",\n                                \"uri\": \"maps/en/examples/geojson\",\n                                \"_src\":\"en/examples/geojson.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Работа с WKT\",\n                                \"uri\": \"maps/ru/examples/wkt\",\n                                \"_src\":\"ru/examples/wkt.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Work with WKT\",\n                                \"uri\": \"maps/en/examples/wkt\",\n                                \"_src\":\"en/examples/wkt.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Обработка событий\",\n                                \"uri\": \"maps/ru/examples/events\",\n                                \"_src\":\"ru/examples/events.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"Processing of Events\",\n                                \"uri\": \"maps/en/examples/events\",\n                                \"_src\":\"en/examples/events.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    },\n                    {\n                        \"content\": {\n                            \"ru\": {\n                                \"title\": \"Внешние модули\",\n                                \"uri\": \"maps/ru/examples/external-modules\",\n                                \"_src\":\"ru/examples/external-modules.md\",\n                                \"hide\": false\n                            },\n                            \"en\": {\n                                \"title\": \"External Modules\",\n                                \"uri\": \"maps/en/examples/external-modules\",\n                                \"_src\":\"en/examples/external-modules.md\",\n                                \"hide\": false\n                            }\n                        },\n                        \"children\": null\n                    }\n                ]\n            }\n        ]\n    }\n}\n"
  },
  {
    "path": "test/after.js",
    "content": "// this script will be run after loading js, but before starting tests\nDG.Map.mergeOptions({\n    tilesCheck: false\n});\n\n// Add function for remove all layers on map. Need for tests of leaflet, because we have our layers.\nDG.Map.include({\n    'clearLayers': function() {\n        this.eachLayer(function(layer) {\n            this.removeLayer(layer);\n        }, this);\n    }\n});\n"
  },
  {
    "path": "test/excludedTests.js",
    "content": "// excluded, because L.DG.TileLayer added to the map by default,\n// but leaflet tests think that map without layers and fails\nmodule.exports = [\n    'node_modules/leaflet/spec/suites/core/UtilSpec.js',\n    'node_modules/leaflet/spec/suites/map/MapSpec.js',\n    'node_modules/leaflet/spec/suites/map/handler/Map.DragSpec.js',\n    'node_modules/leaflet/spec/suites/layer/tile/GridLayerSpec.js',\n    'node_modules/leaflet/spec/suites/layer/PopupSpec.js',\n    'node_modules/leaflet/spec/suites/layer/vector/CanvasSpec.js',\n    'node_modules/leaflet/spec/suites/layer/marker/Icon.DefaultSpec.js',\n    'node_modules/leaflet/spec/suites/layer/TooltipSpec.js',\n    'node_modules/leaflet/spec/suites/layer/vector/PathSpec.js'\n];\n"
  },
  {
    "path": "test/karma.conf.js",
    "content": "require('dotenv').config();\nmodule.exports = function(config) {\n    config.set({\n        basePath: '../',\n\n        frameworks: ['mocha', 'expect', 'sinon'],\n\n        client: {\n            captureConsole: true,\n            mocha: {\n                timeout: 480000\n            },\n            secretKey: process.env.TEST_SECRET_KEY || '',\n            secretInvalidKey: process.env.TEST_REACHED_LIMITS_SECRET_KEY  || ''\n        },\n\n        // use dots reporter, as travis terminal does not support escaping sequences\n        // possible values: 'dots', 'progress', 'junit', 'teamcity'\n        // CLI --reporters progress\n        reporters: ['dots', 'coverage'],\n\n        coverageReporter: {\n            type : 'lcov',\n            dir : 'coverage/',\n            subdir: '.'\n        },\n\n        // web server port\n        // CLI --port 9876\n        port: 9876,\n\n        // cli runner port\n        // CLI --runner-port 9100\n        runnerPort: 9100,\n\n        // enable / disable colors in the output (reporters and logs)\n        // CLI --colors --no-colors\n        colors: true,\n\n        // level of logging\n        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG\n        // CLI --log-level debug\n        logLevel: config.LOG_ERROR,\n\n        // enable / disable watching file and executing test whenever any file changes\n        // CLI --auto-watch --no-auto-watch\n        autoWatch: true,\n\n        // Start these browsers, currently available:\n        // - Chrome\n        // - ChromeCanary\n        // - Firefox\n        // - Opera\n        // - Safari (only Mac)\n        // - PhantomJS\n        // - IE (only Windows)\n        // CLI --browsers Chrome,Firefox,Safari\n        browsers: ['PhantomJS'],\n\n        // If browser does not capture in given timeout [ms], kill it\n        // CLI --capture-timeout 5000\n        captureTimeout: 480000,\n        browserNoActivityTimeout: 480000,\n\n        // Auto run test on start (when browsers are captured) and exit\n        // CLI --single-run --no-single-run\n        singleRun: false,\n\n        // report which specs are slower than 500ms\n        // CLI --report-slower-than 1000\n        reportSlowerThan: 1000,\n\n        plugins: [\n            'karma-mocha',\n            'karma-expect',\n            'karma-sinon',\n            'karma-phantomjs-launcher',\n            'karma-chrome-launcher',\n            'karma-opera-launcher',\n            'karma-firefox-launcher',\n            'karma-mocha-reporter',\n            'karma-coverage'\n        ]\n    });\n};\n"
  },
  {
    "path": "test/test.js",
    "content": "var argv = require('optimist').argv;\n\nexports.getBrowsers = function() {\n    var browsers = ['PhantomJS'];\n\n    if (argv.hasOwnProperty('ff')) {\n        browsers.push('Firefox');\n    }\n    if (argv.hasOwnProperty('chrome')) {\n        browsers.push('Chrome');\n    }\n    if (argv.hasOwnProperty('opera')) {\n        browsers.push('Opera');\n    }\n    if (argv.hasOwnProperty('safari')) {\n        browsers.push('Safari');\n    }\n    if (argv.hasOwnProperty('ie')) {\n        browsers.push('IE');\n    }\n\n    return browsers;\n};\n\nexports.getReporters = function(isDebug) {\n    var reporters = isDebug ? ['mocha'] : ['dots'];\n\n    reporters.push('coverage');\n\n    if (argv.hasOwnProperty('reporters')) {\n        reporters = argv.reporters.split(',');\n    }\n\n    return reporters;\n};\n\nexports.getJunitReporter = function() {\n    var junitReporter = {};\n\n    if (argv.hasOwnProperty('junitOutput')) {\n        junitReporter['outputFile'] = argv.junitOutput;\n    }\n\n    return junitReporter;\n};\n"
  },
  {
    "path": "vendors/baron/Gruntfile.js",
    "content": "module.exports = function (grunt) {\n\n    grunt.initConfig({\n        pkg: grunt.file.readJSON('package.json'),\n        jshint: {\n            appjs: {\n                options: {\n                    \"indent\": 4,\n                    \"node\": true,\n                    \"browser\": true,\n                    \"jquery\": true,\n                    \"eqnull\": true,\n                    \"eqeqeq\": false,\n                    \"devel\": false,\n                    \"boss\": true,\n                    \"trailing\": true,\n                    \"loopfunc\": true,\n                    \"-W041\": true,\n                    \"-W015\": true,\n                    \"sub\": true,\n                    \"unused\": true\n                },\n                src: ['src/*.js', 'demo/*.js', 'test/*.js']\n            }\n        },\n        concat: {\n            def: {\n                files: {\n                    'dist/<%= pkg.name %>.js': ['src/core.js', 'src/fix.js', 'src/controls.js', 'src/pull.js'],\n                    '<%= pkg.name %>.js': ['src/core.js', 'src/fix.js', 'src/controls.js', 'src/pull.js']\n                }\n            },\n            core: {\n                src: [\n                    'src/core.js'\n                ],\n                dest: 'dist/<%= pkg.name %>.js'\n            },\n            full: {\n                files: {\n                    'dist/<%= pkg.name %>.js': ['src/core.js', 'src/fix.js', 'src/controls.js', 'src/test.js', 'src/pull.js'],\n                    'demo/<%= pkg.name %>.full.js': ['src/core.js', 'src/fix.js', 'src/controls.js', 'src/test.js', 'src/pull.js']\n                }\n            }\n        },\n        uglify: {\n            options: {\n                banner: '/*! <%= pkg.name %> <%= grunt.template.today(\"dd-mm-yyyy\") %> */\\n'\n            },\n            def: {\n                files: {\n                    'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.js'],\n                    '<%= pkg.name %>.min.js': ['<%= pkg.name %>.js']\n                }\n            },\n            core: {\n                files: {\n                    'dist/<%= pkg.name %>.min.js': ['<%= concat.core.dest %>'],\n                    '<%= pkg.name %>.min.js': ['<%= concat.core.dest %>']\n                }\n            },\n            full: {\n                files: {\n                    'dist/<%= pkg.name %>.min.js': ['dist/<%= pkg.name %>.js'],\n                    '<%= pkg.name %>.min.js': ['<%= pkg.name %>.js']\n                }\n            }\n        },\n        'mocha-phantomjs': {\n            options: {\n                view: '1024x768'\n            },\n            all: ['test/*.auto.html']\n        }\n    });\n\n    grunt.loadTasks('tasks'); // Для grunt-mocha-phantomjs\n    grunt.loadNpmTasks('grunt-contrib-jshint');\n    grunt.loadNpmTasks('grunt-contrib-uglify');\n    grunt.loadNpmTasks('grunt-contrib-concat');\n\n    grunt.registerTask('default', ['concat:def', 'uglify:def']);\n    grunt.registerTask('core', ['concat:core', 'uglify:core']);\n    grunt.registerTask('full', ['concat:full', 'uglify:full']);\n    grunt.registerTask('test', ['mocha-phantomjs']);\n    grunt.registerTask('t', ['jshint', 'mocha-phantomjs']);\n};"
  },
  {
    "path": "vendors/baron/baron.css",
    "content": "/* CSS styles in this file are need for proper Baron work */\n.dg-wrapper {\n    position: relative;\n    overflow: hidden;\n}\n.dg-scroller {\n    height: 100%;\n    overflow-y: scroll;\n    border: 0;\n}\n.dg-scroller::-webkit-scrollbar { /* Preventing webkit bug of horizontal scrolling */\n    width: 0;\n}\n.dg-scroller__bar { /* The bar. You should define width, right and background */\n    position: absolute;    \n    z-index: 1;\n    right: 0;\n    width: 10px;\n    background: #999;\n}\n.dg-scroller__bar_h {\n    bottom: 2px;\n    height: 8px;\n}\n\n.dg-header__title {\n    width: 100%;\n    margin: 0;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box; /* For padding and border, if exist */\n    background: #999;\n\n    /* pointer-events: none; /* IE9+ https://developer.mozilla.org/en-US/docs/CSS/pointer-events */\n}\n.dg-header__title_state_fixed {\n    position: absolute;\n    z-index: 1; /* Removing flicker effect */\n}\n"
  },
  {
    "path": "vendors/baron/baron.js",
    "content": "(function(window, undefined) {\n    'use strict';\n\n    if (!window) return; // Server side\n\nvar\n    _baron = window.baron, // Stored baron value for noConflict usage\n    $ = window.jQuery, // Trying to use jQuery\n    origin = {\n        v: { // Vertical\n            x: 'Y', pos: 'top', crossPos: 'left', size: 'height', crossSize: 'width',\n            client: 'clientHeight', crossClient: 'clientWidth', offset: 'offsetHeight', crossOffset: 'offsetWidth', offsetPos: 'offsetTop',\n            scroll: 'scrollTop', scrollSize: 'scrollHeight'\n        },\n        h: { // Horizontal\n            x: 'X', pos: 'left', crossPos: 'top', size: 'width', crossSize: 'height',\n            client: 'clientWidth', crossClient: 'clientHeight', offset: 'offsetWidth', crossOffset: 'offsetHeight', offsetPos: 'offsetLeft',\n            scroll: 'scrollLeft', scrollSize: 'scrollWidth'\n        }\n    },\n\n    each = function(obj, iterator) {\n        var i = 0;\n\n        if (obj.length === undefined || obj === window) obj = [obj];\n\n        while (obj[i]) {\n            iterator.call(this, obj[i], i);\n            i++;\n        }\n    },\n\n    baron = function(params) { // this - window or jQuery instance\n        var jQueryMode = false,//(this && this[0] && this[0].nodeType),\n            roots,\n            $;\n\n        params = params || {};\n        $ = params.$ || window.jQuery;\n\n        if (jQueryMode) {\n            params.root = roots = this;\n        } else {\n            roots = $(params.root || params.scroller);\n        }\n\n        return new baron.fn.constructor(roots, params, $);\n    };\n\n    baron.fn = {\n        constructor: function(roots, input, $) {\n            var params = validate(input);\n\n            params.$ = $;\n            each.call(this, roots, function(root, i) {\n                var localParams = clone(params);\n\n                if (params.root && params.scroller) {\n                    localParams.scroller = params.$(params.scroller, root);\n                    if (!localParams.scroller.length) {\n                        localParams.scroller = root;\n                    }\n                } else {\n                    localParams.scroller = root;\n                }\n\n                localParams.root = root;\n                this[i] = init(localParams);\n                this.length = i + 1;\n            });\n\n            this.params = params;\n        },\n\n        dispose: function() {\n            var params = this.params;\n\n            each(this, function(item) {\n                item.dispose(params);\n            });\n            this.params = null;\n        },\n\n        update: function() {\n            var i = 0;\n\n            while (this[i]) {\n                this[i].update.apply(this[i], arguments);\n                i++;\n            }\n        },\n\n        baron: function(params) {\n            params.root = [];\n            params.scroller = this.params.scroller;\n\n            each.call(this, this, function(elem) {\n                params.root.push(elem.root);\n            });\n            params.direction = (this.params.direction == 'v') ? 'h' : 'v';\n            params._chain = true;\n\n            return baron(params);\n        }\n    };\n\n    function manageEvents(item, eventManager, mode) {\n        item._eventHandlers = item._eventHandlers || [ // Creating new functions for one baron item only one time\n            {\n                // onScroll:\n                element: item.scroller,\n\n                handler: function(e) {\n                    item.scroll(e);\n                },\n\n                type: 'scroll'\n            }, {\n                // onMouseDown:\n                element: item.bar,\n\n                handler: function(e) {\n                    e.preventDefault ? e.preventDefault() : e.returnValue = false; // Text selection disabling in Opera... and all other browsers?\n                    item.selection(); // Disable text selection in ie8\n                    item.drag.now = 1; // Save private byte\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseUp:\n                element: document,\n\n                handler: function() {\n                    item.selection(1); // Enable text selection\n                    item.drag.now = 0;\n                },\n\n                type: 'mouseup blur touchend'\n            }, {\n                // onCoordinateReset:\n                element: item.bar,\n\n                handler: function(e) {\n                    if (e.button != 2) { // Not RM\n                        item._pos0(e);\n                    }\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseMove:\n                element: document,\n\n                handler: function(e) {\n                    if (item.drag.now) {\n                        item.drag(e);\n                    }\n                },\n\n                type: 'mousemove touchmove'\n            }, {\n                // onResize:\n                element: window,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'resize'\n            }, {\n                // sizeChange:\n                element: item.root,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'sizeChange'\n            }\n        ];\n\n        each(item._eventHandlers, function(event) {\n            if (event.element) {\n                eventManager(event.element, event.type, event.handler, mode);\n            }\n        });\n\n        // if (item.scroller) {\n        //     event(item.scroller, 'scroll', item._eventHandlers.onScroll, mode);\n        // }\n        // if (item.bar) {\n        //     event(item.bar, 'touchstart mousedown', item._eventHandlers.onMouseDown, mode);\n        // }\n        // event(document, 'mouseup blur touchend', item._eventHandlers.onMouseUp, mode);\n        // event(document, 'touchstart mousedown', item._eventHandlers.onCoordinateReset, mode);\n        // event(document, 'mousemove touchmove', item._eventHandlers.onMouseMove, mode);\n        // event(window, 'resize', item._eventHandlers.onResize, mode);\n        // if (item.root) {\n        //     event(item.root, 'sizeChange', item._eventHandlers.onResize, mode); // Custon event for alternate baron update mechanism\n        // }\n    }\n\n    function manageAttr(node, direction, mode) {\n        var attrName = 'data-baron-' + direction;\n\n        if (mode == 'on') {\n            node.setAttribute(attrName, 'inited');\n        } else if (mode == 'off') {\n            node.removeAttribute(attrName);\n        } else {\n            return node.getAttribute(attrName);\n        }\n    }\n\n    function init(params) {\n        if (manageAttr(params.root, params.direction)) return;\n\n        var out = new item.prototype.constructor(params); // __proto__ of returning object is baron.prototype\n\n        manageEvents(out, params.event, 'on');\n\n        manageAttr(out.root, params.direction, 'on');\n\n        out.update();\n\n        return out;\n    }\n\n    function clone(input) {\n        var output = {};\n\n        input = input || {};\n\n        for (var key in input) {\n            if (input.hasOwnProperty(key)) {\n                output[key] = input[key];\n            }\n        }\n\n        return output;\n    }\n\n    function validate(input) {\n        var output = clone(input);\n\n        output.direction = output.direction || 'v';\n\n        var event = input.event || function(elem, event, func, mode) {\n            output.$(elem)[mode || 'on'](event, func);\n        };\n\n        output.event = function(elems, e, func, mode) {\n            each(elems, function(elem) {\n                event(elem, e, func, mode);\n            });\n        };\n\n        return output;\n    }\n\n    function fire(eventName) {\n        /* jshint validthis:true */\n        if (this.events && this.events[eventName]) {\n            for (var i = 0 ; i < this.events[eventName].length ; i++) {\n                var args = Array.prototype.slice.call( arguments, 1 );\n\n                this.events[eventName][i].apply(this, args);\n            }\n        }\n    }\n\n    var item = {};\n\n    item.prototype = {\n        constructor: function(params) {\n            var $,\n                barPos,\n                scrollerPos0,\n                track,\n                resizePauseTimer,\n                scrollPauseTimer,\n                pause,\n                scrollLastFire,\n                resizeLastFire;\n\n            resizeLastFire = scrollLastFire = new Date().getTime();\n\n            $ = this.$ = params.$;\n            this.event = params.event;\n            this.events = {};\n\n            function getNode(sel, context) {\n                return $(sel, context)[0]; // Can be undefined\n            }\n\n            // DOM elements\n            this.root = params.root; // Always html node, not just selector\n            this.scroller = getNode(params.scroller); // (params.scroller) ? getNode(params.scroller, this.root) : this.root;\n            this.bar = getNode(params.bar, this.root);\n            track = this.track = getNode(params.track, this.root);\n            if (!this.track && this.bar) {\n                track = this.bar.parentNode;\n            }\n            this.clipper = this.scroller.parentNode;\n\n            // Parameters\n            this.direction = params.direction;\n            this.origin = origin[this.direction];\n            this.barOnCls = params.barOnCls;\n            this.barTopLimit = 0;\n            pause = params.pause * 1000 || 0;\n\n            // Updating height or width of bar\n            function setBarSize(size) {\n                /* jshint validthis:true */\n                var barMinSize = this.barMinSize || 20;\n\n                if (size > 0 && size < barMinSize) {\n                    size = barMinSize;\n                }\n\n                if (this.bar) {\n                    $(this.bar).css(this.origin.size, parseInt(size, 10) + 'px');\n                }\n            }\n\n            // Updating top or left bar position\n            function posBar(pos) {\n                /* jshint validthis:true */\n                if (this.bar) {\n                    $(this.bar).css(this.origin.pos, +pos + 'px');\n                }\n            }\n\n            // Free path for bar\n            function k() {\n                /* jshint validthis:true */\n                return track[this.origin.client] - this.barTopLimit - this.bar[this.origin.offset];\n            }\n\n            // Relative content top position to bar top position\n            function relToPos(r) {\n                /* jshint validthis:true */\n                return r * k.call(this) + this.barTopLimit;\n            }\n\n            // Bar position to relative content position\n            function posToRel(t) {\n                /* jshint validthis:true */\n                return (t - this.barTopLimit) / k.call(this);\n            }\n\n            // Cursor position in main direction in px // Now with iOs support\n            this.cursor = function(e) {\n                return e['client' + this.origin.x] || (((e.originalEvent || e).touches || {})[0] || {})['page' + this.origin.x];\n            };\n\n            // Text selection pos preventing\n            function dontPosSelect() {\n                return false;\n            }\n\n            this.pos = function(x) { // Absolute scroller position in px\n                var ie = 'page' + this.origin.x + 'Offset',\n                    key = (this.scroller[ie]) ? ie : this.origin.scroll;\n\n                if (x !== undefined) this.scroller[key] = x;\n\n                return this.scroller[key];\n            };\n\n            this.rpos = function(r) { // Relative scroller position (0..1)\n                var free = this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client],\n                    x;\n\n                if (r) x = this.pos(r * free);\n                else x = this.pos();\n\n                return x / (free || 1);\n            };\n\n            // Switch on the bar by adding user-defined CSS classname to scroller\n            this.barOn = function(dispose) {\n                if (this.barOnCls) {\n                    if (dispose || this.scroller[this.origin.client] >= this.scroller[this.origin.scrollSize]) {\n                        $(this.root).removeClass(this.barOnCls);\n                    } else {\n                        $(this.root).addClass(this.barOnCls);\n                    }\n                }\n            };\n\n            this._pos0 = function(e) {\n                scrollerPos0 = this.cursor(e) - barPos;\n            };\n\n            this.drag = function(e) {\n                this.scroller[this.origin.scroll] = posToRel.call(this, this.cursor(e) - scrollerPos0) * (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]);\n            };\n\n            // Text selection preventing on drag\n            this.selection = function(enable) {\n                this.event(document, 'selectpos selectstart', dontPosSelect, enable ? 'off' : 'on');\n            };\n\n            // onResize & DOM modified handler\n            this.resize = function() {\n                var self = this,\n                    delay = 0;\n\n                if (new Date().getTime() - resizeLastFire < pause) {\n                    clearTimeout(resizePauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    var delta = self.scroller[self.origin.crossOffset] - self.scroller[self.origin.crossClient];\n\n                    if (params.freeze && !self.clipper.style[self.origin.crossSize]) { // Sould fire only once\n                        $(self.clipper).css(self.origin.crossSize, self.clipper[self.origin.crossClient] - delta + 'px');\n                    }\n                    $(self.scroller).css(self.origin.crossSize, self.clipper[self.origin.crossClient] + delta + 'px');\n\n                    Array.prototype.unshift.call(arguments, 'resize');\n                    fire.apply(self, arguments);\n\n                    resizeLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    resizePauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n            };\n\n            // onScroll handler\n            this.scroll = function() {\n                var oldBarSize, newBarSize,\n                    delay = 0,\n                    self = this;\n\n                if (new Date().getTime() - scrollLastFire < pause) {\n                    clearTimeout(scrollPauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    if (self.bar) {\n                        newBarSize = (track[self.origin.client] - self.barTopLimit) * self.scroller[self.origin.client] / self.scroller[self.origin.scrollSize];\n\n                        // Positioning bar\n                        if (oldBarSize != newBarSize) {\n                            setBarSize.call(self, newBarSize);\n                            oldBarSize = newBarSize;\n                        }\n\n                        barPos = relToPos.call(self, self.rpos());\n\n                        posBar.call(self, barPos);\n                    }\n\n                    Array.prototype.unshift.call( arguments, 'scroll' );\n                    fire.apply(self, arguments);\n\n                    scrollLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    scrollPauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n\n            };\n\n            return this;\n        },\n\n        update: function(params) {\n            fire.call(this, 'upd', params); // Обновляем параметры всех плагинов\n\n            this.resize(1);\n            this.barOn();\n            this.scroll();\n\n            return this;\n        },\n\n        dispose: function(params) {\n            manageEvents(this, this.event, 'off');\n            manageAttr(this.root, params.direction, 'off');\n            $(this.scroller).css(this.origin.crossSize, '');\n            this.barOn(true);\n            fire.call(this, 'dispose');\n        },\n\n        on: function(eventName, func, arg) {\n            var names = eventName.split(' ');\n\n            for (var i = 0 ; i < names.length ; i++) {\n                if (names[i] == 'init') {\n                    func.call(this, arg);\n                } else {\n                    this.events[names[i]] = this.events[names[i]] || [];\n\n                    this.events[names[i]].push(function(userArg) {\n                        func.call(this, userArg || arg);\n                    });\n                }\n            }\n        }\n    };\n\n    baron.fn.constructor.prototype = baron.fn;\n    item.prototype.constructor.prototype = item.prototype;\n\n    // Use when you need \"baron\" global var for another purposes\n    baron.noConflict = function() {\n        window.baron = _baron; // Restoring original value of \"baron\" global var\n        return baron;\n    };\n\n    baron.version = '0.6.6';\n\n    if ($ && $.fn) { // Adding baron to jQuery as plugin\n        $.fn.baron = baron;\n    }\n    window.baron = baron; // Use noConflict method if you need window.baron var for another purposes\n\n    var fix = function(userParams) {\n        var elements, viewPortSize,\n            params = { // Default params\n                outside: '',\n                before: '',\n                after: '',\n                past: '',\n                future: '',\n                radius: 0,\n                minView: 0\n            },\n            topFixHeights = [], // inline style for element\n            topRealHeights = [], // real offset position when not fixed\n            headerTops = [],\n            scroller = this.scroller,\n            eventManager = this.event,\n            $ = this.$,\n            self = this;\n\n        function fixElement(i, pos) {\n            if (viewPortSize < (params.minView || 0)) { // No headers fixing when no enought space for viewport\n                pos = undefined;\n            }\n\n            if (pos !== undefined) {\n                pos += 'px';\n                this.$(elements[i]).css(this.origin.pos, pos).addClass(params.outside);\n            } else {\n                this.$(elements[i]).css(this.origin.pos, '').removeClass(params.outside);\n            }\n        }\n\n        function bubbleWheel(e) {\n            try {\n                i = document.createEvent('WheelEvent'); // i - for extra byte\n                // evt.initWebKitWheelEvent(deltaX, deltaY, window, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);\n                i.initWebKitWheelEvent(e.originalEvent.wheelDeltaX, e.originalEvent.wheelDeltaY);\n                scroller.dispatchEvent(i);\n                e.preventDefault();\n            } catch (e) {}\n        }\n\n        function init(_params) {\n            var pos;\n\n            for (var key in _params) {\n                params[key] = _params[key];\n            }\n\n            elements = this.$(params.elements, this.scroller);\n\n            if (elements) {\n                viewPortSize = this.scroller[this.origin.client];\n                for (var i = 0 ; i < elements.length ; i++) {\n                    // Variable header heights\n                    pos = {};\n                    pos[this.origin.size] = elements[i][this.origin.offset];\n                    if (elements[i].parentNode !== this.scroller) {\n                        this.$(elements[i].parentNode).css(pos);\n                    }\n                    pos = {};\n                    pos[this.origin.crossSize] = elements[i].parentNode[this.origin.crossClient];\n                    this.$(elements[i]).css(pos);\n\n                    // Between fixed headers\n                    viewPortSize -= elements[i][this.origin.offset];\n\n                    headerTops[i] = elements[i].parentNode[this.origin.offsetPos]; // No paddings for parentNode\n\n                    // Summary elements height above current\n                    topFixHeights[i] = (topFixHeights[i - 1] || 0); // Not zero because of negative margins\n                    topRealHeights[i] = (topRealHeights[i - 1] || Math.min(headerTops[i], 0));\n\n                    if (elements[i - 1]) {\n                        topFixHeights[i] += elements[i - 1][this.origin.offset];\n                        topRealHeights[i] += elements[i - 1][this.origin.offset];\n                    }\n\n                    if ( !(i == 0 && headerTops[i] == 0)/* && force */) {\n                        this.event(elements[i], 'mousewheel', bubbleWheel, 'off');\n                        this.event(elements[i], 'mousewheel', bubbleWheel);\n                    }\n                }\n\n                if (params.limiter && elements[0]) { // Bottom edge of first header as top limit for track\n                    if (this.track && this.track != this.scroller) {\n                        pos = {};\n                        pos[this.origin.pos] = elements[0].parentNode[this.origin.offset];\n                        this.$(this.track).css(pos);\n                    } else {\n                        this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    }\n                    // this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    this.scroll();\n                }\n\n                if (params.limiter === false) { // undefined (in second fix instance) should have no influence on bar limit\n                    this.barTopLimit = 0;\n                }\n            }\n\n            var event = {\n                element: elements,\n\n                handler: function() {\n                    var parent = $(this)[0].parentNode,\n                        top = parent.offsetTop,\n                        num;\n\n                    // finding num -> elements[num] === this\n                    for (var i = 0 ; i < elements.length ; i++ ) {\n                        if (elements[i] === this) num = i;\n                    }\n\n                    var pos = top - topFixHeights[num];\n\n                    if (params.scroll) { // User defined callback\n                        params.scroll({\n                            x1: self.scroller.scrollTop,\n                            x2: pos\n                        });\n                    } else {\n                        self.scroller.scrollTop = pos;\n                    }\n                },\n\n                type: 'click'\n            };\n\n            if (params.clickable) {\n                this._eventHandlers.push(event); // For auto-dispose\n                eventManager(event.element, event.type, event.handler, 'off');\n                eventManager(event.element, event.type, event.handler, 'on');\n            }\n        }\n\n        this.on('init', init, userParams);\n\n        this.on('init scroll', function() {\n            var fixState, hTop,\n                fixFlag = []; // 1 - past, 2 - future, 3 - current (not fixed)\n\n            if (elements) {\n                var change;\n\n                // fixFlag update\n                for (var i = 0 ; i < elements.length ; i++) {\n                    fixState = 0;\n                    if (headerTops[i] - this.pos() < topRealHeights[i] + params.radius) {\n                        // Header trying to go up\n                        fixState = 1;\n                        hTop = topFixHeights[i];\n                    } else if (headerTops[i] - this.pos() > topRealHeights[i] + viewPortSize - params.radius) {\n                        // Header trying to go down\n                        fixState = 2;\n                        hTop = topFixHeights[i] + viewPortSize;\n                    } else {\n                        // Header in viewport\n                        fixState = 3;\n                        hTop = undefined;\n                    }\n                    if (fixState != fixFlag[i]) {\n                        fixElement.call(this, i, hTop);\n                        fixFlag[i] = fixState;\n                        change = true;\n                    }\n                }\n\n                // Adding positioning classes (on last top and first bottom header)\n                if (change) { // At leats one change in elements flag structure occured\n                    for (i = 0 ; i < elements.length ; i++) {\n                        if (fixFlag[i] == 1 && params.past) {\n                            this.$(elements[i]).addClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] == 2 && params.future) {\n                            this.$(elements[i]).addClass(params.future).removeClass(params.past);\n                        }\n\n                        if (fixFlag[i] == 3 && (params.future || params.past)) {\n                            this.$(elements[i]).removeClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] != fixFlag[i + 1] && fixFlag[i] == 1 && params.before) {\n                            this.$(elements[i]).addClass(params.before).removeClass(params.after); // Last top fixed header\n                        } else if (fixFlag[i] != fixFlag[i - 1] && fixFlag[i] == 2 && params.after) {\n                            this.$(elements[i]).addClass(params.after).removeClass(params.before); // First bottom fixed header\n                        } else {\n                            this.$(elements[i]).removeClass(params.before).removeClass(params.after);\n                        }\n                    }\n                }\n            }\n        });\n\n        this.on('resize upd', function(updParams) {\n            init.call(this, updParams && updParams.fix);\n        });\n    };\n\n    baron.fn.fix = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            fix.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n\n    var controls = function(params) {\n        var forward, backward, track, screen,\n            self = this; // AAAAAA!!!!!11\n\n        screen = params.screen || 0.9;\n\n        if (params.forward) {\n            forward = this.$(params.forward, this.clipper);\n\n            this.event(forward, 'click', function() {\n                var y = self.pos() - params.delta || 30;\n\n                self.pos(y);\n            });\n        }\n\n        if (params.backward) {\n            backward = this.$(params.backward, this.clipper);\n\n            this.event(backward, 'click', function() {\n                var y = self.pos() + params.delta || 30;\n\n                self.pos(y);\n            });\n        }\n\n        if (params.track) {\n            if (params.track === true) {\n                track = this.track;\n            } else {\n                track = this.$(params.track, this.clipper)[0];\n            }\n\n            if (track) {\n                this.event(track, 'mousedown', function(e) {\n                    var x = e['offset' + self.origin.x],\n                        xBar = self.bar[self.origin.offsetPos],\n                        sign = 0;\n\n                    if (x < xBar) {\n                        sign = -1;\n                    } else if (x > xBar + self.bar[self.origin.offset]) {\n                        sign = 1;\n                    }\n\n                    var y = self.pos() + sign * screen * self.scroller[self.origin.client];\n                    self.pos(y);\n                });\n            }\n        }\n\n    };\n\n    baron.fn.controls = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            controls.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n\n    var pull = function(params) {\n        var block = this.$(params.block),\n            size = params.size || this.origin.size,\n            limit = params.limit || 80,\n            onExpand = params.onExpand,\n            elements = params.elements || [],\n            inProgress = params.inProgress || '',\n            self = this,\n            _insistence = 0,\n            _zeroXCount = 0,\n            _interval,\n            _timer,\n            _x = 0,\n            _onExpandCalled,\n            _waiting = params.waiting || 500,\n            _on;\n\n        function getSize() {\n            return self.scroller[self.origin.scroll] + self.scroller[self.origin.offset];\n        }\n\n        // Scroller content height\n        function getContentSize() {\n            return self.scroller[self.origin.scrollSize];\n        }\n\n        // Scroller height\n        function getScrollerSize() {\n            return self.scroller[self.origin.client];\n        }\n\n        function step(x, force) {\n            var k = x * 0.0005;\n\n            return Math.floor(force - k * (x + 550));\n        }\n\n        function toggle(on) {\n            _on = on;\n\n            if (on) {\n                update(); // First time with no delay\n                _interval = setInterval(update, 200);\n            } else {\n                clearInterval(_interval);\n            }\n        }\n\n        function update() {\n            var pos = {},\n                height = getSize(),\n                scrollHeight = getContentSize(),\n                dx,\n                op4,\n                scrollInProgress = _insistence == 1;\n\n            op4 = 0; // Возвращающая сила\n            if (_insistence > 0) {\n                op4 = 40;\n            }\n            //if (_insistence > -1) {\n                dx = step(_x, op4);\n                if (height >= scrollHeight - _x && _insistence > -1) {\n                    if (scrollInProgress) {\n                        _x += dx;\n                    }\n                } else {\n                    _x = 0;\n                }\n\n                if (_x < 0) _x = 0;\n\n                pos[size] = _x + 'px';\n                if (getScrollerSize() <= getContentSize()) {\n                    self.$(block).css(pos);\n                    for (var i = 0 ; i < elements.length ; i++) {\n                        self.$(elements[i].self).css(elements[i].property, Math.min(_x / limit * 100, 100) + '%');\n                    }\n                }\n\n                if (inProgress && _x) {\n                    self.$(self.root).addClass(inProgress);\n                }\n\n                if (_x == 0) {\n                    if (params.onCollapse) {\n                        params.onCollapse();\n                    }\n                }\n\n                _insistence = 0;\n                _timer = setTimeout(function() {\n                    _insistence = -1;\n                }, _waiting);\n            //}\n\n            if (onExpand && _x > limit && !_onExpandCalled) {\n                onExpand();\n                _onExpandCalled = true;\n            }\n\n            if (_x == 0) {\n                _zeroXCount++;\n            } else {\n                _zeroXCount = 0;\n\n            }\n            if (_zeroXCount > 1) {\n                toggle(false);\n                _onExpandCalled = false;\n                if (inProgress) {\n                    self.$(self.root).removeClass(inProgress);\n                }\n            }\n        }\n\n        this.on('init', function() {\n            toggle(true);\n        });\n\n        this.on('dispose', function() {\n            toggle(false);\n        });\n\n        this.event(this.scroller, 'mousewheel DOMMouseScroll', function(e) {\n            var down = e.wheelDelta < 0 || (e.originalEvent && e.originalEvent.wheelDelta < 0) || e.detail > 0;\n\n            if (down) {\n                _insistence = 1;\n                clearTimeout(_timer);\n                if (!_on && getSize() >= getContentSize()) {\n                    toggle(true);\n                }\n            }\n            //  else {\n            //     toggle(false);\n            // }\n        });\n    };\n\n    baron.fn.pull = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            pull.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);\n"
  },
  {
    "path": "vendors/baron/changelog.md",
    "content": "## 0.6.2\n\n- dispose method added (to free memory and remove event listeners when scroller removed from dom)\n\n## 0.6.0\n\ncore:\n- Plugin system added (alpha version)\n- fixable headers moved to 'fix' plugin\n- 'grunt full' now includes test plugin to build\n- 'u' method renamed to 'update'\n- 0.2s delay for update on resize event removed (use 'pause' param instead)\n\nparams change\n- 'bar' default value now 'undefined' (!)\n- '$' param added, default value: window.jQuery\n- 'dom' and 'selector' params removed\n- 'direction' ['v', 'h'] param added, default value: 'v'.\n- 'freeze' param added: size of scroller parent freezes at initialization, if true\n- 'pause' param added: use it on slow hardware to limit event trigger frequency (minimum time delay between two triggers in seconds)\n- all params for fixable headers moved to 'fix' plugin\n\nfix plugin:\n- 'header' param renamed to 'elements'\n- 'hFixCls' param renamed to 'outside'\n- 'hBeforeFixCls' param renamed to 'before'\n- 'hAfterFixCls' param renamed to 'after'\n- 'fixRadius' param renamed to 'radius'\n- 'trackSmartLim' param renamed to 'limiter'\n\nplugins:\n- 'controls' plugin added\n- 'test' plugin added\n\n## 0.5.0\n\n- Horizontal scroll support\n- Textarea support\n- Dev build added (with error console messages)\n\n## 0.4.0\n\nImprovements\n\n- Grunt task runner for build customization added\n- root var removed (use scroller param instead)\n- barOnCls now applied to scroller, not the bar\n- trackSmartLim param added (if true bottom edge of first header uses as bar top limit)\n- fixRadius param added\n- Variable (tex-dependent) headers heights support added\n- noConflict method added\n\nBugs\n\n- Right click drag bug fixed\n- Update method now invalidates bar visibility\n- Margin collapse and positioned elements bug fixed\n\nMisc\n\n- heightChange custom event renamed to sizeChange\n- container param removed\n- hTopFixCls param renamed to hBeforeFixCls\n- hBottomFixCls param renamed to hAfterFixCls\n- barTop param removed\n- \"require()\" support added\n- Server-side \"usage\" handler added"
  },
  {
    "path": "vendors/baron/demo/baron.full.js",
    "content": "(function(window, undefined) {\n    'use strict';\n\n    if (!window) return; // Server side\n\nvar\n    _baron = window.baron, // Stored baron value for noConflict usage\n    $ = window.jQuery, // Trying to use jQuery\n    origin = {\n        v: { // Vertical\n            x: 'Y', pos: 'top', crossPos: 'left', size: 'height', crossSize: 'width',\n            client: 'clientHeight', crossClient: 'clientWidth', offset: 'offsetHeight', crossOffset: 'offsetWidth', offsetPos: 'offsetTop',\n            scroll: 'scrollTop', scrollSize: 'scrollHeight'\n        },\n        h: { // Horizontal\n            x: 'X', pos: 'left', crossPos: 'top', size: 'width', crossSize: 'height',\n            client: 'clientWidth', crossClient: 'clientHeight', offset: 'offsetWidth', crossOffset: 'offsetHeight', offsetPos: 'offsetLeft',\n            scroll: 'scrollLeft', scrollSize: 'scrollWidth'\n        }\n    },\n\n    each = function(obj, iterator) {\n        var i = 0;\n\n        if (obj.length === undefined || obj === window) obj = [obj];\n\n        while (obj[i]) {\n            iterator.call(this, obj[i], i);\n            i++;\n        }\n    },\n\n    baron = function(params) { // this - window or jQuery instance\n        var jQueryMode = (this && this[0] && this[0].nodeType),\n            roots,\n            $;\n\n        params = params || {};\n        $ = params.$ || window.jQuery;\n\n        if (jQueryMode) {\n            params.root = roots = this;\n        } else {\n            roots = $(params.root || params.scroller);\n        }\n\n        return new baron.fn.constructor(roots, params, $);\n    };\n\n    baron.fn = {\n        constructor: function(roots, input, $) {\n            var params = validate(input);\n\n            params.$ = $;\n            each.call(this, roots, function(root, i) {\n                var localParams = clone(params);\n\n                if (params.root && params.scroller) {\n                    localParams.scroller = params.$(params.scroller, root);\n                    if (!localParams.scroller.length) {\n                        localParams.scroller = root;\n                    }\n                } else {\n                    localParams.scroller = root;\n                }\n\n                localParams.root = root;\n                this[i] = init(localParams);\n                this.length = i + 1;\n            });\n\n            this.params = params;\n        },\n\n        dispose: function() {\n            var params = this.params;\n\n            each(this, function(item) {\n                item.dispose(params);\n            });\n            this.params = null;\n        },\n\n        update: function() {\n            var i = 0;\n\n            while (this[i]) {\n                this[i].update.apply(this[i], arguments);\n                i++;\n            }\n        },\n\n        baron: function(params) {\n            params.root = [];\n            params.scroller = this.params.scroller;\n\n            each.call(this, this, function(elem) {\n                params.root.push(elem.root);\n            });\n            params.direction = (this.params.direction == 'v') ? 'h' : 'v';\n            params._chain = true;\n\n            return baron(params);\n        }\n    };\n\n    function manageEvents(item, eventManager, mode) {\n        item._eventHandlers = item._eventHandlers || [ // Creating new functions for one baron item only one time\n            {\n                // onScroll: \n                element: item.scroller,\n\n                handler: function(e) {\n                    item.scroll(e);\n                },\n\n                type: 'scroll'\n            }, {\n                // onMouseDown: \n                element: item.bar,\n\n                handler: function(e) {\n                    e.preventDefault(); // Text selection disabling in Opera... and all other browsers?\n                    item.selection(); // Disable text selection in ie8\n                    item.drag.now = 1; // Save private byte\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseUp: \n                element: document,\n\n                handler: function() {\n                    item.selection(1); // Enable text selection\n                    item.drag.now = 0;\n                },\n\n                type: 'mouseup blur touchend'\n            }, {\n                // onCoordinateReset: \n                element: document,\n\n                handler: function(e) {\n                    if (e.button != 2) { // Not RM\n                        item._pos0(e);\n                    }\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseMove: \n                element: document,\n\n                handler: function(e) {\n                    if (item.drag.now) {\n                        item.drag(e);\n                    }\n                },\n\n                type: 'mousemove touchmove'\n            }, {\n                // onResize: \n                element: window,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'resize'\n            }, {\n                // sizeChange: \n                element: item.root,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'sizeChange'\n            }\n        ];\n\n        each(item._eventHandlers, function(event) {\n            if (event.element) {\n                eventManager(event.element, event.type, event.handler, mode);\n            }\n        });\n\n        // if (item.scroller) {\n        //     event(item.scroller, 'scroll', item._eventHandlers.onScroll, mode);\n        // }\n        // if (item.bar) {\n        //     event(item.bar, 'touchstart mousedown', item._eventHandlers.onMouseDown, mode);\n        // }\n        // event(document, 'mouseup blur touchend', item._eventHandlers.onMouseUp, mode);\n        // event(document, 'touchstart mousedown', item._eventHandlers.onCoordinateReset, mode);\n        // event(document, 'mousemove touchmove', item._eventHandlers.onMouseMove, mode);\n        // event(window, 'resize', item._eventHandlers.onResize, mode);\n        // if (item.root) {\n        //     event(item.root, 'sizeChange', item._eventHandlers.onResize, mode); // Custon event for alternate baron update mechanism\n        // }\n    }\n\n    function manageAttr(node, direction, mode) {\n        var attrName = 'data-baron-' + direction;\n\n        if (mode == 'on') {\n            node.setAttribute(attrName, 'inited');\n        } else if (mode == 'off') {\n            node.removeAttribute(attrName);\n        } else {\n            return node.getAttribute(attrName);\n        }\n    }\n\n    function init(params) {\n        if (manageAttr(params.root, params.direction)) return;\n\n        var out = new item.prototype.constructor(params); // __proto__ of returning object is baron.prototype\n\n        manageEvents(out, params.event, 'on');\n\n        manageAttr(out.root, params.direction, 'on');\n\n        out.update();\n\n        return out;\n    }\n\n    function clone(input) {\n        var output = {};\n\n        input = input || {};\n\n        for (var key in input) {\n            if (input.hasOwnProperty(key)) {\n                output[key] = input[key];\n            }\n        }\n\n        return output;\n    }\n\n    function validate(input) {\n        var output = clone(input);\n\n        output.direction = output.direction || 'v';\n\n        var event = input.event || function(elem, event, func, mode) {\n            output.$(elem)[mode || 'on'](event, func);\n        };\n\n        output.event = function(elems, e, func, mode) {\n            each(elems, function(elem) {\n                event(elem, e, func, mode);\n            });\n        };\n\n        return output;\n    }\n\n    function fire(eventName) {\n        /* jshint validthis:true */\n        if (this.events && this.events[eventName]) {\n            for (var i = 0 ; i < this.events[eventName].length ; i++) {\n                var args = Array.prototype.slice.call( arguments, 1 );\n\n                this.events[eventName][i].apply(this, args);\n            }\n        }\n    }\n\n    var item = {};\n\n    item.prototype = {\n        constructor: function(params) {\n            var $,\n                barPos,\n                scrollerPos0,\n                track,\n                resizePauseTimer,\n                scrollPauseTimer,\n                pause,\n                scrollLastFire,\n                resizeLastFire;\n\n            resizeLastFire = scrollLastFire = new Date().getTime();\n\n            $ = this.$ = params.$;\n            this.event = params.event;\n            this.events = {};\n\n            function getNode(sel, context) {\n                return $(sel, context)[0]; // Can be undefined\n            }\n\n            // DOM elements\n            this.root = params.root; // Always html node, not just selector\n            this.scroller = getNode(params.scroller); // (params.scroller) ? getNode(params.scroller, this.root) : this.root;\n            this.bar = getNode(params.bar, this.root);\n            track = this.track = getNode(params.track, this.root);\n            if (!this.track && this.bar) {\n                track = this.bar.parentNode;\n            }\n            this.clipper = this.scroller.parentNode;\n\n            // Parameters\n            this.direction = params.direction;\n            this.origin = origin[this.direction];\n            this.barOnCls = params.barOnCls;\n            this.barTopLimit = 0;\n            pause = params.pause * 1000 || 0;\n\n            // Updating height or width of bar\n            function setBarSize(size) {\n                /* jshint validthis:true */\n                var barMinSize = this.barMinSize || 20;\n\n                if (size > 0 && size < barMinSize) {\n                    size = barMinSize;\n                }\n\n                if (this.bar) {\n                    $(this.bar).css(this.origin.size, parseInt(size, 10) + 'px');\n                }\n            }\n\n            // Updating top or left bar position\n            function posBar(pos) {\n                /* jshint validthis:true */\n                if (this.bar) {\n                    $(this.bar).css(this.origin.pos, +pos + 'px');\n                }\n            }\n\n            // Free path for bar\n            function k() {\n                /* jshint validthis:true */\n                return track[this.origin.client] - this.barTopLimit - this.bar[this.origin.offset];\n            }\n\n            // Relative content top position to bar top position\n            function relToPos(r) {\n                /* jshint validthis:true */\n                return r * k.call(this) + this.barTopLimit;\n            }\n\n            // Bar position to relative content position\n            function posToRel(t) {\n                /* jshint validthis:true */\n                return (t - this.barTopLimit) / k.call(this);\n            }\n\n            // Cursor position in main direction in px // Now with iOs support\n            this.cursor = function(e) {\n                return e['client' + this.origin.x] || (((e.originalEvent || e).touches || {})[0] || {})['page' + this.origin.x];\n            };\n\n            // Text selection pos preventing\n            function dontPosSelect() {\n                return false;\n            }\n\n            this.pos = function(x) { // Absolute scroller position in px\n                var ie = 'page' + this.origin.x + 'Offset',\n                    key = (this.scroller[ie]) ? ie : this.origin.scroll;\n\n                if (x !== undefined) this.scroller[key] = x;\n\n                return this.scroller[key];\n            };\n\n            this.rpos = function(r) { // Relative scroller position (0..1)\n                var free = this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client],\n                    x;\n\n                if (r) x = this.pos(r * free);\n                else x = this.pos();\n\n                return x / (free || 1);\n            };\n\n            // Switch on the bar by adding user-defined CSS classname to scroller\n            this.barOn = function(dispose) {\n                if (this.barOnCls) {\n                    if (dispose || this.scroller[this.origin.client] >= this.scroller[this.origin.scrollSize]) {\n                        $(this.root).removeClass(this.barOnCls);\n                    } else {\n                        $(this.root).addClass(this.barOnCls);\n                    }\n                }\n            };\n\n            this._pos0 = function(e) {\n                scrollerPos0 = this.cursor(e) - barPos;\n            };\n\n            this.drag = function(e) {\n                this.scroller[this.origin.scroll] = posToRel.call(this, this.cursor(e) - scrollerPos0) * (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]);\n            };\n\n            // Text selection preventing on drag\n            this.selection = function(enable) {\n                this.event(document, 'selectpos selectstart', dontPosSelect, enable ? 'off' : 'on');\n            };\n\n            // onResize & DOM modified handler\n            this.resize = function() {\n                var self = this,\n                    delay = 0;\n\n                if (new Date().getTime() - resizeLastFire < pause) {\n                    clearTimeout(resizePauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    var delta = self.scroller[self.origin.crossOffset] - self.scroller[self.origin.crossClient];\n\n                    if (params.freeze && !self.clipper.style[self.origin.crossSize]) { // Sould fire only once\n                        $(self.clipper).css(self.origin.crossSize, self.clipper[self.origin.crossClient] - delta + 'px');\n                    }\n                    $(self.scroller).css(self.origin.crossSize, self.clipper[self.origin.crossClient] + delta + 'px');\n                    \n                    Array.prototype.unshift.call(arguments, 'resize');\n                    fire.apply(self, arguments);\n\n                    resizeLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    resizePauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n            };\n\n            // onScroll handler\n            this.scroll = function() {\n                var oldBarSize, newBarSize,\n                    delay = 0,\n                    self = this;\n\n                if (new Date().getTime() - scrollLastFire < pause) {\n                    clearTimeout(scrollPauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    if (self.bar) {\n                        newBarSize = (track[self.origin.client] - self.barTopLimit) * self.scroller[self.origin.client] / self.scroller[self.origin.scrollSize];\n\n                        // Positioning bar\n                        if (oldBarSize != newBarSize) {\n                            setBarSize.call(self, newBarSize);\n                            oldBarSize = newBarSize;\n                        }\n                        \n                        barPos = relToPos.call(self, self.rpos());\n\n                        posBar.call(self, barPos);\n                    }\n\n                    Array.prototype.unshift.call( arguments, 'scroll' );\n                    fire.apply(self, arguments);\n\n                    scrollLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    scrollPauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n                \n            };\n\n            return this;\n        },\n\n        update: function(params) {\n            fire.call(this, 'upd', params); // Обновляем параметры всех плагинов\n\n            this.resize(1);\n            this.barOn();\n            this.scroll();\n\n            return this;\n        },\n\n        dispose: function(params) {\n            manageEvents(this, this.event, 'off');\n            manageAttr(this.root, params.direction, 'off');\n            $(this.scroller).css(this.origin.crossSize, '');\n            this.barOn(true);\n            fire.call(this, 'dispose');\n        },\n\n        on: function(eventName, func, arg) {\n            var names = eventName.split(' ');\n\n            for (var i = 0 ; i < names.length ; i++) {\n                if (names[i] == 'init') {\n                    func.call(this, arg);\n                } else {\n                    this.events[names[i]] = this.events[names[i]] || [];\n\n                    this.events[names[i]].push(function(userArg) {\n                        func.call(this, userArg || arg);\n                    });\n                }\n            }\n        }\n    };\n\n    baron.fn.constructor.prototype = baron.fn;\n    item.prototype.constructor.prototype = item.prototype;\n\n    // Use when you need \"baron\" global var for another purposes\n    baron.noConflict = function() {\n        window.baron = _baron; // Restoring original value of \"baron\" global var\n\n        return baron;\n    };\n\n    baron.version = '0.6.6';\n\n    if ($ && $.fn) { // Adding baron to jQuery as plugin\n        $.fn.baron = baron;\n    }\n    window.baron = baron; // Use noConflict method if you need window.baron var for another purposes\n    if (window['module'] && module.exports) {\n        module.exports = baron.noConflict();\n    }\n})(window);\n/* Fixable elements plugin for baron 0.6+ */\n(function(window, undefined) {\n    var fix = function(userParams) {\n        var elements, viewPortSize,\n            params = { // Default params\n                outside: '',\n                before: '',\n                after: '',\n                past: '',\n                future: '',\n                radius: 0,\n                minView: 0\n            },\n            topFixHeights = [], // inline style for element\n            topRealHeights = [], // real offset position when not fixed\n            headerTops = [],\n            scroller = this.scroller,\n            eventManager = this.event,\n            $ = this.$,\n            self = this;\n\n        function fixElement(i, pos) {\n            if (viewPortSize < (params.minView || 0)) { // No headers fixing when no enought space for viewport\n                pos = undefined;\n            }\n\n            if (pos !== undefined) {\n                pos += 'px';\n                this.$(elements[i]).css(this.origin.pos, pos).addClass(params.outside);\n            } else {\n                this.$(elements[i]).css(this.origin.pos, '').removeClass(params.outside);\n            }\n        }\n\n        function bubbleWheel(e) {\n            try {\n                i = document.createEvent('WheelEvent'); // i - for extra byte\n                // evt.initWebKitWheelEvent(deltaX, deltaY, window, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);\n                i.initWebKitWheelEvent(e.originalEvent.wheelDeltaX, e.originalEvent.wheelDeltaY);\n                scroller.dispatchEvent(i);\n                e.preventDefault();\n            } catch (e) {}\n        }\n\n        function init(_params) {\n            var pos;\n\n            for (var key in _params) {\n                params[key] = _params[key];\n            }\n\n            elements = this.$(params.elements, this.scroller);\n\n            if (elements) {\n                viewPortSize = this.scroller[this.origin.client];\n                for (var i = 0 ; i < elements.length ; i++) {\n                    // Variable header heights\n                    pos = {};\n                    pos[this.origin.size] = elements[i][this.origin.offset];\n                    if (elements[i].parentNode !== this.scroller) {\n                        this.$(elements[i].parentNode).css(pos);\n                    }\n                    pos = {};\n                    pos[this.origin.crossSize] = elements[i].parentNode[this.origin.crossClient];\n                    this.$(elements[i]).css(pos);\n\n                    // Between fixed headers\n                    viewPortSize -= elements[i][this.origin.offset];\n\n                    headerTops[i] = elements[i].parentNode[this.origin.offsetPos]; // No paddings for parentNode\n\n                    // Summary elements height above current\n                    topFixHeights[i] = (topFixHeights[i - 1] || 0); // Not zero because of negative margins\n                    topRealHeights[i] = (topRealHeights[i - 1] || Math.min(headerTops[i], 0));\n\n                    if (elements[i - 1]) {\n                        topFixHeights[i] += elements[i - 1][this.origin.offset];\n                        topRealHeights[i] += elements[i - 1][this.origin.offset];\n                    }\n\n                    if ( !(i == 0 && headerTops[i] == 0)/* && force */) {\n                        this.event(elements[i], 'mousewheel', bubbleWheel, 'off');\n                        this.event(elements[i], 'mousewheel', bubbleWheel);\n                    }\n                }\n\n                if (params.limiter && elements[0]) { // Bottom edge of first header as top limit for track\n                    if (this.track && this.track != this.scroller) {\n                        pos = {};\n                        pos[this.origin.pos] = elements[0].parentNode[this.origin.offset];\n                        this.$(this.track).css(pos);\n                    } else {\n                        this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    }\n                    // this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    this.scroll();\n                }\n\n                if (params.limiter === false) { // undefined (in second fix instance) should have no influence on bar limit\n                    this.barTopLimit = 0;\n                }\n            }\n\n            var event = {\n                element: elements,\n                \n                handler: function() {\n                    var parent = $(this)[0].parentNode,\n                        top = parent.offsetTop,\n                        num;\n\n                    // finding num -> elements[num] === this\n                    for (var i = 0 ; i < elements.length ; i++ ) {\n                        if (elements[i] === this) num = i;\n                    }\n\n                    var pos = top - topFixHeights[num];\n\n                    if (params.scroll) { // User defined callback\n                        params.scroll({\n                            x1: self.scroller.scrollTop,\n                            x2: pos\n                        });\n                    } else {\n                        self.scroller.scrollTop = pos;\n                    }\n                },\n\n                type: 'click'\n            };\n\n            if (params.clickable) {\n                this._eventHandlers.push(event); // For auto-dispose\n                eventManager(event.element, event.type, event.handler, 'off');\n                eventManager(event.element, event.type, event.handler, 'on');\n            }\n        }\n\n        this.on('init', init, userParams);\n\n        this.on('init scroll', function() {\n            var fixState, hTop,\n                fixFlag = []; // 1 - past, 2 - future, 3 - current (not fixed)\n\n            if (elements) {\n                var change;\n\n                // fixFlag update\n                for (var i = 0 ; i < elements.length ; i++) {\n                    fixState = 0;\n                    if (headerTops[i] - this.pos() < topRealHeights[i] + params.radius) {\n                        // Header trying to go up\n                        fixState = 1;\n                        hTop = topFixHeights[i];\n                    } else if (headerTops[i] - this.pos() > topRealHeights[i] + viewPortSize - params.radius) {\n                        // Header trying to go down\n                        fixState = 2;\n                        hTop = topFixHeights[i] + viewPortSize;\n                    } else {\n                        // Header in viewport\n                        fixState = 3;\n                        hTop = undefined;\n                    }\n                    if (fixState != fixFlag[i]) {\n                        fixElement.call(this, i, hTop);\n                        fixFlag[i] = fixState;\n                        change = true;\n                    }\n                }\n\n                // Adding positioning classes (on last top and first bottom header)\n                if (change) { // At leats one change in elements flag structure occured\n                    for (i = 0 ; i < elements.length ; i++) {\n                        if (fixFlag[i] == 1 && params.past) {\n                            this.$(elements[i]).addClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] == 2 && params.future) {\n                            this.$(elements[i]).addClass(params.future).removeClass(params.past);\n                        }\n\n                        if (fixFlag[i] == 3 && (params.future || params.past)) {\n                            this.$(elements[i]).removeClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] != fixFlag[i + 1] && fixFlag[i] == 1 && params.before) {\n                            this.$(elements[i]).addClass(params.before).removeClass(params.after); // Last top fixed header\n                        } else if (fixFlag[i] != fixFlag[i - 1] && fixFlag[i] == 2 && params.after) {\n                            this.$(elements[i]).addClass(params.after).removeClass(params.before); // First bottom fixed header\n                        } else {\n                            this.$(elements[i]).removeClass(params.before).removeClass(params.after);\n                        }\n                    }\n                }\n            }\n        });\n\n        this.on('resize upd', function(updParams) {\n            init.call(this, updParams && updParams.fix);\n        });\n    };\n\n    baron.fn.fix = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            fix.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);\n/* Controls plugin for baron 0.6+ */\n(function(window, undefined) {\n    var controls = function(params) {\n        var forward, backward, track, screen,\n            self = this; // AAAAAA!!!!!11\n\n        screen = params.screen || 0.9;\n\n        if (params.forward) {\n            forward = this.$(params.forward, this.clipper);\n\n            this.event(forward, 'click', function() {\n                var y = self.pos() - params.delta || 30;\n                \n                self.pos(y);\n            });\n        }\n\n        if (params.backward) {\n            backward = this.$(params.backward, this.clipper);\n\n            this.event(backward, 'click', function() {\n                var y = self.pos() + params.delta || 30;\n\n                self.pos(y);\n            });\n        }\n\n        if (params.track) {\n            if (params.track === true) {\n                track = this.track;\n            } else {\n                track = this.$(params.track, this.clipper)[0];\n            }\n\n            if (track) {\n                this.event(track, 'mousedown', function(e) {\n                    var x = e['offset' + self.origin.x],\n                        xBar = self.bar[self.origin.offsetPos],\n                        sign = 0;\n\n                    if (x < xBar) {\n                        sign = -1;\n                    } else if (x > xBar + self.bar[self.origin.offset]) {\n                        sign = 1;\n                    }\n\n                    var y = self.pos() + sign * screen * self.scroller[self.origin.client];\n                    self.pos(y);\n                });\n            }\n        }\n\n    };\n\n    baron.fn.controls = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            controls.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);\n/* Autotests plugin for baron 0.6+ (for developers) */\n(function(window, undefined) {\n    var test = function(params) {\n        var errCount = 0,\n            totalCount = 0;\n\n        var log = function(type, msg, obj) {\n            var text = type + ': ' + msg;\n\n            switch (type) {\n                case 'log': css = 'color: #0b0'; break;\n                case 'warn': css = 'color: #fc9'; break;\n                case 'error': css = 'color: #f00'; break;\n            }\n            totalCount++;\n            if (type == 'log') {\n                errCount++;\n            }\n\n            console.log('%c ' + totalCount + '. ' + text, css);\n            if (obj !== undefined) {\n                console.log(obj);\n            }\n        };\n\n        if (this.scroller && this.scroller.nodeType === 1) {\n            log('log', 'Scroller defined and has proper nodeType value', this.scroller);\n        } else {\n            log('error', 'Scroller not defined or has wrong type (should be html node).', this.scroller);\n        }\n\n        if (this.$ && typeof this.$ == 'function') {\n            log('log', 'Local $ defined and it is a function');\n        } else {\n            log('error', 'Local $ has wrong value or is not defined, or custom params.dom and params.selector not defined', params.$);\n        }\n\n        if (this.scroller.getAttribute('data-baron-v')) {\n            log('log', 'Baron initialized in vertical direction', this.scroller.getAttribute('data-baron-v'));\n            if (this.scroller.clientHeight < this.scroller.scrollHeight && this.scroller.getAttribute('data-baron-v')) {\n                log('log', 'There are enought space for scrolling in vertical direction right now', this.scroller.scrollHeight - this.scroller.clientHeight + 'px');\n            } else {\n                log('log', 'There are not enought space for scrolling in vertical direction right now');\n            }\n        }\n        if (this.scroller.getAttribute('data-baron-h')) {\n            log('log', 'Baron initialized in horizontal direction', this.scroller.getAttribute('data-baron-h'));\n            if (this.scroller.clientWidth < this.scroller.scrollWidth) {\n                log('log', 'There are enought space for scrolling in horizontal direction right now', this.scroller.scrollWidth - this.scroller.clientWidth + 'px');\n            } else {\n                log('log', 'There are not enought space for scrolling in horizontal direction right now');\n            }\n        }\n\n        if (this.bar && this.bar.nodeType === 1) {\n            log('log', 'Bar defined and has proper nodeType value', this.bar);\n        } else {\n            log('warn', 'Bar not defined or has wrong type (should be html node).', this.bar);\n        }\n        \n        if (this.barOnCls) {\n            log('log', 'CSS classname barOnCls defined', this.barOnCls);\n        } else {\n            log('warn', 'barOnCls not defined - bar will be visible or not visible all the time', this.barOnCls);\n        }\n\n        // Preformance test\n        var t1 = new Date().getTime(),\n            x;\n        for (var i = 0 ; i < 1000 ; i += 10) {\n            x = i % (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]);\n            this.pos(x);\n            this.event(this.scroller, 'scroll', undefined, 'trigger');\n        }\n        var t2 = new Date().getTime();\n        log('log', 'Preformance test: ' + (t2 - t1) / 1000 + ' milliseconds per scroll event');\n        \n        log('log', 'Result is ' + errCount + ' / ' + totalCount + '\\n');\n    };\n\n    baron.fn.test = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            test.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);\n/* Pull to load plugin for baron 0.6+ */\n(function(window, undefined) {\n    var pull = function(params) {\n        var block = this.$(params.block),\n            size = params.size || this.origin.size,\n            limit = params.limit || 80,\n            onExpand = params.onExpand,\n            elements = params.elements || [],\n            inProgress = params.inProgress || '',\n            self = this,\n            _insistence = 0,\n            _zeroXCount = 0,\n            _interval,\n            _timer,\n            _x = 0,\n            _onExpandCalled,\n            _waiting = params.waiting || 500,\n            _on;\n\n        function getSize() {\n            return self.scroller[self.origin.scroll] + self.scroller[self.origin.offset];\n        }\n\n        // Scroller content height\n        function getContentSize() {\n            return self.scroller[self.origin.scrollSize];\n        }\n\n        // Scroller height\n        function getScrollerSize() {\n            return self.scroller[self.origin.client];\n        }\n\n        function step(x, force) {\n            var k = x * 0.0005;\n            \n            return Math.floor(force - k * (x + 550));\n        }\n\n        function toggle(on) {\n            _on = on;\n\n            if (on) {\n                update(); // First time with no delay\n                _interval = setInterval(update, 200);\n            } else {\n                clearInterval(_interval);\n            }\n        }\n\n        function update() {\n            var pos = {},\n                height = getSize(),\n                scrollHeight = getContentSize(),\n                dx,\n                op4,\n                scrollInProgress = _insistence == 1;\n\n            op4 = 0; // Возвращающая сила\n            if (_insistence > 0) {\n                op4 = 40;\n            }\n            //if (_insistence > -1) {\n                dx = step(_x, op4);\n                if (height >= scrollHeight - _x && _insistence > -1) {\n                    if (scrollInProgress) {\n                        _x += dx;\n                    }\n                } else {\n                    _x = 0;\n                }\n\n                if (_x < 0) _x = 0;\n\n                pos[size] = _x + 'px';\n                if (getScrollerSize() <= getContentSize()) {\n                    self.$(block).css(pos);\n                    for (var i = 0 ; i < elements.length ; i++) {\n                        self.$(elements[i].self).css(elements[i].property, Math.min(_x / limit * 100, 100) + '%');\n                    }\n                }\n\n                if (inProgress && _x) {\n                    self.$(self.root).addClass(inProgress);\n                }\n\n                if (_x == 0) {\n                    if (params.onCollapse) {\n                        params.onCollapse();\n                    }\n                }\n\n                _insistence = 0;\n                _timer = setTimeout(function() {\n                    _insistence = -1;\n                }, _waiting);\n            //}\n\n            if (onExpand && _x > limit && !_onExpandCalled) {\n                onExpand();\n                _onExpandCalled = true;\n            }\n\n            if (_x == 0) {\n                _zeroXCount++;\n            } else {\n                _zeroXCount = 0;\n                \n            }\n            if (_zeroXCount > 1) {\n                toggle(false);\n                _onExpandCalled = false;\n                if (inProgress) {\n                    self.$(self.root).removeClass(inProgress);\n                }\n            }\n        }\n\n        this.on('init', function() {\n            toggle(true);\n        });\n\n        this.on('dispose', function() {\n            toggle(false);\n        });\n\n        this.event(this.scroller, 'mousewheel DOMMouseScroll', function(e) {\n            var down = e.wheelDelta < 0 || (e.originalEvent && e.originalEvent.wheelDelta < 0) || e.detail > 0;\n\n            if (down) {\n                _insistence = 1;\n                clearTimeout(_timer);\n                if (!_on && getSize() >= getContentSize()) {\n                    toggle(true);\n                }\n            }\n            //  else {\n            //     toggle(false);\n            // }\n        });\n    };\n\n    baron.fn.pull = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            pull.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);"
  },
  {
    "path": "vendors/baron/demo/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n\n    <meta charset=\"utf-8\" />\n\n    <script src=\"../js/jquery-1.9.0.js\"></script>\n\n    <script src=\"baron.full.js\"></script>\n    <script src=\"../src/pull.js\"></script>\n    <script src=\"script.js\"></script>\n\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../baron.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n\n    <title>Baron.js demo page</title>\n\n</head>\n\n<body>\n\n    <div class=\"wrapper wrapper_1\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">Baron is a title of nobility. In the kingdom of England, the medieval Latin word baro, baronis was used originally to denote a tenant-in-chief of the early Norman kings who held his lands by the feudal tenure of \"barony\" (in Latin per baroniam), and who was entitled to attend the Great Council which by the 13th century had developed into the Parliament of England.\n                <p class=\"text\">The title was quite common in most European countries often in a slightly modified form. In Italian, the word used was Barone. The corresponding title in the Holy Roman Empire was Freiherr.\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Etymology and very long header, more than one line. I said more! ++++++++++++++</h1>\n                </div>\n                <p class=\"text\">The word baron comes from the Old French baron, from a Late Latin baro \"man; servant, soldier, mercenary\" (so used in Salic Law; Alemannic Law has barus in the same sense). Isidore in the 7th century thought the word was from Greek βαρύς \"heavy\" (because of the \"heavy work\" done by mercenaries), but the word is presumably of Old Frankish origin, cognate with Old English beorn meaning \"warrior, nobleman\"). Cornutus in the first century already reports a word barones which he took to be of Gaulish origin. He glosses it as meaning servos militum and explains it as meaning \"stupid\", by reference to classical Latin bāro \"simpleton, dunce\"; because of this early reference, the word has also been suggested to derive from an otherwise unknown Celtic *bar, but OED takes this to be \"a figment\".\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Barons in the United Kingdom</h1>\n                </div>\n                <p class=\"text\">In the Peerage of England, Peerage of Ireland, Peerage of Great Britain and the Peerage of the United Kingdom, barons form the lowest rank, placed immediately below viscounts. A female of baronial rank has the title baroness. Feudal baronies (or \"baronies by tenure\") are now obsolete in England and without any legal force but any such historical titles are held in gross, that is to say are deemed to be enveloped within a more modern extant peerage title also held by the holder, sometimes along with vestigial manorial rights and tenures by grand serjeanty.\n                <p class=\"text\">William I introduced \"baron\" as a rank in England to distinguish the men who had pledged their loyalty to him under the feudal system. Previously, in the Anglo-Saxon kingdom of England, the king's companions held the title of earl and in Scotland, the title of thane. All who held their feudal barony \"in-chief of the king\", that is with the king as his immediate overlord, became alike barones regis (\"barons of the king\"), bound to perform a stipulated annual military service, and obliged to attend his council. Eventually the greatest of the nobles, especially those in the marches, such as the Earls of Chester or the Bishops of Durham, whose territories were often deemed palatinate, that is to say \"worthy of a prince\", might refer to their own tenants as \"barons\", where lesser magnates spoke simply of their \"men\" (homines).\n                <p class=\"text\">Initially those who held land directly from the king by military service, from earls downwards, all bore alike the title of baron, which was thus the factor uniting all members of the ancient baronage as peers one of another. Under King Henry II, the Dialogus de Scaccario already distinguished between greater barons, who held per baroniam by knight's service, and lesser barons, who held manors. Technically, Lords of Manors are barons, or freemen, however they do not use the term as a title. John Selden in his esteemed work Titles of Honour writes, \"The word Baro (Latin for Baron) hath been also so much communicated, that not only all Lords of Mannors have been from antient time, and are at this day called sometimes Barons (as in the stile of their Court Barons, which is Curia Baronis, &c. And I have read hors de son Barony in a barr to an Avowry for hors de son fee) But also the Judges of the Exchequer have it from antient time fixed on them.\"[4] Within a century of the Norman Conquest of 1066, as in the case of Thomas Becket in 1164, there arose the practice of sending to each greater baron a personal summons demanding his attendance at the King's Council, which evolved into the Parliament and later into the House of Lords, whilst as was stipulated in Magna Carta of 1215, the lesser barons of each county would receive a single summons as a group through the sheriff, and representatives only from their number would be elected to attend on behalf of the group. These representatives developed into the Knights of the Shire, elected by the County Court presided over by the sheriff, who themselves formed the precursor of the House of Commons. Thus appeared a definite distinction, which eventually had the effect of restricting to the greater barons alone the privileges and duties of peerage.\n                <p class=\"text\">Later, the king started to create new baronies in one of two ways: by a writ of summons directing a chosen man to attend Parliament, and in an even later development by letters patent. Writs of summons became the normal method in medieval times, displacing the method of feudal barony, but creation of baronies by letters patent is the sole method adopted in modern times. Since the adoption of summons by writ, baronies thus no longer relate directly to land-holding, and thus no more feudal baronies needed thenceforth to be created. Following the Modus Tenendi Parliamenta of 1419, the Tenures Abolition Act 1660, the Feudal Tenure Act (1662), and the Fines and Recoveries Act of 1834, titles of feudal barony became obsolete and without legal force.\n                <p class=\"text\">In the twentieth century Britain introduced the concept of non-hereditary life peers. All appointees to this distinction have been at the rank of baron. Life-peers are not counted as part of the aristocracy although in accordance with the tradition applied to hereditary peers they too are formally addressed in parliament by their peers as \"The Noble Lord\".\n                <p class=\"text\">In addition, baronies are often used by their holders as subsidiary titles, for example as courtesy titles for the son and heir of an Earl or higher peer.\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Scotland</h1>\n                </div>\n                <p class=\"text\">In Scotland, the rank of baron is a rank of the ancient feudal nobility of Scotland and refers to a holder of a feudal barony, formerly a feudal superiority over a proper territorial entity erected into a free barony by a Crown Charter, and is not usually considered a rank of Peerage; as such it can be transferred by either inheritance or conveyance.\n                <p class=\"text\">The Scottish equivalent of an English baron is a Lord of Parliament.\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Style of address</h1>\n                </div>\n                <p class=\"text\">Normally one refers to or addresses Baron [X] as Lord [X] and his wife as Lady [X]. In the case of women who hold baronies in their own right, they can be referred to as Baroness [X] as well as Lady [X]. In direct address, they can also be referred to as My Lord, Your Lordship, or Your Ladyship, but never as My Lady (except in the case of a female judge). The husband of a Baroness in her own right does not receive any style in her right. Children of Barons and Baronesses in their own right, whether hereditary or for life, have the style The Honourable [Forename] [Surname]. After the death of the father or mother, the child may continue to use the style Honourable.\n                <p class=\"text\">Scottish feudal barons style their surnames similarly to Clan Chiefs, with the name of their barony following their name, as in John Smith of Edinburgh or John Smith, Baron of Edinburgh.[5] Most formally, and in writing, they are styled as The Much Honoured Baron of Edinburgh. Their wives are styled Lady Edinburgh, or The Baroness of Edinburgh. The phrase Lady of Edinburgh is wrong, if the lady in question does not hold a Scottish barony in her own right. Orally, Scottish barons may be addressed with the name of their barony, as in Edinburgh or else as Baron without anything else following, which if present would suggest a peerage barony. Informally, when referring to a Scots feudal baron in the third person, the name Laird of [X] is used or simply [X].\n                <p class=\"text\">Non-Scottish barons are styled The Right Honourable The Lord [Barony]. Barons' wives are styled The Right Honourable The Lady [Barony]. Baronesses in their own right are either titled The Right Honourable The Baroness [Barony] or The Right Honourable The Lady [Barony], mainly based on personal preference (e.g., Margaret, Lady Thatcher and Brenda, Baroness Hale, both created baronesses in their own right). Note the order of the names. 'Lady Margaret Thatcher' would denote that she was the daughter of an earl, marquess or duke. Right Honourable is frequently abbreviated to Rt Hon. When referred to by the Sovereign in public instruments, The Right Honourable is changed to Our right trusty and well-beloved, with counsellor attached if they are a Privy Counsellor.\n                <p class=\"text\">Courtesy barons are styled simply Lord [Barony], and their wives are Lady [Barony]. The style of Right Honourable and/or the article \"The\" in front of the title is not used for them.\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Coronet</h1>\n                </div>\n                <p class=\"text\">A person holding a peerage in the rank of baron is entitled to a coronet bearing six silver balls (called pearls) around the rim, equally spaced and all of equal size and height. The rim itself is neither jeweled, nor \"chased\" (which is the case for the coronets of peers of higher degree).\n                <p class=\"text\">The actual coronet is mostly worn on certain ceremonial occasions, such as the coronation of a new monarch, but a baron can bear his coronet of rank on his coat of arms above the shield. In heraldry, the baron's coronet is shown with four of the balls visible.\n                <p class=\"text\">Scottish feudal barons were entitled to a red cap of maintenance (chapeau) turned up ermine if petitioning for a grant or matriculation of a coat of arms between the 1930s and 2004. This chapeau is identical to the red cap worn by an English baron, but without the silver balls or gilt. This is sometimes depicted in armorial paintings between the shield and the helmet. Additionally, if the baron is the head of a family he may include a chiefly coronet which is similar to a ducal coronet, but with four strawberry leaves. Because the chapeau was a relatively recent innovation, a number of ancient Arms of Scottish feudal barons do not display the chapeau. Now Scottish feudal barons are principally recognised by the baron's helm, which in Scotland is a steel helmet with grille of three grilles, garnished in gold. Occasionally the great tilting-helm garnished with gold is shown, or a helmet befitting a higher rank, if held.\n\n                <div class=\"load\">\n                    <div class=\"load__value\"></div>\n                </div>\n            </div>\n        </div>\n        <div class=\"scroller__bar-wrapper\">\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n\n    <div class=\"wrapper wrapper_2\">\n        <div class=\"scroller\">\n            <p class=\"text\">Baron is a title of nobility. In the kingdom of England, the medieval Latin word baro, baronis was used originally to denote a tenant-in-chief of the early Norman kings who held his lands by the feudal tenure of \"barony\" (in Latin per baroniam), and who was entitled to attend the Great Council which by the 13th century had developed into the Parliament of England.\n            <p class=\"text\">The title was quite common in most European countries often in a slightly modified form. In Italian, the word used was Barone. The corresponding title in the Holy Roman Empire was Freiherr.\n            <div class=\"header\">\n                <h1 class=\"header__title\">Sticky footer</h1>\n            </div>\n            <div class=\"scroller__bar\"></div>\n            <div class=\"scroller__bar scroller__bar_h\"></div>\n        </div>\n    </div>\n\n</body>\n\n</html>"
  },
  {
    "path": "vendors/baron/demo/script.js",
    "content": "window.onload = function() {\n    window.dima = baron({\n        root: '.wrapper_1',\n        scroller: '.scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        before: 'header__title_position_top',\n        after: 'header__title_position_bottom',\n        clickable: true\n    }).pull({\n        block: '.load',\n        elements: [{\n            self: '.load__value',\n            property: 'width'\n        }],\n        limit: 115,\n        onExpand: function() {\n            $('.load').css('background', 'red');\n        }\n    });\n\n    baron({\n        scroller: '.wrapper_2 .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        before: 'header__title_position_top',\n        after: 'header__title_position_bottom'\n    }).baron({\n        barOnCls: 'baron_h',\n        bar: '.scroller__bar_h'\n    });\n};"
  },
  {
    "path": "vendors/baron/demo/style.css",
    "content": "html, body {height: 100%;margin: 0; padding: 0; font-family: Verdana}\n\nbody {\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n    margin: 0 auto;\n    padding: 10px;\n    text-align: center;\n}\n\n.wrapper {\n    display: inline-block;\n    vertical-align: top;\n    position: relative;\n    overflow: hidden;\n    width: 30%;\n    height: 70%;\n    \n    background: #fff;\n    border: 1px solid #fc9;\n    box-shadow:\n        0 5px 15px -3px rgba(0, 0, 0, .7),\n        0 0 0 1px rgba(0, 0, 0, .05);\n    text-align: left;\n}\n.scroller {\n    height: 100%;\n    overflow-y: scroll;\n    /*-webkit-overflow-scrolling: touch;*/\n    /* uncomment to accelerate scrolling on iOs */\n}\n.scroller::-webkit-scrollbar {\n    width: 0;\n}\n.scroller__bar-wrapper {\n    position: absolute;\n    z-index: 3;\n    top: 10px;\n    bottom: 10px;\n    right: 5px;\n    width: 8px;\n    border-radius: 5px;\n    background: #ddf;\n    background: rgba(0, 0, 255, .1);\n    pointer-events: none;\n}\n.scroller__bar {\n    position: absolute;\n    z-index: 1;\n    width: 8px;\n    border-radius: 3px;\n    background: #987;\n    opacity: 0;\n    -webkit-transition: opacity .2s linear;\n    transition: opacity .2s linear;\n    pointer-events: auto;\n}\n.scroller__bar:hover {\n    opacity: .8;\n}\n.baron .scroller__bar {\n    opacity: .6;\n}\n.baron_h .scroller__bar_h {\n    opacity: .6;\n    bottom: 30px;\n}\n\n.header__title {\n    position: relative;\n    z-index: 2;\n    width: 100%;\n    margin: 0;\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n    background: #ebe7e4;\n    background-color: rgba(200, 209, 250, 1);\n    box-shadow: 0 -1px 0 rgba(0, 0, 0, .05);\n    color: #222;\n    font-size: 14px;\n    line-height: 20px; /* sync with .search-results__header-wrapper height */\n    opacity: 1;\n    -webkit-transition: background-color .2s;\n    transition: background-color .2s;\n    cursor: pointer;\n}\n.header__title_state_fixed {\n    position: absolute;\n    z-index: 1;\n    background-color: rgba(220, 209, 250, .95);\n    text-shadow: 0 0 5px #fff;\n}\n.header__title_position_top {\n    background-color: rgba(200, 250, 200, .8);\n}\n.header__title_position_top:after {\n    content: '';\n    position: absolute;\n    left: 0;\n    bottom: -30px;\n    width: 100%;\n    height: 30px;\n    background: -webkit-linear-gradient(top, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);\n    background: linear-gradient(to bottom, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0) 100%);\n    pointer-events: none;\n}\n.header__title_position_bottom {\n    background-color: rgba(250, 200, 200, .8);\n}\n.header__title_position_bottom:after {\n    content: '';\n    position: absolute;\n    left: 0;\n    top: -30px;\n    width: 100%;\n    height: 30px;\n    background: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);\n    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);\n    pointer-events: none;\n}\n\n.wrapper_2 .text {\n    width: 800px;\n}\n.wrapper_2 .header__title {\n    position: absolute;\n    bottom: 0;\n    z-index: 1;\n}\n.wrapper_2 .header__title_state_fixed {\n    position: static;\n}\n\n.text {\n    overflow: hidden;\n    margin: 10px;\n    font-size: 12px;\n}\n\n.wrapper_iphone .header__title_state_fixed {\n    position: relative;\n}\n.wrapper_iphone .header__title_position_top {\n    position: absolute;\n    top: 0;\n}\n.wrapper_iphone .header__title_position_bottom {\n    position: absolute;\n    bottom: 0;\n}\n\n.load {\n    background: yellow;\n    -webkit-transition: all .2s linear;\n    transition: all .2s linear;\n}\n.load__value {\n    background: green;\n    width: 0%;\n    height: 100%;\n    -webkit-transition: all .2s linear;\n    transition: all .2s linear;\n}"
  },
  {
    "path": "vendors/baron/js/bean.js",
    "content": "/*!\n  * Bean - copyright (c) Jacob Thornton 2011-2012\n  * https://github.com/fat/bean\n  * MIT license\n  */\n(function (name, context, definition) {\n  if (typeof module != 'undefined' && module.exports) module.exports = definition()\n  else if (typeof define == 'function' && define.amd) define(definition)\n  else context[name] = definition()\n})('bean', this, function (name, context) {\n  name    = name    || 'bean'\n  context = context || this\n\n  var win            = window\n    , old            = context[name]\n    , namespaceRegex = /[^\\.]*(?=\\..*)\\.|.*/\n    , nameRegex      = /\\..*/\n    , addEvent       = 'addEventListener'\n    , removeEvent    = 'removeEventListener'\n    , doc            = document || {}\n    , root           = doc.documentElement || {}\n    , W3C_MODEL      = root[addEvent]\n    , eventSupport   = W3C_MODEL ? addEvent : 'attachEvent'\n    , ONE            = {} // singleton for quick matching making add() do one()\n\n    , slice          = Array.prototype.slice\n    , str2arr        = function (s, d) { return s.split(d || ' ') }\n    , isString       = function (o) { return typeof o == 'string' }\n    , isFunction     = function (o) { return typeof o == 'function' }\n\n      // events that we consider to be 'native', anything not in this list will\n      // be treated as a custom event\n    , standardNativeEvents =\n        'click dblclick mouseup mousedown contextmenu '                  + // mouse buttons\n        'mousewheel mousemultiwheel DOMMouseScroll '                     + // mouse wheel\n        'mouseover mouseout mousemove selectstart selectend '            + // mouse movement\n        'keydown keypress keyup '                                        + // keyboard\n        'orientationchange '                                             + // mobile\n        'focus blur change reset select submit '                         + // form elements\n        'load unload beforeunload resize move DOMContentLoaded '         + // window\n        'readystatechange message '                                      + // window\n        'error abort scroll '                                              // misc\n      // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event\n      // that doesn't actually exist, so make sure we only do these on newer browsers\n    , w3cNativeEvents =\n        'show '                                                          + // mouse buttons\n        'input invalid '                                                 + // form elements\n        'touchstart touchmove touchend touchcancel '                     + // touch\n        'gesturestart gesturechange gestureend '                         + // gesture\n        'textinput'                                                      + // TextEvent\n        'readystatechange pageshow pagehide popstate '                   + // window\n        'hashchange offline online '                                     + // window\n        'afterprint beforeprint '                                        + // printing\n        'dragstart dragenter dragover dragleave drag drop dragend '      + // dnd\n        'loadstart progress suspend emptied stalled loadmetadata '       + // media\n        'loadeddata canplay canplaythrough playing waiting seeking '     + // media\n        'seeked ended durationchange timeupdate play pause ratechange '  + // media\n        'volumechange cuechange '                                        + // media\n        'checking noupdate downloading cached updateready obsolete '       // appcache\n\n      // convert to a hash for quick lookups\n    , nativeEvents = (function (hash, events, i) {\n        for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1)\n        return hash\n      }({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : ''))))\n\n      // custom events are events that we *fake*, they are not provided natively but\n      // we can use native events to generate them\n    , customEvents = (function () {\n        var isAncestor = 'compareDocumentPosition' in root\n              ? function (element, container) {\n                  return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16\n                }\n              : 'contains' in root\n                ? function (element, container) {\n                    container = container.nodeType === 9 || container === window ? root : container\n                    return container !== element && container.contains(element)\n                  }\n                : function (element, container) {\n                    while (element = element.parentNode) if (element === container) return 1\n                    return 0\n                  }\n          , check = function (event) {\n              var related = event.relatedTarget\n              return !related\n                ? related == null\n                : (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString())\n                    && !isAncestor(related, this))\n            }\n\n        return {\n            mouseenter: { base: 'mouseover', condition: check }\n          , mouseleave: { base: 'mouseout', condition: check }\n          , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }\n        }\n      }())\n\n      // we provide a consistent Event object across browsers by taking the actual DOM\n      // event object and generating a new one from its properties.\n    , Event = (function () {\n            // a whitelist of properties (for different event types) tells us what to check for and copy\n        var commonProps  = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' +\n              'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey '  +\n              'srcElement target timeStamp type view which propertyName')\n          , mouseProps   = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer '      +\n              'fromElement offsetX offsetY pageX pageY screenX screenY toElement'))\n          , mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' +\n              'axis')) // 'axis' is FF specific\n          , keyProps     = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier '          +\n              'keyLocation location'))\n          , textProps    = commonProps.concat(str2arr('data'))\n          , touchProps   = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation'))\n          , messageProps = commonProps.concat(str2arr('data origin source'))\n          , stateProps   = commonProps.concat(str2arr('state'))\n          , overOutRegex = /over|out/\n            // some event types need special handling and some need special properties, do that all here\n          , typeFixers   = [\n                { // key events\n                    reg: /key/i\n                  , fix: function (event, newEvent) {\n                      newEvent.keyCode = event.keyCode || event.which\n                      return keyProps\n                    }\n                }\n              , { // mouse events\n                    reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i\n                  , fix: function (event, newEvent, type) {\n                      newEvent.rightClick = event.which === 3 || event.button === 2\n                      newEvent.pos = { x: 0, y: 0 }\n                      if (event.pageX || event.pageY) {\n                        newEvent.clientX = event.pageX\n                        newEvent.clientY = event.pageY\n                      } else if (event.clientX || event.clientY) {\n                        newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft\n                        newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop\n                      }\n                      if (overOutRegex.test(type)) {\n                        newEvent.relatedTarget = event.relatedTarget\n                          || event[(type == 'mouseover' ? 'from' : 'to') + 'Element']\n                      }\n                      return mouseProps\n                    }\n                }\n              , { // mouse wheel events\n                    reg: /mouse.*(wheel|scroll)/i\n                  , fix: function () { return mouseWheelProps }\n                }\n              , { // TextEvent\n                    reg: /^text/i\n                  , fix: function () { return textProps }\n                }\n              , { // touch and gesture events\n                    reg: /^touch|^gesture/i\n                  , fix: function () { return touchProps }\n                }\n              , { // message events\n                    reg: /^message$/i\n                  , fix: function () { return messageProps }\n                }\n              , { // popstate events\n                    reg: /^popstate$/i\n                  , fix: function () { return stateProps }\n                }\n              , { // everything else\n                    reg: /.*/\n                  , fix: function () { return commonProps }\n                }\n            ]\n          , typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism\n\n          , Event = function (event, element, isNative) {\n              if (!arguments.length) return\n              event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event\n              this.originalEvent = event\n              this.isNative       = isNative\n              this.isBean         = true\n\n              if (!event) return\n\n              var type   = event.type\n                , target = event.target || event.srcElement\n                , i, l, p, props, fixer\n\n              this.target = target && target.nodeType === 3 ? target.parentNode : target\n\n              if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless\n                fixer = typeFixerMap[type]\n                if (!fixer) { // haven't encountered this event type before, map a fixer function for it\n                  for (i = 0, l = typeFixers.length; i < l; i++) {\n                    if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .*\n                      typeFixerMap[type] = fixer = typeFixers[i].fix\n                      break\n                    }\n                  }\n                }\n\n                props = fixer(event, this, type)\n                for (i = props.length; i--;) {\n                  if (!((p = props[i]) in this) && p in event) this[p] = event[p]\n                }\n              }\n            }\n\n        // preventDefault() and stopPropagation() are a consistent interface to those functions\n        // on the DOM, stop() is an alias for both of them together\n        Event.prototype.preventDefault = function () {\n          if (this.originalEvent.preventDefault) this.originalEvent.preventDefault()\n          else this.originalEvent.returnValue = false\n        }\n        Event.prototype.stopPropagation = function () {\n          if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation()\n          else this.originalEvent.cancelBubble = true\n        }\n        Event.prototype.stop = function () {\n          this.preventDefault()\n          this.stopPropagation()\n          this.stopped = true\n        }\n        // stopImmediatePropagation() has to be handled internally because we manage the event list for\n        // each element\n        // note that originalElement may be a Bean#Event object in some situations\n        Event.prototype.stopImmediatePropagation = function () {\n          if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation()\n          this.isImmediatePropagationStopped = function () { return true }\n        }\n        Event.prototype.isImmediatePropagationStopped = function () {\n          return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped()\n        }\n        Event.prototype.clone = function (currentTarget) {\n          //TODO: this is ripe for optimisation, new events are *expensive*\n          // improving this will speed up delegated events\n          var ne = new Event(this, this.element, this.isNative)\n          ne.currentTarget = currentTarget\n          return ne\n        }\n\n        return Event\n      }())\n\n      // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both\n    , targetElement = function (element, isNative) {\n        return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element\n      }\n\n      /**\n        * Bean maintains an internal registry for event listeners. We don't touch elements, objects\n        * or functions to identify them, instead we store everything in the registry.\n        * Each event listener has a RegEntry object, we have one 'registry' for the whole instance.\n        */\n    , RegEntry = (function () {\n        // each handler is wrapped so we can handle delegation and custom events\n        var wrappedHandler = function (element, fn, condition, args) {\n            var call = function (event, eargs) {\n                  return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs)\n                }\n              , findTarget = function (event, eventElement) {\n                  return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement\n                }\n              , handler = condition\n                  ? function (event) {\n                      var target = findTarget(event, this) // deleated event\n                      if (condition.apply(target, arguments)) {\n                        if (event) event.currentTarget = target\n                        return call(event, arguments)\n                      }\n                    }\n                  : function (event) {\n                      if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix\n                      return call(event, arguments)\n                    }\n            handler.__beanDel = fn.__beanDel\n            return handler\n          }\n\n        , RegEntry = function (element, type, handler, original, namespaces, args, root) {\n            var customType     = customEvents[type]\n              , isNative\n\n            if (type == 'unload') {\n              // self clean-up\n              handler = once(removeListener, element, type, handler, original)\n            }\n\n            if (customType) {\n              if (customType.condition) {\n                handler = wrappedHandler(element, handler, customType.condition, args)\n              }\n              type = customType.base || type\n            }\n\n            this.isNative      = isNative = nativeEvents[type] && !!element[eventSupport]\n            this.customType    = !W3C_MODEL && !isNative && type\n            this.element       = element\n            this.type          = type\n            this.original      = original\n            this.namespaces    = namespaces\n            this.eventType     = W3C_MODEL || isNative ? type : 'propertychange'\n            this.target        = targetElement(element, isNative)\n            this[eventSupport] = !!this.target[eventSupport]\n            this.root          = root\n            this.handler       = wrappedHandler(element, handler, null, args)\n          }\n\n        // given a list of namespaces, is our entry in any of them?\n        RegEntry.prototype.inNamespaces = function (checkNamespaces) {\n          var i, j, c = 0\n          if (!checkNamespaces) return true\n          if (!this.namespaces) return false\n          for (i = checkNamespaces.length; i--;) {\n            for (j = this.namespaces.length; j--;) {\n              if (checkNamespaces[i] == this.namespaces[j]) c++\n            }\n          }\n          return checkNamespaces.length === c\n        }\n\n        // match by element, original fn (opt), handler fn (opt)\n        RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) {\n          return this.element === checkElement &&\n            (!checkOriginal || this.original === checkOriginal) &&\n            (!checkHandler || this.handler === checkHandler)\n        }\n\n        return RegEntry\n      }())\n\n    , registry = (function () {\n        // our map stores arrays by event type, just because it's better than storing\n        // everything in a single array.\n        // uses '$' as a prefix for the keys for safety and 'r' as a special prefix for\n        // rootListeners so we can look them up fast\n        var map = {}\n\n          // generic functional search of our registry for matching listeners,\n          // `fn` returns false to break out of the loop\n          , forAll = function (element, type, original, handler, root, fn) {\n              var pfx = root ? 'r' : '$'\n              if (!type || type == '*') {\n                // search the whole registry\n                for (var t in map) {\n                  if (t.charAt(0) == pfx) {\n                    forAll(element, t.substr(1), original, handler, root, fn)\n                  }\n                }\n              } else {\n                var i = 0, l, list = map[pfx + type], all = element == '*'\n                if (!list) return\n                for (l = list.length; i < l; i++) {\n                  if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return\n                }\n              }\n            }\n\n          , has = function (element, type, original, root) {\n              // we're not using forAll here simply because it's a bit slower and this\n              // needs to be fast\n              var i, list = map[(root ? 'r' : '$') + type]\n              if (list) {\n                for (i = list.length; i--;) {\n                  if (!list[i].root && list[i].matches(element, original, null)) return true\n                }\n              }\n              return false\n            }\n\n          , get = function (element, type, original, root) {\n              var entries = []\n              forAll(element, type, original, null, root, function (entry) {\n                return entries.push(entry)\n              })\n              return entries\n            }\n\n          , put = function (entry) {\n              var has = !entry.root && !this.has(entry.element, entry.type, null, false)\n                , key = (entry.root ? 'r' : '$') + entry.type\n              ;(map[key] || (map[key] = [])).push(entry)\n              return has\n            }\n\n          , del = function (entry) {\n              forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) {\n                list.splice(i, 1)\n                entry.removed = true\n                if (list.length === 0) delete map[(entry.root ? 'r' : '$') + entry.type]\n                return false\n              })\n            }\n\n            // dump all entries, used for onunload\n          , entries = function () {\n              var t, entries = []\n              for (t in map) {\n                if (t.charAt(0) == '$') entries = entries.concat(map[t])\n              }\n              return entries\n            }\n\n        return { has: has, get: get, put: put, del: del, entries: entries }\n      }())\n\n      // we need a selector engine for delegated events, use querySelectorAll if it exists\n      // but for older browsers we need Qwery, Sizzle or similar\n    , selectorEngine\n    , setSelectorEngine = function (e) {\n        if (!arguments.length) {\n          selectorEngine = doc.querySelectorAll\n            ? function (s, r) {\n                return r.querySelectorAll(s)\n              }\n            : function () {\n                throw new Error('Bean: No selector engine installed') // eeek\n              }\n        } else {\n          selectorEngine = e\n        }\n      }\n\n      // we attach this listener to each DOM event that we need to listen to, only once\n      // per event type per DOM element\n    , rootListener = function (event, type) {\n        if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return\n\n        var listeners = registry.get(this, type || event.type, null, false)\n          , l = listeners.length\n          , i = 0\n\n        event = new Event(event, this, true)\n        if (type) event.type = type\n\n        // iterate through all handlers registered for this type, calling them unless they have\n        // been removed by a previous handler or stopImmediatePropagation() has been called\n        for (; i < l && !event.isImmediatePropagationStopped(); i++) {\n          if (!listeners[i].removed) listeners[i].handler.call(this, event)\n        }\n      }\n\n      // add and remove listeners to DOM elements\n    , listener = W3C_MODEL\n        ? function (element, type, add) {\n            // new browsers\n            element[add ? addEvent : removeEvent](type, rootListener, false)\n          }\n        : function (element, type, add, custom) {\n            // IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events\n            // to simulate event bubbling etc.\n            var entry\n            if (add) {\n              registry.put(entry = new RegEntry(\n                  element\n                , custom || type\n                , function (event) { // handler\n                    rootListener.call(element, event, custom)\n                  }\n                , rootListener\n                , null\n                , null\n                , true // is root\n              ))\n              if (custom && element['_on' + custom] == null) element['_on' + custom] = 0\n              entry.target.attachEvent('on' + entry.eventType, entry.handler)\n            } else {\n              entry = registry.get(element, custom || type, rootListener, true)[0]\n              if (entry) {\n                entry.target.detachEvent('on' + entry.eventType, entry.handler)\n                registry.del(entry)\n              }\n            }\n          }\n\n    , once = function (rm, element, type, fn, originalFn) {\n        // wrap the handler in a handler that does a remove as well\n        return function () {\n          fn.apply(this, arguments)\n          rm(element, type, originalFn)\n        }\n      }\n\n    , removeListener = function (element, orgType, handler, namespaces) {\n        var type     = orgType && orgType.replace(nameRegex, '')\n          , handlers = registry.get(element, type, null, false)\n          , removed  = {}\n          , i, l\n\n        for (i = 0, l = handlers.length; i < l; i++) {\n          if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) {\n            // TODO: this is problematic, we have a registry.get() and registry.del() that\n            // both do registry searches so we waste cycles doing this. Needs to be rolled into\n            // a single registry.forAll(fn) that removes while finding, but the catch is that\n            // we'll be splicing the arrays that we're iterating over. Needs extra tests to\n            // make sure we don't screw it up. @rvagg\n            registry.del(handlers[i])\n            if (!removed[handlers[i].eventType] && handlers[i][eventSupport])\n              removed[handlers[i].eventType] = { t: handlers[i].eventType, c: handlers[i].type }\n          }\n        }\n        // check each type/element for removed listeners and remove the rootListener where it's no longer needed\n        for (i in removed) {\n          if (!registry.has(element, removed[i].t, null, false)) {\n            // last listener of this type, remove the rootListener\n            listener(element, removed[i].t, false, removed[i].c)\n          }\n        }\n      }\n\n      // set up a delegate helper using the given selector, wrap the handler function\n    , delegate = function (selector, fn) {\n        //TODO: findTarget (therefore $) is called twice, once for match and once for\n        // setting e.currentTarget, fix this so it's only needed once\n        var findTarget = function (target, root) {\n              var i, array = isString(selector) ? selectorEngine(selector, root) : selector\n              for (; target && target !== root; target = target.parentNode) {\n                for (i = array.length; i--;) {\n                  if (array[i] === target) return target\n                }\n              }\n            }\n          , handler = function (e) {\n              var match = findTarget(e.target, this)\n              if (match) fn.apply(match, arguments)\n            }\n\n        // __beanDel isn't pleasant but it's a private function, not exposed outside of Bean\n        handler.__beanDel = {\n            ft       : findTarget // attach it here for customEvents to use too\n          , selector : selector\n        }\n        return handler\n      }\n\n    , fireListener = W3C_MODEL ? function (isNative, type, element) {\n        // modern browsers, do a proper dispatchEvent()\n        var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')\n        evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)\n        element.dispatchEvent(evt)\n      } : function (isNative, type, element) {\n        // old browser use onpropertychange, just increment a custom property to trigger the event\n        element = targetElement(element, isNative)\n        isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++\n      }\n\n      /**\n        * Public API: off(), on(), add(), (remove()), one(), fire(), clone()\n        */\n\n      /**\n        * off(element[, eventType(s)[, handler ]])\n        */\n    , off = function (element, typeSpec, fn) {\n        var isTypeStr = isString(typeSpec)\n          , k, type, namespaces, i\n\n        if (isTypeStr && typeSpec.indexOf(' ') > 0) {\n          // off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3')\n          typeSpec = str2arr(typeSpec)\n          for (i = typeSpec.length; i--;)\n            off(element, typeSpec[i], fn)\n          return element\n        }\n\n        type = isTypeStr && typeSpec.replace(nameRegex, '')\n        if (type && customEvents[type]) type = customEvents[type].base\n\n        if (!typeSpec || isTypeStr) {\n          // off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3)\n          if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.')\n          removeListener(element, type, fn, namespaces)\n        } else if (isFunction(typeSpec)) {\n          // off(el, fn)\n          removeListener(element, null, typeSpec)\n        } else {\n          // off(el, { t1: fn1, t2, fn2 })\n          for (k in typeSpec) {\n            if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k])\n          }\n        }\n\n        return element\n      }\n\n      /**\n        * on(element, eventType(s)[, selector], handler[, args ])\n        */\n    , on = function(element, events, selector, fn) {\n        var originalFn, type, types, i, args, entry, first\n\n        //TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps?\n        if (selector === undefined && typeof events == 'object') {\n          //TODO: this can't handle delegated events\n          for (type in events) {\n            if (events.hasOwnProperty(type)) {\n              on.call(this, element, type, events[type])\n            }\n          }\n          return\n        }\n\n        if (!isFunction(selector)) {\n          // delegated event\n          originalFn = fn\n          args       = slice.call(arguments, 4)\n          fn         = delegate(selector, originalFn, selectorEngine)\n        } else {\n          args       = slice.call(arguments, 3)\n          fn         = originalFn = selector\n        }\n\n        types = str2arr(events)\n\n        // special case for one(), wrap in a self-removing handler\n        if (this === ONE) {\n          fn = once(off, element, events, fn, originalFn)\n        }\n\n        for (i = types.length; i--;) {\n          // add new handler to the registry and check if it's the first for this element/type\n          first = registry.put(entry = new RegEntry(\n              element\n            , types[i].replace(nameRegex, '') // event type\n            , fn\n            , originalFn\n            , str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces\n            , args\n            , false // not root\n          ))\n          if (entry[eventSupport] && first) {\n            // first event of this type on this element, add root listener\n            listener(element, entry.eventType, true, entry.customType)\n          }\n        }\n\n        return element\n      }\n\n      /**\n        * add(element[, selector], eventType(s), handler[, args ])\n        *\n        * Deprecated: kept (for now) for backward-compatibility\n        */\n    , add = function (element, events, fn, delfn) {\n        return on.apply(\n            null\n          , !isString(fn)\n              ? slice.call(arguments)\n              : [ element, fn, events, delfn ].concat(arguments.length > 3 ? slice.call(arguments, 5) : [])\n        )\n      }\n\n      /**\n        * one(element, eventType(s)[, selector], handler[, args ])\n        */\n    , one = function () {\n        return on.apply(ONE, arguments)\n      }\n\n      /**\n        * fire(element, eventType(s)[, args ])\n        *\n        * The optional 'args' argument must be an array, if no 'args' argument is provided\n        * then we can use the browser's DOM event system, otherwise we trigger handlers manually\n        */\n    , fire = function (element, type, args) {\n        var types = str2arr(type)\n          , i, j, l, names, handlers\n\n        for (i = types.length; i--;) {\n          type = types[i].replace(nameRegex, '')\n          if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.')\n          if (!names && !args && element[eventSupport]) {\n            fireListener(nativeEvents[type], type, element)\n          } else {\n            // non-native event, either because of a namespace, arguments or a non DOM element\n            // iterate over all listeners and manually 'fire'\n            handlers = registry.get(element, type, null, false)\n            args = [false].concat(args)\n            for (j = 0, l = handlers.length; j < l; j++) {\n              if (handlers[j].inNamespaces(names)) {\n                handlers[j].handler.apply(element, args)\n              }\n            }\n          }\n        }\n        return element\n      }\n\n      /**\n        * clone(dstElement, srcElement[, eventType ])\n        *\n        * TODO: perhaps for consistency we should allow the same flexibility in type specifiers?\n        */\n    , clone = function (element, from, type) {\n        var handlers = registry.get(from, type, null, false)\n          , l = handlers.length\n          , i = 0\n          , args, beanDel\n\n        for (; i < l; i++) {\n          if (handlers[i].original) {\n            args = [ element, handlers[i].type ]\n            if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector)\n            args.push(handlers[i].original)\n            on.apply(null, args)\n          }\n        }\n        return element\n      }\n\n    , bean = {\n          on                : on\n        , add               : add\n        , one               : one\n        , off               : off\n        , remove            : off\n        , clone             : clone\n        , fire              : fire\n        , setSelectorEngine : setSelectorEngine\n        , noConflict        : function () {\n            context[name] = old\n            return this\n          }\n      }\n\n  // for IE, clean up on unload to avoid leaks\n  if (win.attachEvent) {\n    var cleanup = function () {\n      var i, entries = registry.entries()\n      for (i in entries) {\n        if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type)\n      }\n      win.detachEvent('onunload', cleanup)\n      win.CollectGarbage && win.CollectGarbage()\n    }\n    win.attachEvent('onunload', cleanup)\n  }\n\n  // initialize selector engine to internal default (qSA or throw Error)\n  setSelectorEngine()\n\n  return bean\n});"
  },
  {
    "path": "vendors/baron/js/bonzo.js",
    "content": "/*!\n  * Bonzo: DOM Utility (c) Dustin Diaz 2012\n  * https://github.com/ded/bonzo\n  * License MIT\n  */\n(function (name, context, definition) {\n  if (typeof module != 'undefined' && module.exports) module.exports = definition()\n  else if (typeof define == 'function' && define.amd) define(definition)\n  else context[name] = definition()\n})('bonzo', this, function() {\n  var win = window\n    , doc = win.document\n    , html = doc.documentElement\n    , parentNode = 'parentNode'\n    , specialAttributes = /^(checked|value|selected|disabled)$/i\n    , specialTags = /^(select|fieldset|table|tbody|tfoot|td|tr|colgroup)$/i // tags that we have trouble inserting *into*\n    , simpleScriptTagRe = /\\s*<script +src=['\"]([^'\"]+)['\"]>/\n    , table = ['<table>', '</table>', 1]\n    , td = ['<table><tbody><tr>', '</tr></tbody></table>', 3]\n    , option = ['<select>', '</select>', 1]\n    , noscope = ['_', '', 0, 1]\n    , tagMap = { // tags that we have trouble *inserting*\n          thead: table, tbody: table, tfoot: table, colgroup: table, caption: table\n        , tr: ['<table><tbody>', '</tbody></table>', 2]\n        , th: td , td: td\n        , col: ['<table><colgroup>', '</colgroup></table>', 2]\n        , fieldset: ['<form>', '</form>', 1]\n        , legend: ['<form><fieldset>', '</fieldset></form>', 2]\n        , option: option, optgroup: option\n        , script: noscope, style: noscope, link: noscope, param: noscope, base: noscope\n      }\n    , stateAttributes = /^(checked|selected|disabled)$/\n    , ie = /msie/i.test(navigator.userAgent)\n    , hasClass, addClass, removeClass\n    , uidMap = {}\n    , uuids = 0\n    , digit = /^-?[\\d\\.]+$/\n    , dattr = /^data-(.+)$/\n    , px = 'px'\n    , setAttribute = 'setAttribute'\n    , getAttribute = 'getAttribute'\n    , byTag = 'getElementsByTagName'\n    , features = function() {\n        var e = doc.createElement('p')\n        e.innerHTML = '<a href=\"#x\">x</a><table style=\"float:left;\"></table>'\n        return {\n          hrefExtended: e[byTag]('a')[0][getAttribute]('href') != '#x' // IE < 8\n        , autoTbody: e[byTag]('tbody').length !== 0 // IE < 8\n        , computedStyle: doc.defaultView && doc.defaultView.getComputedStyle\n        , cssFloat: e[byTag]('table')[0].style.styleFloat ? 'styleFloat' : 'cssFloat'\n        , transform: function () {\n            var props = ['transform', 'webkitTransform', 'MozTransform', 'OTransform', 'msTransform'], i\n            for (i = 0; i < props.length; i++) {\n              if (props[i] in e.style) return props[i]\n            }\n          }()\n        , classList: 'classList' in e\n        , opasity: function () {\n            return typeof doc.createElement('a').style.opacity !== 'undefined'\n          }()\n        }\n      }()\n    , trimReplace = /(^\\s*|\\s*$)/g\n    , whitespaceRegex = /\\s+/\n    , toString = String.prototype.toString\n    , unitless = { lineHeight: 1, zoom: 1, zIndex: 1, opacity: 1, boxFlex: 1, WebkitBoxFlex: 1, MozBoxFlex: 1 }\n    , query = doc.querySelectorAll && function (selector) { return doc.querySelectorAll(selector) }\n    , trim = String.prototype.trim ?\n        function (s) {\n          return s.trim()\n        } :\n        function (s) {\n          return s.replace(trimReplace, '')\n        }\n\n\n  function isNode(node) {\n    return node && node.nodeName && (node.nodeType == 1 || node.nodeType == 11)\n  }\n\n\n  function normalize(node, host, clone) {\n    var i, l, ret\n    if (typeof node == 'string') return bonzo.create(node)\n    if (isNode(node)) node = [ node ]\n    if (clone) {\n      ret = [] // don't change original array\n      for (i = 0, l = node.length; i < l; i++) ret[i] = cloneNode(host, node[i])\n      return ret\n    }\n    return node\n  }\n\n\n  /**\n   * @param {string} c a class name to test\n   * @return {boolean}\n   */\n  function classReg(c) {\n    return new RegExp(\"(^|\\\\s+)\" + c + \"(\\\\s+|$)\")\n  }\n\n\n  /**\n   * @param {Bonzo|Array} ar\n   * @param {function(Object, number, (Bonzo|Array))} fn\n   * @param {Object=} opt_scope\n   * @param {boolean=} opt_rev\n   * @return {Bonzo|Array}\n   */\n  function each(ar, fn, opt_scope, opt_rev) {\n    var ind, i = 0, l = ar.length\n    for (; i < l; i++) {\n      ind = opt_rev ? ar.length - i - 1 : i\n      fn.call(opt_scope || ar[ind], ar[ind], ind, ar)\n    }\n    return ar\n  }\n\n\n  /**\n   * @param {Bonzo|Array} ar\n   * @param {function(Object, number, (Bonzo|Array))} fn\n   * @param {Object=} opt_scope\n   * @return {Bonzo|Array}\n   */\n  function deepEach(ar, fn, opt_scope) {\n    for (var i = 0, l = ar.length; i < l; i++) {\n      if (isNode(ar[i])) {\n        deepEach(ar[i].childNodes, fn, opt_scope)\n        fn.call(opt_scope || ar[i], ar[i], i, ar)\n      }\n    }\n    return ar\n  }\n\n\n  /**\n   * @param {string} s\n   * @return {string}\n   */\n  function camelize(s) {\n    return s.replace(/-(.)/g, function (m, m1) {\n      return m1.toUpperCase()\n    })\n  }\n\n\n  /**\n   * @param {string} s\n   * @return {string}\n   */\n  function decamelize(s) {\n    return s ? s.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : s\n  }\n\n\n  /**\n   * @param {Element} el\n   * @return {*}\n   */\n  function data(el) {\n    el[getAttribute]('data-node-uid') || el[setAttribute]('data-node-uid', ++uuids)\n    var uid = el[getAttribute]('data-node-uid')\n    return uidMap[uid] || (uidMap[uid] = {})\n  }\n\n\n  /**\n   * removes the data associated with an element\n   * @param {Element} el\n   */\n  function clearData(el) {\n    var uid = el[getAttribute]('data-node-uid')\n    if (uid) delete uidMap[uid]\n  }\n\n\n  function dataValue(d) {\n    var f\n    try {\n      return (d === null || d === undefined) ? undefined :\n        d === 'true' ? true :\n          d === 'false' ? false :\n            d === 'null' ? null :\n              (f = parseFloat(d)) == d ? f : d;\n    } catch(e) {}\n    return undefined\n  }\n\n\n  /**\n   * @param {Bonzo|Array} ar\n   * @param {function(Object, number, (Bonzo|Array))} fn\n   * @param {Object=} opt_scope\n   * @return {boolean} whether `some`thing was found\n   */\n  function some(ar, fn, opt_scope) {\n    for (var i = 0, j = ar.length; i < j; ++i) if (fn.call(opt_scope || null, ar[i], i, ar)) return true\n    return false\n  }\n\n\n  /**\n   * this could be a giant enum of CSS properties\n   * but in favor of file size sans-closure deadcode optimizations\n   * we're just asking for any ol string\n   * then it gets transformed into the appropriate style property for JS access\n   * @param {string} p\n   * @return {string}\n   */\n  function styleProperty(p) {\n      (p == 'transform' && (p = features.transform)) ||\n        (/^transform-?[Oo]rigin$/.test(p) && (p = features.transform + 'Origin')) ||\n        (p == 'float' && (p = features.cssFloat))\n      return p ? camelize(p) : null\n  }\n\n  var getStyle = features.computedStyle ?\n    function (el, property) {\n      var value = null\n        , computed = doc.defaultView.getComputedStyle(el, '')\n      computed && (value = computed[property])\n      return el.style[property] || value\n    } :\n\n    (ie && html.currentStyle) ?\n\n    /**\n     * @param {Element} el\n     * @param {string} property\n     * @return {string|number}\n     */\n    function (el, property) {\n      if (property == 'opacity' && !features.opasity) {\n        var val = 100\n        try {\n          val = el['filters']['DXImageTransform.Microsoft.Alpha'].opacity\n        } catch (e1) {\n          try {\n            val = el['filters']('alpha').opacity\n          } catch (e2) {}\n        }\n        return val / 100\n      }\n      var value = el.currentStyle ? el.currentStyle[property] : null\n      return el.style[property] || value\n    } :\n\n    function (el, property) {\n      return el.style[property]\n    }\n\n  // this insert method is intense\n  function insert(target, host, fn, rev) {\n    var i = 0, self = host || this, r = []\n      // target nodes could be a css selector if it's a string and a selector engine is present\n      // otherwise, just use target\n      , nodes = query && typeof target == 'string' && target.charAt(0) != '<' ? query(target) : target\n    // normalize each node in case it's still a string and we need to create nodes on the fly\n    each(normalize(nodes), function (t, j) {\n      each(self, function (el) {\n        fn(t, r[i++] = j > 0 ? cloneNode(self, el) : el)\n      }, null, rev)\n    }, this, rev)\n    self.length = i\n    each(r, function (e) {\n      self[--i] = e\n    }, null, !rev)\n    return self\n  }\n\n\n  /**\n   * sets an element to an explicit x/y position on the page\n   * @param {Element} el\n   * @param {?number} x\n   * @param {?number} y\n   */\n  function xy(el, x, y) {\n    var $el = bonzo(el)\n      , style = $el.css('position')\n      , offset = $el.offset()\n      , rel = 'relative'\n      , isRel = style == rel\n      , delta = [parseInt($el.css('left'), 10), parseInt($el.css('top'), 10)]\n\n    if (style == 'static') {\n      $el.css('position', rel)\n      style = rel\n    }\n\n    isNaN(delta[0]) && (delta[0] = isRel ? 0 : el.offsetLeft)\n    isNaN(delta[1]) && (delta[1] = isRel ? 0 : el.offsetTop)\n\n    x != null && (el.style.left = x - offset.left + delta[0] + px)\n    y != null && (el.style.top = y - offset.top + delta[1] + px)\n\n  }\n\n  // classList support for class management\n  // altho to be fair, the api sucks because it won't accept multiple classes at once\n  if (features.classList) {\n    hasClass = function (el, c) {\n      return el.classList.contains(c)\n    }\n    addClass = function (el, c) {\n      el.classList.add(c)\n    }\n    removeClass = function (el, c) {\n      el.classList.remove(c)\n    }\n  }\n  else {\n    hasClass = function (el, c) {\n      return classReg(c).test(el.className)\n    }\n    addClass = function (el, c) {\n      el.className = trim(el.className + ' ' + c)\n    }\n    removeClass = function (el, c) {\n      el.className = trim(el.className.replace(classReg(c), ' '))\n    }\n  }\n\n\n  /**\n   * this allows method calling for setting values\n   *\n   * @example\n   * bonzo(elements).css('color', function (el) {\n   *   return el.getAttribute('data-original-color')\n   * })\n   *\n   * @param {Element} el\n   * @param {function (Element)|string}\n   * @return {string}\n   */\n  function setter(el, v) {\n    return typeof v == 'function' ? v(el) : v\n  }\n\n  /**\n   * @constructor\n   * @param {Array.<Element>|Element|Node|string} elements\n   */\n  function Bonzo(elements) {\n    this.length = 0\n    if (elements) {\n      elements = typeof elements !== 'string' &&\n        !elements.nodeType &&\n        typeof elements.length !== 'undefined' ?\n          elements :\n          [elements]\n      this.length = elements.length\n      for (var i = 0; i < elements.length; i++) this[i] = elements[i]\n    }\n  }\n\n  Bonzo.prototype = {\n\n      /**\n       * @param {number} index\n       * @return {Element|Node}\n       */\n      get: function (index) {\n        return this[index] || null\n      }\n\n      // itetators\n      /**\n       * @param {function(Element|Node)} fn\n       * @param {Object=} opt_scope\n       * @return {Bonzo}\n       */\n    , each: function (fn, opt_scope) {\n        return each(this, fn, opt_scope)\n      }\n\n      /**\n       * @param {Function} fn\n       * @param {Object=} opt_scope\n       * @return {Bonzo}\n       */\n    , deepEach: function (fn, opt_scope) {\n        return deepEach(this, fn, opt_scope)\n      }\n\n\n      /**\n       * @param {Function} fn\n       * @param {Function=} opt_reject\n       * @return {Array}\n       */\n    , map: function (fn, opt_reject) {\n        var m = [], n, i\n        for (i = 0; i < this.length; i++) {\n          n = fn.call(this, this[i], i)\n          opt_reject ? (opt_reject(n) && m.push(n)) : m.push(n)\n        }\n        return m\n      }\n\n    // text and html inserters!\n\n    /**\n     * @param {string} h the HTML to insert\n     * @param {boolean=} opt_text whether to set or get text content\n     * @return {Bonzo|string}\n     */\n    , html: function (h, opt_text) {\n        var method = opt_text\n              ? html.textContent === undefined ? 'innerText' : 'textContent'\n              : 'innerHTML'\n          , that = this\n          , append = function (el, i) {\n              each(normalize(h, that, i), function (node) {\n                el.appendChild(node)\n              })\n            }\n          , updateElement = function (el, i) {\n              try {\n                if (opt_text || (typeof h == 'string' && !specialTags.test(el.tagName))) {\n                  return el[method] = h\n                }\n              } catch (e) {}\n              append(el, i)\n            }\n        return typeof h != 'undefined'\n          ? this.empty().each(updateElement)\n          : this[0] ? this[0][method] : ''\n      }\n\n      /**\n       * @param {string=} opt_text the text to set, otherwise this is a getter\n       * @return {Bonzo|string}\n       */\n    , text: function (opt_text) {\n        return this.html(opt_text, true)\n      }\n\n      // more related insertion methods\n\n      /**\n       * @param {Bonzo|string|Element|Array} node\n       * @return {Bonzo}\n       */\n    , append: function (node) {\n        var that = this\n        return this.each(function (el, i) {\n          each(normalize(node, that, i), function (i) {\n            el.appendChild(i)\n          })\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} node\n       * @return {Bonzo}\n       */\n    , prepend: function (node) {\n        var that = this\n        return this.each(function (el, i) {\n          var first = el.firstChild\n          each(normalize(node, that, i), function (i) {\n            el.insertBefore(i, first)\n          })\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content\n       * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)\n       * @return {Bonzo}\n       */\n    , appendTo: function (target, opt_host) {\n        return insert.call(this, target, opt_host, function (t, el) {\n          t.appendChild(el)\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content\n       * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)\n       * @return {Bonzo}\n       */\n    , prependTo: function (target, opt_host) {\n        return insert.call(this, target, opt_host, function (t, el) {\n          t.insertBefore(el, t.firstChild)\n        }, 1)\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} node\n       * @return {Bonzo}\n       */\n    , before: function (node) {\n        var that = this\n        return this.each(function (el, i) {\n          each(normalize(node, that, i), function (i) {\n            el[parentNode].insertBefore(i, el)\n          })\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} node\n       * @return {Bonzo}\n       */\n    , after: function (node) {\n        var that = this\n        return this.each(function (el, i) {\n          each(normalize(node, that, i), function (i) {\n            el[parentNode].insertBefore(i, el.nextSibling)\n          }, null, 1)\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content\n       * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)\n       * @return {Bonzo}\n       */\n    , insertBefore: function (target, opt_host) {\n        return insert.call(this, target, opt_host, function (t, el) {\n          t[parentNode].insertBefore(el, t)\n        })\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} target the location for which you'll insert your new content\n       * @param {Object=} opt_host an optional host scope (primarily used when integrated with Ender)\n       * @return {Bonzo}\n       */\n    , insertAfter: function (target, opt_host) {\n        return insert.call(this, target, opt_host, function (t, el) {\n          var sibling = t.nextSibling\n          sibling ?\n            t[parentNode].insertBefore(el, sibling) :\n            t[parentNode].appendChild(el)\n        }, 1)\n      }\n\n\n      /**\n       * @param {Bonzo|string|Element|Array} node\n       * @return {Bonzo}\n       */\n    , replaceWith: function (node) {\n        bonzo(normalize(node)).insertAfter(this)\n        return this.remove()\n      }\n\n      // class management\n\n      /**\n       * @param {string} c\n       * @return {Bonzo}\n       */\n    , addClass: function (c) {\n        c = toString.call(c).split(whitespaceRegex)\n        return this.each(function (el) {\n          // we `each` here so you can do $el.addClass('foo bar')\n          each(c, function (c) {\n            if (c && !hasClass(el, setter(el, c)))\n              addClass(el, setter(el, c))\n          })\n        })\n      }\n\n\n      /**\n       * @param {string} c\n       * @return {Bonzo}\n       */\n    , removeClass: function (c) {\n        c = toString.call(c).split(whitespaceRegex)\n        return this.each(function (el) {\n          each(c, function (c) {\n            if (c && hasClass(el, setter(el, c)))\n              removeClass(el, setter(el, c))\n          })\n        })\n      }\n\n\n      /**\n       * @param {string} c\n       * @return {boolean}\n       */\n    , hasClass: function (c) {\n        c = toString.call(c).split(whitespaceRegex)\n        return some(this, function (el) {\n          return some(c, function (c) {\n            return c && hasClass(el, c)\n          })\n        })\n      }\n\n\n      /**\n       * @param {string} c classname to toggle\n       * @param {boolean=} opt_condition whether to add or remove the class straight away\n       * @return {Bonzo}\n       */\n    , toggleClass: function (c, opt_condition) {\n        c = toString.call(c).split(whitespaceRegex)\n        return this.each(function (el) {\n          each(c, function (c) {\n            if (c) {\n              typeof opt_condition !== 'undefined' ?\n                opt_condition ? !hasClass(el, c) && addClass(el, c) : removeClass(el, c) :\n                hasClass(el, c) ? removeClass(el, c) : addClass(el, c)\n            }\n          })\n        })\n      }\n\n      // display togglers\n\n      /**\n       * @param {string=} opt_type useful to set back to anything other than an empty string\n       * @return {Bonzo}\n       */\n    , show: function (opt_type) {\n        opt_type = typeof opt_type == 'string' ? opt_type : ''\n        return this.each(function (el) {\n          el.style.display = opt_type\n        })\n      }\n\n\n      /**\n       * @return {Bonzo}\n       */\n    , hide: function () {\n        return this.each(function (el) {\n          el.style.display = 'none'\n        })\n      }\n\n\n      /**\n       * @param {Function=} opt_callback\n       * @param {string=} opt_type\n       * @return {Bonzo}\n       */\n    , toggle: function (opt_callback, opt_type) {\n        opt_type = typeof opt_type == 'string' ? opt_type : '';\n        typeof opt_callback != 'function' && (opt_callback = null)\n        return this.each(function (el) {\n          el.style.display = (el.offsetWidth || el.offsetHeight) ? 'none' : opt_type;\n          opt_callback && opt_callback.call(el)\n        })\n      }\n\n\n      // DOM Walkers & getters\n\n      /**\n       * @return {Element|Node}\n       */\n    , first: function () {\n        return bonzo(this.length ? this[0] : [])\n      }\n\n\n      /**\n       * @return {Element|Node}\n       */\n    , last: function () {\n        return bonzo(this.length ? this[this.length - 1] : [])\n      }\n\n\n      /**\n       * @return {Element|Node}\n       */\n    , next: function () {\n        return this.related('nextSibling')\n      }\n\n\n      /**\n       * @return {Element|Node}\n       */\n    , previous: function () {\n        return this.related('previousSibling')\n      }\n\n\n      /**\n       * @return {Element|Node}\n       */\n    , parent: function() {\n        return this.related(parentNode)\n      }\n\n\n      /**\n       * @private\n       * @param {string} method the directional DOM method\n       * @return {Element|Node}\n       */\n    , related: function (method) {\n        return this.map(\n          function (el) {\n            el = el[method]\n            while (el && el.nodeType !== 1) {\n              el = el[method]\n            }\n            return el || 0\n          },\n          function (el) {\n            return el\n          }\n        )\n      }\n\n\n      /**\n       * @return {Bonzo}\n       */\n    , focus: function () {\n        this.length && this[0].focus()\n        return this\n      }\n\n\n      /**\n       * @return {Bonzo}\n       */\n    , blur: function () {\n        this.length && this[0].blur()\n        return this\n      }\n\n      // style getter setter & related methods\n\n      /**\n       * @param {Object|string} o\n       * @param {string=} opt_v\n       * @return {Bonzo|string}\n       */\n    , css: function (o, opt_v) {\n        var p, iter = o\n        // is this a request for just getting a style?\n        if (opt_v === undefined && typeof o == 'string') {\n          // repurpose 'v'\n          opt_v = this[0]\n          if (!opt_v) return null\n          if (opt_v === doc || opt_v === win) {\n            p = (opt_v === doc) ? bonzo.doc() : bonzo.viewport()\n            return o == 'width' ? p.width : o == 'height' ? p.height : ''\n          }\n          return (o = styleProperty(o)) ? getStyle(opt_v, o) : null\n        }\n\n        if (typeof o == 'string') {\n          iter = {}\n          iter[o] = opt_v\n        }\n\n        if (ie && iter.opacity) {\n          // oh this 'ol gamut\n          iter.filter = 'alpha(opacity=' + (iter.opacity * 100) + ')'\n          // give it layout\n          iter.zoom = o.zoom || 1;\n          delete iter.opacity;\n        }\n\n        function fn(el, p, v) {\n          for (var k in iter) {\n            if (iter.hasOwnProperty(k)) {\n              v = iter[k];\n              // change \"5\" to \"5px\" - unless you're line-height, which is allowed\n              (p = styleProperty(k)) && digit.test(v) && !(p in unitless) && (v += px)\n              try { el.style[p] = setter(el, v) } catch(e) {}\n            }\n          }\n        }\n        return this.each(fn)\n      }\n\n\n      /**\n       * @param {number=} opt_x\n       * @param {number=} opt_y\n       * @return {Bonzo|number}\n       */\n    , offset: function (opt_x, opt_y) {\n        if (opt_x && typeof opt_x == 'object' && (typeof opt_x.top == 'number' || typeof opt_x.left == 'number')) {\n          return this.each(function (el) {\n            xy(el, opt_x.left, opt_x.top)\n          })\n        } else if (typeof opt_x == 'number' || typeof opt_y == 'number') {\n          return this.each(function (el) {\n            xy(el, opt_x, opt_y)\n          })\n        }\n        if (!this[0]) return {\n            top: 0\n          , left: 0\n          , height: 0\n          , width: 0\n        }\n        var el = this[0]\n          , de = el.ownerDocument.documentElement\n          , bcr = el.getBoundingClientRect()\n          , scroll = getWindowScroll()\n          , width = el.offsetWidth\n          , height = el.offsetHeight\n          , top = bcr.top + scroll.y - Math.max(0, de && de.clientTop, doc.body.clientTop)\n          , left = bcr.left + scroll.x - Math.max(0, de && de.clientLeft, doc.body.clientLeft)\n\n        return {\n            top: top\n          , left: left\n          , height: height\n          , width: width\n        }\n      }\n\n\n      /**\n       * @return {number}\n       */\n    , dim: function () {\n        if (!this.length) return { height: 0, width: 0 }\n        var el = this[0]\n          , de = el.nodeType == 9 && el.documentElement // document\n          , orig = !de && !!el.style && !el.offsetWidth && !el.offsetHeight ?\n             // el isn't visible, can't be measured properly, so fix that\n             function (t) {\n               var s = {\n                   position: el.style.position || ''\n                 , visibility: el.style.visibility || ''\n                 , display: el.style.display || ''\n               }\n               t.first().css({\n                   position: 'absolute'\n                 , visibility: 'hidden'\n                 , display: 'block'\n               })\n               return s\n            }(this) : null\n          , width = de\n              ? Math.max(el.body.scrollWidth, el.body.offsetWidth, de.scrollWidth, de.offsetWidth, de.clientWidth)\n              : el.offsetWidth\n          , height = de\n              ? Math.max(el.body.scrollHeight, el.body.offsetHeight, de.scrollHeight, de.offsetHeight, de.clientHeight)\n              : el.offsetHeight\n\n        orig && this.first().css(orig)\n        return {\n            height: height\n          , width: width\n        }\n      }\n\n      // attributes are hard. go shopping\n\n      /**\n       * @param {string} k an attribute to get or set\n       * @param {string=} opt_v the value to set\n       * @return {Bonzo|string}\n       */\n    , attr: function (k, opt_v) {\n        var el = this[0]\n        if (typeof k != 'string' && !(k instanceof String)) {\n          for (var n in k) {\n            k.hasOwnProperty(n) && this.attr(n, k[n])\n          }\n          return this\n        }\n        return typeof opt_v == 'undefined' ?\n          !el ? null : specialAttributes.test(k) ?\n            stateAttributes.test(k) && typeof el[k] == 'string' ?\n              true : el[k] : (k == 'href' || k =='src') && features.hrefExtended ?\n                el[getAttribute](k, 2) : el[getAttribute](k) :\n          this.each(function (el) {\n            specialAttributes.test(k) ? (el[k] = setter(el, opt_v)) : el[setAttribute](k, setter(el, opt_v))\n          })\n      }\n\n\n      /**\n       * @param {string} k\n       * @return {Bonzo}\n       */\n    , removeAttr: function (k) {\n        return this.each(function (el) {\n          stateAttributes.test(k) ? (el[k] = false) : el.removeAttribute(k)\n        })\n      }\n\n\n      /**\n       * @param {string=} opt_s\n       * @return {Bonzo|string}\n       */\n    , val: function (s) {\n        return (typeof s == 'string') ?\n          this.attr('value', s) :\n          this.length ? this[0].value : null\n      }\n\n      // use with care and knowledge. this data() method uses data attributes on the DOM nodes\n      // to do this differently costs a lot more code. c'est la vie\n      /**\n       * @param {string|Object=} opt_k the key for which to get or set data\n       * @param {Object=} opt_v\n       * @return {Bonzo|Object}\n       */\n    , data: function (opt_k, opt_v) {\n        var el = this[0], o, m\n        if (typeof opt_v === 'undefined') {\n          if (!el) return null\n          o = data(el)\n          if (typeof opt_k === 'undefined') {\n            each(el.attributes, function (a) {\n              (m = ('' + a.name).match(dattr)) && (o[camelize(m[1])] = dataValue(a.value))\n            })\n            return o\n          } else {\n            if (typeof o[opt_k] === 'undefined')\n              o[opt_k] = dataValue(this.attr('data-' + decamelize(opt_k)))\n            return o[opt_k]\n          }\n        } else {\n          return this.each(function (el) { data(el)[opt_k] = opt_v })\n        }\n      }\n\n      // DOM detachment & related\n\n      /**\n       * @return {Bonzo}\n       */\n    , remove: function () {\n        this.deepEach(clearData)\n        return this.detach()\n      }\n\n\n      /**\n       * @return {Bonzo}\n       */\n    , empty: function () {\n        return this.each(function (el) {\n          deepEach(el.childNodes, clearData)\n\n          while (el.firstChild) {\n            el.removeChild(el.firstChild)\n          }\n        })\n      }\n\n\n      /**\n       * @return {Bonzo}\n       */\n    , detach: function () {\n        return this.each(function (el) {\n          el[parentNode] && el[parentNode].removeChild(el)\n        })\n      }\n\n      // who uses a mouse anyway? oh right.\n\n      /**\n       * @param {number} y\n       */\n    , scrollTop: function (y) {\n        return scroll.call(this, null, y, 'y')\n      }\n\n\n      /**\n       * @param {number} x\n       */\n    , scrollLeft: function (x) {\n        return scroll.call(this, x, null, 'x')\n      }\n\n  }\n\n\n  function cloneNode(host, el) {\n    var c = el.cloneNode(true)\n      , cloneElems\n      , elElems\n\n    // check for existence of an event cloner\n    // preferably https://github.com/fat/bean\n    // otherwise Bonzo won't do this for you\n    if (host.$ && typeof host.cloneEvents == 'function') {\n      host.$(c).cloneEvents(el)\n\n      // clone events from every child node\n      cloneElems = host.$(c).find('*')\n      elElems = host.$(el).find('*')\n\n      for (var i = 0; i < elElems.length; i++)\n        host.$(cloneElems[i]).cloneEvents(elElems[i])\n    }\n    return c\n  }\n\n  function scroll(x, y, type) {\n    var el = this[0]\n    if (!el) return this\n    if (x == null && y == null) {\n      return (isBody(el) ? getWindowScroll() : { x: el.scrollLeft, y: el.scrollTop })[type]\n    }\n    if (isBody(el)) {\n      win.scrollTo(x, y)\n    } else {\n      x != null && (el.scrollLeft = x)\n      y != null && (el.scrollTop = y)\n    }\n    return this\n  }\n\n  function isBody(element) {\n    return element === win || (/^(?:body|html)$/i).test(element.tagName)\n  }\n\n  function getWindowScroll() {\n    return { x: win.pageXOffset || html.scrollLeft, y: win.pageYOffset || html.scrollTop }\n  }\n\n  function createScriptFromHtml(html) {\n    var scriptEl = document.createElement('script')\n      , matches = html.match(simpleScriptTagRe)\n    scriptEl.src = matches[1]\n    return scriptEl\n  }\n\n  /**\n   * @param {Array.<Element>|Element|Node|string} els\n   * @return {Bonzo}\n   */\n  function bonzo(els) {\n    return new Bonzo(els)\n  }\n\n  bonzo.setQueryEngine = function (q) {\n    query = q;\n    delete bonzo.setQueryEngine\n  }\n\n  bonzo.aug = function (o, target) {\n    // for those standalone bonzo users. this love is for you.\n    for (var k in o) {\n      o.hasOwnProperty(k) && ((target || Bonzo.prototype)[k] = o[k])\n    }\n  }\n\n  bonzo.create = function (node) {\n    // hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n    return typeof node == 'string' && node !== '' ?\n      function () {\n        if (simpleScriptTagRe.test(node)) return [createScriptFromHtml(node)]\n        var tag = node.match(/^\\s*<([^\\s>]+)/)\n          , el = doc.createElement('div')\n          , els = []\n          , p = tag ? tagMap[tag[1].toLowerCase()] : null\n          , dep = p ? p[2] + 1 : 1\n          , ns = p && p[3]\n          , pn = parentNode\n          , tb = features.autoTbody && p && p[0] == '<table>' && !(/<tbody/i).test(node)\n\n        el.innerHTML = p ? (p[0] + node + p[1]) : node\n        while (dep--) el = el.firstChild\n        // for IE NoScope, we may insert cruft at the begining just to get it to work\n        if (ns && el && el.nodeType !== 1) el = el.nextSibling\n        do {\n          // tbody special case for IE<8, creates tbody on any empty table\n          // we don't want it if we're just after a <thead>, <caption>, etc.\n          if ((!tag || el.nodeType == 1) && (!tb || (el.tagName && el.tagName != 'TBODY'))) {\n            els.push(el)\n          }\n        } while (el = el.nextSibling)\n        // IE < 9 gives us a parentNode which messes up insert() check for cloning\n        // `dep` > 1 can also cause problems with the insert() check (must do this last)\n        each(els, function(el) { el[pn] && el[pn].removeChild(el) })\n        return els\n      }() : isNode(node) ? [node.cloneNode(true)] : []\n  }\n\n  bonzo.doc = function () {\n    var vp = bonzo.viewport()\n    return {\n        width: Math.max(doc.body.scrollWidth, html.scrollWidth, vp.width)\n      , height: Math.max(doc.body.scrollHeight, html.scrollHeight, vp.height)\n    }\n  }\n\n  bonzo.firstChild = function (el) {\n    for (var c = el.childNodes, i = 0, j = (c && c.length) || 0, e; i < j; i++) {\n      if (c[i].nodeType === 1) e = c[j = i]\n    }\n    return e\n  }\n\n  bonzo.viewport = function () {\n    return {\n        width: ie ? html.clientWidth : self.innerWidth\n      , height: ie ? html.clientHeight : self.innerHeight\n    }\n  }\n\n  bonzo.isAncestor = 'compareDocumentPosition' in html ?\n    function (container, element) {\n      return (container.compareDocumentPosition(element) & 16) == 16\n    } : 'contains' in html ?\n    function (container, element) {\n      return container !== element && container.contains(element);\n    } :\n    function (container, element) {\n      while (element = element[parentNode]) {\n        if (element === container) {\n          return true\n        }\n      }\n      return false\n    }\n\n  return bonzo\n}); // the only line we care about using a semi-colon. placed here for concatenation tools"
  },
  {
    "path": "vendors/baron/js/jquery-1.9.0.js",
    "content": "/*!\n * jQuery JavaScript Library v1.9.0\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2013-1-14\n */\n(function( window, undefined ) {\n\"use strict\";\nvar\n\t// A central reference to the root jQuery(document)\n\trootjQuery,\n\n\t// The deferred used on DOM ready\n\treadyList,\n\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\tlocation = window.location,\n\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$,\n\n\t// [[Class]] -> type pairs\n\tclass2type = {},\n\n\t// List of deleted data cache ids, so we can reuse them\n\tcore_deletedIds = [],\n\n\tcore_version = \"1.9.0\",\n\n\t// Save a reference to some core methods\n\tcore_concat = core_deletedIds.concat,\n\tcore_push = core_deletedIds.push,\n\tcore_slice = core_deletedIds.slice,\n\tcore_indexOf = core_deletedIds.indexOf,\n\tcore_toString = class2type.toString,\n\tcore_hasOwn = class2type.hasOwnProperty,\n\tcore_trim = core_version.trim,\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\treturn new jQuery.fn.init( selector, context, rootjQuery );\n\t},\n\n\t// Used for matching numbers\n\tcore_pnum = /[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,\n\n\t// Used for splitting on whitespace\n\tcore_rnotwhite = /\\S+/g,\n\n\t// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\t// Match a standalone tag\n\trsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/,\n\n\t// JSON RegExp\n\trvalidchars = /^[\\],:{}\\s]*$/,\n\trvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\trvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[\\da-fA-F]{4})/g,\n\trvalidtokens = /\"[^\"\\\\\\r\\n]*\"|true|false|null|-?(?:\\d+\\.|)\\d+(?:[eE][+-]?\\d+|)/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t},\n\n\t// The ready event handler and self cleanup method\n\tDOMContentLoaded = function() {\n\t\tif ( document.addEventListener ) {\n\t\t\tdocument.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\t\t\tjQuery.ready();\n\t\t} else if ( document.readyState === \"complete\" ) {\n\t\t\t// we're here because readyState === \"complete\" in oldIE\n\t\t\t// which is good enough for us to call the dom ready!\n\t\t\tdocument.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n\t\t\tjQuery.ready();\n\t\t}\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: core_version,\n\n\tconstructor: jQuery,\n\tinit: function( selector, context, rootjQuery ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector.charAt(0) === \"<\" && selector.charAt( selector.length - 1 ) === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\n\t\t\t\t\t// scripts is true for back-compat\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE and Opera return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id !== match[2] ) {\n\t\t\t\t\t\t\treturn rootjQuery.find( selector );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Otherwise, we inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn rootjQuery.ready( selector );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t},\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\t// The number of elements contained in the matched element set\n\tsize: function() {\n\t\treturn this.length;\n\t},\n\n\ttoArray: function() {\n\t\treturn core_slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num == null ?\n\n\t\t\t// Return a 'clean' array\n\t\t\tthis.toArray() :\n\n\t\t\t// Return just the object\n\t\t\t( num < 0 ? this[ this.length + num ] : this[ num ] );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tready: function( fn ) {\n\t\t// Add the callback\n\t\tjQuery.ready.promise().done( fn );\n\n\t\treturn this;\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( core_slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: core_push,\n\tsort: [].sort,\n\tsplice: [].splice\n};\n\n// Give the init function the jQuery prototype for later instantiation\njQuery.fn.init.prototype = jQuery.fn;\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// extend jQuery itself if only one argument is passed\n\tif ( length === i ) {\n\t\ttarget = this;\n\t\t--i;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\tnoConflict: function( deep ) {\n\t\tif ( window.$ === jQuery ) {\n\t\t\twindow.$ = _$;\n\t\t}\n\n\t\tif ( deep && window.jQuery === jQuery ) {\n\t\t\twindow.jQuery = _jQuery;\n\t\t}\n\n\t\treturn jQuery;\n\t},\n\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n\t\tif ( !document.body ) {\n\t\t\treturn setTimeout( jQuery.ready );\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.trigger ) {\n\t\t\tjQuery( document ).trigger(\"ready\").off(\"ready\");\n\t\t}\n\t},\n\n\t// See test/unit/core.js for details concerning isFunction.\n\t// Since version 1.3, DOM methods and functions like alert\n\t// aren't supported. They return false on IE (#2968).\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray || function( obj ) {\n\t\treturn jQuery.type(obj) === \"array\";\n\t},\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj == obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\treturn !isNaN( parseFloat(obj) ) && isFinite( obj );\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn String( obj );\n\t\t}\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ core_toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Must be an Object.\n\t\t// Because of IE, we also have to check the presence of the constructor property.\n\t\t// Make sure that DOM nodes and window objects don't pass through, as well\n\t\tif ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\t// Not own constructor property must be Object\n\t\t\tif ( obj.constructor &&\n\t\t\t\t!core_hasOwn.call(obj, \"constructor\") &&\n\t\t\t\t!core_hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch ( e ) {\n\t\t\t// IE8,9 Will throw exceptions on certain host objects #9897\n\t\t\treturn false;\n\t\t}\n\n\t\t// Own properties are enumerated firstly, so to speed up,\n\t\t// if last one is own, then all properties are own.\n\n\t\tvar key;\n\t\tfor ( key in obj ) {}\n\n\t\treturn key === undefined || core_hasOwn.call( obj, key );\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\t// data: string of html\n\t// context (optional): If specified, the fragment will be created in this context, defaults to document\n\t// keepScripts (optional): If true, will include scripts passed in the html string\n\tparseHTML: function( data, context, keepScripts ) {\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\tif ( typeof context === \"boolean\" ) {\n\t\t\tkeepScripts = context;\n\t\t\tcontext = false;\n\t\t}\n\t\tcontext = context || document;\n\n\t\tvar parsed = rsingleTag.exec( data ),\n\t\t\tscripts = !keepScripts && [];\n\n\t\t// Single tag\n\t\tif ( parsed ) {\n\t\t\treturn [ context.createElement( parsed[1] ) ];\n\t\t}\n\n\t\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\t\tif ( scripts ) {\n\t\t\tjQuery( scripts ).remove();\n\t\t}\n\t\treturn jQuery.merge( [], parsed.childNodes );\n\t},\n\n\tparseJSON: function( data ) {\n\t\t// Attempt to parse using the native JSON parser first\n\t\tif ( window.JSON && window.JSON.parse ) {\n\t\t\treturn window.JSON.parse( data );\n\t\t}\n\n\t\tif ( data === null ) {\n\t\t\treturn data;\n\t\t}\n\n\t\tif ( typeof data === \"string\" ) {\n\n\t\t\t// Make sure leading/trailing whitespace is removed (IE can't handle it)\n\t\t\tdata = jQuery.trim( data );\n\n\t\t\tif ( data ) {\n\t\t\t\t// Make sure the incoming data is actual JSON\n\t\t\t\t// Logic borrowed from http://json.org/json2.js\n\t\t\t\tif ( rvalidchars.test( data.replace( rvalidescape, \"@\" )\n\t\t\t\t\t.replace( rvalidtokens, \"]\" )\n\t\t\t\t\t.replace( rvalidbraces, \"\")) ) {\n\n\t\t\t\t\treturn ( new Function( \"return \" + data ) )();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tjQuery.error( \"Invalid JSON: \" + data );\n\t},\n\n\t// Cross-browser xml parsing\n\tparseXML: function( data ) {\n\t\tvar xml, tmp;\n\t\tif ( !data || typeof data !== \"string\" ) {\n\t\t\treturn null;\n\t\t}\n\t\ttry {\n\t\t\tif ( window.DOMParser ) { // Standard\n\t\t\t\ttmp = new DOMParser();\n\t\t\t\txml = tmp.parseFromString( data , \"text/xml\" );\n\t\t\t} else { // IE\n\t\t\t\txml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n\t\t\t\txml.async = \"false\";\n\t\t\t\txml.loadXML( data );\n\t\t\t}\n\t\t} catch( e ) {\n\t\t\txml = undefined;\n\t\t}\n\t\tif ( !xml || !xml.documentElement || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\t\tjQuery.error( \"Invalid XML: \" + data );\n\t\t}\n\t\treturn xml;\n\t},\n\n\tnoop: function() {},\n\n\t// Evaluates a script in a global context\n\t// Workarounds based on findings by Jim Driscoll\n\t// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context\n\tglobalEval: function( data ) {\n\t\tif ( data && jQuery.trim( data ) ) {\n\t\t\t// We use execScript on Internet Explorer\n\t\t\t// We use an anonymous function so that context is window\n\t\t\t// rather than jQuery in Firefox\n\t\t\t( window.execScript || function( data ) {\n\t\t\t\twindow[ \"eval\" ].call( window, data );\n\t\t\t} )( data );\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Use native String.trim function wherever possible\n\ttrim: core_trim && !core_trim.call(\"\\uFEFF\\xA0\") ?\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\tcore_trim.call( text );\n\t\t} :\n\n\t\t// Otherwise use our own trimming functionality\n\t\tfunction( text ) {\n\t\t\treturn text == null ?\n\t\t\t\t\"\" :\n\t\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tcore_push.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\tvar len;\n\n\t\tif ( arr ) {\n\t\t\tif ( core_indexOf ) {\n\t\t\t\treturn core_indexOf.call( arr, elem, i );\n\t\t\t}\n\n\t\t\tlen = arr.length;\n\t\t\ti = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t// Skip accessing in sparse arrays\n\t\t\t\tif ( i in arr && arr[ i ] === elem ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar l = second.length,\n\t\t\ti = first.length,\n\t\t\tj = 0;\n\n\t\tif ( typeof l === \"number\" ) {\n\t\t\tfor ( ; j < l; j++ ) {\n\t\t\t\tfirst[ i++ ] = second[ j ];\n\t\t\t}\n\t\t} else {\n\t\t\twhile ( second[j] !== undefined ) {\n\t\t\t\tfirst[ i++ ] = second[ j++ ];\n\t\t\t}\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, inv ) {\n\t\tvar retVal,\n\t\t\tret = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length;\n\t\tinv = !!inv;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tretVal = !!callback( elems[ i ], i );\n\t\t\tif ( inv !== retVal ) {\n\t\t\t\tret.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret[ ret.length ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn core_concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = core_slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\t// Multifunctional method to get and set values of a collection\n\t// The value/s can optionally be executed if it's a function\n\taccess: function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\t\tvar i = 0,\n\t\t\tlength = elems.length,\n\t\t\tbulk = key == null;\n\n\t\t// Sets many values\n\t\tif ( jQuery.type( key ) === \"object\" ) {\n\t\t\tchainable = true;\n\t\t\tfor ( i in key ) {\n\t\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t\t}\n\n\t\t// Sets one value\n\t\t} else if ( value !== undefined ) {\n\t\t\tchainable = true;\n\n\t\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\t\traw = true;\n\t\t\t}\n\n\t\t\tif ( bulk ) {\n\t\t\t\t// Bulk operations run against the entire set\n\t\t\t\tif ( raw ) {\n\t\t\t\t\tfn.call( elems, value );\n\t\t\t\t\tfn = null;\n\n\t\t\t\t// ...except when executing function values\n\t\t\t\t} else {\n\t\t\t\t\tbulk = fn;\n\t\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( fn ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn chainable ?\n\t\t\telems :\n\n\t\t\t// Gets\n\t\t\tbulk ?\n\t\t\t\tfn.call( elems ) :\n\t\t\t\tlength ? fn( elems[0], key ) : emptyGet;\n\t},\n\n\tnow: function() {\n\t\treturn ( new Date() ).getTime();\n\t}\n});\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// we once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t// Standards-based browsers support DOMContentLoaded\n\t\t} else if ( document.addEventListener ) {\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", jQuery.ready, false );\n\n\t\t// If IE event model is used\n\t\t} else {\n\t\t\t// Ensure firing before onload, maybe late but safe also for iframes\n\t\t\tdocument.attachEvent( \"onreadystatechange\", DOMContentLoaded );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.attachEvent( \"onload\", jQuery.ready );\n\n\t\t\t// If IE and not a frame\n\t\t\t// continually check to see if the document is ready\n\t\t\tvar top = false;\n\n\t\t\ttry {\n\t\t\t\ttop = window.frameElement == null && document.documentElement;\n\t\t\t} catch(e) {}\n\n\t\t\tif ( top && top.doScroll ) {\n\t\t\t\t(function doScrollCheck() {\n\t\t\t\t\tif ( !jQuery.isReady ) {\n\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Use the trick by Diego Perini\n\t\t\t\t\t\t\t// http://javascript.nwbox.com/IEContentLoaded/\n\t\t\t\t\t\t\ttop.doScroll(\"left\");\n\t\t\t\t\t\t} catch(e) {\n\t\t\t\t\t\t\treturn setTimeout( doScrollCheck, 50 );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// and execute any waiting functions\n\t\t\t\t\t\tjQuery.ready();\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t}\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\tvar length = obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || type !== \"function\" &&\n\t\t( length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj );\n}\n\n// All jQuery objects should point back to these\nrootjQuery = jQuery(document);\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// Flag to know if list is currently firing\n\t\tfiring,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Control if a given callback is in the list\n\t\t\thas: function( fn ) {\n\t\t\t\treturn jQuery.inArray( fn, list ) > -1;\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\targs = args || [];\n\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar action = tuple[ 0 ],\n\t\t\t\t\t\t\t\tfn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ action + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = core_slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;\n\t\t\t\t\tif( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// if we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\njQuery.support = (function() {\n\n\tvar support, all, a, select, opt, input, fragment, eventName, isSupported, i,\n\t\tdiv = document.createElement(\"div\");\n\n\t// Setup\n\tdiv.setAttribute( \"className\", \"t\" );\n\tdiv.innerHTML = \"  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>\";\n\n\t// Support tests won't run in some limited or non-browser environments\n\tall = div.getElementsByTagName(\"*\");\n\ta = div.getElementsByTagName(\"a\")[ 0 ];\n\tif ( !all || !a || !all.length ) {\n\t\treturn {};\n\t}\n\n\t// First batch of tests\n\tselect = document.createElement(\"select\");\n\topt = select.appendChild( document.createElement(\"option\") );\n\tinput = div.getElementsByTagName(\"input\")[ 0 ];\n\n\ta.style.cssText = \"top:1px;float:left;opacity:.5\";\n\tsupport = {\n\t\t// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)\n\t\tgetSetAttribute: div.className !== \"t\",\n\n\t\t// IE strips leading whitespace when .innerHTML is used\n\t\tleadingWhitespace: div.firstChild.nodeType === 3,\n\n\t\t// Make sure that tbody elements aren't automatically inserted\n\t\t// IE will insert them into empty tables\n\t\ttbody: !div.getElementsByTagName(\"tbody\").length,\n\n\t\t// Make sure that link elements get serialized correctly by innerHTML\n\t\t// This requires a wrapper element in IE\n\t\thtmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n\t\t// Get the style information from getAttribute\n\t\t// (IE uses .cssText instead)\n\t\tstyle: /top/.test( a.getAttribute(\"style\") ),\n\n\t\t// Make sure that URLs aren't manipulated\n\t\t// (IE normalizes it by default)\n\t\threfNormalized: a.getAttribute(\"href\") === \"/a\",\n\n\t\t// Make sure that element opacity exists\n\t\t// (IE uses filter instead)\n\t\t// Use a regex to work around a WebKit issue. See #5145\n\t\topacity: /^0.5/.test( a.style.opacity ),\n\n\t\t// Verify style float existence\n\t\t// (IE uses styleFloat instead of cssFloat)\n\t\tcssFloat: !!a.style.cssFloat,\n\n\t\t// Check the default checkbox/radio value (\"\" on WebKit; \"on\" elsewhere)\n\t\tcheckOn: !!input.value,\n\n\t\t// Make sure that a selected-by-default option has a working selected property.\n\t\t// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n\t\toptSelected: opt.selected,\n\n\t\t// Tests for enctype support on a form (#6743)\n\t\tenctype: !!document.createElement(\"form\").enctype,\n\n\t\t// Makes sure cloning an html5 element does not cause problems\n\t\t// Where outerHTML is undefined, this still works\n\t\thtml5Clone: document.createElement(\"nav\").cloneNode( true ).outerHTML !== \"<:nav></:nav>\",\n\n\t\t// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode\n\t\tboxModel: document.compatMode === \"CSS1Compat\",\n\n\t\t// Will be defined later\n\t\tdeleteExpando: true,\n\t\tnoCloneEvent: true,\n\t\tinlineBlockNeedsLayout: false,\n\t\tshrinkWrapBlocks: false,\n\t\treliableMarginRight: true,\n\t\tboxSizingReliable: true,\n\t\tpixelPosition: false\n\t};\n\n\t// Make sure checked status is properly cloned\n\tinput.checked = true;\n\tsupport.noCloneChecked = input.cloneNode( true ).checked;\n\n\t// Make sure that the options inside disabled selects aren't marked as disabled\n\t// (WebKit marks them as disabled)\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<9\n\ttry {\n\t\tdelete div.test;\n\t} catch( e ) {\n\t\tsupport.deleteExpando = false;\n\t}\n\n\t// Check if we can trust getAttribute(\"value\")\n\tinput = document.createElement(\"input\");\n\tinput.setAttribute( \"value\", \"\" );\n\tsupport.input = input.getAttribute( \"value\" ) === \"\";\n\n\t// Check if an input maintains its value after becoming a radio\n\tinput.value = \"t\";\n\tinput.setAttribute( \"type\", \"radio\" );\n\tsupport.radioValue = input.value === \"t\";\n\n\t// #11217 - WebKit loses check when the name is after the checked attribute\n\tinput.setAttribute( \"checked\", \"t\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tfragment = document.createDocumentFragment();\n\tfragment.appendChild( input );\n\n\t// Check if a disconnected checkbox will retain its checked\n\t// value of true after appended to the DOM (IE6/7)\n\tsupport.appendChecked = input.checked;\n\n\t// WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<9\n\t// Opera does not clone events (and typeof div.attachEvent === undefined).\n\t// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()\n\tif ( div.attachEvent ) {\n\t\tdiv.attachEvent( \"onclick\", function() {\n\t\t\tsupport.noCloneEvent = false;\n\t\t});\n\n\t\tdiv.cloneNode( true ).click();\n\t}\n\n\t// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)\n\t// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php\n\tfor ( i in { submit: true, change: true, focusin: true }) {\n\t\tdiv.setAttribute( eventName = \"on\" + i, \"t\" );\n\n\t\tsupport[ i + \"Bubbles\" ] = eventName in window || div.attributes[ eventName ].expando === false;\n\t}\n\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\t// Run tests that need a body at doc ready\n\tjQuery(function() {\n\t\tvar container, marginDiv, tds,\n\t\t\tdivReset = \"padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;\",\n\t\t\tbody = document.getElementsByTagName(\"body\")[0];\n\n\t\tif ( !body ) {\n\t\t\t// Return for frameset docs that don't have a body\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer = document.createElement(\"div\");\n\t\tcontainer.style.cssText = \"border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px\";\n\n\t\tbody.appendChild( container ).appendChild( div );\n\n\t\t// Support: IE8\n\t\t// Check if table cells still have offsetWidth/Height when they are set\n\t\t// to display:none and there are still other visible table cells in a\n\t\t// table row; if so, offsetWidth/Height are not reliable for use when\n\t\t// determining if an element has been hidden directly using\n\t\t// display:none (it is still safe to use offsets if a parent element is\n\t\t// hidden; don safety goggles and see bug #4512 for more information).\n\t\tdiv.innerHTML = \"<table><tr><td></td><td>t</td></tr></table>\";\n\t\ttds = div.getElementsByTagName(\"td\");\n\t\ttds[ 0 ].style.cssText = \"padding:0;margin:0;border:0;display:none\";\n\t\tisSupported = ( tds[ 0 ].offsetHeight === 0 );\n\n\t\ttds[ 0 ].style.display = \"\";\n\t\ttds[ 1 ].style.display = \"none\";\n\n\t\t// Support: IE8\n\t\t// Check if empty table cells still have offsetWidth/Height\n\t\tsupport.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );\n\n\t\t// Check box-sizing and margin behavior\n\t\tdiv.innerHTML = \"\";\n\t\tdiv.style.cssText = \"box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;\";\n\t\tsupport.boxSizing = ( div.offsetWidth === 4 );\n\t\tsupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );\n\n\t\t// Use window.getComputedStyle because jsdom on node.js will break without it.\n\t\tif ( window.getComputedStyle ) {\n\t\t\tsupport.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== \"1%\";\n\t\t\tsupport.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: \"4px\" } ).width === \"4px\";\n\n\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t// Fails in WebKit before Feb 2011 nightlies\n\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\tmarginDiv = div.appendChild( document.createElement(\"div\") );\n\t\t\tmarginDiv.style.cssText = div.style.cssText = divReset;\n\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\tdiv.style.width = \"1px\";\n\n\t\t\tsupport.reliableMarginRight =\n\t\t\t\t!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );\n\t\t}\n\n\t\tif ( typeof div.style.zoom !== \"undefined\" ) {\n\t\t\t// Support: IE<8\n\t\t\t// Check if natively block-level elements act like inline-block\n\t\t\t// elements when setting their display to 'inline' and giving\n\t\t\t// them layout\n\t\t\tdiv.innerHTML = \"\";\n\t\t\tdiv.style.cssText = divReset + \"width:1px;padding:1px;display:inline;zoom:1\";\n\t\t\tsupport.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );\n\n\t\t\t// Support: IE6\n\t\t\t// Check if elements with layout shrink-wrap their children\n\t\t\tdiv.style.display = \"block\";\n\t\t\tdiv.innerHTML = \"<div></div>\";\n\t\t\tdiv.firstChild.style.width = \"5px\";\n\t\t\tsupport.shrinkWrapBlocks = ( div.offsetWidth !== 3 );\n\n\t\t\t// Prevent IE 6 from affecting layout for positioned elements #11048\n\t\t\t// Prevent IE from shrinking the body in IE 7 mode #12869\n\t\t\tbody.style.zoom = 1;\n\t\t}\n\n\t\tbody.removeChild( container );\n\n\t\t// Null elements to avoid leaks in IE\n\t\tcontainer = div = tds = marginDiv = null;\n\t});\n\n\t// Null elements to avoid leaks in IE\n\tall = select = fragment = opt = a = input = null;\n\n\treturn support;\n})();\n\nvar rbrace = /(?:\\{[\\s\\S]*\\}|\\[[\\s\\S]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\t\nfunction internalData( elem, name, data, pvt /* Internal Use Only */ ){\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar thisCache, ret,\n\t\tinternalKey = jQuery.expando,\n\t\tgetByName = typeof name === \"string\",\n\n\t\t// We have to handle DOM nodes and JS objects differently because IE6-7\n\t\t// can't GC object references properly across the DOM-JS boundary\n\t\tisNode = elem.nodeType,\n\n\t\t// Only DOM nodes need the global jQuery cache; JS object data is\n\t\t// attached directly to the object so GC can occur automatically\n\t\tcache = isNode ? jQuery.cache : elem,\n\n\t\t// Only defining an ID for JS objects if its cache already exists allows\n\t\t// the code to shortcut on the same path as a DOM node with no cache\n\t\tid = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;\n\n\t// Avoid doing any more work than we need to when trying to get data on an\n\t// object that has no data at all\n\tif ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {\n\t\treturn;\n\t}\n\n\tif ( !id ) {\n\t\t// Only DOM nodes need a new unique ID for each element since their data\n\t\t// ends up in the global cache\n\t\tif ( isNode ) {\n\t\t\telem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;\n\t\t} else {\n\t\t\tid = internalKey;\n\t\t}\n\t}\n\n\tif ( !cache[ id ] ) {\n\t\tcache[ id ] = {};\n\n\t\t// Avoids exposing jQuery metadata on plain JS objects when the object\n\t\t// is serialized using JSON.stringify\n\t\tif ( !isNode ) {\n\t\t\tcache[ id ].toJSON = jQuery.noop;\n\t\t}\n\t}\n\n\t// An object can be passed to jQuery.data instead of a key/value pair; this gets\n\t// shallow copied over onto the existing cache\n\tif ( typeof name === \"object\" || typeof name === \"function\" ) {\n\t\tif ( pvt ) {\n\t\t\tcache[ id ] = jQuery.extend( cache[ id ], name );\n\t\t} else {\n\t\t\tcache[ id ].data = jQuery.extend( cache[ id ].data, name );\n\t\t}\n\t}\n\n\tthisCache = cache[ id ];\n\n\t// jQuery data() is stored in a separate object inside the object's internal data\n\t// cache in order to avoid key collisions between internal data and user-defined\n\t// data.\n\tif ( !pvt ) {\n\t\tif ( !thisCache.data ) {\n\t\t\tthisCache.data = {};\n\t\t}\n\n\t\tthisCache = thisCache.data;\n\t}\n\n\tif ( data !== undefined ) {\n\t\tthisCache[ jQuery.camelCase( name ) ] = data;\n\t}\n\n\t// Check for both converted-to-camel and non-converted data property names\n\t// If a data property was specified\n\tif ( getByName ) {\n\n\t\t// First Try to find as-is property data\n\t\tret = thisCache[ name ];\n\n\t\t// Test for null|undefined property data\n\t\tif ( ret == null ) {\n\n\t\t\t// Try to find the camelCased property\n\t\t\tret = thisCache[ jQuery.camelCase( name ) ];\n\t\t}\n\t} else {\n\t\tret = thisCache;\n\t}\n\n\treturn ret;\n}\n\nfunction internalRemoveData( elem, name, pvt /* For internal use only */ ){\n\tif ( !jQuery.acceptData( elem ) ) {\n\t\treturn;\n\t}\n\n\tvar thisCache, i, l,\n\n\t\tisNode = elem.nodeType,\n\n\t\t// See jQuery.data for more information\n\t\tcache = isNode ? jQuery.cache : elem,\n\t\tid = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n\t// If there is already no cache entry for this object, there is no\n\t// purpose in continuing\n\tif ( !cache[ id ] ) {\n\t\treturn;\n\t}\n\n\tif ( name ) {\n\n\t\tthisCache = pvt ? cache[ id ] : cache[ id ].data;\n\n\t\tif ( thisCache ) {\n\n\t\t\t// Support array or space separated string names for data keys\n\t\t\tif ( !jQuery.isArray( name ) ) {\n\n\t\t\t\t// try the string as a key before any manipulation\n\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\tname = [ name ];\n\t\t\t\t} else {\n\n\t\t\t\t\t// split the camel cased version by spaces unless a key with the spaces exists\n\t\t\t\t\tname = jQuery.camelCase( name );\n\t\t\t\t\tif ( name in thisCache ) {\n\t\t\t\t\t\tname = [ name ];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tname = name.split(\" \");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = name.concat( jQuery.map( name, jQuery.camelCase ) );\n\t\t\t}\n\n\t\t\tfor ( i = 0, l = name.length; i < l; i++ ) {\n\t\t\t\tdelete thisCache[ name[i] ];\n\t\t\t}\n\n\t\t\t// If there is no data left in the cache, we want to continue\n\t\t\t// and let the cache object itself get destroyed\n\t\t\tif ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t// See jQuery.data for more information\n\tif ( !pvt ) {\n\t\tdelete cache[ id ].data;\n\n\t\t// Don't destroy the parent cache unless the internal data object\n\t\t// had been the only thing left in it\n\t\tif ( !isEmptyDataObject( cache[ id ] ) ) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// Destroy the cache\n\tif ( isNode ) {\n\t\tjQuery.cleanData( [ elem ], true );\n\n\t// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)\n\t} else if ( jQuery.support.deleteExpando || cache != cache.window ) {\n\t\tdelete cache[ id ];\n\n\t// When all else fails, null\n\t} else {\n\t\tcache[ id ] = null;\n\t}\n}\n\njQuery.extend({\n\tcache: {},\n\n\t// Unique for each copy of jQuery on the page\n\t// Non-digits removed to match rinlinejQuery\n\texpando: \"jQuery\" + ( core_version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// The following elements throw uncatchable exceptions if you\n\t// attempt to add expando properties to them.\n\tnoData: {\n\t\t\"embed\": true,\n\t\t// Ban all objects except for Flash (which handle expandos)\n\t\t\"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n\t\t\"applet\": true\n\t},\n\n\thasData: function( elem ) {\n\t\telem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\t\treturn !!elem && !isEmptyDataObject( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data, false );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name, false );\n\t},\n\n\t// For internal use only.\n\t_data: function( elem, name, data ) {\n\t\treturn internalData( elem, name, data, true );\n\t},\n\t\n\t_removeData: function( elem, name ) {\n\t\treturn internalRemoveData( elem, name, true );\n\t},\n\n\t// A method for determining if a DOM node can handle the data expando\n\tacceptData: function( elem ) {\n\t\tvar noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n\t\t// nodes accept data unless otherwise specified; rejection can be conditional\n\t\treturn !noData || noData !== true && elem.getAttribute(\"classid\") === noData;\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar attrs, name,\n\t\t\telem = this[0],\n\t\t\ti = 0,\n\t\t\tdata = null;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = jQuery.data( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !jQuery._data( elem, \"parsedAttrs\" ) ) {\n\t\t\t\t\tattrs = elem.attributes;\n\t\t\t\t\tfor ( ; i < attrs.length; i++ ) {\n\t\t\t\t\t\tname = attrs[i].name;\n\n\t\t\t\t\t\tif ( !name.indexOf( \"data-\" ) ) {\n\t\t\t\t\t\t\tname = jQuery.camelCase( name.substring(5) );\n\n\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tjQuery._data( elem, \"parsedAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tjQuery.data( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn jQuery.access( this, function( value ) {\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\t// Try to fetch any internally stored data first\n\t\t\t\treturn elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;\n\t\t\t}\n\n\t\t\tthis.each(function() {\n\t\t\t\tjQuery.data( this, key, value );\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeData( this, key );\n\t\t});\n\t}\n});\n\nfunction dataAttr( elem, key, data ) {\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\n\t\tvar name = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\tdata === \"false\" ? false :\n\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tjQuery.data( elem, key, data );\n\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// checks a cache object for emptiness\nfunction isEmptyDataObject( obj ) {\n\tvar name;\n\tfor ( name in obj ) {\n\n\t\t// if the public data object is empty, the private is still empty\n\t\tif ( name === \"data\" && jQuery.isEmptyObject( obj[name] ) ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( name !== \"toJSON\" ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = jQuery._data( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray(data) ) {\n\t\t\t\t\tqueue = jQuery._data( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\thooks.cur = fn;\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// not intended for public consumption - generates a queueHooks object, or returns the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn jQuery._data( elem, key ) || jQuery._data( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tjQuery._removeData( elem, type + \"queue\" );\n\t\t\t\tjQuery._removeData( elem, key );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\t// Based off of the plugin by Clint Helfers, with permission.\n\t// http://blindsignals.com/index.php/2009/07/jquery-delay/\n\tdelay: function( time, type ) {\n\t\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\t\ttype = type || \"fx\";\n\n\t\treturn this.queue( type, function( next, hooks ) {\n\t\t\tvar timeout = setTimeout( next, time );\n\t\t\thooks.stop = function() {\n\t\t\t\tclearTimeout( timeout );\n\t\t\t};\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile( i-- ) {\n\t\t\ttmp = jQuery._data( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar nodeHook, boolHook,\n\trclass = /[\\t\\r\\n]/g,\n\trreturn = /\\r/g,\n\trfocusable = /^(?:input|select|textarea|button|object)$/i,\n\trclickable = /^(?:a|area)$/i,\n\trboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,\n\truseDefault = /^(?:checked|selected)$/i,\n\tgetSetAttribute = jQuery.support.getSetAttribute,\n\tgetSetInput = jQuery.support.input;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t},\n\n\tprop: function( name, value ) {\n\t\treturn jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\tname = jQuery.propFix[ name ] || name;\n\t\treturn this.each(function() {\n\t\t\t// try/catch handles cases where IE balks (such as removing a property on window)\n\t\t\ttry {\n\t\t\t\tthis[ name ] = undefined;\n\t\t\t\tdelete this[ name ];\n\t\t\t} catch( e ) {}\n\t\t});\n\t},\n\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( core_rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telem.className = jQuery.trim( cur );\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j,\n\t\t\ti = 0,\n\t\t\tlen = this.length,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( core_rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telem.className = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisBool = typeof stateVal === \"boolean\";\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tstate = stateVal,\n\t\t\t\t\tclassNames = value.match( core_rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// check each className given, space separated list\n\t\t\t\t\tstate = isBool ? state : !self.hasClass( className );\n\t\t\t\t\tself[ state ? \"addClass\" : \"removeClass\" ]( className );\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === \"undefined\" || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tjQuery._data( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed \"false\",\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tthis.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t},\n\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar val,\n\t\t\t\tself = jQuery(this);\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, self.val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map(val, function ( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// attributes.value is undefined in Blackberry 4.7 but\n\t\t\t\t// uses .value. See #6932\n\t\t\t\tvar val = elem.attributes.value;\n\t\t\t\treturn !val || val.specified ? elem.value : elem.text;\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// oldIE doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar values = jQuery.makeArray( value );\n\n\t\t\t\tjQuery(elem).find(\"option\").each(function() {\n\t\t\t\t\tthis.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n\t\t\t\t});\n\n\t\t\t\tif ( !values.length ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t},\n\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( notxml ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\n\t\t\t} else if ( hooks && notxml && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && notxml && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\n\t\t\t// In IE9+, Flash objects don't have .getAttribute (#12945)\n\t\t\t// Support: IE9+\n\t\t\tif ( typeof elem.getAttribute !== \"undefined\" ) {\n\t\t\t\tret =  elem.getAttribute( name );\n\t\t\t}\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret == null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( core_rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( rboolean.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false for boolean attributes\n\t\t\t\t\t// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8\n\t\t\t\t\tif ( !getSetAttribute && ruseDefault.test( name ) ) {\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] =\n\t\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t\t}\n\n\t\t\t\t// See #9699 for explanation of this approach (setting first, then removal)\n\t\t\t\t} else {\n\t\t\t\t\tjQuery.attr( elem, name, \"\" );\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( getSetAttribute ? name : propName );\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !jQuery.support.radioValue && value === \"radio\" && jQuery.nodeName(elem, \"input\") ) {\n\t\t\t\t\t// Setting the type on a radio button after the value resets the value in IE6-9\n\t\t\t\t\t// Reset value to default in case type is set after value during creation\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\ttabindex: \"tabIndex\",\n\t\treadonly: \"readOnly\",\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\",\n\t\tmaxlength: \"maxLength\",\n\t\tcellspacing: \"cellSpacing\",\n\t\tcellpadding: \"cellPadding\",\n\t\trowspan: \"rowSpan\",\n\t\tcolspan: \"colSpan\",\n\t\tusemap: \"useMap\",\n\t\tframeborder: \"frameBorder\",\n\t\tcontenteditable: \"contentEditable\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn ( elem[ name ] = value );\n\t\t\t}\n\n\t\t} else {\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\treturn elem[ name ];\n\t\t\t}\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\t// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n\t\t\t\t// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\tvar attributeNode = elem.getAttributeNode(\"tabindex\");\n\n\t\t\t\treturn attributeNode && attributeNode.specified ?\n\t\t\t\t\tparseInt( attributeNode.value, 10 ) :\n\t\t\t\t\trfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n\t\t\t\t\t\t0 :\n\t\t\t\t\t\tundefined;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hook for boolean attributes\nboolHook = {\n\tget: function( elem, name ) {\n\t\tvar\n\t\t\t// Use .prop to determine if this attribute is understood as boolean\n\t\t\tprop = jQuery.prop( elem, name ),\n\n\t\t\t// Fetch it accordingly\n\t\t\tattr = typeof prop === \"boolean\" && elem.getAttribute( name ),\n\t\t\tdetail = typeof prop === \"boolean\" ?\n\n\t\t\t\tgetSetInput && getSetAttribute ?\n\t\t\t\t\tattr != null :\n\t\t\t\t\t// oldIE fabricates an empty string for missing boolean attributes\n\t\t\t\t\t// and conflates checked/selected into attroperties\n\t\t\t\t\truseDefault.test( name ) ?\n\t\t\t\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] :\n\t\t\t\t\t\t!!attr :\n\n\t\t\t\t// fetch an attribute node for properties not recognized as boolean\n\t\t\t\telem.getAttributeNode( name );\n\n\t\treturn detail && detail.value !== false ?\n\t\t\tname.toLowerCase() :\n\t\t\tundefined;\n\t},\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {\n\t\t\t// IE<8 needs the *property* name\n\t\t\telem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );\n\n\t\t// Use defaultChecked and defaultSelected for oldIE\n\t\t} else {\n\t\t\telem[ jQuery.camelCase( \"default-\" + name ) ] = elem[ name ] = true;\n\t\t}\n\n\t\treturn name;\n\t}\n};\n\n// fix oldIE value attroperty\nif ( !getSetInput || !getSetAttribute ) {\n\tjQuery.attrHooks.value = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn jQuery.nodeName( elem, \"input\" ) ?\n\n\t\t\t\t// Ignore the value *property* by using defaultValue\n\t\t\t\telem.defaultValue :\n\n\t\t\t\tret && ret.specified ? ret.value : undefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\tif ( jQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t// Does not return so that setAttribute is also used\n\t\t\t\telem.defaultValue = value;\n\t\t\t} else {\n\t\t\t\t// Use nodeHook if defined (#1954); otherwise setAttribute is fine\n\t\t\t\treturn nodeHook && nodeHook.set( elem, value, name );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// IE6/7 do not support getting/setting some attributes with get/setAttribute\nif ( !getSetAttribute ) {\n\n\t// Use this for any attribute in IE6/7\n\t// This fixes almost every IE6/7 issue\n\tnodeHook = jQuery.valHooks.button = {\n\t\tget: function( elem, name ) {\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\treturn ret && ( name === \"id\" || name === \"name\" || name === \"coords\" ? ret.value !== \"\" : ret.specified ) ?\n\t\t\t\tret.value :\n\t\t\t\tundefined;\n\t\t},\n\t\tset: function( elem, value, name ) {\n\t\t\t// Set the existing or create a new attribute node\n\t\t\tvar ret = elem.getAttributeNode( name );\n\t\t\tif ( !ret ) {\n\t\t\t\telem.setAttributeNode(\n\t\t\t\t\t(ret = elem.ownerDocument.createAttribute( name ))\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tret.value = value += \"\";\n\n\t\t\t// Break association with cloned elements by also using setAttribute (#9646)\n\t\t\treturn name === \"value\" || value === elem.getAttribute( name ) ?\n\t\t\t\tvalue :\n\t\t\t\tundefined;\n\t\t}\n\t};\n\n\t// Set contenteditable to false on removals(#10429)\n\t// Setting to empty string throws an error as an invalid value\n\tjQuery.attrHooks.contenteditable = {\n\t\tget: nodeHook.get,\n\t\tset: function( elem, value, name ) {\n\t\t\tnodeHook.set( elem, value === \"\" ? false : value, name );\n\t\t}\n\t};\n\n\t// Set width and height to auto instead of 0 on empty string( Bug #8150 )\n\t// This is for removals\n\tjQuery.each([ \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\telem.setAttribute( name, \"auto\" );\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n\n// Some attributes require a special call on IE\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !jQuery.support.hrefNormalized ) {\n\tjQuery.each([ \"href\", \"src\", \"width\", \"height\" ], function( i, name ) {\n\t\tjQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar ret = elem.getAttribute( name, 2 );\n\t\t\t\treturn ret == null ? undefined : ret;\n\t\t\t}\n\t\t});\n\t});\n\n\t// href/src property should get the full normalized URL (#10299/#12915)\n\tjQuery.each([ \"href\", \"src\" ], function( i, name ) {\n\t\tjQuery.propHooks[ name ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.getAttribute( name, 4 );\n\t\t\t}\n\t\t};\n\t});\n}\n\nif ( !jQuery.support.style ) {\n\tjQuery.attrHooks.style = {\n\t\tget: function( elem ) {\n\t\t\t// Return undefined in the case of empty string\n\t\t\t// Note: IE uppercases css property names, but if we were to .toLowerCase()\n\t\t\t// .cssText, that would destroy case senstitivity in URL's, like in \"background\"\n\t\t\treturn elem.style.cssText || undefined;\n\t\t},\n\t\tset: function( elem, value ) {\n\t\t\treturn ( elem.style.cssText = value + \"\" );\n\t\t}\n\t};\n}\n\n// Safari mis-reports the default selected property of an option\n// Accessing the parent's selectedIndex property fixes it\nif ( !jQuery.support.optSelected ) {\n\tjQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\t// Make sure that it also works with optgroups, see #5701\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t});\n}\n\n// IE6/7 call enctype encoding\nif ( !jQuery.support.enctype ) {\n\tjQuery.propFix.enctype = \"encoding\";\n}\n\n// Radios and checkboxes getter/setter\nif ( !jQuery.support.checkOn ) {\n\tjQuery.each([ \"radio\", \"checkbox\" ], function() {\n\t\tjQuery.valHooks[ this ] = {\n\t\t\tget: function( elem ) {\n\t\t\t\t// Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n\t\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t\t}\n\t\t};\n\t});\n}\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t});\n});\nvar rformElems = /^(?:input|select|textarea)$/i,\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\t\telemData = elem.nodeType !== 3 && elem.nodeType !== 8 && jQuery._data( elem );\n\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && (!e || jQuery.event.triggered !== e.type) ?\n\t\t\t\t\tjQuery.event.dispatch.apply( eventHandle.elem, arguments ) :\n\t\t\t\t\tundefined;\n\t\t\t};\n\t\t\t// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events\n\t\t\teventHandle.elem = elem;\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\t// jQuery(...).bind(\"mouseover mouseout\", fn);\n\t\ttypes = ( types || \"\" ).match( core_rnotwhite ) || [\"\"];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener/attachEvent if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\t// Bind the global event handler to the element\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\n\t\t\t\t\t} else if ( elem.attachEvent ) {\n\t\t\t\t\t\telem.attachEvent( \"on\" + type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t\t// Nullify elem to prevent memory leaks in IE\n\t\telem = null;\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = jQuery.hasData( elem ) && jQuery._data( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( core_rnotwhite ) || [\"\"];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdelete elemData.handle;\n\n\t\t\t// removeData also checks for emptiness and clears the expando if empty\n\t\t\t// so use it instead of delete\n\t\t\tjQuery._removeData( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = event.type || event,\n\t\t\tnamespaces = event.namespace ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\tevent.isTrigger = true;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( jQuery._data( cur, \"events\" ) || {} )[ event.type ] && jQuery._data( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&\n\t\t\t\t!(type === \"click\" && jQuery.nodeName( elem, \"a\" )) && jQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Can't use an .isFunction() check here because IE6/7 fails that test.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\ttry {\n\t\t\t\t\t\telem[ type ]();\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// IE<9 dies on focus/blur to hidden element (#1486,#12518)\n\t\t\t\t\t\t// only reproducible on winXP IE8 native, not IE9 in IE8 mode\n\t\t\t\t\t}\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = core_slice.call( arguments ),\n\t\t\thandlers = ( jQuery._data( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or\n\t\t\t\t// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\tfor ( ; cur != this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.disabled !== true || event.type !== \"click\" ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = jQuery.event.fixHooks[ event.type ] || {},\n\t\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// Fix target property (#1925)\n\t\tif ( !event.target ) {\n\t\t\tevent.target = originalEvent.srcElement || document;\n\t\t}\n\n\t\t// Support: Chrome 23+, Safari?\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\t// Support: IE<9\n\t\t// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)\n\t\tevent.metaKey = !!event.metaKey;\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button,\n\t\t\t\tfromElement = original.fromElement;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add relatedTarget, if necessary\n\t\t\tif ( !event.relatedTarget && fromElement ) {\n\t\t\t\tevent.relatedTarget = fromElement === event.target ? original.toElement : fromElement;\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( jQuery.nodeName( this, \"input\" ) && this.type === \"checkbox\" && this.click ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== document.activeElement && this.focus ) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.focus();\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t// Support: IE<9\n\t\t\t\t\t\t// If we error on focus to hidden element (#1486, #12518),\n\t\t\t\t\t\t// let .trigger() run the handlers\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === document.activeElement && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Even when returnValue equals to undefined Firefox will still show alert\n\t\t\t\tif ( event.result !== undefined ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{ type: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\njQuery.removeEvent = document.removeEventListener ?\n\tfunction( elem, type, handle ) {\n\t\tif ( elem.removeEventListener ) {\n\t\t\telem.removeEventListener( type, handle, false );\n\t\t}\n\t} :\n\tfunction( elem, type, handle ) {\n\t\tvar name = \"on\" + type;\n\n\t\tif ( elem.detachEvent ) {\n\n\t\t\t// #8545, #7054, preventing memory leaks for custom events in IE6-8\n\t\t\t// detachEvent needed property on element, by name of that event, to properly expose it to GC\n\t\t\tif ( typeof elem[ name ] === \"undefined\" ) {\n\t\t\t\telem[ name ] = null;\n\t\t\t}\n\n\t\t\telem.detachEvent( name, handle );\n\t\t}\n\t};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||\n\t\t\tsrc.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If preventDefault exists, run it on the original event\n\t\tif ( e.preventDefault ) {\n\t\t\te.preventDefault();\n\n\t\t// Support: IE\n\t\t// Otherwise set the returnValue property of the original event to false\n\t\t} else {\n\t\t\te.returnValue = false;\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\t\tif ( !e ) {\n\t\t\treturn;\n\t\t}\n\t\t// If stopPropagation exists, run it on the original event\n\t\tif ( e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\n\t\t// Support: IE\n\t\t// Set the cancelBubble property of the original event to true\n\t\te.cancelBubble = true;\n\t},\n\tstopImmediatePropagation: function() {\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// IE submit delegation\nif ( !jQuery.support.submitBubbles ) {\n\n\tjQuery.event.special.submit = {\n\t\tsetup: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Lazy-add a submit handler when a descendant form may potentially be submitted\n\t\t\tjQuery.event.add( this, \"click._submit keypress._submit\", function( e ) {\n\t\t\t\t// Node name check avoids a VML-related crash in IE (#9807)\n\t\t\t\tvar elem = e.target,\n\t\t\t\t\tform = jQuery.nodeName( elem, \"input\" ) || jQuery.nodeName( elem, \"button\" ) ? elem.form : undefined;\n\t\t\t\tif ( form && !jQuery._data( form, \"submitBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( form, \"submit._submit\", function( event ) {\n\t\t\t\t\t\tevent._submit_bubble = true;\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( form, \"submitBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t\t// return undefined since we don't need an event listener\n\t\t},\n\n\t\tpostDispatch: function( event ) {\n\t\t\t// If form was submitted by the user, bubble the event up the tree\n\t\t\tif ( event._submit_bubble ) {\n\t\t\t\tdelete event._submit_bubble;\n\t\t\t\tif ( this.parentNode && !event.isTrigger ) {\n\t\t\t\t\tjQuery.event.simulate( \"submit\", this.parentNode, event, true );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\t// Only need this for delegated form submit events\n\t\t\tif ( jQuery.nodeName( this, \"form\" ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Remove delegated handlers; cleanData eventually reaps submit handlers attached above\n\t\t\tjQuery.event.remove( this, \"._submit\" );\n\t\t}\n\t};\n}\n\n// IE change delegation and checkbox/radio fix\nif ( !jQuery.support.changeBubbles ) {\n\n\tjQuery.event.special.change = {\n\n\t\tsetup: function() {\n\n\t\t\tif ( rformElems.test( this.nodeName ) ) {\n\t\t\t\t// IE doesn't fire change on a check/radio until blur; trigger it on click\n\t\t\t\t// after a propertychange. Eat the blur-change in special.change.handle.\n\t\t\t\t// This still fires onchange a second time for check/radio after blur.\n\t\t\t\tif ( this.type === \"checkbox\" || this.type === \"radio\" ) {\n\t\t\t\t\tjQuery.event.add( this, \"propertychange._change\", function( event ) {\n\t\t\t\t\t\tif ( event.originalEvent.propertyName === \"checked\" ) {\n\t\t\t\t\t\t\tthis._just_changed = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery.event.add( this, \"click._change\", function( event ) {\n\t\t\t\t\t\tif ( this._just_changed && !event.isTrigger ) {\n\t\t\t\t\t\t\tthis._just_changed = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Allow triggered, simulated change events (#11500)\n\t\t\t\t\t\tjQuery.event.simulate( \"change\", this, event, true );\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Delegated event; lazy-add a change handler on descendant inputs\n\t\t\tjQuery.event.add( this, \"beforeactivate._change\", function( e ) {\n\t\t\t\tvar elem = e.target;\n\n\t\t\t\tif ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, \"changeBubbles\" ) ) {\n\t\t\t\t\tjQuery.event.add( elem, \"change._change\", function( event ) {\n\t\t\t\t\t\tif ( this.parentNode && !event.isSimulated && !event.isTrigger ) {\n\t\t\t\t\t\t\tjQuery.event.simulate( \"change\", this.parentNode, event, true );\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tjQuery._data( elem, \"changeBubbles\", true );\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\t\thandle: function( event ) {\n\t\t\tvar elem = event.target;\n\n\t\t\t// Swallow native change events from checkbox/radio, we already triggered them above\n\t\t\tif ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== \"radio\" && elem.type !== \"checkbox\") ) {\n\t\t\t\treturn event.handleObj.handler.apply( this, arguments );\n\t\t\t}\n\t\t},\n\n\t\tteardown: function() {\n\t\t\tjQuery.event.remove( this, \"._change\" );\n\n\t\t\treturn !rformElems.test( this.nodeName );\n\t\t}\n\t};\n}\n\n// Create \"bubbling\" focus and blur events\nif ( !jQuery.support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler while someone wants focusin/focusout\n\t\tvar attaches = 0,\n\t\t\thandler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tif ( attaches++ === 0 ) {\n\t\t\t\t\tdocument.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tif ( --attaches === 0 ) {\n\t\t\t\t\tdocument.removeEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar origFn, type;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t},\n\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t}\n});\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n\n\tif ( rkeyEvent.test( name ) ) {\n\t\tjQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;\n\t}\n\n\tif ( rmouseEvent.test( name ) ) {\n\t\tjQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;\n\t}\n});\n/*!\n * Sizzle CSS Selector Engine\n * Copyright 2012 jQuery Foundation and other contributors\n * Released under the MIT license\n * http://sizzlejs.com/\n */\n(function( window, undefined ) {\n\nvar i,\n\tcachedruns,\n\tExpr,\n\tgetText,\n\tisXML,\n\tcompile,\n\thasDuplicate,\n\toutermostContext,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsXML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\tsortOrder,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + -(new Date()),\n\tpreferredDoc = window.document,\n\tsupport = {},\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\n\t// General-purpose constants\n\tstrundefined = typeof undefined,\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Array methods\n\tarr = [],\n\tpop = arr.pop,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf if we can't use a native one\n\tindexOf = arr.indexOf || function( elem ) {\n\t\tvar i = 0,\n\t\t\tlen = this.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( this[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors\n\toperators = \"([*^$|!~]?=)\",\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")\" + whitespace +\n\t\t\"*(?:\" + operators + whitespace + \"*(?:(['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|(\" + identifier + \")|)|)\" + whitespace + \"*\\\\]\",\n\n\t// Prefer arguments quoted,\n\t//   then not containing pseudos/brackets,\n\t//   then attribute selectors/non-parenthetical expressions,\n\t//   then anything else\n\t// These preferences are here to reduce the number of selectors\n\t//   needing tokenize in the PSEUDO preFilter\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\(((['\\\"])((?:\\\\\\\\.|[^\\\\\\\\])*?)\\\\3|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes.replace( 3, 8 ) + \")*)|.*)\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([\\\\x20\\\\t\\\\r\\\\n\\\\f>+~])\" + whitespace + \"*\" ),\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"NAME\": new RegExp( \"^\\\\[name=['\\\"]?(\" + characterEncoding + \")['\\\"]?\\\\]\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trsibling = /[\\x20\\t\\r\\n\\f]*[+~]/,\n\n\trnative = /\\{\\s*\\[native code\\]\\s*\\}/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trescape = /'|\\\\/g,\n\trattributeQuotes = /\\=[\\x20\\t\\r\\n\\f]*([^'\"\\]]*)[\\x20\\t\\r\\n\\f]*\\]/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = /\\\\([\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|.)/g,\n\tfunescape = function( _, escaped ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\treturn high !== high ?\n\t\t\tescaped :\n\t\t\t// BMP codepoint\n\t\t\thigh < 0 ?\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t};\n\n// Use a stripped-down slice if we can't use a native one\ntry {\n\tslice.call( docElem.childNodes, 0 )[0].nodeType;\n} catch ( e ) {\n\tslice = function( i ) {\n\t\tvar elem,\n\t\t\tresults = [];\n\t\tfor ( ; (elem = this[i]); i++ ) {\n\t\t\tresults.push( elem );\n\t\t}\n\t\treturn results;\n\t};\n}\n\n/**\n * For feature detection\n * @param {Function} fn The function to test for native support\n */\nfunction isNative( fn ) {\n\treturn rnative.test( fn + \"\" );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar cache,\n\t\tkeys = [];\n\n\treturn (cache = function( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key += \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key ] = value);\n\t});\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\n\tif ( !selector || typeof selector !== \"string\" ) {\n\t\treturn results;\n\t}\n\n\tif ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {\n\t\treturn [];\n\t}\n\n\tif ( !documentIsXML && !seed ) {\n\n\t\t// Shortcuts\n\t\tif ( (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, slice.call(context.getElementsByClassName( m ), 0) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && !rbuggyQSA.test(selector) ) {\n\t\t\told = true;\n\t\t\tnid = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType === 9 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && context.parentNode || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results, slice.call( newContext.querySelectorAll(\n\t\t\t\t\t\tnewSelector\n\t\t\t\t\t), 0 ) );\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Detect xml\n * @param {Element|Object} elem An element or a document\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar doc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\n\t// Support tests\n\tdocumentIsXML = isXML( doc );\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.tagNameNoComments = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Check if attributes should be retrieved by attribute nodes\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.innerHTML = \"<select></select>\";\n\t\tvar type = typeof div.lastChild.getAttribute(\"multiple\");\n\t\t// IE8 returns a string for some attributes even when not present\n\t\treturn type !== \"boolean\" && type !== \"string\";\n\t});\n\n\t// Check if getElementsByClassName can be trusted\n\tsupport.getByClassName = assert(function( div ) {\n\t\t// Opera can't find a second classname (in 9.6)\n\t\tdiv.innerHTML = \"<div class='hidden e'></div><div class='hidden'></div>\";\n\t\tif ( !div.getElementsByClassName || !div.getElementsByClassName(\"e\").length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Safari 3.2 caches class attributes and doesn't catch changes\n\t\tdiv.lastChild.className = \"e\";\n\t\treturn div.getElementsByClassName(\"e\").length === 2;\n\t});\n\n\t// Check if getElementById returns elements by name\n\t// Check if getElementsByName privileges form controls or returns elements by ID\n\tsupport.getByName = assert(function( div ) {\n\t\t// Inject content\n\t\tdiv.id = expando + 0;\n\t\tdiv.innerHTML = \"<a name='\" + expando + \"'></a><div name='\" + expando + \"'></div>\";\n\t\tdocElem.insertBefore( div, docElem.firstChild );\n\n\t\t// Test\n\t\tvar pass = doc.getElementsByName &&\n\t\t\t// buggy browsers will return fewer than the correct 2\n\t\t\tdoc.getElementsByName( expando ).length === 2 +\n\t\t\t// buggy browsers will return more than the correct 0\n\t\t\tdoc.getElementsByName( expando + 0 ).length;\n\t\tsupport.getIdNotName = !doc.getElementById( expando );\n\n\t\t// Cleanup\n\t\tdocElem.removeChild( div );\n\n\t\treturn pass;\n\t});\n\n\t// IE6/7 return modified attributes\n\tExpr.attrHandle = assert(function( div ) {\n\t\tdiv.innerHTML = \"<a href='#'></a>\";\n\t\treturn div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&\n\t\t\tdiv.firstChild.getAttribute(\"href\") === \"#\";\n\t}) ?\n\t\t{} :\n\t\t{\n\t\t\t\"href\": function( elem ) {\n\t\t\t\treturn elem.getAttribute( \"href\", 2 );\n\t\t\t},\n\t\t\t\"type\": function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"type\");\n\t\t\t}\n\t\t};\n\n\t// ID find and filter\n\tif ( support.getIdNotName ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [m] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== strundefined && !documentIsXML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\n\t\t\t\treturn m ?\n\t\t\t\t\tm.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode(\"id\").value === id ?\n\t\t\t\t\t\t[m] :\n\t\t\t\t\t\tundefined :\n\t\t\t\t\t[];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.tagNameNoComments ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== strundefined ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\t\t\t}\n\t\t} :\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\tfor ( ; (elem = results[i]); i++ ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Name\n\tExpr.find[\"NAME\"] = support.getByName && function( tag, context ) {\n\t\tif ( typeof context.getElementsByName !== strundefined ) {\n\t\t\treturn context.getElementsByName( name );\n\t\t}\n\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getByClassName && function( className, context ) {\n\t\tif ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21),\n\t// no need to also add to buggyMatches since matches checks buggyQSA\n\t// A support test would require too much code (would include document ready)\n\trbuggyQSA = [ \":focus\" ];\n\n\tif ( (support.qsa = isNative(doc.querySelectorAll)) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explictly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdiv.innerHTML = \"<select><option selected=''></option></select>\";\n\n\t\t\t// IE8 - Some boolean attributes are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:checked|disabled|ismap|multiple|readonly|selected|value)\" );\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\n\t\t\t// Opera 10-12/IE8 - ^= $= *= and empty values\n\t\t\t// Should not select anything\n\t\t\tdiv.innerHTML = \"<input type='hidden' i=''/>\";\n\t\t\tif ( div.querySelectorAll(\"[i^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:\\\"\\\"|'')\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = new RegExp( rbuggyMatches.join(\"|\") );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = isNative(docElem.contains) || docElem.compareDocumentPosition ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t// Document order sorting\n\tsortOrder = docElem.compareDocumentPosition ?\n\tfunction( a, b ) {\n\t\tvar compare;\n\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tif ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {\n\t\t\tif ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {\n\t\t\t\tif ( a === doc || contains( preferredDoc, a ) ) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tif ( b === doc || contains( preferredDoc, b ) ) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn compare & 4 ? -1 : 1;\n\t\t}\n\n\t\treturn a.compareDocumentPosition ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// The nodes are identical, we can exit early\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\n\t\t// Fallback to using sourceIndex (in IE) if it's available on both nodes\n\t\t} else if ( a.sourceIndex && b.sourceIndex ) {\n\t\t\treturn ( ~b.sourceIndex || MAX_NEGATIVE ) - ( contains( preferredDoc, a ) && ~a.sourceIndex || MAX_NEGATIVE );\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\t} else if ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\t// Always assume the presence of duplicates if sort doesn't\n\t// pass them to our comparison function (as in Google Chrome).\n\thasDuplicate = false;\n\t[0, 0].sort( sortOrder );\n\tsupport.detectDuplicates = hasDuplicate;\n\n\treturn document;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\t// rbuggyQSA always contains :focus, so no need for an existence check\n\tif ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch(e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [elem] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\tvar val;\n\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tif ( !documentIsXML ) {\n\t\tname = name.toLowerCase();\n\t}\n\tif ( (val = Expr.attrHandle[ name ]) ) {\n\t\treturn val( elem );\n\t}\n\tif ( documentIsXML || support.attributes ) {\n\t\treturn elem.getAttribute( name );\n\t}\n\treturn ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?\n\t\tname :\n\t\tval && val.specified ? val.value : null;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n// Document sorting and removing duplicates\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\ti = 1,\n\t\tj = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\tfor ( ; (elem = results[i]); i++ ) {\n\t\t\tif ( elem === results[ i - 1 ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\treturn results;\n};\n\nfunction siblingCheck( a, b ) {\n\tvar cur = a && b && a.nextSibling;\n\n\tfor ( ; cur; cur = cur.nextSibling ) {\n\t\tif ( cur === b ) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n// Returns a function to use in pseudos for input types\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n// Returns a function to use in pseudos for buttons\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n// Returns a function to use in pseudos for positionals\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\tfor ( ; (node = elem[i]); i++ ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (see #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[5] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[4] ) {\n\t\t\t\tmatch[2] = match[4];\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeName ) {\n\t\t\tif ( nodeName === \"*\" ) {\n\t\t\t\treturn function() { return true; };\n\t\t\t}\n\n\t\t\tnodeName = nodeName.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute(\"class\")) || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.substr( result.length - check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.substr( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf.call( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifider\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsXML ?\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\") :\n\t\t\t\t\t\telem.lang) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),\n\t\t\t//   not comment, processing instructions, or others\n\t\t\t// Thanks to Diego Perini for the nodeName shortcut\n\t\t\t//   Greater than \"@\" means alpha characters (specifically not starting with \"#\" or \"?\")\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeName > \"@\" || elem.nodeType === 3 || elem.nodeType === 4 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\t// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)\n\t\t\t// use getAttribute instead to test this case\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === elem.type );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\nfunction tokenize( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( tokens = [] );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push( {\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t} );\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push( {\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t} );\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n}\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && combinator.dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar data, cache, outerCache,\n\t\t\t\tdirkey = dirruns + \" \" + doneName;\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {\n\t\t\t\t\t\t\tif ( (data = cache[1]) === true || data === cachedruns ) {\n\t\t\t\t\t\t\t\treturn data === true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tcache = outerCache[ dir ] = [ dirkey ];\n\t\t\t\t\t\t\tcache[1] = matcher( elem, context, xml ) || cachedruns;\n\t\t\t\t\t\t\tif ( cache[1] === true ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf.call( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\treturn ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\t// A counter to specify which element is currently being matched\n\tvar matcherCachedRuns = 0,\n\t\tbySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, expandContext ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tsetMatched = [],\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\toutermost = expandContext != null,\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", expandContext && context.parentNode || context ),\n\t\t\t\t// Nested matchers should use non-integer dirruns\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t\tcachedruns = matcherCachedRuns;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tfor ( j = 0; (matcher = elementMatchers[j]); j++ ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t\tcachedruns = ++matcherCachedRuns;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\t// `i` starts as a string, so matchedCount would equal \"00\" if there are no elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tfor ( j = 0; (matcher = setMatchers[j]); j++ ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !group ) {\n\t\t\tgroup = tokenize( selector );\n\t\t}\n\t\ti = group.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( group[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\t}\n\treturn cached;\n};\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction select( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tmatch = tokenize( selector );\n\n\tif ( !seed ) {\n\t\t// Try to minimize operations if there is only one group\n\t\tif ( match.length === 1 ) {\n\n\t\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\t\ttokens = match[0] = match[0].slice( 0 );\n\t\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\t\tcontext.nodeType === 9 && !documentIsXML &&\n\t\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\t\tcontext = Expr.find[\"ID\"]( token.matches[0].replace( runescape, funescape ), context )[0];\n\t\t\t\tif ( !context ) {\n\t\t\t\t\treturn results;\n\t\t\t\t}\n\n\t\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t\t}\n\n\t\t\t// Fetch a seed set for right-to-left matching\n\t\t\tfor ( i = matchExpr[\"needsContext\"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {\n\t\t\t\ttoken = tokens[i];\n\n\t\t\t\t// Abort if we hit a combinator\n\t\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\t\tif ( (seed = find(\n\t\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\t\trsibling.test( tokens[0].type ) && context.parentNode || context\n\t\t\t\t\t)) ) {\n\n\t\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\t\tpush.apply( results, slice.call( seed, 0 ) );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\tcompile( selector, match )(\n\t\tseed,\n\t\tcontext,\n\t\tdocumentIsXML,\n\t\tresults,\n\t\trsibling.test( selector )\n\t);\n\treturn results;\n}\n\n// Deprecated\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nExpr.filters = setFilters.prototype = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\n// Initialize with the default document\nsetDocument();\n\n// Override sizzle attribute retrieval\nSizzle.attr = jQuery.attr;\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n})( window );\nvar runtil = /Until$/,\n\trparentsprev = /^(?:parents|prev(?:Until|All))/,\n\tisSimple = /^.[^:#\\[\\.,]*$/,\n\trneedsContext = jQuery.expr.match.needsContext,\n\t// methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i, ret, self;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\tself = this;\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < self.length; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}) );\n\t\t}\n\n\t\tret = [];\n\t\tfor ( i = 0; i < this.length; i++ ) {\n\t\t\tjQuery.find( selector, this[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( jQuery.unique( ret ) );\n\t\tret.selector = ( this.selector ? this.selector + \" \" : \"\" ) + selector;\n\t\treturn ret;\n\t},\n\n\thas: function( target ) {\n\t\tvar i,\n\t\t\ttargets = jQuery( target, this ),\n\t\t\tlen = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, false) );\n\t},\n\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector, true) );\n\t},\n\n\tis: function( selector ) {\n\t\treturn !!selector && (\n\t\t\ttypeof selector === \"string\" ?\n\t\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\t\trneedsContext.test( selector ) ?\n\t\t\t\t\tjQuery( selector, this.context ).index( this[0] ) >= 0 :\n\t\t\t\t\tjQuery.filter( selector, this ).length > 0 :\n\t\t\t\tthis.filter( selector ).length > 0 );\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tret = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tcur = this[i];\n\n\t\t\twhile ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {\n\t\t\t\tif ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n\t\t\t\t\tret.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );\n\t},\n\n\t// Determine the position of an element within\n\t// the matched set of elements\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn jQuery.inArray( this[0], jQuery( elem ) );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn jQuery.inArray(\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[0] : elem, this );\n\t},\n\n\tadd: function( selector, context ) {\n\t\tvar set = typeof selector === \"string\" ?\n\t\t\t\tjQuery( selector, context ) :\n\t\t\t\tjQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),\n\t\t\tall = jQuery.merge( this.get(), set );\n\n\t\treturn this.pushStack( jQuery.unique(all) );\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\nfunction sibling( cur, dir ) {\n\tdo {\n\t\tcur = cur[ dir ];\n\t} while ( cur && cur.nodeType !== 1 );\n\n\treturn cur;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn jQuery.nodeName( elem, \"iframe\" ) ?\n\t\t\telem.contentDocument || elem.contentWindow.document :\n\t\t\tjQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar ret = jQuery.map( this, fn, until );\n\n\t\tif ( !runtil.test( name ) ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tret = jQuery.filter( selector, ret );\n\t\t}\n\n\t\tret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n\t\tif ( this.length > 1 && rparentsprev.test( name ) ) {\n\t\t\tret = ret.reverse();\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\njQuery.extend({\n\tfilter: function( expr, elems, not ) {\n\t\tif ( not ) {\n\t\t\texpr = \":not(\" + expr + \")\";\n\t\t}\n\n\t\treturn elems.length === 1 ?\n\t\t\tjQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n\t\t\tjQuery.find.matches(expr, elems);\n\t},\n\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\tcur = elem[ dir ];\n\n\t\twhile ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n\t\t\tif ( cur.nodeType === 1 ) {\n\t\t\t\tmatched.push( cur );\n\t\t\t}\n\t\t\tcur = cur[dir];\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar r = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tr.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn r;\n\t}\n});\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, keep ) {\n\n\t// Can't pass null or undefined to indexOf in Firefox 4\n\t// Set to 0 to skip string check\n\tqualifier = qualifier || 0;\n\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep(elements, function( elem, i ) {\n\t\t\tvar retVal = !!qualifier.call( elem, i, elem );\n\t\t\treturn retVal === keep;\n\t\t});\n\n\t} else if ( qualifier.nodeType ) {\n\t\treturn jQuery.grep(elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) === keep;\n\t\t});\n\n\t} else if ( typeof qualifier === \"string\" ) {\n\t\tvar filtered = jQuery.grep(elements, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t});\n\n\t\tif ( isSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter(qualifier, filtered, !keep);\n\t\t} else {\n\t\t\tqualifier = jQuery.filter( qualifier, filtered );\n\t\t}\n\t}\n\n\treturn jQuery.grep(elements, function( elem ) {\n\t\treturn ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;\n\t});\n}\nfunction createSafeFragment( document ) {\n\tvar list = nodeNames.split( \"|\" ),\n\t\tsafeFrag = document.createDocumentFragment();\n\n\tif ( safeFrag.createElement ) {\n\t\twhile ( list.length ) {\n\t\t\tsafeFrag.createElement(\n\t\t\t\tlist.pop()\n\t\t\t);\n\t\t}\n\t}\n\treturn safeFrag;\n}\n\nvar nodeNames = \"abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|\" +\n\t\t\"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video\",\n\trinlinejQuery = / jQuery\\d+=\"(?:null|\\d+)\"/g,\n\trnoshimcache = new RegExp(\"<(?:\" + nodeNames + \")[\\\\s/>]\", \"i\"),\n\trleadingWhitespace = /^\\s+/,\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trtbody = /<tbody/i,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\tmanipulation_rcheckableType = /^(?:checkbox|radio)$/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\t\tlegend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n\t\tarea: [ 1, \"<map>\", \"</map>\" ],\n\t\tparam: [ 1, \"<object>\", \"</object>\" ],\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\tcol: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,\n\t\t// unless wrapped in a div with non-breaking characters in front of it.\n\t\t_default: jQuery.support.htmlSerialize ? [ 0, \"\", \"\" ] : [ 1, \"X<div>\", \"</div>\"  ]\n\t},\n\tsafeFragment = createSafeFragment( document ),\n\tfragmentDiv = safeFragment.appendChild( document.createElement(\"div\") );\n\nwrapMap.optgroup = wrapMap.option;\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );\n\t\t}, null, value, arguments.length );\n\t},\n\n\twrapAll: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[0] ) {\n\t\t\t// The elements to wrap the target around\n\t\t\tvar wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n\t\t\tif ( this[0].parentNode ) {\n\t\t\t\twrap.insertBefore( this[0] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n\t\t\t\t\telem = elem.firstChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function(i) {\n\t\t\t\tjQuery(this).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function(i) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip(arguments, true, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tthis.insertBefore( elem, this.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, false, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, false, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\t// keepData is for internal use only--do not document\n\tremove: function( selector, keepData ) {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {\n\t\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t\t}\n\n\t\t\t\tif ( elem.parentNode ) {\n\t\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t}\n\n\t\t\t// Remove any remaining nodes\n\t\t\twhile ( elem.firstChild ) {\n\t\t\t\telem.removeChild( elem.firstChild );\n\t\t\t}\n\n\t\t\t// If this is a select, ensure that it displays empty (#12336)\n\t\t\t// Support: IE<9\n\t\t\tif ( elem.options && jQuery.nodeName( elem, \"select\" ) ) {\n\t\t\t\telem.options.length = 0;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function () {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn jQuery.access( this, function( value ) {\n\t\t\tvar elem = this[0] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined ) {\n\t\t\t\treturn elem.nodeType === 1 ?\n\t\t\t\t\telem.innerHTML.replace( rinlinejQuery, \"\" ) :\n\t\t\t\t\tundefined;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&\n\t\t\t\t( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [\"\", \"\"] )[1].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor (; i < l; i++ ) {\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\telem = this[i] || {};\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function( value ) {\n\t\tvar isFunc = jQuery.isFunction( value );\n\n\t\t// Make sure that the elements are removed from the DOM before they are inserted\n\t\t// this can help fix replacing a parent with child elements\n\t\tif ( !isFunc && typeof value !== \"string\" ) {\n\t\t\tvalue = jQuery( value ).not( this ).detach();\n\t\t}\n\n\t\treturn this.domManip( [ value ], true, function( elem ) {\n\t\t\tvar next = this.nextSibling,\n\t\t\t\tparent = this.parentNode;\n\n\t\t\tif ( parent && this.nodeType === 1 || this.nodeType === 11 ) {\n\n\t\t\t\tjQuery( this ).remove();\n\n\t\t\t\tif ( next ) {\n\t\t\t\t\tnext.parentNode.insertBefore( elem, next );\n\t\t\t\t} else {\n\t\t\t\t\tparent.appendChild( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, table, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = core_concat.apply( [], args );\n\n\t\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[0],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction || !( l <= 1 || typeof value !== \"string\" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[0] = value.call( this, index, table ? self.html() : undefined );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, table, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\ttable = table && jQuery.nodeName( first, \"tr\" );\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call(\n\t\t\t\t\t\ttable && jQuery.nodeName( this[i], \"table\" ) ?\n\t\t\t\t\t\t\tfindOrAppend( this[i], \"tbody\" ) :\n\t\t\t\t\t\t\tthis[i],\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\ti\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!jQuery._data( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Hope ajax is available...\n\t\t\t\t\t\t\t\tjQuery.ajax({\n\t\t\t\t\t\t\t\t\turl: node.src,\n\t\t\t\t\t\t\t\t\ttype: \"GET\",\n\t\t\t\t\t\t\t\t\tdataType: \"script\",\n\t\t\t\t\t\t\t\t\tasync: false,\n\t\t\t\t\t\t\t\t\tglobal: false,\n\t\t\t\t\t\t\t\t\t\"throws\": true\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( ( node.text || node.textContent || node.innerHTML || \"\" ).replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fix #11809: Avoid leaking memory\n\t\t\t\tfragment = first = null;\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\nfunction findOrAppend( elem, tag ) {\n\treturn elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\tvar attr = elem.getAttributeNode(\"type\");\n\telem.type = ( attr && attr.specified ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\tif ( match ) {\n\t\telem.type = match[1];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar elem,\n\t\ti = 0;\n\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\tjQuery._data( elem, \"globalEval\", !refElements || jQuery._data( refElements[i], \"globalEval\" ) );\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\n\tif ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n\t\treturn;\n\t}\n\n\tvar type, i, l,\n\t\toldData = jQuery._data( src ),\n\t\tcurData = jQuery._data( dest, oldData ),\n\t\tevents = oldData.events;\n\n\tif ( events ) {\n\t\tdelete curData.handle;\n\t\tcurData.events = {};\n\n\t\tfor ( type in events ) {\n\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t// make the cloned public data object a copy from the original\n\tif ( curData.data ) {\n\t\tcurData.data = jQuery.extend( {}, curData.data );\n\t}\n}\n\nfunction fixCloneNodeIssues( src, dest ) {\n\tvar nodeName, data, e;\n\n\t// We do not need to do anything for non-Elements\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\tnodeName = dest.nodeName.toLowerCase();\n\n\t// IE6-8 copies events bound via attachEvent when using cloneNode.\n\tif ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {\n\t\tdata = jQuery._data( dest );\n\n\t\tfor ( e in data.events ) {\n\t\t\tjQuery.removeEvent( dest, e, data.handle );\n\t\t}\n\n\t\t// Event data gets referenced instead of copied if the expando gets copied too\n\t\tdest.removeAttribute( jQuery.expando );\n\t}\n\n\t// IE blanks contents when cloning scripts, and tries to evaluate newly-set text\n\tif ( nodeName === \"script\" && dest.text !== src.text ) {\n\t\tdisableScript( dest ).text = src.text;\n\t\trestoreScript( dest );\n\n\t// IE6-10 improperly clones children of object elements using classid.\n\t// IE10 throws NoModificationAllowedError if parent is null, #12132.\n\t} else if ( nodeName === \"object\" ) {\n\t\tif ( dest.parentNode ) {\n\t\t\tdest.outerHTML = src.outerHTML;\n\t\t}\n\n\t\t// This path appears unavoidable for IE9. When cloning an object\n\t\t// element in IE9, the outerHTML strategy above is not sufficient.\n\t\t// If the src has innerHTML and the destination does not,\n\t\t// copy the src.innerHTML into the dest.innerHTML. #10324\n\t\tif ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {\n\t\t\tdest.innerHTML = src.innerHTML;\n\t\t}\n\n\t} else if ( nodeName === \"input\" && manipulation_rcheckableType.test( src.type ) ) {\n\t\t// IE6-8 fails to persist the checked state of a cloned checkbox\n\t\t// or radio button. Worse, IE6-7 fail to give the cloned element\n\t\t// a checked appearance if the defaultChecked value isn't also set\n\n\t\tdest.defaultChecked = dest.checked = src.checked;\n\n\t\t// IE6-7 get confused and end up setting the value of a cloned\n\t\t// checkbox/radio button to an empty string instead of \"on\"\n\t\tif ( dest.value !== src.value ) {\n\t\t\tdest.value = src.value;\n\t\t}\n\n\t// IE6-8 fails to return the selected option to the default selected\n\t// state when cloning options\n\t} else if ( nodeName === \"option\" ) {\n\t\tdest.defaultSelected = dest.selected = src.defaultSelected;\n\n\t// IE6-8 fails to set the defaultValue to the correct value when\n\t// cloning other types of input fields\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\ti = 0,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone(true);\n\t\t\tjQuery( insert[i] )[ original ]( elems );\n\n\t\t\t// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()\n\t\t\tcore_push.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\nfunction getAll( context, tag ) {\n\tvar elems, elem,\n\t\ti = 0,\n\t\tfound = typeof context.getElementsByTagName !== \"undefined\" ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\ttypeof context.querySelectorAll !== \"undefined\" ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\tundefined;\n\n\tif ( !found ) {\n\t\tfor ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !tag || jQuery.nodeName( elem, tag ) ) {\n\t\t\t\tfound.push( elem );\n\t\t\t} else {\n\t\t\t\tjQuery.merge( found, getAll( elem, tag ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], found ) :\n\t\tfound;\n}\n\n// Used in buildFragment, fixes the defaultChecked property\nfunction fixDefaultChecked( elem ) {\n\tif ( manipulation_rcheckableType.test( elem.type ) ) {\n\t\telem.defaultChecked = elem.checked;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar destElements, srcElements, node, i, clone,\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\tif ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( \"<\" + elem.nodeName + \">\" ) ) {\n\t\t\tclone = elem.cloneNode( true );\n\n\t\t// IE<=8 does not properly clone detached, unknown element nodes\n\t\t} else {\n\t\t\tfragmentDiv.innerHTML = elem.outerHTML;\n\t\t\tfragmentDiv.removeChild( clone = fragmentDiv.firstChild );\n\t\t}\n\n\t\tif ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n\t\t\t\t(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\t// Fix all IE cloning issues\n\t\t\tfor ( i = 0; (node = srcElements[i]) != null; ++i ) {\n\t\t\t\t// Ensure that the destination node is not null; Fixes #9587\n\t\t\t\tif ( destElements[i] ) {\n\t\t\t\t\tfixCloneNodeIssues( node, destElements[i] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0; (node = srcElements[i]) != null; i++ ) {\n\t\t\t\t\tcloneCopyEvent( node, destElements[i] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\tdestElements = srcElements = node = null;\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar contains, elem, tag, tmp, wrap, tbody, j,\n\t\t\tl = elems.length,\n\n\t\t\t// Ensure a safe fragment\n\t\t\tsafe = createSafeFragment( context ),\n\n\t\t\tnodes = [],\n\t\t\ti = 0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || safe.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = ( rtagName.exec( elem ) || [\"\", \"\"] )[1].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\n\t\t\t\t\ttmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[2];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[0];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Manually add leading whitespace removed by IE\n\t\t\t\t\tif ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n\t\t\t\t\t\tnodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove IE's autoinserted <tbody> from table fragments\n\t\t\t\t\tif ( !jQuery.support.tbody ) {\n\n\t\t\t\t\t\t// String was a <table>, *may* have spurious <tbody>\n\t\t\t\t\t\telem = tag === \"table\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\ttmp.firstChild :\n\n\t\t\t\t\t\t\t// String was a bare <thead> or <tfoot>\n\t\t\t\t\t\t\twrap[1] === \"<table>\" && !rtbody.test( elem ) ?\n\t\t\t\t\t\t\t\ttmp :\n\t\t\t\t\t\t\t\t0;\n\n\t\t\t\t\t\tj = elem && elem.childNodes.length;\n\t\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\t\tif ( jQuery.nodeName( (tbody = elem.childNodes[j]), \"tbody\" ) && !tbody.childNodes.length ) {\n\t\t\t\t\t\t\t\telem.removeChild( tbody );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Fix #12392 for WebKit and IE > 9\n\t\t\t\t\ttmp.textContent = \"\";\n\n\t\t\t\t\t// Fix #12392 for oldIE\n\t\t\t\t\twhile ( tmp.firstChild ) {\n\t\t\t\t\t\ttmp.removeChild( tmp.firstChild );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remember the top-level container for proper cleanup\n\t\t\t\t\ttmp = safe.lastChild;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Fix #11356: Clear elements from fragment\n\t\tif ( tmp ) {\n\t\t\tsafe.removeChild( tmp );\n\t\t}\n\n\t\t// Reset defaultChecked for any radios and checkboxes\n\t\t// about to be appended to the DOM in IE 6/7 (#8060)\n\t\tif ( !jQuery.support.appendChecked ) {\n\t\t\tjQuery.grep( getAll( nodes, \"input\" ), fixDefaultChecked );\n\t\t}\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( safe.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\ttmp = null;\n\n\t\treturn safe;\n\t},\n\n\tcleanData: function( elems, /* internal */ acceptData ) {\n\t\tvar data, id, elem, type,\n\t\t\ti = 0,\n\t\t\tinternalKey = jQuery.expando,\n\t\t\tcache = jQuery.cache,\n\t\t\tdeleteExpando = jQuery.support.deleteExpando,\n\t\t\tspecial = jQuery.event.special;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\n\t\t\tif ( acceptData || jQuery.acceptData( elem ) ) {\n\n\t\t\t\tid = elem[ internalKey ];\n\t\t\t\tdata = id && cache[ id ];\n\n\t\t\t\tif ( data ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove cache only if it was not already removed by jQuery.event.remove\n\t\t\t\t\tif ( cache[ id ] ) {\n\n\t\t\t\t\t\tdelete cache[ id ];\n\n\t\t\t\t\t\t// IE does not allow us to delete expando properties from nodes,\n\t\t\t\t\t\t// nor does it have a removeAttribute function on Document nodes;\n\t\t\t\t\t\t// we must handle all of these cases\n\t\t\t\t\t\tif ( deleteExpando ) {\n\t\t\t\t\t\t\tdelete elem[ internalKey ];\n\n\t\t\t\t\t\t} else if ( typeof elem.removeAttribute !== \"undefined\" ) {\n\t\t\t\t\t\t\telem.removeAttribute( internalKey );\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\telem[ internalKey ] = null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcore_deletedIds.push( id );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\nvar curCSS, getStyles, iframe,\n\tralpha = /alpha\\([^)]*\\)/i,\n\tropacity = /opacity\\s*=\\s*([^)]*)/,\n\trposition = /^(top|right|bottom|left)$/,\n\t// swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trmargin = /^margin/,\n\trnumsplit = new RegExp( \"^(\" + core_pnum + \")(.*)$\", \"i\" ),\n\trnumnonpx = new RegExp( \"^(\" + core_pnum + \")(?!px)[a-z%]+$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + core_pnum + \")\", \"i\" ),\n\telemdisplay = { BODY: \"block\" },\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: 0,\n\t\tfontWeight: 400\n\t},\n\n\tcssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ],\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n// return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// check for vendor prefixed names\n\tvar capName = name.charAt(0).toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction isHidden( elem, el ) {\n\t// isHidden might be called from jQuery#filter function;\n\t// in that case, element will be second argument\n\telem = el || elem;\n\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n}\n\nfunction showHide( elements, show ) {\n\tvar elem,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\" );\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && elem.style.display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = jQuery._data( elem, \"olddisplay\", css_defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else if ( !values[ index ] && !isHidden( elem ) ) {\n\t\t\tjQuery._data( elem, \"olddisplay\", jQuery.css( elem, \"display\" ) );\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn jQuery.access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tvar bool = typeof state === \"boolean\";\n\n\t\treturn this.each(function() {\n\t\t\tif ( bool ? state : isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Exclude the following css properties to add px\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t// normalize float css property\n\t\t\"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// convert relative number strings (+= or -=) to relative numbers. #7345\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that NaN and null values aren't set. See: #7116\n\t\t\tif ( value == null || type === \"number\" && isNaN( value ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,\n\t\t\t// but it would mean to define eight (for every problematic property) identical functions\n\t\t\tif ( !jQuery.support.clearCloneStyle && value === \"\" && name.indexOf(\"background\") === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {\n\n\t\t\t\t// Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n\t\t\t\t// Fixes bug #5509\n\t\t\t\ttry {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t} catch(e) {}\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// gets hook for the prefixed version\n\t\t// followed by the unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t//convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Return, converting to number if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t},\n\n\t// A method for quickly swapping in/out CSS properties to get correct calculations\n\tswap: function( elem, options, callback, args ) {\n\t\tvar ret, name,\n\t\t\told = {};\n\n\t\t// Remember the old values, and insert the new ones\n\t\tfor ( name in options ) {\n\t\t\told[ name ] = elem.style[ name ];\n\t\t\telem.style[ name ] = options[ name ];\n\t\t}\n\n\t\tret = callback.apply( elem, args || [] );\n\n\t\t// Revert the old values\n\t\tfor ( name in options ) {\n\t\t\telem.style[ name ] = old[ name ];\n\t\t}\n\n\t\treturn ret;\n\t}\n});\n\n// NOTE: we've included the \"window\" in window.getComputedStyle\n// because jsdom on node.js will break without it.\nif ( window.getComputedStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn window.getComputedStyle( elem, null );\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar width, minWidth, maxWidth,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\n\t\t\t// getPropertyValue is only needed for .css('filter') in IE9, see #12537\n\t\t\tret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\tif ( computed ) {\n\n\t\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\tret = jQuery.style( elem, name );\n\t\t\t}\n\n\t\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t\t// Chrome < 17 and Safari 5.0 uses \"computed value\" instead of \"used value\" for margin-right\n\t\t\t// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t\t// Remember the original values\n\t\t\t\twidth = style.width;\n\t\t\t\tminWidth = style.minWidth;\n\t\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t\t// Put in the new values to get a computed value out\n\t\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\t\tret = computed.width;\n\n\t\t\t\t// Revert the changed values\n\t\t\t\tstyle.width = width;\n\t\t\t\tstyle.minWidth = minWidth;\n\t\t\t\tstyle.maxWidth = maxWidth;\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t};\n} else if ( document.documentElement.currentStyle ) {\n\tgetStyles = function( elem ) {\n\t\treturn elem.currentStyle;\n\t};\n\n\tcurCSS = function( elem, name, _computed ) {\n\t\tvar left, rs, rsLeft,\n\t\t\tcomputed = _computed || getStyles( elem ),\n\t\t\tret = computed ? computed[ name ] : undefined,\n\t\t\tstyle = elem.style;\n\n\t\t// Avoid setting ret to empty string here\n\t\t// so we don't default to auto\n\t\tif ( ret == null && style && style[ name ] ) {\n\t\t\tret = style[ name ];\n\t\t}\n\n\t\t// From the awesome hack by Dean Edwards\n\t\t// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n\t\t// If we're not dealing with a regular pixel number\n\t\t// but a number that has a weird ending, we need to convert it to pixels\n\t\t// but not position css attributes, as those are proportional to the parent element instead\n\t\t// and we can't measure the parent instead because it might trigger a \"stacking dolls\" problem\n\t\tif ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\tleft = style.left;\n\t\t\trs = elem.runtimeStyle;\n\t\t\trsLeft = rs && rs.left;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = elem.currentStyle.left;\n\t\t\t}\n\t\t\tstyle.left = name === \"fontSize\" ? \"1em\" : ret;\n\t\t\tret = style.pixelLeft + \"px\";\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.left = left;\n\t\t\tif ( rsLeft ) {\n\t\t\t\trs.left = rsLeft;\n\t\t\t}\n\t\t}\n\n\t\treturn ret === \"\" ? \"auto\" : ret;\n\t};\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// at this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// at this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// at this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.support.boxSizing && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// we need the check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\n// Try to determine the default display value of an element\nfunction css_defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = ( iframe ||\n\t\t\t\tjQuery(\"<iframe frameborder='0' width='0' height='0'/>\")\n\t\t\t\t.css( \"cssText\", \"display:block !important\" )\n\t\t\t).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;\n\t\t\tdoc.write(\"<!doctype html><html><body>\");\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\n\n// Called ONLY from within css_defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\t\tdisplay = jQuery.css( elem[0], \"display\" );\n\telem.remove();\n\treturn display;\n}\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\t\t\t\t// certain elements can have dimension info if we invisibly show them\n\t\t\t\t// however, it must have a current display style that would benefit from this\n\t\t\t\treturn elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, \"display\" ) ) ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.support.boxSizing && jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\nif ( !jQuery.support.opacity ) {\n\tjQuery.cssHooks.opacity = {\n\t\tget: function( elem, computed ) {\n\t\t\t// IE uses filters for opacity\n\t\t\treturn ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\" ) ?\n\t\t\t\t( 0.01 * parseFloat( RegExp.$1 ) ) + \"\" :\n\t\t\t\tcomputed ? \"1\" : \"\";\n\t\t},\n\n\t\tset: function( elem, value ) {\n\t\t\tvar style = elem.style,\n\t\t\t\tcurrentStyle = elem.currentStyle,\n\t\t\t\topacity = jQuery.isNumeric( value ) ? \"alpha(opacity=\" + value * 100 + \")\" : \"\",\n\t\t\t\tfilter = currentStyle && currentStyle.filter || style.filter || \"\";\n\n\t\t\t// IE has trouble with opacity if it does not have layout\n\t\t\t// Force it by setting the zoom level\n\t\t\tstyle.zoom = 1;\n\n\t\t\t// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652\n\t\t\t// if value === \"\", then remove inline opacity #12685\n\t\t\tif ( ( value >= 1 || value === \"\" ) &&\n\t\t\t\t\tjQuery.trim( filter.replace( ralpha, \"\" ) ) === \"\" &&\n\t\t\t\t\tstyle.removeAttribute ) {\n\n\t\t\t\t// Setting style.filter to null, \"\" & \" \" still leave \"filter:\" in the cssText\n\t\t\t\t// if \"filter:\" is present at all, clearType is disabled, we want to avoid this\n\t\t\t\t// style.removeAttribute is IE Only, but so apparently is this code path...\n\t\t\t\tstyle.removeAttribute( \"filter\" );\n\n\t\t\t\t// if there is no filter style applied in a css rule or unset inline opacity, we are done\n\t\t\t\tif ( value === \"\" || currentStyle && !currentStyle.filter ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// otherwise, set new filter values\n\t\t\tstyle.filter = ralpha.test( filter ) ?\n\t\t\t\tfilter.replace( ralpha, opacity ) :\n\t\t\t\tfilter + \" \" + opacity;\n\t\t}\n\t};\n}\n\n// These hooks cannot be added until DOM ready because the support test\n// for it is not run until after DOM ready\njQuery(function() {\n\tif ( !jQuery.support.reliableMarginRight ) {\n\t\tjQuery.cssHooks.marginRight = {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\t\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t\t// Work around by temporarily setting element display to inline-block\n\t\t\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n\t// getComputedStyle returns percent when specified for top/left/bottom/right\n\t// rather than make the css module depend on the offset module, we just check for it here\n\tif ( !jQuery.support.pixelPosition && jQuery.fn.position ) {\n\t\tjQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\t\t\tjQuery.cssHooks[ prop ] = {\n\t\t\t\tget: function( elem, computed ) {\n\t\t\t\t\tif ( computed ) {\n\t\t\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\t\t\tcomputed;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t});\n\t}\n\n});\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.hidden = function( elem ) {\n\t\treturn ( elem.offsetWidth === 0 && elem.offsetHeight === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, \"display\" )) === \"none\");\n\t};\n\n\tjQuery.expr.filters.visible = function( elem ) {\n\t\treturn !jQuery.expr.filters.hidden( elem );\n\t};\n}\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function(){\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function(){\n\t\t\tvar type = this.type;\n\t\t\t// Use .is(\":disabled\") so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !manipulation_rcheckableType.test( type ) );\n\t\t})\n\t\t.map(function( i, elem ){\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ){\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n//Serialize an array of form elements or a set of\n//key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\nvar\n\t// Document location\n\tajaxLocParts,\n\tajaxLocation,\n\t\n\tajax_nonce = jQuery.now(),\n\n\tajax_rquery = /\\?/,\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+)|)|)/,\n\n\t// Keep a copy of the old load method\n\t_load = jQuery.fn.load,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat(\"*\");\n\n// #8138, IE may throw an exception when accessing\n// a field from window.location if document.domain has been set\ntry {\n\tajaxLocation = location.href;\n} catch( e ) {\n\t// Use the href attribute of an A element\n\t// since IE will modify it given document.location\n\tajaxLocation = document.createElement( \"a\" );\n\tajaxLocation.href = \"\";\n\tajaxLocation = ajaxLocation.href;\n}\n\n// Segment location into parts\najaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[0] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = url.slice( off, url.length );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ){\n\tjQuery.fn[ type ] = function( fn ){\n\t\treturn this.on( type, fn );\n\t};\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": window.String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( (match = rheaders.exec( responseHeadersString )) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( core_rnotwhite ) || [\"\"];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\tfireGlobals = s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger(\"ajaxStart\");\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + ajax_nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( ajax_rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ajax_nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout(function() {\n\t\t\t\t\tjqXHR.abort(\"timeout\");\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( status >= 200 && status < 300 || status === 304 ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// If not modified\n\t\t\t\tif ( status === 304 ) {\n\t\t\t\t\tisSuccess = true;\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data\n\t\t\t\t} else {\n\t\t\t\t\tisSuccess = ajaxConvert( s, response );\n\t\t\t\t\tstatusText = isSuccess.state;\n\t\t\t\t\tsuccess = isSuccess.data;\n\t\t\t\t\terror = isSuccess.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We extract error from statusText\n\t\t\t\t// then normalize statusText and status for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t}\n});\n\n/* Handles responses to an ajax request:\n * - sets all responseXXX fields accordingly\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes,\n\t\tresponseFields = s.responseFields;\n\n\t// Fill responseXXX fields\n\tfor ( type in responseFields ) {\n\t\tif ( type in responses ) {\n\t\t\tjqXHR[ responseFields[type] ] = responses[ type ];\n\t\t}\n\t}\n\n\t// Remove auto dataType and get content-type in the process\n\twhile( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader(\"Content-Type\");\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n// Chain conversions given the request and the original response\nfunction ajaxConvert( s, response ) {\n\n\tvar conv, conv2, current, tmp,\n\t\tconverters = {},\n\t\ti = 0,\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice(),\n\t\tprev = dataTypes[ 0 ];\n\n\t// Apply the dataFilter if provided\n\tif ( s.dataFilter ) {\n\t\tresponse = s.dataFilter( response, s.dataType );\n\t}\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\t// Convert to each sequential dataType, tolerating list modification\n\tfor ( ; (current = dataTypes[++i]); ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\tif ( current !== \"*\" ) {\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\tif ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split(\" \");\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.splice( i--, 0, current );\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[\"throws\"] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update prev for next iteration\n\t\t\tprev = current;\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /(?:java|ecma)script/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and global\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t\ts.global = false;\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function(s) {\n\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\n\t\tvar script,\n\t\t\thead = document.head || jQuery(\"head\")[0] || document.documentElement;\n\n\t\treturn {\n\n\t\t\tsend: function( _, callback ) {\n\n\t\t\t\tscript = document.createElement(\"script\");\n\n\t\t\t\tscript.async = true;\n\n\t\t\t\tif ( s.scriptCharset ) {\n\t\t\t\t\tscript.charset = s.scriptCharset;\n\t\t\t\t}\n\n\t\t\t\tscript.src = s.url;\n\n\t\t\t\t// Attach handlers for all browsers\n\t\t\t\tscript.onload = script.onreadystatechange = function( _, isAbort ) {\n\n\t\t\t\t\tif ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n\t\t\t\t\t\t// Handle memory leak in IE\n\t\t\t\t\t\tscript.onload = script.onreadystatechange = null;\n\n\t\t\t\t\t\t// Remove the script\n\t\t\t\t\t\tif ( script.parentNode ) {\n\t\t\t\t\t\t\tscript.parentNode.removeChild( script );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Dereference the script\n\t\t\t\t\t\tscript = null;\n\n\t\t\t\t\t\t// Callback if not abort\n\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\tcallback( 200, \"success\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending\n\t\t\t\t// Use native DOM manipulation to avoid our domManip AJAX trickery\n\t\t\t\thead.insertBefore( script, head.firstChild );\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( script ) {\n\t\t\t\t\tscript.onload( undefined, true );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( ajax_nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( ajax_rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\nvar xhrCallbacks, xhrSupported,\n\txhrId = 0,\n\t// #5280: Internet Explorer will keep connections alive if we don't abort on unload\n\txhrOnUnloadAbort = window.ActiveXObject && function() {\n\t\t// Abort all pending requests\n\t\tvar key;\n\t\tfor ( key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]( undefined, true );\n\t\t}\n\t};\n\n// Functions to create xhrs\nfunction createStandardXHR() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch( e ) {}\n}\n\nfunction createActiveXHR() {\n\ttry {\n\t\treturn new window.ActiveXObject(\"Microsoft.XMLHTTP\");\n\t} catch( e ) {}\n}\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\njQuery.ajaxSettings.xhr = window.ActiveXObject ?\n\t/* Microsoft failed to properly\n\t * implement the XMLHttpRequest in IE7 (can't request local files),\n\t * so we use the ActiveXObject when it is available\n\t * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n\t * we need a fallback.\n\t */\n\tfunction() {\n\t\treturn !this.isLocal && createStandardXHR() || createActiveXHR();\n\t} :\n\t// For all other browsers, use the standard XMLHttpRequest object\n\tcreateStandardXHR;\n\n// Determine support properties\nxhrSupported = jQuery.ajaxSettings.xhr();\njQuery.support.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nxhrSupported = jQuery.support.ajax = !!xhrSupported;\n\n// Create transport if the browser can provide an xhr\nif ( xhrSupported ) {\n\n\tjQuery.ajaxTransport(function( s ) {\n\t\t// Cross domain only allowed if supported through XMLHttpRequest\n\t\tif ( !s.crossDomain || jQuery.support.cors ) {\n\n\t\t\tvar callback;\n\n\t\t\treturn {\n\t\t\t\tsend: function( headers, complete ) {\n\n\t\t\t\t\t// Get a new xhr\n\t\t\t\t\tvar handle, i,\n\t\t\t\t\t\txhr = s.xhr();\n\n\t\t\t\t\t// Open the socket\n\t\t\t\t\t// Passing null username, generates a login popup on Opera (#2865)\n\t\t\t\t\tif ( s.username ) {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async, s.username, s.password );\n\t\t\t\t\t} else {\n\t\t\t\t\t\txhr.open( s.type, s.url, s.async );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply custom fields if provided\n\t\t\t\t\tif ( s.xhrFields ) {\n\t\t\t\t\t\tfor ( i in s.xhrFields ) {\n\t\t\t\t\t\t\txhr[ i ] = s.xhrFields[ i ];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Override mime type if needed\n\t\t\t\t\tif ( s.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\t\txhr.overrideMimeType( s.mimeType );\n\t\t\t\t\t}\n\n\t\t\t\t\t// X-Requested-With header\n\t\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\t\tif ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Need an extra try/catch for cross domain requests in Firefox 3\n\t\t\t\t\ttry {\n\t\t\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch( err ) {}\n\n\t\t\t\t\t// Do send the request\n\t\t\t\t\t// This may raise an exception which is actually\n\t\t\t\t\t// handled in jQuery.ajax (so no try/catch here)\n\t\t\t\t\txhr.send( ( s.hasContent && s.data ) || null );\n\n\t\t\t\t\t// Listener\n\t\t\t\t\tcallback = function( _, isAbort ) {\n\n\t\t\t\t\t\tvar status,\n\t\t\t\t\t\t\tstatusText,\n\t\t\t\t\t\t\tresponseHeaders,\n\t\t\t\t\t\t\tresponses,\n\t\t\t\t\t\t\txml;\n\n\t\t\t\t\t\t// Firefox throws exceptions when accessing properties\n\t\t\t\t\t\t// of an xhr when a network error occurred\n\t\t\t\t\t\t// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t// Was never called and is aborted or complete\n\t\t\t\t\t\t\tif ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n\t\t\t\t\t\t\t\t// Only called once\n\t\t\t\t\t\t\t\tcallback = undefined;\n\n\t\t\t\t\t\t\t\t// Do not keep as active anymore\n\t\t\t\t\t\t\t\tif ( handle ) {\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = jQuery.noop;\n\t\t\t\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t\t\t\tdelete xhrCallbacks[ handle ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// If it's an abort\n\t\t\t\t\t\t\t\tif ( isAbort ) {\n\t\t\t\t\t\t\t\t\t// Abort it manually if needed\n\t\t\t\t\t\t\t\t\tif ( xhr.readyState !== 4 ) {\n\t\t\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tresponses = {};\n\t\t\t\t\t\t\t\t\tstatus = xhr.status;\n\t\t\t\t\t\t\t\t\txml = xhr.responseXML;\n\t\t\t\t\t\t\t\t\tresponseHeaders = xhr.getAllResponseHeaders();\n\n\t\t\t\t\t\t\t\t\t// Construct response list\n\t\t\t\t\t\t\t\t\tif ( xml && xml.documentElement /* #4958 */ ) {\n\t\t\t\t\t\t\t\t\t\tresponses.xml = xml;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// When requesting binary data, IE6-9 will throw an exception\n\t\t\t\t\t\t\t\t\t// on any attempt to access responseText (#11426)\n\t\t\t\t\t\t\t\t\tif ( typeof xhr.responseText === \"string\" ) {\n\t\t\t\t\t\t\t\t\t\tresponses.text = xhr.responseText;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Firefox throws an exception when accessing\n\t\t\t\t\t\t\t\t\t// statusText for faulty cross-domain requests\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tstatusText = xhr.statusText;\n\t\t\t\t\t\t\t\t\t} catch( e ) {\n\t\t\t\t\t\t\t\t\t\t// We normalize with Webkit giving an empty statusText\n\t\t\t\t\t\t\t\t\t\tstatusText = \"\";\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Filter status for non standard behaviors\n\n\t\t\t\t\t\t\t\t\t// If the request is local and we have data: assume a success\n\t\t\t\t\t\t\t\t\t// (success with no data won't get notified, that's the best we\n\t\t\t\t\t\t\t\t\t// can do given current implementations)\n\t\t\t\t\t\t\t\t\tif ( !status && s.isLocal && !s.crossDomain ) {\n\t\t\t\t\t\t\t\t\t\tstatus = responses.text ? 200 : 404;\n\t\t\t\t\t\t\t\t\t// IE - #1450: sometimes returns 1223 when it should be 204\n\t\t\t\t\t\t\t\t\t} else if ( status === 1223 ) {\n\t\t\t\t\t\t\t\t\t\tstatus = 204;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch( firefoxAccessException ) {\n\t\t\t\t\t\t\tif ( !isAbort ) {\n\t\t\t\t\t\t\t\tcomplete( -1, firefoxAccessException );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Call complete if needed\n\t\t\t\t\t\tif ( responses ) {\n\t\t\t\t\t\t\tcomplete( status, statusText, responses, responseHeaders );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( !s.async ) {\n\t\t\t\t\t\t// if we're in sync mode we fire the callback\n\t\t\t\t\t\tcallback();\n\t\t\t\t\t} else if ( xhr.readyState === 4 ) {\n\t\t\t\t\t\t// (IE6 & IE7) if it's in cache and has been\n\t\t\t\t\t\t// retrieved directly we need to fire the callback\n\t\t\t\t\t\tsetTimeout( callback );\n\t\t\t\t\t} else {\n\t\t\t\t\t\thandle = ++xhrId;\n\t\t\t\t\t\tif ( xhrOnUnloadAbort ) {\n\t\t\t\t\t\t\t// Create the active xhrs callbacks list if needed\n\t\t\t\t\t\t\t// and attach the unload handler\n\t\t\t\t\t\t\tif ( !xhrCallbacks ) {\n\t\t\t\t\t\t\t\txhrCallbacks = {};\n\t\t\t\t\t\t\t\tjQuery( window ).unload( xhrOnUnloadAbort );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Add to list of active xhrs callbacks\n\t\t\t\t\t\t\txhrCallbacks[ handle ] = callback;\n\t\t\t\t\t\t}\n\t\t\t\t\t\txhr.onreadystatechange = callback;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tabort: function() {\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tcallback( undefined, true );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t});\n}\nvar fxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + core_pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [function( prop, value ) {\n\t\t\tvar end, unit,\n\t\t\t\ttween = this.createTween( prop, value ),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tstart = +target || 0,\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( parts ) {\n\t\t\t\tend = +parts[2];\n\t\t\t\tunit = parts[3] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\n\t\t\t\t// We need to compute starting value\n\t\t\t\tif ( unit !== \"px\" && start ) {\n\t\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\t\t// Prefer the current property, because this process will be trivial if it uses the same units\n\t\t\t\t\t// Fallback to end or a simple constant\n\t\t\t\t\tstart = jQuery.css( tween.elem, prop, true ) || end || 1;\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*\n\t\t\t\t\t\t// Use a string for doubling factor so we don't accidentally see scale as unchanged below\n\t\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t\t// Adjust and apply\n\t\t\t\t\t\tstart = start / scale;\n\t\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur()\n\t\t\t\t\t// And breaking the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t\t}\n\n\t\t\t\ttween.unit = unit;\n\t\t\t\ttween.start = start;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;\n\t\t\t}\n\t\t\treturn tween;\n\t\t}]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\nfunction createTweens( animation, props ) {\n\tjQuery.each( props, function( prop, value ) {\n\t\tvar collection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\t\tindex = 0,\n\t\t\tlength = collection.length;\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tif ( collection[ index ].call( animation, prop, value ) ) {\n\n\t\t\t\t// we're done with this property\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// if we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// resolve when we played the last frame\n\t\t\t\t// otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tcreateTweens( animation, props );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// not quite $.extend, this wont overwrite keys already present.\n\t\t\t// also - reusing 'index' from above because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/*jshint validthis:true */\n\tvar index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,\n\t\tanim = this,\n\t\tstyle = elem.style,\n\t\torig = {},\n\t\thandled = [],\n\t\thidden = elem.nodeType && isHidden( elem );\n\n\t// handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// doing this makes sure that the complete handler will be called\n\t\t\t// before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE does not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tif ( jQuery.css( elem, \"display\" ) === \"inline\" &&\n\t\t\t\tjQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t// inline-level elements accept inline-block;\n\t\t\t// block-level elements need to be inline with layout\n\t\t\tif ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === \"inline\" ) {\n\t\t\t\tstyle.display = \"inline-block\";\n\n\t\t\t} else {\n\t\t\t\tstyle.zoom = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tif ( !jQuery.support.shrinkWrapBlocks ) {\n\t\t\tanim.done(function() {\n\t\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t\t});\n\t\t}\n\t}\n\n\n\t// show/hide pass\n\tfor ( index in props ) {\n\t\tvalue = props[ index ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ index ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\thandled.push( index );\n\t\t}\n\t}\n\n\tlength = handled.length;\n\tif ( length ) {\n\t\tdataShow = jQuery._data( elem, \"fxshow\" ) || jQuery._data( elem, \"fxshow\", {} );\n\t\tif ( \"hidden\" in dataShow ) {\n\t\t\thidden = dataShow.hidden;\n\t\t}\n\n\t\t// store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\t\t\tjQuery._removeData( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( index = 0 ; index < length ; index++ ) {\n\t\t\tprop = handled[ index ];\n\t\t\ttween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );\n\t\t\torig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// passing a non empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails\n\t\t\t// so, simple values such as \"10px\" are parsed to Float.\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"auto\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// use step hook for back compat - use cssHook if its there - use .style if its\n\t\t\t// available and use plain properties where available\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Remove in 2.0 - this supports IE8's panic based approach\n// to setting things on disconnected nodes\n\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\t\t\t\tdoAnimation.finish = function() {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t};\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || jQuery._data( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = jQuery._data( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// start the next in the queue if the last step wasn't forced\n\t\t\t// timers currently will call their complete callbacks, which will dequeue\n\t\t\t// but only if they were gotoEnd\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = jQuery._data( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.cur && hooks.cur.finish ) {\n\t\t\t\thooks.cur.finish.call( this );\n\t\t\t}\n\n\t\t\t// look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\tattrs = { height: type },\n\t\ti = 0;\n\n\t// if we include width, step value is 1 to do all cssExpand values,\n\t// if we don't include width, step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth? 1 : 0;\n\tfor( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p*Math.PI ) / 2;\n\t}\n};\n\njQuery.timers = [];\njQuery.fx = Tween.prototype.init;\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ttimers = jQuery.timers,\n\t\ti = 0;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tif ( timer() && jQuery.timers.push( timer ) ) {\n\t\tjQuery.fx.start();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\nif ( jQuery.expr && jQuery.expr.filters ) {\n\tjQuery.expr.filters.animated = function( elem ) {\n\t\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\t\treturn elem === fn.elem;\n\t\t}).length;\n\t};\n}\njQuery.fn.offset = function( options ) {\n\tif ( arguments.length ) {\n\t\treturn options === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function( i ) {\n\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t});\n\t}\n\n\tvar docElem, win,\n\t\tbox = { top: 0, left: 0 },\n\t\telem = this[ 0 ],\n\t\tdoc = elem && elem.ownerDocument;\n\n\tif ( !doc ) {\n\t\treturn;\n\t}\n\n\tdocElem = doc.documentElement;\n\n\t// Make sure it's not a disconnected DOM node\n\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\treturn box;\n\t}\n\n\t// If we don't have gBCR, just use 0,0 rather than error\n\t// BlackBerry 5, iOS 3 (original iPhone)\n\tif ( typeof elem.getBoundingClientRect !== \"undefined\" ) {\n\t\tbox = elem.getBoundingClientRect();\n\t}\n\twin = getWindow( doc );\n\treturn {\n\t\ttop: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),\n\t\tleft: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )\n\t};\n};\n\njQuery.offset = {\n\n\tsetOffset: function( elem, options, i ) {\n\t\tvar position = jQuery.css( elem, \"position\" );\n\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tvar curElem = jQuery( elem ),\n\t\t\tcurOffset = curElem.offset(),\n\t\t\tcurCSSTop = jQuery.css( elem, \"top\" ),\n\t\t\tcurCSSLeft = jQuery.css( elem, \"left\" ),\n\t\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) && jQuery.inArray(\"auto\", [curCSSTop, curCSSLeft]) > -1,\n\t\t\tprops = {}, curPosition = {}, curTop, curLeft;\n\n\t\t// need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\n\njQuery.fn.extend({\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\tparentOffset = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ];\n\n\t\t// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// we assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top  += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\treturn {\n\t\t\ttop:  offset.top  - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true)\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || document.documentElement;\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\") === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent || document.documentElement;\n\t\t});\n\t}\n});\n\n\n// Create scrollLeft and scrollTop methods\njQuery.each( {scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\"}, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn jQuery.access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? (prop in win) ? win[ prop ] :\n\t\t\t\t\twin.document.documentElement[ method ] :\n\t\t\t\t\telem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\ttop ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn jQuery.access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest\n\t\t\t\t\t// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n// Limit scope pollution from any deprecated API\n// (function() {\n\n// })();\n// Expose jQuery to the global object\nwindow.jQuery = window.$ = jQuery;\n\n// Expose jQuery as an AMD module, but only for AMD loaders that\n// understand the issues with loading multiple versions of jQuery\n// in a page that all might call define(). The loader will indicate\n// they have special allowances for multiple jQuery versions by\n// specifying define.amd.jQuery = true. Register as a named module,\n// since jQuery can be concatenated with other files that may use define,\n// but not use a proper concatenation script that understands anonymous\n// AMD modules. A named AMD is safest and most robust way to register.\n// Lowercase jquery is used because AMD module names are derived from\n// file names, and jQuery is normally delivered in a lowercase file name.\n// Do this after creating the global so that if an AMD module wants to call\n// noConflict to hide this version of jQuery, it will work.\nif ( typeof define === \"function\" && define.amd && define.amd.jQuery ) {\n\tdefine( \"jquery\", [], function () { return jQuery; } );\n}\n\n})( window );"
  },
  {
    "path": "vendors/baron/js/qwery.js",
    "content": "/*!\n  * @preserve Qwery - A Blazing Fast query selector engine\n  * https://github.com/ded/qwery\n  * copyright Dustin Diaz 2012\n  * MIT License\n  */\n\n(function (name, context, definition) {\n  if (typeof module != 'undefined' && module.exports) module.exports = definition()\n  else if (typeof define == 'function' && define.amd) define(definition)\n  else context[name] = definition()\n})('qwery', this, function () {\n  var doc = document\n    , html = doc.documentElement\n    , byClass = 'getElementsByClassName'\n    , byTag = 'getElementsByTagName'\n    , qSA = 'querySelectorAll'\n    , useNativeQSA = 'useNativeQSA'\n    , tagName = 'tagName'\n    , nodeType = 'nodeType'\n    , select // main select() method, assign later\n\n    , id = /#([\\w\\-]+)/\n    , clas = /\\.[\\w\\-]+/g\n    , idOnly = /^#([\\w\\-]+)$/\n    , classOnly = /^\\.([\\w\\-]+)$/\n    , tagOnly = /^([\\w\\-]+)$/\n    , tagAndOrClass = /^([\\w]+)?\\.([\\w\\-]+)$/\n    , splittable = /(^|,)\\s*[>~+]/\n    , normalizr = /^\\s+|\\s*([,\\s\\+\\~>]|$)\\s*/g\n    , splitters = /[\\s\\>\\+\\~]/\n    , splittersMore = /(?![\\s\\w\\-\\/\\?\\&\\=\\:\\.\\(\\)\\!,@#%<>\\{\\}\\$\\*\\^'\"]*\\]|[\\s\\w\\+\\-]*\\))/\n    , specialChars = /([.*+?\\^=!:${}()|\\[\\]\\/\\\\])/g\n    , simple = /^(\\*|[a-z0-9]+)?(?:([\\.\\#]+[\\w\\-\\.#]+)?)/\n    , attr = /\\[([\\w\\-]+)(?:([\\|\\^\\$\\*\\~]?\\=)['\"]?([ \\w\\-\\/\\?\\&\\=\\:\\.\\(\\)\\!,@#%<>\\{\\}\\$\\*\\^]+)[\"']?)?\\]/\n    , pseudo = /:([\\w\\-]+)(\\(['\"]?([^()]+)['\"]?\\))?/\n    , easy = new RegExp(idOnly.source + '|' + tagOnly.source + '|' + classOnly.source)\n    , dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g')\n    , tokenizr = new RegExp(splitters.source + splittersMore.source)\n    , chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?')\n\n  var walker = {\n      ' ': function (node) {\n        return node && node !== html && node.parentNode\n      }\n    , '>': function (node, contestant) {\n        return node && node.parentNode == contestant.parentNode && node.parentNode\n      }\n    , '~': function (node) {\n        return node && node.previousSibling\n      }\n    , '+': function (node, contestant, p1, p2) {\n        if (!node) return false\n        return (p1 = previous(node)) && (p2 = previous(contestant)) && p1 == p2 && p1\n      }\n    }\n\n  function cache() {\n    this.c = {}\n  }\n  cache.prototype = {\n    g: function (k) {\n      return this.c[k] || undefined\n    }\n  , s: function (k, v, r) {\n      v = r ? new RegExp(v) : v\n      return (this.c[k] = v)\n    }\n  }\n\n  var classCache = new cache()\n    , cleanCache = new cache()\n    , attrCache = new cache()\n    , tokenCache = new cache()\n\n  function classRegex(c) {\n    return classCache.g(c) || classCache.s(c, '(^|\\\\s+)' + c + '(\\\\s+|$)', 1)\n  }\n\n  // not quite as fast as inline loops in older browsers so don't use liberally\n  function each(a, fn) {\n    var i = 0, l = a.length\n    for (; i < l; i++) fn(a[i])\n  }\n\n  function flatten(ar) {\n    for (var r = [], i = 0, l = ar.length; i < l; ++i) arrayLike(ar[i]) ? (r = r.concat(ar[i])) : (r[r.length] = ar[i])\n    return r\n  }\n\n  function arrayify(ar) {\n    var i = 0, l = ar.length, r = []\n    for (; i < l; i++) r[i] = ar[i]\n    return r\n  }\n\n  function previous(n) {\n    while (n = n.previousSibling) if (n[nodeType] == 1) break;\n    return n\n  }\n\n  function q(query) {\n    return query.match(chunker)\n  }\n\n  // called using `this` as element and arguments from regex group results.\n  // given => div.hello[title=\"world\"]:foo('bar')\n  // div.hello[title=\"world\"]:foo('bar'), div, .hello, [title=\"world\"], title, =, world, :foo('bar'), foo, ('bar'), bar]\n  function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) {\n    var i, m, k, o, classes\n    if (this[nodeType] !== 1) return false\n    if (tag && tag !== '*' && this[tagName] && this[tagName].toLowerCase() !== tag) return false\n    if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) return false\n    if (idsAndClasses && (classes = idsAndClasses.match(clas))) {\n      for (i = classes.length; i--;) if (!classRegex(classes[i].slice(1)).test(this.className)) return false\n    }\n    if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) return false\n    if (wholeAttribute && !value) { // select is just for existance of attrib\n      o = this.attributes\n      for (k in o) {\n        if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) {\n          return this\n        }\n      }\n    }\n    if (wholeAttribute && !checkAttr(qualifier, getAttr(this, attribute) || '', value)) {\n      // select is for attrib equality\n      return false\n    }\n    return this\n  }\n\n  function clean(s) {\n    return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\\\$1'))\n  }\n\n  function checkAttr(qualify, actual, val) {\n    switch (qualify) {\n    case '=':\n      return actual == val\n    case '^=':\n      return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, '^' + clean(val), 1))\n    case '$=':\n      return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, clean(val) + '$', 1))\n    case '*=':\n      return actual.match(attrCache.g(val) || attrCache.s(val, clean(val), 1))\n    case '~=':\n      return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, '(?:^|\\\\s+)' + clean(val) + '(?:\\\\s+|$)', 1))\n    case '|=':\n      return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, '^' + clean(val) + '(-|$)', 1))\n    }\n    return 0\n  }\n\n  // given a selector, first check for simple cases then collect all base candidate matches and filter\n  function _qwery(selector, _root) {\n    var r = [], ret = [], i, l, m, token, tag, els, intr, item, root = _root\n      , tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))\n      , dividedTokens = selector.match(dividers)\n\n    if (!tokens.length) return r\n\n    token = (tokens = tokens.slice(0)).pop() // copy cached tokens, take the last one\n    if (tokens.length && (m = tokens[tokens.length - 1].match(idOnly))) root = byId(_root, m[1])\n    if (!root) return r\n\n    intr = q(token)\n    // collect base candidates to filter\n    els = root !== _root && root[nodeType] !== 9 && dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ?\n      function (r) {\n        while (root = root.nextSibling) {\n          root[nodeType] == 1 && (intr[1] ? intr[1] == root[tagName].toLowerCase() : 1) && (r[r.length] = root)\n        }\n        return r\n      }([]) :\n      root[byTag](intr[1] || '*')\n    // filter elements according to the right-most part of the selector\n    for (i = 0, l = els.length; i < l; i++) {\n      if (item = interpret.apply(els[i], intr)) r[r.length] = item\n    }\n    if (!tokens.length) return r\n\n    // filter further according to the rest of the selector (the left side)\n    each(r, function (e) { if (ancestorMatch(e, tokens, dividedTokens)) ret[ret.length] = e })\n    return ret\n  }\n\n  // compare element to a selector\n  function is(el, selector, root) {\n    if (isNode(selector)) return el == selector\n    if (arrayLike(selector)) return !!~flatten(selector).indexOf(el) // if selector is an array, is el a member?\n\n    var selectors = selector.split(','), tokens, dividedTokens\n    while (selector = selectors.pop()) {\n      tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr))\n      dividedTokens = selector.match(dividers)\n      tokens = tokens.slice(0) // copy array\n      if (interpret.apply(el, q(tokens.pop())) && (!tokens.length || ancestorMatch(el, tokens, dividedTokens, root))) {\n        return true\n      }\n    }\n    return false\n  }\n\n  // given elements matching the right-most part of a selector, filter out any that don't match the rest\n  function ancestorMatch(el, tokens, dividedTokens, root) {\n    var cand\n    // recursively work backwards through the tokens and up the dom, covering all options\n    function crawl(e, i, p) {\n      while (p = walker[dividedTokens[i]](p, e)) {\n        if (isNode(p) && (interpret.apply(p, q(tokens[i])))) {\n          if (i) {\n            if (cand = crawl(p, i - 1, p)) return cand\n          } else return p\n        }\n      }\n    }\n    return (cand = crawl(el, tokens.length - 1, el)) && (!root || isAncestor(cand, root))\n  }\n\n  function isNode(el, t) {\n    return el && typeof el === 'object' && (t = el[nodeType]) && (t == 1 || t == 9)\n  }\n\n  function uniq(ar) {\n    var a = [], i, j;\n    o:\n    for (i = 0; i < ar.length; ++i) {\n      for (j = 0; j < a.length; ++j) if (a[j] == ar[i]) continue o\n      a[a.length] = ar[i]\n    }\n    return a\n  }\n\n  function arrayLike(o) {\n    return (typeof o === 'object' && isFinite(o.length))\n  }\n\n  function normalizeRoot(root) {\n    if (!root) return doc\n    if (typeof root == 'string') return qwery(root)[0]\n    if (!root[nodeType] && arrayLike(root)) return root[0]\n    return root\n  }\n\n  function byId(root, id, el) {\n    // if doc, query on it, else query the parent doc or if a detached fragment rewrite the query and run on the fragment\n    return root[nodeType] === 9 ? root.getElementById(id) :\n      root.ownerDocument &&\n        (((el = root.ownerDocument.getElementById(id)) && isAncestor(el, root) && el) ||\n          (!isAncestor(root, root.ownerDocument) && select('[id=\"' + id + '\"]', root)[0]))\n  }\n\n  function qwery(selector, _root) {\n    var m, el, root = normalizeRoot(_root)\n\n    // easy, fast cases that we can dispatch with simple DOM calls\n    if (!root || !selector) return []\n    if (selector === window || isNode(selector)) {\n      return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : []\n    }\n    if (selector && arrayLike(selector)) return flatten(selector)\n    if (m = selector.match(easy)) {\n      if (m[1]) return (el = byId(root, m[1])) ? [el] : []\n      if (m[2]) return arrayify(root[byTag](m[2]))\n      if (hasByClass && m[3]) return arrayify(root[byClass](m[3]))\n    }\n\n    return select(selector, root)\n  }\n\n  // where the root is not document and a relationship selector is first we have to\n  // do some awkward adjustments to get it to work, even with qSA\n  function collectSelector(root, collector) {\n    return function (s) {\n      var oid, nid\n      if (splittable.test(s)) {\n        if (root[nodeType] !== 9) {\n          // make sure the el has an id, rewrite the query, set root to doc and run it\n          if (!(nid = oid = root.getAttribute('id'))) root.setAttribute('id', nid = '__qwerymeupscotty')\n          s = '[id=\"' + nid + '\"]' + s // avoid byId and allow us to match context element\n          collector(root.parentNode || root, s, true)\n          oid || root.removeAttribute('id')\n        }\n        return;\n      }\n      s.length && collector(root, s, false)\n    }\n  }\n\n  var isAncestor = 'compareDocumentPosition' in html ?\n    function (element, container) {\n      return (container.compareDocumentPosition(element) & 16) == 16\n    } : 'contains' in html ?\n    function (element, container) {\n      container = container[nodeType] === 9 || container == window ? html : container\n      return container !== element && container.contains(element)\n    } :\n    function (element, container) {\n      while (element = element.parentNode) if (element === container) return 1\n      return 0\n    }\n  , getAttr = function () {\n      // detect buggy IE src/href getAttribute() call\n      var e = doc.createElement('p')\n      return ((e.innerHTML = '<a href=\"#x\">x</a>') && e.firstChild.getAttribute('href') != '#x') ?\n        function (e, a) {\n          return a === 'class' ? e.className : (a === 'href' || a === 'src') ?\n            e.getAttribute(a, 2) : e.getAttribute(a)\n        } :\n        function (e, a) { return e.getAttribute(a) }\n    }()\n  , hasByClass = !!doc[byClass]\n    // has native qSA support\n  , hasQSA = doc.querySelector && doc[qSA]\n    // use native qSA\n  , selectQSA = function (selector, root) {\n      var result = [], ss, e\n      try {\n        if (root[nodeType] === 9 || !splittable.test(selector)) {\n          // most work is done right here, defer to qSA\n          return arrayify(root[qSA](selector))\n        }\n        // special case where we need the services of `collectSelector()`\n        each(ss = selector.split(','), collectSelector(root, function (ctx, s) {\n          e = ctx[qSA](s)\n          if (e.length == 1) result[result.length] = e.item(0)\n          else if (e.length) result = result.concat(arrayify(e))\n        }))\n        return ss.length > 1 && result.length > 1 ? uniq(result) : result\n      } catch (ex) { }\n      return selectNonNative(selector, root)\n    }\n    // no native selector support\n  , selectNonNative = function (selector, root) {\n      var result = [], items, m, i, l, r, ss\n      selector = selector.replace(normalizr, '$1')\n      if (m = selector.match(tagAndOrClass)) {\n        r = classRegex(m[2])\n        items = root[byTag](m[1] || '*')\n        for (i = 0, l = items.length; i < l; i++) {\n          if (r.test(items[i].className)) result[result.length] = items[i]\n        }\n        return result\n      }\n      // more complex selector, get `_qwery()` to do the work for us\n      each(ss = selector.split(','), collectSelector(root, function (ctx, s, rewrite) {\n        r = _qwery(s, ctx)\n        for (i = 0, l = r.length; i < l; i++) {\n          if (ctx[nodeType] === 9 || rewrite || isAncestor(r[i], root)) result[result.length] = r[i]\n        }\n      }))\n      return ss.length > 1 && result.length > 1 ? uniq(result) : result\n    }\n  , configure = function (options) {\n      // configNativeQSA: use fully-internal selector or native qSA where present\n      if (typeof options[useNativeQSA] !== 'undefined')\n        select = !options[useNativeQSA] ? selectNonNative : hasQSA ? selectQSA : selectNonNative\n    }\n\n  configure({ useNativeQSA: true })\n\n  qwery.configure = configure\n  qwery.uniq = uniq\n  qwery.is = is\n  qwery.pseudos = {}\n\n  return qwery\n});"
  },
  {
    "path": "vendors/baron/package.json",
    "content": "{\n    \"name\": \"baron\",\n    \"description\": \"A small, fast and crossbrowser custom scrollbar with native system scroll mechanic.\",\n    \"version\": \"0.6.2\",\n    \"homepage\": \"https://github.com/Diokuz/baron\",\n    \"authors\": [\n        \"Dmitry Kuznecov <@Diokuz>\"\n    ],\n    \"repository\": {\n        \"type\": \"git\",\n        \"url\": \"https://github.com/Diokuz/baron.git\"\n    },\n    \"keywords\": [\n        \"scrollbar\",\n        \"custom\",\n        \"crossbrowser\"\n    ],\n    \"main\": \"./baron.js\",\n    \"devDependencies\": {\n        \"grunt\": \"~0.4.1\",\n        \"grunt-contrib-jshint\": \"~0.6.0\",\n        \"grunt-contrib-concat\": \"~0.1.3\",\n        \"grunt-contrib-uglify\": \"~0.2.0\",\n        \"mocha\": \"~1.9.0\",\n        \"mocha-phantomjs\": \"~3.0.0\",\n        \"grunt-mocha-phantomjs\": \"~0.3.0\",\n        \"chai\": \"~1.7.0\"\n    }\n}"
  },
  {
    "path": "vendors/baron/readme.md",
    "content": "Baron — a small, fast and crossbrowser custom scrollbar with native system scroll mechanic.\n\n## Demo\n\nhttp://diokuz.github.io/baron/\n\n## Features\n\n- Doesn't replace native system scroll mechanic.\n- Customizable scrollbar design with full CSS support.\n- No strong dependencies on jQuery.\n- Plugin system (fixable headers, sticky footer, autotests and more)\n\nBaron just hides the system scrollbar, without removing it. This guarantees scrolling will work on any system where the CSS property 'overflow: scroll' is applied.\n\n## Simple usage\n\nIf you want only to hide system scrollbar:\n\n* Include either the development or minified version of baron.js:\n\n```js\n<script src=\"baron.js\"></script>\n```\n\n* Make some HTML:\n\n```html\n<div class=\"scroller\">\n    Your scrollable content here\n</div>\n```\n\n* And some CSS:\n\n```css\n.scroller {\n    overflow-y: scroll;\n    /* -webkit-overflow-scrolling: touch; *//* uncomment to accelerate scrolling on iOS */\n}\n.scroller::-webkit-scrollbar { /* Prevents webkit cross-direction scrolling bug */\n    width: 0;\n}\n```\n\nNote: you can choose any class names, and style them as you want.\n\n* Initialize baron:\n\n```js\n$('.scroller').baron();\n```\n\n## Advanced usage\n\n```html\n<div class=\"scroller\">\n    Your scrollable content here\n    <div class=\"scroller__track\"><!-- Track is optional -->\n        <div class=\"scroller__bar\"></div>\n    </div>\n</div>\n```\n\n```css\n.scroller {\n    overflow-y: scroll;\n    /* -webkit-overflow-scrolling: touch; *//* uncomment to accelerate scrolling on iOS */\n}\n.scroller::-webkit-scrollbar { /* Preventing webkit cross-direction scrolling bug */\n    width: 0;\n}\n.scroller__track {\n    display: none; /* Invisible by default */\n    position: absolute;\n    right: 4px;\n    top: 10px;\n    bottom: 4px;\n    width: 10px;\n    background: rgba(0, 0, 0, .1);\n}\n.baron .scroller__track {\n    display: block; /* Visible when scrolling is possible */\n}\n.scroller__bar { /* The bar. You should define width, right position and background */\n    position: absolute;    \n    z-index: 1;\n    right: 0;\n    width: 10px;\n    background: #999;\n}\n```\n\nYou can specify some parameters on baron initialization:\n\n```js\nvar scroll = $('.scroller').baron(params);\n\n// or\nvar scroll = baron(params);\n```\n\nand store baron scrollbar object to `scroll` variable.\n\nwhere:\n\n```js\nparams = {\n    // Selector for scroller element.\n    // Default: this (in jQuery mode).\n    scroller: '.scroller',\n\n    // Root html element for baron. Use this param when your html-scrollbar content is outside scroller\n    // Default: scroller\n    root: $('.my_scroller'),\n\n    // Selector for bar element\n    // Default: 'undefined'\n    bar: '.scroller__bar',\n\n    // Track\n    // Default: parent node of bar\n    track: '.scroller__track',\n\n    // CSS classname for scroller when its needed (when content height above scroller heights)\n    // Default: ''\n    barOnCls: 'baron',\n    // Note: by default scroller__bar should be invisible\n\n    // Scroll direction\n    // Default: 'v' (vertical), 'h' for second baron invocation\n    direction: 'h',\n\n    // Freezing size of scroller parent, if true. Actual for horizontal scrolling.\n    // Default: false\n    freeze: true,\n\n    // Minimum time delay between two scroll or resize events fires in seconds\n    // Default: 0\n    pause: .2,\n\n    // Local copy of jQuery-like utility\n    // Default: window.jQuery\n    $: function(selector, context) {\n        return bonzo(qwery(selector, context));\n    },\n\n    // Event manager\n    // Default: function(elem, event, func, mode) { params.$(elem)[mode || 'on'](event, func); };\n    event: function(elem, event, func, mode) { // Events manager\n        if (mode == 'trigger') {\n            mode = 'fire';\n        }\n\n        bean[mode || 'on'](elem, event, func);\n    }\n}\n```\n\nAll parameters are optional (except scroller or root, if you are not using baron as jQuery plugin).\n\n`scroll` methods:\n\n```js\nscroll.update(); // Update scroller\nscroll.dispose(); // Remove baron instance and related event handlers\n```\n\nNote: baron returns the baron object, even in jQuery mode. That can break jQuery chaining. For example, you can't do this:\n\n```js\n$('.scroller').baron().css().animate();\n```\n\nbut you can:\n\n```js\n$('.scroller').css().animate().baron();\n```\n\nand even more:\n\n```js\nvar scroll = $('.scroller').css().animate().baron().fix();\n\nscroll.baron({direction: 'h'}).test().anotherBaronPlugin();\n```\n\nEvery baron plugin sould return baron object (this);\n\n## Horizontal and bidirectional scroll\n\nTo switch default vertical direction to horizontal direction just set 'direction' param to 'h' value:\n\n```js\nbaron({\n    ...\n    direction: 'h'\n});\n```\n\nIf you want to scroll in both directions (vertical and horizontal) you must initialize baron two times: one per direction. In than case you can do chaining:\n\n```js\nbaron(vParams).baron(hParams);\n```\n\nNote: think about horizontal baron as about second independent baron instance, or as about plugin for 'baron', which simply calls 'baron' with redefined default params - both statements are true, actually. Unfortunately, in case above you only can manage last baron instance in chain (to update or dispose it). To manage both you have to initialize them independently:\n\n```js\nvScroll = baron(vParams);\nhScroll = baron(hParams);\n...\nvScroll.dispose();\nhScroll.dispose();\n```\n\n##Updating baron\n\nWhen container size changed (for example: you load additional data to the container using ajax), you should call update() method:\n\n```js\nscroll.update();\n```\n\nor fire custom event 'sizeChange' to wrapper:\n\n```js\n$('.scroller').trigger('sizeChange');\n```\n\n##Disposing baron\n\nIf you removed html-nodes, which used baron, from DOM, dont forget dispose related baron instance manually. Use 'dispose' method for that.\n\n##noConflict mode\n\nIf you need window.baron for another purposes you can restore original value:\n```js\n// window.baron points to some other library\n...\n// you include baron, it replaces the window.baron variable to baron namespace\n\nvar graf = baron.noConflict();\n// now window.baron points to that other library again, and you can use window.graf() etc.\n```\n\n## Custom build (Grunt)\n\nIf you want exclude plugins functionality, type\n```js\ngrunt core\n```\nin your console, and you will get dist/baron.js and dist/baron.min.js only with core functionality.\n\nType\n```js\ngrunt full\n```\nto build full version of baron (including all available plugins).\n\nOutput files you can find in /dist/ folder.\n\n## Browsers support\n\nFull support: Chrome 1+, Firefox 3.6+, Safari 5+, Opera 9+ on Windows, OS X and iOS. Also, the best ever browser downloader - Internet Explorer - supported since version 7.\n\nPartial (core) support: IE6.\n\nNot supported: Opera mini, old versions of Android browser, and other browsers which does not implemented the `overflow: scroll` CSS property.\n\n## fix plugin\n\nTo use fixable headers you should initialize fix plugin after baron:\n\n```html\n<div class=\"scroller\">\n    <div class=\"header__title-wrapper\">\n        <div class=\"header__title\">First element</div>\n    </div>\n    ...content...\n    <div class=\"header__title-wrapper\">\n        <div class=\"header__title\">Second element</div>\n    </div>\n    ...content...\n</div>\n```\n\n```js\nbaron(baronParams).fix(params);\n```\n\nwhere:\n```js\nparams = {\n    // CSS selector for fixable elements\n    // Must have parentNode (no margin and padding allowed!) with same height (see demo for details). Also see 'limiter' parameter.\n    elements: '.header__title',\n\n    // CSS class for elements which now are outside of viewport\n    outside: 'header__title_state_fixed',\n\n    // CSS class for closest outsite element wrapper from top (left)\n    before: 'header__title_position_top',\n\n    // CSS class for closest outsite element wrapper from bottom (right)\n    after: 'header__title_position_bottom',\n\n    // if true - sets track top (left) position to header[0].parentNode.offsetHeight (offsetWidth)\n    // Default: false\n    limiter: true,\n\n    // Radius for element fixing in px\n    // Default: 0\n    radius: 10,\n\n    // Wether click on element should scroll to\n    clickable: false,\n\n    // User defined callback on click (data == {x1: current scrollTop, x2: new scrollTop})\n    scroll: function(data) {}\n}\n```\n\n## Controls plugin\n\n```js\nbaron().controls(params);\n\nparams = {\n    // Element to be used as interactive track. Note: it could be different from 'track' param of baron.\n    track: '.visual-track',\n\n    // Element to be used as 'down' / 'right' button\n    forward: '.forward-btn',\n\n    // Element to be used as 'up' / 'left' button\n    backward: '.backward-btn',\n\n    // Multiplyer for page-down action. Use 1 to scroll preciesly one screen per track click.\n    // Default: .9\n    screen: .5\n\n    // Scroll distance per control button click in px\n    // Default: 30\n    delta: 40\n}\n```\n\n## test plugin\n\nIf you have some troubles with baron, use test plugin:\n\n```js\nbaron(...).test(params);\n```\n\nAnd read results in browser console.\n\nThere is no params for test() right now.\n\n## License\n\nMIT.\n"
  },
  {
    "path": "vendors/baron/src/controls.js",
    "content": "/* Controls plugin for baron 0.6+ */\n(function(window, undefined) {\n    var controls = function(params) {\n        var forward, backward, track, screen,\n            self = this; // AAAAAA!!!!!11\n\n        screen = params.screen || 0.9;\n\n        if (params.forward) {\n            forward = this.$(params.forward, this.clipper);\n\n            this.event(forward, 'click', function() {\n                var y = self.pos() - params.delta || 30;\n                \n                self.pos(y);\n            });\n        }\n\n        if (params.backward) {\n            backward = this.$(params.backward, this.clipper);\n\n            this.event(backward, 'click', function() {\n                var y = self.pos() + params.delta || 30;\n\n                self.pos(y);\n            });\n        }\n\n        if (params.track) {\n            if (params.track === true) {\n                track = this.track;\n            } else {\n                track = this.$(params.track, this.clipper)[0];\n            }\n\n            if (track) {\n                this.event(track, 'mousedown', function(e) {\n                    var x = e['offset' + self.origin.x],\n                        xBar = self.bar[self.origin.offsetPos],\n                        sign = 0;\n\n                    if (x < xBar) {\n                        sign = -1;\n                    } else if (x > xBar + self.bar[self.origin.offset]) {\n                        sign = 1;\n                    }\n\n                    var y = self.pos() + sign * screen * self.scroller[self.origin.client];\n                    self.pos(y);\n                });\n            }\n        }\n\n    };\n\n    baron.fn.controls = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            controls.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);"
  },
  {
    "path": "vendors/baron/src/core.js",
    "content": "(function(window, undefined) {\n    'use strict';\n\n    if (!window) return; // Server side\n\nvar\n    _baron = window.baron, // Stored baron value for noConflict usage\n    $ = window.jQuery, // Trying to use jQuery\n    origin = {\n        v: { // Vertical\n            x: 'Y', pos: 'top', crossPos: 'left', size: 'height', crossSize: 'width',\n            client: 'clientHeight', crossClient: 'clientWidth', offset: 'offsetHeight', crossOffset: 'offsetWidth', offsetPos: 'offsetTop',\n            scroll: 'scrollTop', scrollSize: 'scrollHeight'\n        },\n        h: { // Horizontal\n            x: 'X', pos: 'left', crossPos: 'top', size: 'width', crossSize: 'height',\n            client: 'clientWidth', crossClient: 'clientHeight', offset: 'offsetWidth', crossOffset: 'offsetHeight', offsetPos: 'offsetLeft',\n            scroll: 'scrollLeft', scrollSize: 'scrollWidth'\n        }\n    },\n\n    each = function(obj, iterator) {\n        var i = 0;\n\n        if (obj.length === undefined || obj === window) obj = [obj];\n\n        while (obj[i]) {\n            iterator.call(this, obj[i], i);\n            i++;\n        }\n    },\n\n    baron = function(params) { // this - window or jQuery instance\n        var jQueryMode = (this && this[0] && this[0].nodeType),\n            roots,\n            $;\n\n        params = params || {};\n        $ = params.$ || window.jQuery;\n\n        if (jQueryMode) {\n            params.root = roots = this;\n        } else {\n            roots = $(params.root || params.scroller);\n        }\n\n        return new baron.fn.constructor(roots, params, $);\n    };\n\n    baron.fn = {\n        constructor: function(roots, input, $) {\n            var params = validate(input);\n\n            params.$ = $;\n            each.call(this, roots, function(root, i) {\n                var localParams = clone(params);\n\n                if (params.root && params.scroller) {\n                    localParams.scroller = params.$(params.scroller, root);\n                    if (!localParams.scroller.length) {\n                        localParams.scroller = root;\n                    }\n                } else {\n                    localParams.scroller = root;\n                }\n\n                localParams.root = root;\n                this[i] = init(localParams);\n                this.length = i + 1;\n            });\n\n            this.params = params;\n        },\n\n        dispose: function() {\n            var params = this.params;\n\n            each(this, function(item) {\n                item.dispose(params);\n            });\n            this.params = null;\n        },\n\n        update: function() {\n            var i = 0;\n\n            while (this[i]) {\n                this[i].update.apply(this[i], arguments);\n                i++;\n            }\n        },\n\n        baron: function(params) {\n            params.root = [];\n            params.scroller = this.params.scroller;\n\n            each.call(this, this, function(elem) {\n                params.root.push(elem.root);\n            });\n            params.direction = (this.params.direction == 'v') ? 'h' : 'v';\n            params._chain = true;\n\n            return baron(params);\n        }\n    };\n\n    function manageEvents(item, eventManager, mode) {\n        item._eventHandlers = item._eventHandlers || [ // Creating new functions for one baron item only one time\n            {\n                // onScroll: \n                element: item.scroller,\n\n                handler: function(e) {\n                    item.scroll(e);\n                },\n\n                type: 'scroll'\n            }, {\n                // onMouseDown: \n                element: item.bar,\n\n                handler: function(e) {\n                    e.preventDefault(); // Text selection disabling in Opera... and all other browsers?\n                    item.selection(); // Disable text selection in ie8\n                    item.drag.now = 1; // Save private byte\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseUp: \n                element: document,\n\n                handler: function() {\n                    item.selection(1); // Enable text selection\n                    item.drag.now = 0;\n                },\n\n                type: 'mouseup blur touchend'\n            }, {\n                // onCoordinateReset: \n                element: document,\n\n                handler: function(e) {\n                    if (e.button != 2) { // Not RM\n                        item._pos0(e);\n                    }\n                },\n\n                type: 'touchstart mousedown'\n            }, {\n                // onMouseMove: \n                element: document,\n\n                handler: function(e) {\n                    if (item.drag.now) {\n                        item.drag(e);\n                    }\n                },\n\n                type: 'mousemove touchmove'\n            }, {\n                // onResize: \n                element: window,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'resize'\n            }, {\n                // sizeChange: \n                element: item.root,\n\n                handler: function() {\n                    item.update();\n                },\n\n                type: 'sizeChange'\n            }\n        ];\n\n        each(item._eventHandlers, function(event) {\n            if (event.element) {\n                eventManager(event.element, event.type, event.handler, mode);\n            }\n        });\n\n        // if (item.scroller) {\n        //     event(item.scroller, 'scroll', item._eventHandlers.onScroll, mode);\n        // }\n        // if (item.bar) {\n        //     event(item.bar, 'touchstart mousedown', item._eventHandlers.onMouseDown, mode);\n        // }\n        // event(document, 'mouseup blur touchend', item._eventHandlers.onMouseUp, mode);\n        // event(document, 'touchstart mousedown', item._eventHandlers.onCoordinateReset, mode);\n        // event(document, 'mousemove touchmove', item._eventHandlers.onMouseMove, mode);\n        // event(window, 'resize', item._eventHandlers.onResize, mode);\n        // if (item.root) {\n        //     event(item.root, 'sizeChange', item._eventHandlers.onResize, mode); // Custon event for alternate baron update mechanism\n        // }\n    }\n\n    function manageAttr(node, direction, mode) {\n        var attrName = 'data-baron-' + direction;\n\n        if (mode == 'on') {\n            node.setAttribute(attrName, 'inited');\n        } else if (mode == 'off') {\n            node.removeAttribute(attrName);\n        } else {\n            return node.getAttribute(attrName);\n        }\n    }\n\n    function init(params) {\n        if (manageAttr(params.root, params.direction)) return;\n\n        var out = new item.prototype.constructor(params); // __proto__ of returning object is baron.prototype\n\n        manageEvents(out, params.event, 'on');\n\n        manageAttr(out.root, params.direction, 'on');\n\n        out.update();\n\n        return out;\n    }\n\n    function clone(input) {\n        var output = {};\n\n        input = input || {};\n\n        for (var key in input) {\n            if (input.hasOwnProperty(key)) {\n                output[key] = input[key];\n            }\n        }\n\n        return output;\n    }\n\n    function validate(input) {\n        var output = clone(input);\n\n        output.direction = output.direction || 'v';\n\n        var event = input.event || function(elem, event, func, mode) {\n            output.$(elem)[mode || 'on'](event, func);\n        };\n\n        output.event = function(elems, e, func, mode) {\n            each(elems, function(elem) {\n                event(elem, e, func, mode);\n            });\n        };\n\n        return output;\n    }\n\n    function fire(eventName) {\n        /* jshint validthis:true */\n        if (this.events && this.events[eventName]) {\n            for (var i = 0 ; i < this.events[eventName].length ; i++) {\n                var args = Array.prototype.slice.call( arguments, 1 );\n\n                this.events[eventName][i].apply(this, args);\n            }\n        }\n    }\n\n    var item = {};\n\n    item.prototype = {\n        constructor: function(params) {\n            var $,\n                barPos,\n                scrollerPos0,\n                track,\n                resizePauseTimer,\n                scrollPauseTimer,\n                pause,\n                scrollLastFire,\n                resizeLastFire;\n\n            resizeLastFire = scrollLastFire = new Date().getTime();\n\n            $ = this.$ = params.$;\n            this.event = params.event;\n            this.events = {};\n\n            function getNode(sel, context) {\n                return $(sel, context)[0]; // Can be undefined\n            }\n\n            // DOM elements\n            this.root = params.root; // Always html node, not just selector\n            this.scroller = getNode(params.scroller); // (params.scroller) ? getNode(params.scroller, this.root) : this.root;\n            this.bar = getNode(params.bar, this.root);\n            track = this.track = getNode(params.track, this.root);\n            if (!this.track && this.bar) {\n                track = this.bar.parentNode;\n            }\n            this.clipper = this.scroller.parentNode;\n\n            // Parameters\n            this.direction = params.direction;\n            this.origin = origin[this.direction];\n            this.barOnCls = params.barOnCls;\n            this.barTopLimit = 0;\n            pause = params.pause * 1000 || 0;\n\n            // Updating height or width of bar\n            function setBarSize(size) {\n                /* jshint validthis:true */\n                var barMinSize = this.barMinSize || 20;\n\n                if (size > 0 && size < barMinSize) {\n                    size = barMinSize;\n                }\n\n                if (this.bar) {\n                    $(this.bar).css(this.origin.size, parseInt(size, 10) + 'px');\n                }\n            }\n\n            // Updating top or left bar position\n            function posBar(pos) {\n                /* jshint validthis:true */\n                if (this.bar) {\n                    $(this.bar).css(this.origin.pos, +pos + 'px');\n                }\n            }\n\n            // Free path for bar\n            function k() {\n                /* jshint validthis:true */\n                return track[this.origin.client] - this.barTopLimit - this.bar[this.origin.offset];\n            }\n\n            // Relative content top position to bar top position\n            function relToPos(r) {\n                /* jshint validthis:true */\n                return r * k.call(this) + this.barTopLimit;\n            }\n\n            // Bar position to relative content position\n            function posToRel(t) {\n                /* jshint validthis:true */\n                return (t - this.barTopLimit) / k.call(this);\n            }\n\n            // Cursor position in main direction in px // Now with iOs support\n            this.cursor = function(e) {\n                return e['client' + this.origin.x] || (((e.originalEvent || e).touches || {})[0] || {})['page' + this.origin.x];\n            };\n\n            // Text selection pos preventing\n            function dontPosSelect() {\n                return false;\n            }\n\n            this.pos = function(x) { // Absolute scroller position in px\n                var ie = 'page' + this.origin.x + 'Offset',\n                    key = (this.scroller[ie]) ? ie : this.origin.scroll;\n\n                if (x !== undefined) this.scroller[key] = x;\n\n                return this.scroller[key];\n            };\n\n            this.rpos = function(r) { // Relative scroller position (0..1)\n                var free = this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client],\n                    x;\n\n                if (r) x = this.pos(r * free);\n                else x = this.pos();\n\n                return x / (free || 1);\n            };\n\n            // Switch on the bar by adding user-defined CSS classname to scroller\n            this.barOn = function(dispose) {\n                if (this.barOnCls) {\n                    if (dispose || this.scroller[this.origin.client] >= this.scroller[this.origin.scrollSize]) {\n                        $(this.root).removeClass(this.barOnCls);\n                    } else {\n                        $(this.root).addClass(this.barOnCls);\n                    }\n                }\n            };\n\n            this._pos0 = function(e) {\n                scrollerPos0 = this.cursor(e) - barPos;\n            };\n\n            this.drag = function(e) {\n                this.scroller[this.origin.scroll] = posToRel.call(this, this.cursor(e) - scrollerPos0) * (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]);\n            };\n\n            // Text selection preventing on drag\n            this.selection = function(enable) {\n                this.event(document, 'selectpos selectstart', dontPosSelect, enable ? 'off' : 'on');\n            };\n\n            // onResize & DOM modified handler\n            this.resize = function() {\n                var self = this,\n                    delay = 0;\n\n                if (new Date().getTime() - resizeLastFire < pause) {\n                    clearTimeout(resizePauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    var delta = self.scroller[self.origin.crossOffset] - self.scroller[self.origin.crossClient];\n\n                    if (params.freeze && !self.clipper.style[self.origin.crossSize]) { // Sould fire only once\n                        $(self.clipper).css(self.origin.crossSize, self.clipper[self.origin.crossClient] - delta + 'px');\n                    }\n                    $(self.scroller).css(self.origin.crossSize, self.clipper[self.origin.crossClient] + delta + 'px');\n                    \n                    Array.prototype.unshift.call(arguments, 'resize');\n                    fire.apply(self, arguments);\n\n                    resizeLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    resizePauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n            };\n\n            // onScroll handler\n            this.scroll = function() {\n                var oldBarSize, newBarSize,\n                    delay = 0,\n                    self = this;\n\n                if (new Date().getTime() - scrollLastFire < pause) {\n                    clearTimeout(scrollPauseTimer);\n                    delay = pause;\n                }\n\n                function upd() {\n                    if (self.bar) {\n                        newBarSize = (track[self.origin.client] - self.barTopLimit) * self.scroller[self.origin.client] / self.scroller[self.origin.scrollSize];\n\n                        // Positioning bar\n                        if (oldBarSize != newBarSize) {\n                            setBarSize.call(self, newBarSize);\n                            oldBarSize = newBarSize;\n                        }\n                        \n                        barPos = relToPos.call(self, self.rpos());\n\n                        posBar.call(self, barPos);\n                    }\n\n                    Array.prototype.unshift.call( arguments, 'scroll' );\n                    fire.apply(self, arguments);\n\n                    scrollLastFire = new Date().getTime();\n                }\n\n                if (delay) {\n                    scrollPauseTimer = setTimeout(upd, delay);\n                } else {\n                    upd();\n                }\n                \n            };\n\n            return this;\n        },\n\n        update: function(params) {\n            fire.call(this, 'upd', params); // Обновляем параметры всех плагинов\n\n            this.resize(1);\n            this.barOn();\n            this.scroll();\n\n            return this;\n        },\n\n        dispose: function(params) {\n            manageEvents(this, this.event, 'off');\n            manageAttr(this.root, params.direction, 'off');\n            $(this.scroller).css(this.origin.crossSize, '');\n            this.barOn(true);\n            fire.call(this, 'dispose');\n        },\n\n        on: function(eventName, func, arg) {\n            var names = eventName.split(' ');\n\n            for (var i = 0 ; i < names.length ; i++) {\n                if (names[i] == 'init') {\n                    func.call(this, arg);\n                } else {\n                    this.events[names[i]] = this.events[names[i]] || [];\n\n                    this.events[names[i]].push(function(userArg) {\n                        func.call(this, userArg || arg);\n                    });\n                }\n            }\n        }\n    };\n\n    baron.fn.constructor.prototype = baron.fn;\n    item.prototype.constructor.prototype = item.prototype;\n\n    // Use when you need \"baron\" global var for another purposes\n    baron.noConflict = function() {\n        window.baron = _baron; // Restoring original value of \"baron\" global var\n\n        return baron;\n    };\n\n    baron.version = '0.6.6';\n\n    if ($ && $.fn) { // Adding baron to jQuery as plugin\n        $.fn.baron = baron;\n    }\n    window.baron = baron; // Use noConflict method if you need window.baron var for another purposes\n    if (window['module'] && module.exports) {\n        module.exports = baron.noConflict();\n    }\n})(window);"
  },
  {
    "path": "vendors/baron/src/fix.js",
    "content": "/* Fixable elements plugin for baron 0.6+ */\n(function(window, undefined) {\n    var fix = function(userParams) {\n        var elements, viewPortSize,\n            params = { // Default params\n                outside: '',\n                before: '',\n                after: '',\n                past: '',\n                future: '',\n                radius: 0,\n                minView: 0\n            },\n            topFixHeights = [], // inline style for element\n            topRealHeights = [], // real offset position when not fixed\n            headerTops = [],\n            scroller = this.scroller,\n            eventManager = this.event,\n            $ = this.$,\n            self = this;\n\n        function fixElement(i, pos) {\n            if (viewPortSize < (params.minView || 0)) { // No headers fixing when no enought space for viewport\n                pos = undefined;\n            }\n\n            if (pos !== undefined) {\n                pos += 'px';\n                this.$(elements[i]).css(this.origin.pos, pos).addClass(params.outside);\n            } else {\n                this.$(elements[i]).css(this.origin.pos, '').removeClass(params.outside);\n            }\n        }\n\n        function bubbleWheel(e) {\n            try {\n                i = document.createEvent('WheelEvent'); // i - for extra byte\n                // evt.initWebKitWheelEvent(deltaX, deltaY, window, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey);\n                i.initWebKitWheelEvent(e.originalEvent.wheelDeltaX, e.originalEvent.wheelDeltaY);\n                scroller.dispatchEvent(i);\n                e.preventDefault();\n            } catch (e) {}\n        }\n\n        function init(_params) {\n            var pos;\n\n            for (var key in _params) {\n                params[key] = _params[key];\n            }\n\n            elements = this.$(params.elements, this.scroller);\n\n            if (elements) {\n                viewPortSize = this.scroller[this.origin.client];\n                for (var i = 0 ; i < elements.length ; i++) {\n                    // Variable header heights\n                    pos = {};\n                    pos[this.origin.size] = elements[i][this.origin.offset];\n                    if (elements[i].parentNode !== this.scroller) {\n                        this.$(elements[i].parentNode).css(pos);\n                    }\n                    pos = {};\n                    pos[this.origin.crossSize] = elements[i].parentNode[this.origin.crossClient];\n                    this.$(elements[i]).css(pos);\n\n                    // Between fixed headers\n                    viewPortSize -= elements[i][this.origin.offset];\n\n                    headerTops[i] = elements[i].parentNode[this.origin.offsetPos]; // No paddings for parentNode\n\n                    // Summary elements height above current\n                    topFixHeights[i] = (topFixHeights[i - 1] || 0); // Not zero because of negative margins\n                    topRealHeights[i] = (topRealHeights[i - 1] || Math.min(headerTops[i], 0));\n\n                    if (elements[i - 1]) {\n                        topFixHeights[i] += elements[i - 1][this.origin.offset];\n                        topRealHeights[i] += elements[i - 1][this.origin.offset];\n                    }\n\n                    if ( !(i == 0 && headerTops[i] == 0)/* && force */) {\n                        this.event(elements[i], 'mousewheel', bubbleWheel, 'off');\n                        this.event(elements[i], 'mousewheel', bubbleWheel);\n                    }\n                }\n\n                if (params.limiter && elements[0]) { // Bottom edge of first header as top limit for track\n                    if (this.track && this.track != this.scroller) {\n                        pos = {};\n                        pos[this.origin.pos] = elements[0].parentNode[this.origin.offset];\n                        this.$(this.track).css(pos);\n                    } else {\n                        this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    }\n                    // this.barTopLimit = elements[0].parentNode[this.origin.offset];\n                    this.scroll();\n                }\n\n                if (params.limiter === false) { // undefined (in second fix instance) should have no influence on bar limit\n                    this.barTopLimit = 0;\n                }\n            }\n\n            var event = {\n                element: elements,\n                \n                handler: function() {\n                    var parent = $(this)[0].parentNode,\n                        top = parent.offsetTop,\n                        num;\n\n                    // finding num -> elements[num] === this\n                    for (var i = 0 ; i < elements.length ; i++ ) {\n                        if (elements[i] === this) num = i;\n                    }\n\n                    var pos = top - topFixHeights[num];\n\n                    if (params.scroll) { // User defined callback\n                        params.scroll({\n                            x1: self.scroller.scrollTop,\n                            x2: pos\n                        });\n                    } else {\n                        self.scroller.scrollTop = pos;\n                    }\n                },\n\n                type: 'click'\n            };\n\n            if (params.clickable) {\n                this._eventHandlers.push(event); // For auto-dispose\n                eventManager(event.element, event.type, event.handler, 'off');\n                eventManager(event.element, event.type, event.handler, 'on');\n            }\n        }\n\n        this.on('init', init, userParams);\n\n        this.on('init scroll', function() {\n            var fixState, hTop,\n                fixFlag = []; // 1 - past, 2 - future, 3 - current (not fixed)\n\n            if (elements) {\n                var change;\n\n                // fixFlag update\n                for (var i = 0 ; i < elements.length ; i++) {\n                    fixState = 0;\n                    if (headerTops[i] - this.pos() < topRealHeights[i] + params.radius) {\n                        // Header trying to go up\n                        fixState = 1;\n                        hTop = topFixHeights[i];\n                    } else if (headerTops[i] - this.pos() > topRealHeights[i] + viewPortSize - params.radius) {\n                        // Header trying to go down\n                        fixState = 2;\n                        hTop = topFixHeights[i] + viewPortSize;\n                    } else {\n                        // Header in viewport\n                        fixState = 3;\n                        hTop = undefined;\n                    }\n                    if (fixState != fixFlag[i]) {\n                        fixElement.call(this, i, hTop);\n                        fixFlag[i] = fixState;\n                        change = true;\n                    }\n                }\n\n                // Adding positioning classes (on last top and first bottom header)\n                if (change) { // At leats one change in elements flag structure occured\n                    for (i = 0 ; i < elements.length ; i++) {\n                        if (fixFlag[i] == 1 && params.past) {\n                            this.$(elements[i]).addClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] == 2 && params.future) {\n                            this.$(elements[i]).addClass(params.future).removeClass(params.past);\n                        }\n\n                        if (fixFlag[i] == 3 && (params.future || params.past)) {\n                            this.$(elements[i]).removeClass(params.past).removeClass(params.future);\n                        }\n\n                        if (fixFlag[i] != fixFlag[i + 1] && fixFlag[i] == 1 && params.before) {\n                            this.$(elements[i]).addClass(params.before).removeClass(params.after); // Last top fixed header\n                        } else if (fixFlag[i] != fixFlag[i - 1] && fixFlag[i] == 2 && params.after) {\n                            this.$(elements[i]).addClass(params.after).removeClass(params.before); // First bottom fixed header\n                        } else {\n                            this.$(elements[i]).removeClass(params.before).removeClass(params.after);\n                        }\n                    }\n                }\n            }\n        });\n\n        this.on('resize upd', function(updParams) {\n            init.call(this, updParams && updParams.fix);\n        });\n    };\n\n    baron.fn.fix = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            fix.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);"
  },
  {
    "path": "vendors/baron/src/pull.js",
    "content": "/* Pull to load plugin for baron 0.6+ */\n(function(window, undefined) {\n    var pull = function(params) {\n        var block = this.$(params.block),\n            size = params.size || this.origin.size,\n            limit = params.limit || 80,\n            onExpand = params.onExpand,\n            elements = params.elements || [],\n            inProgress = params.inProgress || '',\n            self = this,\n            _insistence = 0,\n            _zeroXCount = 0,\n            _interval,\n            _timer,\n            _x = 0,\n            _onExpandCalled,\n            _waiting = params.waiting || 500,\n            _on;\n\n        function getSize() {\n            return self.scroller[self.origin.scroll] + self.scroller[self.origin.offset];\n        }\n\n        // Scroller content height\n        function getContentSize() {\n            return self.scroller[self.origin.scrollSize];\n        }\n\n        // Scroller height\n        function getScrollerSize() {\n            return self.scroller[self.origin.client];\n        }\n\n        function step(x, force) {\n            var k = x * 0.0005;\n            \n            return Math.floor(force - k * (x + 550));\n        }\n\n        function toggle(on) {\n            _on = on;\n\n            if (on) {\n                update(); // First time with no delay\n                _interval = setInterval(update, 200);\n            } else {\n                clearInterval(_interval);\n            }\n        }\n\n        function update() {\n            var pos = {},\n                height = getSize(),\n                scrollHeight = getContentSize(),\n                dx,\n                op4,\n                scrollInProgress = _insistence == 1;\n\n            op4 = 0; // Возвращающая сила\n            if (_insistence > 0) {\n                op4 = 40;\n            }\n            //if (_insistence > -1) {\n                dx = step(_x, op4);\n                if (height >= scrollHeight - _x && _insistence > -1) {\n                    if (scrollInProgress) {\n                        _x += dx;\n                    }\n                } else {\n                    _x = 0;\n                }\n\n                if (_x < 0) _x = 0;\n\n                pos[size] = _x + 'px';\n                if (getScrollerSize() <= getContentSize()) {\n                    self.$(block).css(pos);\n                    for (var i = 0 ; i < elements.length ; i++) {\n                        self.$(elements[i].self).css(elements[i].property, Math.min(_x / limit * 100, 100) + '%');\n                    }\n                }\n\n                if (inProgress && _x) {\n                    self.$(self.root).addClass(inProgress);\n                }\n\n                if (_x == 0) {\n                    if (params.onCollapse) {\n                        params.onCollapse();\n                    }\n                }\n\n                _insistence = 0;\n                _timer = setTimeout(function() {\n                    _insistence = -1;\n                }, _waiting);\n            //}\n\n            if (onExpand && _x > limit && !_onExpandCalled) {\n                onExpand();\n                _onExpandCalled = true;\n            }\n\n            if (_x == 0) {\n                _zeroXCount++;\n            } else {\n                _zeroXCount = 0;\n                \n            }\n            if (_zeroXCount > 1) {\n                toggle(false);\n                _onExpandCalled = false;\n                if (inProgress) {\n                    self.$(self.root).removeClass(inProgress);\n                }\n            }\n        }\n\n        this.on('init', function() {\n            toggle(true);\n        });\n\n        this.on('dispose', function() {\n            toggle(false);\n        });\n\n        this.event(this.scroller, 'mousewheel DOMMouseScroll', function(e) {\n            var down = e.wheelDelta < 0 || (e.originalEvent && e.originalEvent.wheelDelta < 0) || e.detail > 0;\n\n            if (down) {\n                _insistence = 1;\n                clearTimeout(_timer);\n                if (!_on && getSize() >= getContentSize()) {\n                    toggle(true);\n                }\n            }\n            //  else {\n            //     toggle(false);\n            // }\n        });\n    };\n\n    baron.fn.pull = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            pull.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);"
  },
  {
    "path": "vendors/baron/src/test.js",
    "content": "/* Autotests plugin for baron 0.6+ (for developers) */\n(function(window, undefined) {\n    var test = function(params) {\n        var errCount = 0,\n            totalCount = 0;\n\n        var log = function(type, msg, obj) {\n            var text = type + ': ' + msg;\n\n            switch (type) {\n                case 'log': css = 'color: #0b0'; break;\n                case 'warn': css = 'color: #fc9'; break;\n                case 'error': css = 'color: #f00'; break;\n            }\n            totalCount++;\n            if (type == 'log') {\n                errCount++;\n            }\n\n            console.log('%c ' + totalCount + '. ' + text, css);\n            if (obj !== undefined) {\n                console.log(obj);\n            }\n        };\n\n        if (this.scroller && this.scroller.nodeType === 1) {\n            log('log', 'Scroller defined and has proper nodeType value', this.scroller);\n        } else {\n            log('error', 'Scroller not defined or has wrong type (should be html node).', this.scroller);\n        }\n\n        if (this.$ && typeof this.$ == 'function') {\n            log('log', 'Local $ defined and it is a function');\n        } else {\n            log('error', 'Local $ has wrong value or is not defined, or custom params.dom and params.selector not defined', params.$);\n        }\n\n        if (this.scroller.getAttribute('data-baron-v')) {\n            log('log', 'Baron initialized in vertical direction', this.scroller.getAttribute('data-baron-v'));\n            if (this.scroller.clientHeight < this.scroller.scrollHeight && this.scroller.getAttribute('data-baron-v')) {\n                log('log', 'There are enought space for scrolling in vertical direction right now', this.scroller.scrollHeight - this.scroller.clientHeight + 'px');\n            } else {\n                log('log', 'There are not enought space for scrolling in vertical direction right now');\n            }\n        }\n        if (this.scroller.getAttribute('data-baron-h')) {\n            log('log', 'Baron initialized in horizontal direction', this.scroller.getAttribute('data-baron-h'));\n            if (this.scroller.clientWidth < this.scroller.scrollWidth) {\n                log('log', 'There are enought space for scrolling in horizontal direction right now', this.scroller.scrollWidth - this.scroller.clientWidth + 'px');\n            } else {\n                log('log', 'There are not enought space for scrolling in horizontal direction right now');\n            }\n        }\n\n        if (this.bar && this.bar.nodeType === 1) {\n            log('log', 'Bar defined and has proper nodeType value', this.bar);\n        } else {\n            log('warn', 'Bar not defined or has wrong type (should be html node).', this.bar);\n        }\n        \n        if (this.barOnCls) {\n            log('log', 'CSS classname barOnCls defined', this.barOnCls);\n        } else {\n            log('warn', 'barOnCls not defined - bar will be visible or not visible all the time', this.barOnCls);\n        }\n\n        // Preformance test\n        var t1 = new Date().getTime(),\n            x;\n        for (var i = 0 ; i < 1000 ; i += 10) {\n            x = i % (this.scroller[this.origin.scrollSize] - this.scroller[this.origin.client]);\n            this.pos(x);\n            this.event(this.scroller, 'scroll', undefined, 'trigger');\n        }\n        var t2 = new Date().getTime();\n        log('log', 'Preformance test: ' + (t2 - t1) / 1000 + ' milliseconds per scroll event');\n        \n        log('log', 'Result is ' + errCount + ' / ' + totalCount + '\\n');\n    };\n\n    baron.fn.test = function(params) {\n        var i = 0;\n\n        while (this[i]) {\n            test.call(this[i], params);\n            i++;\n        }\n\n        return this;\n    };\n})(window);"
  },
  {
    "path": "vendors/baron/tasks/mocha-phantomjs.js",
    "content": "/*\n * grunt-mocha-phantomjs\n * https://github.com/jdcataldo/grunt-mocha-phantomjs\n *\n * Copyright (c) 2013 Justin Cataldo\n * Licensed under the MIT license.\n */\n\n'use strict';\n\nmodule.exports = function(grunt) {\n    var util    = grunt.util,\n    // Alias for Lo-Dash\n        _       = util._,\n        path = require(\"path\"),\n        exists = grunt.file.exists;\n\n    grunt.registerMultiTask('mocha-phantomjs', 'Run client-side mocha test with phantomjs.', function() {\n        // Merge options\n        var options        = this.options({\n                reporter: 'spec',\n                // Non file urls to test\n                urls: [],\n                verbose: false\n            }),\n            args           = [],\n            binPath        = '.bin/mocha-phantomjs' + (process.platform === 'win32' ? '.cmd' : ''),\n            phantomjs_path = path.join(__dirname, '..', '/node_modules/', binPath),\n            urls           = options.urls.concat(this.filesSrc),\n            done           = this.async(),\n            errors         = 0,\n            results        = '',\n            output         = options.output || false;\n\n        // Check for a local install of mocha-phantomjs to use\n        if (!exists(phantomjs_path)) {\n            var i = module.paths.length,\n                bin;\n            while(i--) {\n                bin = path.join(module.paths[i], binPath);\n                if (exists(bin)) {\n                    phantomjs_path = bin;\n                    break;\n                }\n            }\n        }\n\n        if(!exists(phantomjs_path)) {\n            grunt.fail.warn('Unable to find mocha-phantomjs.');\n        }\n\n        // Loop through the options and add them to args\n        // Omit urls from the options to be passed through\n        _.each(_.omit(options, 'urls', 'output'), function(value, key) {\n            // Convert to the key to a switch\n            var sw = (key.length > 1 ? '--' : '-') + key;\n            // Add the switch and its value\n            // If the value is an array, add all array elements to the array.\n            if(!_.isArray(value)) {\n                value = [value];\n            }\n\n            _.each(value, function(value) {\n                args.push([sw, value.toString()]);\n            });\n        });\n\n        util.async.forEachSeries(urls, function(f, next) {\n            var phantomjs = grunt.util.spawn({\n                cmd: phantomjs_path,\n                args: _.flatten([f].concat(args))\n            }, function(error, result, code) {\n                next();\n            });\n\n            phantomjs.stdout.pipe(process.stdout);\n            phantomjs.stderr.pipe(process.stderr);\n\n            // Append output to be written to a file\n            if(output) {\n                phantomjs.stdout.on('data', function(data){\n                    results += String(data.toString());\n                });\n            }\n\n            phantomjs.on('exit', function(code){\n                if (code === 127) {\n                    grunt.fail.warn(\"Phantomjs isn't installed\");\n                }\n                errors += code;\n            });\n\n        }, function(){\n            // Fail if errors are reported and we aren't outputing to a file\n            if(!output && errors > 0) {\n                grunt.fail.warn(errors + \" tests failed\");\n            } else if(output) {\n                grunt.file.write(output, results);\n            }\n            done();\n        });\n    });\n\n};"
  },
  {
    "path": "vendors/baron/test/core.auto.html",
    "content": "<!doctype html>\n<html>\n<head>\n\n    <meta charset=\"utf-8\" />\n\n    <script src=\"../js/jquery-1.9.0.js\"></script>\n\n    <script src=\"../js/qwery.js\"></script>\n    <script src=\"../js/bonzo.js\"></script>\n    <script src=\"../js/bean.js\"></script>\n\n    <script src=\"../src/core.js\"></script>\n    <script src=\"../src/fix.js\"></script>\n    <script src=\"../src/pull.js\"></script>\n    <script src=\"../src/test.js\"></script>\n    <script src=\"../src/controls.js\"></script>\n\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../baron.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n    <link rel=\"stylesheet\" href=\"../node_modules/mocha/mocha.css\" />\n    <style>\n        .wrapper {\n            width: 200px;\n        }\n        .test {\n            display: block;\n            height: auto;\n            width: auto;\n            background: #fff;\n            box-shadow: none;\n        }\n    </style>\n\n    <title>Baron test page</title>\n\n</head>\n\n<body>\n    <div id=\"mocha\"></div>\n    <script src=\"../node_modules/mocha/mocha.js\"></script>\n    <script src=\"../node_modules/chai/chai.js\"></script>\n    <script>\n        var assert = chai.assert;\n\n        mocha.ui('bdd');\n        mocha.reporter('html');\n    </script>\n\n    <div class=\"wrapper wrapper_headers\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">...of the bridge's opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n\n    <div class=\"wrapper wrapper_\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Baron</h1>\n                </div>\n                <p class=\"text\">...of the bridge's opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n\n    <script src=\"tests.js\"></script>\n\n    <script>\n        if (window.mochaPhantomJS) { mochaPhantomJS.run(); }\n        else { mocha.run(); }\n    </script>\n\n</body>\n\n</html>"
  },
  {
    "path": "vendors/baron/test/index.html",
    "content": "<!doctype html>\n<html>\n<head>\n\n    <meta charset=\"utf-8\" />\n\n    <script src=\"../js/jquery-1.9.0.js\"></script>\n\n    <script src=\"../js/qwery.js\"></script>\n    <script src=\"../js/bonzo.js\"></script>\n    <script src=\"../js/bean.js\"></script>\n\n    <script>\n        var baron = 5; // noConflict usage test (see console logs)\n        // var module = { // require() test\n        //     exports: function() {}\n        // }\n    </script>\n\n    <script src=\"../src/core.js\"></script>\n    <script src=\"../src/fix.js\"></script>\n    <script src=\"../src/test.js\"></script>\n    <script src=\"../src/controls.js\"></script>\n    <script src=\"script.js\"></script>\n\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../baron.css\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n\n    <title>Baron test page</title>\n\n</head>\n\n<body>\n\n<div class=\"test test_very-simple\">\n    <div class=\"test__description\">\n        Simple\n    </div>\n    <div class=\"wrapper wrapper_very-simple\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Climate</h1>\n                </div>\n                <p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">History</h1>\n                </div>\n                <p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">At the time...</h1>\n                </div>\n                <p class=\"text\">...of the bridge's opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>                \n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n\n<div class=\"test test_simple\">\n    <div class=\"test__description\">\n        With fixable elements, radius 30 px, no bar.\n    </div>\n    <div class=\"wrapper wrapper_simple\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Climate</h1>\n                </div>\n                <p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">History</h1>\n                </div>\n                <p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">At the time...</h1>\n                </div>\n                <p class=\"text\">...of the bridge's opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>                \n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n\n<div class=\"test test_arr\">\n    <div class=\"test__description\">\n        Fixable elements + track + bar + controls + pause.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">The Ob River</h1>\n                </div>\n                <p class=\"text\">iis a major river in western Siberia, Russia and is the world's seventh longest river. It is the westernmost of the three great Siberian rivers that flow into the Arctic Ocean (the other two being the Yenisei River and the Lena River). The Gulf of Ob is the world's longest estuary.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Names</h1>\n                </div>\n                <p class=\"text\">The Ob is known to the Khanty people as the As, Yag, Kolta and Yema; to the Nenets people as the Kolta or Kuay; and to the Siberian Tatars as the Umar or Omass. Possibly from proto-Indo-Iranian *ap- river, water.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Geography</h1>\n                </div>\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.\n            </div>\n            <div class=\"scroller__track-visual\"></div>\n            <div class=\"scroller__track\">\n                <div class=\"scroller__bar\"></div>\n            </div>\n            <div class=\"scroller__control scroller__up\">up</div>\n            <div class=\"scroller__control scroller__down\">down</div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_arr\">\n    <div class=\"test__description\">\n        The Novosibirsk Zoo\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">The Novosibirsk Zoo</h1>\n                </div>\n                <p class=\"text\">The Novosibirsk Zoo is a world-renowned scientific institution as well as a popular tourist attraction. The zoo has over four thousand animals and is an active participant of thirty-two different captive breeding programmes for endangered species. On average, around 700,000 people visit the zoo each year.\n                <p class=\"text\">In 2000, the zoo held the closest relative to the cape lion of South Africa. John Spence was always fascinated about the stories of these grand lions scaling the walls of General van Riebeeck's castle in the 17th century. Spence's search took thirty years, which led him to the Novosibirsk Zoo, where he found the closest living resemblance to the cape lion; the zoo called the lion Simon. The lion and his family are kept outdoors in large, natural settings. \"It is kept all the year around in the climate conditions of the west Siberia at the temperatures from −49 °C (−56 °F) to 36 °C (97 °F). In forty years, more than sixty cubs were born.\"\n                <p class=\"text\">The zoo's current curator is Rostislav Shilo. Simon's cubs were named after him and his wife, Olga.\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_wo-headers\">\n    <div class=\"test__description\">\n        The Novosibirsk Opera and Ballet Theatre\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <p class=\"text\">The Novosibirsk Opera and Ballet Theatre (the official title being the Novosibirsk State Academic Opera and Ballet Theatre (Russian: Новосибирский государственный академический театр оперы и балета) is one the most important theatres in Novosibirsk and Siberia. It is located at the center of Novosibirsk at Lenin square.\n                <p class=\"text\">Building was completed in February 1944, the first performance being held on 12 May 1945. Currently, it is the largest theatre in Russia, larger than the Bolshoi Theatre (literally \"Big theatre\") in Moscow. After its renovation in 2005 with computerized stage equipment, at the time it became the most technically advanced in Russia. The total area of the building is 11 837 m², the volume is 294 340 m³. The theatre is often called the \"Siberian Coliseum\" because of its size and beauty. The auditorium seats more than 1,790 spectators. Its upper gallery is decorated with copies of antique Greek statues.\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_negative-viewport\">\n    <div class=\"test__description\">\n        No header fixing because there not enought space for them.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\"><h1 class=\"header__title\">Novosibirsk</h1></div>\n                <p class=\"text\">is\n                <div class=\"header\"><h1 class=\"header__title\">the</h1></div>\n                <p class=\"text\">third-largest\n                <div class=\"header\"><h1 class=\"header__title\">city</h1></div>\n                <p class=\"text\">in\n                <div class=\"header\"><h1 class=\"header__title\">Russia</h1></div>\n                <p class=\"text\">(after\n                <div class=\"header\"><h1 class=\"header__title\">Moscow</h1></div>\n                <p class=\"text\">and\n                <div class=\"header\"><h1 class=\"header__title\">St. </h1></div>\n                <p class=\"text\">Petersburg\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_flex\">\n    <div class=\"test__description\">\n        Flexible height for bar appearing / disappearing on the fly (try to resize window).\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Novosibirsk Metro</h1>\n                </div>\n                <p class=\"text\">The system contains 13 stations on two lines. There are 80 carriages that form 20 four-carriage trains which carry over 250,000 passengers daily. The stations are vividly decorated in late-Soviet style. Currently, of the 13 stations (12 station plus the interchange station counted twice), seven are pillar-trispan, four are single vaults. There is also a surface level station which follows a 2.145 km covered bridge span of the Ob River.</p>\n            </div>\n            <div class=\"scroller__bar-wrapper\">\n                <div class=\"scroller__bar\"></div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_flex-headers\">\n    <div class=\"test__description\">\n        Flexible height for bottom fixed headers position change. Change window height and see on bottom headers. Also, see what happen when viewport (white segments between headers) goes to negative height.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Novosibirsk State University</h1>\n                </div>\n                <p class=\"text\">Novosibirsk State University was founded in May 1959 in the USSR by Soviet academicians Mikhail Alekseevich Lavrentiev, Sergei Lvovich Sobolev and Sergey Alekseyevich Khristianovich in a program of establishing a Siberian Division of the USSR Academy of Sciences. Novosibirsk State University is one of the most famous universities in Russia, although is somewhat young. The university is located 20 kilometers from the city of Novosibirsk, a cultural and industrial center of Siberia. The total number of students in the year 1999 was 5200.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">History</h1>\n                </div>\n                <p class=\"text\">Three fellow members of the USSR Academy of Sciences Lavrentiev, Sobolev, and Khristianovich, decided to bring international level research over the Urals from Moscow to the vast territories of Siberia. Siberia possessed copious natural resources, but lacked large research institutions which would promote economic development and growth in the region. The idea was implemented with the establishment of the Siberian Division of the USSR Academy of Sciences in 1958 near the large industrial city of Novosibirsk. A new academic town (Akademgorodok) started to grow rapidly and half a year later a new university was founded to train young researchers for the newly born science center.\n                <p class=\"text\">Thus, in May 1959 the USSR Higher Education Ministry issued a decree to begin studies in Novosibirsk State University on September 1, 1959 with Ilia N. Vekua as rector (Russian for president or chancellor of a university). The July 20, 1959 issue of the newspaper Pravda reported the opening of the new university and announced admittance with entrance examinations for future students from all over the USSR in the period of August 1 through 20. 139 first-year students were admitted as full-time students and 119 as part-time students. In addition, the best students from other Soviet universities were selected as second-year students. The applicants for chemistry and physics accounted for eight and five persons per vacancy respectively, with three persons for mathematics, mechanics and geology.\n                <p class=\"text\">First lectures were held in the building of a secondary school, and first dormitories for the students were just tents amidst the forest; but the spirit of novelty and the lust for education and research created a strong motivation among the first students.\n                <p class=\"text\">At first, the only department of the University, the Department of Natural Sciences, combined Mathematics, Physics, Mechanics, Biology,Chemistry and Geology. Between 1960 and 1967 new departments began to separate into their own disciplines. In December, 1963 the first graduates of the Novosibirsk State University, including 26 physicists, 24 mathematicians and ten researchers in mechanics, received diplomas.\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Education and Research</h1>\n                </div>\n                <p class=\"text\">The Novosibirsk State University is a coeval and a creation of the Siberian Division of the Academy of Sciences of the USSR. The \"Founding Fathers of Siberian Science\" believed that it was impossible to organize a scientific center without solving the problem of training young researchers. On the other hand, almost 80% of the Siberian Division staff consists of NSU graduates. Some journalists still argue whether the Siberian Division gave birth to the University or the University built up the Siberian Division.\n                <p class=\"text\">In the USSR and subsequently in Russia, universities serve primarily as educational institutions, in which faculty members rarely do research and focus on training students. Research and graduate training exist in separate research institutions. The main idea of the founders of NSU was to combine research and education in the University by inviting scientists from the nearby research institutions in Akademgorodok as part-time university faculty. This allowed students to gain laboratory experience in addition to regular coursework. Additionally, it allowed students to undertake the writing of theses.\n                <p class=\"text\">This idea propelled NSU toward becoming arguably one of the best Russian universities. However, this design also led to a number of disadvantages. In official ratings of Russian universities NSU is not near the top. This may be attributed to the fact that the ratings do not consider part-time staff and only account for volumes of the university library, while NSU students also have access to a number of institute libraries as well as the large Academy of Sciences Library which is located across the street from the main University building. Another disadvantage is that NSU trains researchers mainly for the Academy of Sciences; therefore, non-science majors are underrepresented in the University. To attempt to correct this imbalance, Law, Medicine, Foreign Languages, and a few other departments were added recently. However, in conditions of post-perestroika financial crisis in Russian higher education, this innovation has received a great deal of criticism. Critics say that new departments drain money from the science departments from which NSU draws its reputation.\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test\">\n    <div class=\"test__description\">\n        No js.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Novosibirsk history</h1>\n                </div>\n                <p class=\"text\">During Stalin's industrialization, Novosibirsk secured its place as one of the largest industrial centers of Siberia. Several massive industrial facilities were created in there, including the 'Sibkombain' plant, specializing in the production of heavy mining equipment. Additionally a metal processing plant, a food processing plant and other industrial enterprises and factories were built, as well as a new power station. The Great Soviet Famine saw the influx of more than 170,000 refugees to Novosibirsk. The new arrivals settled in barracks at the outskirts of the city, giving rise to slums such as Bolshaya Nakhalovka, Malaya Nakhalovka, and others.\n                <p class=\"text\">Rapid growth and industrialization were the reasons behind Novosibirsk's nickname: the \"Chicago of Siberia\".\n                <p class=\"text\">Tram rails were laid down in 1934, by which time the population had reached 287,000, making Novosibirsk the largest city in Siberia. The following year the original bridge over the Ob River was replaced by the new Kommunalny bridge.\n                <p class=\"text\">The rapid growth of the city prompted the construction of a hydroelectric power station with a capacity of 400 megawatts, necessitating the creation of a giant water reservoir, now known as the Ob Sea. As a direct result of the station's construction vast areas of fertile land were flooded as were relic pine woods in the area; additionally, the new open space created by the reservoir's surface caused average wind speeds to double, increasing the rate of soil erosion.\n                <p class=\"text\">In the 1950s, the Soviet Government directed that a center for scientific research be built in Novosibirsk; consequently, the multi-facility scientific research complex of Akademgorodok was constructed about 30 kilometers (19 mi) south of the city center in 1957. The Siberian Division of the Academy of Sciences has its headquarters in Akademgorodok, and the town hosts a total of fourteen research institutions and universities. Although it possesses a fully autonomous infrastructure, Akademgorodok is administered by Novosibirsk.\n                <p class=\"text\">On September 2, 1962, the population of Novosibirsk reached one million. At that time, it was the youngest city in the world with over a million people. Novosibirsk took fewer than seventy years to achieve this milestone.\n                <p class=\"text\">In 1979, work began on the Novosibirsk Metro Transit System, culminating in the opening of the first line in 1985.\n                <p class=\"text\">On August 1, 2008, Novosibirsk was in the center of the path of a solar eclipse, with a duration of 2 minutes and 20 seconds.</p>\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_advanced\">\n    <div class=\"test__description\">\n        No jQuery (qwery, bean and bonzo). Try mousewheel in Chrome on header.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Climate</h1>\n                </div>\n                <p class=\"text\">The climate is humid continental (Köppen Dfb), with warm summers and severely cold winters. Snow is frequent, falling on almost half of all winter days, but individual snowfalls are usually light. On average temperatures range in summer from +15 °C (59 °F) to +26 °C (79 °F), in winter from −20 °C (−4 °F) to −12 °C (10 °F). However, winter temperatures can go as low as −30 °C (−22 °F) to −35 °C (−31 °F), and summer temperatures can go as high as +30 °C (86 °F) to +35 °C (95 °F). The difference between the highest and lowest recorded temperatures is 88 °C (158 °F). Most days the weather is sunny, with an average of 2,880 hours of sunshine per year, but heavy rain is possible in summer.\n                <p class=\"text\">Travelers coming from countries with mild climates may find Novosibirsk’s winter tough, but it may not be extraordinary for those from northern countries. At times, bitter cold may hold for some days, but temperatures of −40 °C (−40 °F) and lower do not occur every year. In the springtime, streets and roads become dirty as a result of mud and melting snow, while the weather is still cold.\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_horizontal\">\n    <div class=\"test__description\">\n        Horizontal scroll.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">C l i m a t e</h1>\n                </div>\n                <p class=\"text\">The climate is humid continental (Köppen Dfb), with warm summers and severely cold winters. Snow is frequent, falling on almost half of all winter days, but individual snowfalls are usually light. On average temperatures range in summer from +15 °C (59 °F) to +26 °C (79 °F), in winter from −20 °C (−4 °F) to −12 °C (10 °F). However, winter temperatures can go as low as −30 °C (−22 °F) to −35 °C (−31 °F), and summer temperatures can go as high as +30 °C (86 °F) to +35 °C (95 °F). The difference between the highest and lowest recorded temperatures is 88 °C (158 °F). Most days the weather is sunny, with an average of 2,880 hours of sunshine per year, but heavy rain is possible in summer.\n                <div class=\"header\">\n                    <h1 class=\"header__title\">C l i m a t e</h1>\n                </div>\n                <p class=\"text\">Travelers coming from countries with mild climates may find Novosibirsk’s winter tough, but it may not be extraordinary for those from northern countries. At times, bitter cold may hold for some days, but temperatures of −40 °C (−40 °F) and lower do not occur every year. In the springtime, streets and roads become dirty as a result of mud and melting snow, while the weather is still cold.\n\n            </div>\n            <div class=\"scroller__bar scroller__bar_h\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_varheights\">\n    <div class=\"test__description\">\n        The Ob River\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">The Ob River, and this header has variable height</h1>\n                </div>\n                <p class=\"text\">iis a major river in western Siberia, Russia and is the world's seventh longest river. It is the westernmost of the three great Siberian rivers that flow into the Arctic Ocean (the other two being the Yenisei River and the Lena River). The Gulf of Ob is the world's longest estuary.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Names</h1>\n                </div>\n                <p class=\"text\">The Ob is known to the Khanty people as the As, Yag, Kolta and Yema; to the Nenets people as the Kolta or Kuay; and to the Siberian Tatars as the Umar or Omass. Possibly from proto-Indo-Iranian *ap- river, water.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Geography</h1>\n                </div>\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.</p>                \n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_scroll-height\">\n    <div class=\"test__description\">\n        Container has absolute positioning elements outside and margin collapse.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\" style=\"overflow: visible;\">\n                <div style=\"margin-top: 1000px; height: 100px; background: red\">AAA</div>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">The Ob River, and this header has variable height</h1>\n                </div>\n                <p class=\"text\">iis a major river in western Siberia, Russia and is the world's seventh longest river. It is the westernmost of the three great Siberian rivers that flow into the Arctic Ocean (the other two being the Yenisei River and the Lena River). The Gulf of Ob is the world's longest estuary.</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Names</h1>\n                </div>\n                <p class=\"text\">The Ob is known to the Khanty people as the As, Yag, Kolta and Yema; to the Nenets people as the Kolta or Kuay; and to the Siberian Tatars as the Umar or Omass. Possibly from proto-Indo-Iranian *ap- river, water.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Geography</h1>\n                </div>\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.</p>\n\n                <div style=\"position: relative; height: 10px; background: #ffa\">\n                    <div style=\"position: absolute; height: 100px; width: 100%; background: red\">ZZZ</div>\n                </div>\n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_bidir\">\n    <div class=\"test__description\">\n        Bidirectional scroll.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\" style=\"width: 800px; height: 400px; background: #fee\">\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.</p>\n            </div>\n            <div class=\"scroller__bar\"></div>\n            <div class=\"scroller__bar scroller__bar_h\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_bidir-2\">\n    <div class=\"test__description\">\n        Bidirectional scroll root bug.\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\" style=\"width: 800px; height: 400px; background: #fee\">\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.</p>\n            </div>\n            <div class=\"scroller__bar\"></div>\n            <div class=\"scroller__bar scroller__bar_h\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_textarea\">\n    <div class=\"test__description\">\n        Bidirectional scroll on textarea.\n    </div>\n    <div class=\"wrapper\">\n        <textarea class=\"scroller\" style=\"font-size: 4000px; line-height: 100px\">-</textarea>\n        <div class=\"scroller__track\">\n            <div class=\"scroller__bar\"></div>\n        </div>\n        \n        <div class=\"scroller__track_h\">\n            <div class=\"scroller__bar scroller__bar_h\"></div>\n        </div>\n    </div>\n</div>\n\n<div class=\"test test_bar-outside\" style=\"position: relative\">\n    <div class=\"test__description\">\n        Bar outside scroller\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\" style=\"width: 700px;\">\n                <p class=\"text\">The Ob forms 16 miles (26 km) southwest of Biysk in Altai Krai at the confluence of the Biya and Katun rivers. Both these streams have their origin in the Altay Mountains, the Biya issuing from Lake Teletskoye, the Katun, 700 kilometres (430 mi) long, bursting out of a glacier on Mount Byelukha.\n                <p class=\"text\">The river splits into more than one arm, especially after joining the large Irtysh tributary at about 69° E. (Originating in China, the Irtysh is actually longer than the Ob from source to the point of their confluence.) From the source of the Irtysh to the mouth of the Ob, the river flow is the longest in Russia at 5,410 kilometres (3,360 mi). Other noteworthy tributaries are: from the east, the Tom, Chulym, Ket, Tym and Vakh rivers; and, from the west and south, the Vasyugan, Irtysh (with the Ishim and Tobol rivers), and Sosva rivers.\n                <p class=\"text\">The Ob zigzags west and north until it reaches 55° N, where it curves round to the northwest, and again north, wheeling finally eastwards into the Gulf of Ob, a 600-mile (970 km)-long bay of the Kara Sea, separating the Yamal Peninsula from the Gydan Peninsula.\n                <p class=\"text\">The combined Ob-Irtysh system, the third-longest river system of Asia (after China's Yangtze and Yellow rivers), is 5,410 kilometres (3,360 mi) long, and the area of its basin 2,990,000 square kilometres (1,150,000 sq mi). The river basin of the Ob consists mostly of steppe, taiga, swamps, tundra, and semi-desert topography. The floodplains of the Ob are characterized by many tributaries and lakes. The Ob is ice-bound at southern Barnaul from early in November to near the end of April, and at northern Salekhard, 100 miles (160 km) above its mouth, from the end of October to the beginning of June. The Ob River crosses several climatic zones. The upper Ob valley, in the south, grows grapes, melons and watermelons, whereas the lower reaches of the Ob are Arctic tundra. The most comfortable climate for the rest on the Ob - are Biysk, Barnaul, and Novosibirsk.</p>\n            </div>\n        </div>\n    </div>\n    <div class=\"scroller__track-visual\"></div>\n    <div class=\"scroller__track\">\n        <div class=\"scroller__bar\"></div>\n    </div>\n\n    <div class=\"scroller__track_h\">\n        <div class=\"scroller__bar scroller__bar_h\"></div>\n    </div>\n</div>\n\n<div class=\"test test_mem-leak\">\n    <div class=\"test__description\">\n        Memory leak & dispose method (should not work)\n    </div>\n    <div class=\"wrapper\">\n        <div class=\"scroller\">\n            <div class=\"container\">\n                <div class=\"header\">\n                    <h1 class=\"header__title\">Climate</h1>\n                </div>\n                <p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p>\n                <div class=\"header\">\n                    <h1 class=\"header__title\">History</h1>\n                </div>\n                <p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p>\n\n\n                <div class=\"header\">\n                    <h1 class=\"header__title\">At the time...</h1>\n                </div>\n                <p class=\"text\">...of the bridge's opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>                \n            </div>\n            <div class=\"scroller__bar\"></div>\n        </div>\n    </div>\n</div>\n\n</body>\n\n</html>"
  },
  {
    "path": "vendors/baron/test/script.js",
    "content": "var b;\n\n$(document).ready(function() {\n    var i;\n\n    b = $('.wrapper_very-simple .scroller').baron();\n\n    b.update();\n\n    // Simple initialization with minimum parameters, but with headers\n    for (i = 0 ; i < 100 ; i++) {\n        $('.wrapper_simple .scroller').baron({\n            barOnCls: 'baron'\n        }).fix({\n            elements: '.header__title',\n            outside: 'header__title_state_fixed',\n            radius: 30\n        });\n    }\n\n    // Array initialization + limiter\n    $('.test_arr .scroller').baron({\n        bar: '.scroller__bar',\n        //track: '.scroller__track',\n        barOnCls: 'baron',\n        pause: 0.1\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        before: 'header__title_position_top',\n        after: 'header__title_position_bottom',\n        limiter: true\n    })\n    .test()\n    .controls({\n        track: '.scroller__track-visual',\n        forward: '.scroller__up',\n        backward: '.scroller__down',\n        screen: 0.5,\n        delta: 60\n    });\n\n    // Init without headers\n    $('.test_wo-headers .scroller').baron({\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    });\n\n    // // Negative viewport\n    $('.test_negative-viewport .scroller').baron({\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    });\n\n    // Flexible height\n    baron({\n        scroller: '.test_flex .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron',\n        track: '.scroller__bar-wrapper',\n        pause: 0.2\n    });\n\n    // Not enought input params\n    //baron();\n\n    var babaron = baron.noConflict(),\n        anotherBaron = babaron;\n    console.log('Original baron value is: ', baron);\n\n    // Flexible height for bottom fixed headers -> they should change positions when window resize occurs.\n    anotherBaron({\n        scroller: '.test_flex-headers .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        minView: 100\n    });\n\n    // No js .test__no-js\n\n    // Maximum variables\n    for (i = 0 ; i < 10 ; i++) {\n        anotherBaron({\n            scroller: '.test_advanced .scroller',\n            bar: '.scroller__bar',\n            barOnCls: 'baron',\n            $: function(selector, context) {\n                return bonzo(qwery(selector, context));\n            },\n            event: function(elem, event, func, mode) { // Events manager\n                if (mode == 'trigger') {\n                    mode = 'fire';\n                }\n\n                bean[mode || 'on'](elem, event, func);\n            }\n        }).fix({\n            elements: '.header__title',\n            outside: 'header__title_state_fixed'\n        });\n    }\n\n    // Variable header \n    anotherBaron({\n        scroller: '.test_varheights .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        minView: 100\n    });\n\n    // Elements outside container\n    anotherBaron({\n        scroller: '.test_scroll-height .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        minView: 100\n    });\n\n    // Horizontal scroll\n    $('.test_horizontal .scroller').baron({\n        bar: '.scroller__bar',\n        barOnCls: 'baron',\n        direction: 'h'\n    }).fix({\n        elements: '.header__title',\n        outside: 'header__title_state_fixed',\n        before: 'before',\n        after: 'after',\n        limiter: true\n    });\n\n    // Bidirectional scroll\n    $('.test_bidir .scroller').baron({\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).baron({\n        bar: '.scroller__bar_h',\n        barOnCls: 'baron_h'\n    });\n\n    // Bidirectional scroll root bug\n    anotherBaron({\n        scroller: '.test_bidir-2 .scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).baron({\n        bar: '.scroller__bar_h',\n        barOnCls: 'baron_h'\n    });\n\n    // Textarea scroll\n    $('.test_textarea').baron({\n        scroller: '.scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).baron({\n        bar: '.scroller__bar_h',\n        barOnCls: 'baron_h'\n    });\n\n    // Bar outside\n    $('.test_bar-outside').baron({\n        scroller: '.scroller',\n        bar: '.scroller__bar',\n        barOnCls: 'baron'\n    }).baron({\n        bar: '.scroller__bar_h',\n        barOnCls: 'baron_h'\n    });\n\n    var leak = [];\n    for (i = 0 ; i < 1000 ; i++) {\n        $('.test_mem-leak').attr('data-baron-v', '');\n        var l = $('.test_mem-leak').baron({\n            scroller: '.scroller',\n            bar: '.scroller__bar',\n            barOnCls: 'baron'\n        });\n        leak.push(l);\n        l.dispose();\n    }\n});"
  },
  {
    "path": "vendors/baron/test/style.css",
    "content": "html, body {height: 100%;margin: 0; padding: 0; font-family: Verdana;}\n\n.test {\n    z-index: 0;\n    width: 30%;\n    height: 400px;\n    display: inline-block;\n    background: #eee;\n    margin: 5px;\n    box-shadow: 0 0 4px #ccc;\n    vertical-align: top;\n}\n\n.test_flex {\n    height: 40%;\n}\n.test_flex .wrapper {\n    height: 70%;\n}\n.test_flex-headers {\n    height: 40%;\n}\n.test_flex-headers .wrapper {\n    height: 70%;\n}\n\n.wrapper {\n    position: relative;\n    z-index: 1;\n    overflow: hidden;\n    height: 200px;\n    margin: 1px auto;\n    background: #fff;\n    border: 1px solid #fc9;\n    box-shadow:\n        0 5px 15px -3px rgba(0, 0, 0, .7),\n        0 0 0 1px rgba(0, 0, 0, .05);\n}\n.scroller {\n    height: 100%;\n    overflow: auto;\n}\n.scroller::-webkit-scrollbar {\n    width: 0;\n    height: 0;\n}\n.scroller__bar-wrapper {\n    display: none;\n    position: absolute;\n    z-index: 1;\n    top: 10px;\n    bottom: 10px;\n    right: 5px;\n    width: 8px;\n    border-radius: 5px;\n    background: #ddf;\n    background: rgba(0, 0, 255, .1);\n}\n.scroller__track {\n    position: absolute;\n    z-index: 3;\n    top: 0;\n    right: 0;\n    bottom: 0;\n}\n.scroller__track-visual {\n    position: absolute;\n    z-index: 2;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    width: 10px;\n    background: rgba(255, 100, 100, .2);\n}\n.scroller__track-visual:active {\n    box-shadow: 0 0 7px rgba(0, 0, 0, .4) inset;\n}\n.scroller__track_h {\n    left: 0;\n    bottom: auto;\n    width: auto;\n}\n.scroller__bar {\n    position: absolute;\n    z-index: 1;\n    display: none;\n    width: 8px;\n    border-radius: 3px;\n    background: #987;\n    opacity: .6;\n    -webkit-transition: width .2s linear;\n    transition: width .2s linear;\n}\n.wrapper_very-simple .scroller__bar {\n    display: block;\n}\n.scroller__bar:hover {\n    opacity: .8;\n}\n.baron .scroller__bar {\n    display: block;\n}\n.hbaron .scroller__bar_h {\n    display: block;\n}\n.baron .scroller__bar-wrapper {\n    display: block;\n}\n\n.container {\n    overflow: hidden;\n}\n\n.header {\n    /*height: 20px;*/\n}\n.header__title {\n    width: 100%;\n    /*height: 20px;*/\n    -moz-box-sizing: border-box;\n    box-sizing: border-box;\n    background: #ebe7e4;\n    background-color: rgba(200, 255, 250, 1);\n    box-shadow: 0 -1px 0 rgba(0, 0, 0, .05);\n    color: #222;\n    font-size: 14px;\n    opacity: 1;\n}\n.header__title_state_fixed {\n    position: absolute;\n    z-index: 1;\n    background-color: rgba(220, 229, 250, .6);\n    text-shadow: 0 0 5px #fff;\n}\n.header__title_position_top {\n    background: rgba(255, 229, 250, .6);\n}\n.header__title_position_bottom {\n    background: rgba(220, 255, 250, .6);\n}\n.header__title_group_top {\n    color: red;\n}\n.header__title_group_bottom {\n    color: green;\n}\n\n.text {\n    overflow: hidden;\n    margin: 10px;\n    font-size: 12px;\n}\n\n\n.test_horizontal .scroller {\n    height: 100%;\n    width: auto;\n    overflow-x: scroll;\n    overflow-y: hidden;\n    white-space: nowrap;\n}\n.test_horizontal .container {\n    display: inline-block;\n    height: 100%;\n}\n.test_horizontal .header {\n    height: 100%;\n    display: inline-block;\n    white-space: normal;\n    vertical-align: top;\n}\n.test_horizontal .text {\n    display: inline-block;\n    white-space: normal;\n    vertical-align: top;\n    width: 800px;\n}\n.test_horizontal .header__title {\n    width: 20px;\n    height: 100%;\n}\n\n.test_textarea .scroller__bar {\n    display: block;\n}\n\n/* Controls */\n.scroller__control {\n    position: absolute;\n    z-index: 4;\n    width: 20px;\n    height: 20px;\n    background: #fc9;\n    cursor: pointer;\n    -webkit-user-select: none;\n    -moz-user-select: none;\n    user-select: none;\n}\n.scroller__up {\n    top: 0;\n    right: 0;\n}\n.scroller__down {\n    bottom: 0;\n    right: 0;\n}\n\n.scroller__pull {\n    background: red;\n}"
  },
  {
    "path": "vendors/baron/test/tests.js",
    "content": "var barOnCls = 'baron';\n\nvar originalHTML = '<div class=\"scroller\"><div class=\"container\"><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">Novosibirsk, founded in 1893 at the future site of a Trans-Siberian Railway bridge crossing the great Siberian river of Ob, first received the name Novonikolayevsk (Новониколаевск), in honor both of Saint Nicholas and of the reigning Tsar Nicholas II. The bridge was completed in the spring of 1897, making the new settlement the regional transport hub. The importance of the city further increased with the completion of the Turkestan-Siberia Railway in the early 20th century. The new railway connected Novosibirsk to Central Asia and the Caspian Sea.</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">...of the bridges opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div></div><div class=\"scroller__bar\"></div></div>';\n\nfunction eachIt(baron) {\n    it(\"Возвращает барон-объект\", function() {\n        assert.ok(baron);\n        assert.ok(baron.update);\n        assert.ok(baron.dispose);\n    });\n}\n\ndescribe(\"Барон.\", function() {\n    describe(\"Успешная инициализация барона по-умолчанию\", function() {\n        var baron,\n            scroller,\n            bar;\n\n        before(function() {\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            });\n\n            scroller = $('.scroller')[0];\n            bar = $('.scroller__bar')[0];\n\n            eachIt(baron);\n        });\n\n        it(\"Выставляет аттрибут data-baron-v в значение inited\", function() {\n            var attrV = $('.scroller').attr('data-baron-v'),\n                attrH = $('.scroller').attr('data-baron-h');\n\n            assert.ok(attrV == 'inited');\n            assert.ok(!attrH);\n        });\n\n        it(\"Находит bar и выставляет ему правильную высоту\", function() {\n            var height = parseInt($(bar).css('height'), 10),\n                expectedHeight = Math.round(scroller.clientHeight * scroller.clientHeight / scroller.scrollHeight);\n\n            assert.ok(baron[0].bar === bar);\n            assert.ok(Math.abs(height - expectedHeight) <= 1);\n        });\n\n        it(\"После вызова метода dispose удаляет атрибуты и классы\", function() {\n            var sizeDim = baron[0].origin.crossSize;\n\n            baron.dispose();\n\n            var attrV = $('.scroller').attr('data-baron-v'),\n                attrH = $('.scroller').attr('data-baron-h'),\n                cls = $('.scroller').hasClass(barOnCls),\n                size = $('.scroller')[0].style[sizeDim];\n\n            //$('.scroller').css(sizeDim)\n\n            assert.ok(!attrV);\n            assert.ok(!attrH);\n            assert.ok(!cls);\n            assert.ok(!size);\n        });\n    });\n});\n\ndescribe(\"Плагин fix.\", function() {\n    describe(\"Base.\", function() {\n        var baron,\n            scroller,\n            scrollTop;\n\n        before(function() {\n            scroller = $('.scroller')[0];\n        });\n\n        it(\"No elements\", function() {\n            $(scroller).find('.header').empty();\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                clickable: true,\n                scroll: function(data) {\n                    scrollTop = data.x2;\n                }\n            });\n\n            $('.wrapper').html(originalHTML);\n        });\n\n        it(\"past and future params\", function() {\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                past: 'header__title_group_top',\n                future: 'header__title_group_bottom',\n                clickable: true,\n                scroll: function(data) {\n                    scrollTop = data.x2;\n                }\n            });\n\n            $('.scroller')[0].scrollTop = 4;\n            baron.update(); // Событие выстреливает позже\n\n            var firstHeader = $('.wrapper_headers .scroller .header__title').eq(0),\n                secondHeader = $('.wrapper_headers .scroller .header__title').eq(1),\n                thirdHeader = $('.wrapper_headers .scroller .header__title').eq(2);\n\n            assert(firstHeader.hasClass('header__title_state_fixed'), '1 outside class');\n            assert(firstHeader.hasClass('header__title_position_top'), '1 before class');\n            assert(firstHeader.hasClass('header__title_group_top'), '1 past class');\n\n            assert(secondHeader.hasClass('header__title_state_fixed'), '2 outside class');\n            assert(secondHeader.hasClass('header__title_position_bottom'), '2 after class');\n            assert(secondHeader.hasClass('header__title_group_bottom'), '2 past class');\n\n            assert(thirdHeader.hasClass('header__title_state_fixed'), '3 outside class');\n            assert(!thirdHeader.hasClass('header__title_position_bottom'), '3 !after class');\n            assert(thirdHeader.hasClass('header__title_group_bottom'), '3 past class');\n\n            baron.dispose();\n        });\n\n        it(\"no future and after classes when bottom edge reached\", function() {\n            $('.wrapper').html(originalHTML);\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                past: 'header__title_group_top',\n                future: 'header__title_group_bottom',\n                clickable: true,\n                scroll: function(data) {\n                    scrollTop = data.x2;\n                }\n            });\n\n            $('.scroller')[0].scrollTop = 99999;\n            baron.update(); // Событие выстреливает позже\n\n            assert(!$('.wrapper_headers .scroller .header__title').hasClass('header__title_group_bottom'), 'no future class');\n            assert(!$('.wrapper_headers .scroller .header__title').hasClass('header__title_position_bottom'), 'no after class');\n\n            // $('.wrapper').html(originalHTML);\n        });\n    });\n\n    describe(\"clickable\", function() {\n        var baron,\n            scroller;\n\n        before(function() {\n            $('.wrapper').html(originalHTML);\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                clickable: true\n            });\n\n            scroller = $('.scroller')[0];\n\n            eachIt(baron);\n        });\n\n        it(\"Клики по второму заголовку скроллит контент\", function() {\n            var e = jQuery.Event('click'),\n                firstTitle = $('.header__title')[0],\n                secondTitle = $('.header__title')[1],\n                top = secondTitle.parentNode.offsetTop - firstTitle.parentNode.offsetHeight;\n\n            scroller.scrollTop = 0;\n            $(secondTitle).trigger(e);\n            assert(scroller.scrollTop == top, 'Проскроллились до уровня ' + scroller.scrollTop + ' при ожидаемом ' + top);\n        });\n\n        it(\"Клики по третьему заголовку\", function() {\n            var e = jQuery.Event('click'),\n                currentTitle = $('.header__title')[2],\n                top = currentTitle.parentNode.offsetTop - $('.header__title')[0].parentNode.offsetHeight - $('.header__title')[1].parentNode.offsetHeight;\n\n            $(currentTitle).trigger(e);\n            assert(scroller.scrollTop == top, 'Проскроллились до уровня ' + scroller.scrollTop + ' при ожидаемом ' + top);\n        });\n\n        it(\"Клики по первому заголовку\", function() {\n            var e = jQuery.Event('click'),\n                firstTitle = $('.header__title')[0];\n\n            $(firstTitle).trigger(e);\n            assert(scroller.scrollTop == 0, 'Проскроллились до уровня ' + scroller.scrollTop + ' при ожидаемом ' + 0);\n        });\n\n        it(\"Клики по четвертому - новому (appended) заголовку\", function() {\n            var html = '<div class=\"header\"><h1 class=\"header__title\">New header</h1></div><p class=\"text\">...of the bridges opening, Novonikolayevsk hosted a population of 7,800 people. Its first bank opened in 1906, with a total of five banks operating by 1915. In 1907, Novonikolayevsk, now with a population exceeding 47,000, was granted town status with full rights for self-government. The pre-revolutionary period saw the population of Novosibirsk reach 80,000. During this period the city experienced steady and rapid economic growth, becoming one of the largest commercial and industrial centers of Siberia and developing a significant agricultural processing industry, as well as a power station, iron foundry, commodity market, several banks, and commercial and shipping companies. By 1917, Novosibirsk possessed seven Orthodox churches and one Roman Catholic church, several cinemas, forty primary schools, a high school, a teaching seminary, and the Romanov House non-classical secondary school. In 1913, Novonikolayevsk became one of the first places in Russia to institute compulsory primary education.</p>';\n\n            $(scroller).append(html);\n            baron.update();\n\n            var e = jQuery.Event('click'),\n                currentTitle = $('.header__title')[3],\n                top = currentTitle.parentNode.offsetTop - $('.header__title')[0].parentNode.offsetHeight - $('.header__title')[1].parentNode.offsetHeight - $('.header__title')[2].parentNode.offsetHeight;\n\n            $(currentTitle).trigger(e);\n            assert(scroller.scrollTop == top, 'Проскроллились до уровня ' + scroller.scrollTop + ' при ожидаемом ' + top);\n        });\n\n        after(function() {\n            baron.dispose();\n        });\n    });\n\n    describe(\"clickable + scroll callback\", function() {\n        var baron,\n            scroller,\n            scrollTop;\n\n        before(function() {\n            scroller = $('.scroller')[0];\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                clickable: true,\n                scroll: function(data) {\n                    scrollTop = data.x2;\n                }\n            });\n\n            eachIt(baron);\n        });\n\n        it(\"Клики по второму заголовку вызывает callback с правильной координатой\", function() {\n            var e = jQuery.Event('click'),\n                firstTitle = $('.header__title')[0],\n                secondTitle = $('.header__title')[1],\n                top = secondTitle.parentNode.offsetTop - firstTitle.parentNode.offsetHeight;\n\n            scroller.scrollTop = 0;\n            $(secondTitle).trigger(e);\n            assert(scrollTop == top, 'Попросили проскроллить до уровня ' + scrollTop + ' при ожидаемом ' + top);\n        });\n\n        after(function() {\n            baron.dispose();\n        });\n    });\n\n    describe(\"Negative margins.\", function() {\n        var baron,\n            scroller;\n\n        before(function() {\n            var html = '<div class=\"scroller\"><div class=\"container\"><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><div class=\"scroller__pull\"></div></div><div class=\"scroller__bar\"></div></div>';\n            $('.wrapper').html(html);\n            $('.header__title').css({margin: '-7px 0 0'});\n\n            scroller = $('.scroller')[0];\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom'\n            });\n\n            eachIt(baron);\n        });\n\n        it(\"No fix classes on first header at start\", function() {\n            assert(!$('.header__title').eq(0).hasClass('header__title_state_fixed'), 'no fix cls');\n            assert(!$('.header__title').eq(0).hasClass('header__title_position_top'), 'no before cls');\n            assert(!$('.header__title').eq(0).hasClass('header__title_position_bottom'), 'no after cls');\n        });\n\n        it(\"offsetTop\", function() {\n            assert($('.header__title')[0].offsetTop == -7, 'offsetTop at start pos ' + $('.header__title')[0].offsetTop);\n            $('.scroller')[0].scrollTop = 1;\n            baron.update();\n            assert($('.header__title')[0].offsetTop == -7, 'offsetTop at 1px scroll ' + $('.header__title')[0].offsetTop);\n        });\n\n        after(function() {\n            baron.dispose();\n        });\n    });\n\n    describe(\"Live params update.\", function() {\n        var baron,\n            scroller;\n\n        before(function() {\n            var html = '<div class=\"scroller\"><div class=\"container\"><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><div class=\"scroller__pull\"></div></div><div class=\"scroller__bar\"></div></div>';\n            \n            $('.wrapper').html(html);\n\n            scroller = $('.scroller')[0];\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: '.header__title',\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom'\n            });\n\n            eachIt(baron);\n        });\n\n        it(\"Add limiter param\", function() {\n            baron.update({\n                fix: {\n                    limiter: true\n                }\n            });\n            scroller.scrollTop = 1;\n            scroller.scrollTop = 0;\n\n            assert(parseInt($('.scroller__bar').css('top'), 10) == $('.header').height(), 'Самое высокое положение скроллбара теперь ограничено высотой заголовка');\n\n            baron.update({\n                fix: {\n                    limiter: false\n                }\n            });\n            scroller.scrollTop = 1;\n            scroller.scrollTop = 0;\n            \n            assert(parseInt($('.scroller__bar').css('top'), 10) == 0, 'Самое высокое положение скроллбара снова неограничено высотой заголовка');\n        });\n\n        // it(\"offsetTop\", function() {\n        //     assert($('.header__title')[0].offsetTop == -7, 'offsetTop at start pos ' + $('.header__title')[0].offsetTop);\n        //     $('.scroller')[0].scrollTop = 1;\n        //     baron.update();\n        //     assert($('.header__title')[0].offsetTop == -7, 'offsetTop at 1px scroll ' + $('.header__title')[0].offsetTop);\n        // });\n\n        after(function() {\n            baron.dispose();\n        });\n    });\n\n    describe(\"Two independed fix.\", function() {\n        var baron,\n            scroller;\n\n        before(function() {\n            var html = '<div class=\"scroller\"><div class=\"container\"><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><p class=\"text\">is the third most populous city in Russia after Moscow and St. Petersburg and the most populous city in Asian Russia, with a population of 1,473,754 (2010 Census). It is the administrative center of Novosibirsk Oblast as well as of Siberian Federal District. The city is located in the southwestern part of Siberia at the banks of the Ob River and occupies an area of 502.1 square kilometers (193.9 sq mi).</p><div class=\"header\"><h1 class=\"header__title\">Baron</h1></div><div class=\"scroller__pull\"></div></div><div class=\"scroller__bar\"></div></div>';\n            \n            $('.wrapper').html(html);\n\n            scroller = $('.scroller')[0];\n            $('.header__title').eq(1).css({height: '100px'});\n\n            baron = $('.scroller').baron({\n                bar: '.scroller__bar',\n                barOnCls: barOnCls\n            }).fix({\n                elements: $('.header__title').eq(0),\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom',\n                limiter: true\n            }).fix({\n                elements: $('.header__title').eq(1),\n                outside: 'header__title_state_fixed',\n                before: 'header__title_position_top',\n                after: 'header__title_position_bottom'\n            });\n\n            eachIt(baron);\n        });\n\n        it(\"Bar limited by first header\", function() {\n            baron.update();\n            assert(parseInt($('.scroller__bar').css('top'), 10) == $('.header').height(), 'Самое высокое положение скроллбара ограничено высотой первого заголовка');\n        });\n\n        // it(\"offsetTop\", function() {\n        //     assert($('.header__title')[0].offsetTop == -7, 'offsetTop at start pos ' + $('.header__title')[0].offsetTop);\n        //     $('.scroller')[0].scrollTop = 1;\n        //     baron.update();\n        //     assert($('.header__title')[0].offsetTop == -7, 'offsetTop at 1px scroll ' + $('.header__title')[0].offsetTop);\n        // });\n\n        after(function() {\n            baron.dispose();\n            $('.header__title').eq(1).css({height: ''});\n        });\n    });\n});\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "vendors/firmcard/doc/Schedule.md",
    "content": "### Цель\n\nОблегчить работу пользователей с информацией о времени работы организаций.&nbsp;\n\n### Упрощение способа отображения времени работы\n\nСегодня мы отображаем время работы в виде таблицы. Такая форма отображения избыточна для наиболее распространённых расписаний организаций: когда&nbsp;организации&nbsp;имеют одинаковый график во все рабочие дни без обеда и фиксированные выходные.&nbsp;\n\nПримеры:&nbsp;\n\n![](./img/schedule-table.png \"График работы в виде таблицы\")\n\n##### Правила отображения в кратком (\"свёрнутом\") виде\n\n1.  Для случая, когда организация имеет одинаковый график во все дни недели без обеда: пишем \"Ежедневно [время работы]\", время работы не раскрывается по клику.&nbsp;\n\n&nbsp;![](./img/everyday.png \"Ежедневно\")\n\n&nbsp; &nbsp; &nbsp;2. Если организация работает круглосуточно: показываем строку \"работает круглосуточно\", время работы не&nbsp;раскрывается&nbsp;по клику.\n\n![](./img/24x7.png \"Круглосуточно\")\n\n&nbsp; &nbsp; &nbsp;3. Если организация работает по разному расписанию в разные дни, имеет перерывы на обед или выходные &nbsp;- время работы раскрывается по клику.\n\n&nbsp; &nbsp; &nbsp;![](./img/today-dropdown.png \"Сегодня,-раскрывающийся-список\")\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3.1. Если у организации сегодня есть обед - говорим об этом в свёрнутом виде.\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;![](./img/today-dinner.png \"Сегодня,-обед\")\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3.2. Если у организации сегодня выходной.\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;![](./img/holiday.png \"Сегодня выходной\")\n\n##### Правила отображения полного (\"развёрнутого\") вида\n\n&nbsp; &nbsp;По данным новосибирского каталога (общее кол-во фирм - 51 255):\n\n&nbsp; &nbsp; &nbsp; компаний, работающих ежедневно по одному графику -&nbsp;15 203 (29,66%)\n\n&nbsp; &nbsp; &nbsp; компаний, имеющих не более трёх интервалов работы (пн-пт, сб, вс) - 49 923 (95,45%)\n\n&nbsp; &nbsp; &nbsp;&nbsp;компании, имеющих обеденный перерыв - 4 554 (8,88%)\n\n&nbsp; &nbsp;В развернутом виде заменяем табличное представление на строчное, для случаев &nbsp;когда у организации два или три интервала работы:\n\n![](./img/schedule-strings.png)\n\n&nbsp; При форматировании строчного представления используем следующие правила\n\n&nbsp; &nbsp; 1. Если время работы одинаково с понедельника по пятницу - оформляем строкой \"Будние дни\"\n\n&nbsp; &nbsp; 2. Если время работы одинаково, для двух дней подрят - оформляем строкой с перечислением каждого дня \"понедельник, вторник\"\n\n&nbsp; &nbsp; 3. Если время работы одинаково для трёх и более дней - оформляем периодом \"пятница - среда\"\n\n&nbsp; &nbsp; 4. Каждая группа должна начинаться с новой строки.&nbsp;\n\n&nbsp; &nbsp;Несмотря на то, что компаний с большим количеством интервалов работы немного (менее 5%), как правило, это социально значимые организации. Например,&nbsp;УФМС в Москве&nbsp;-&nbsp;[http://go.2gis.ru/nzit](http://go.2gis.ru/nzit)&nbsp;. В случае, если у&nbsp;организации более трёх интервалов работы,&nbsp;необходимо оставить табличное представление.&nbsp;\n\n&nbsp; &nbsp;![](./img/table.png)\n\n##### Отображения комментария ко времени работы\n\nЕсли ко времени работы организации указан комментарий, отображаем его только в раскрытой карточке:&nbsp;\n\n![](./img/schedule-comment.png \"Комментарий-ко-времени-работы\")\n\nВ случае если время работы организации одинаково для всех дней недели или организация работает круглосуточно комментарий отображается после краткой записи\n\n![](./img/24x7-comment.png \"Круглосуточно,-коммент.\")&nbsp;\n\n![](./img/everyday-comment.png \"Коммент-ко-времени-работы,-свёрнутое-время-работы.png\")\n\n### Подсказки ко времени работы\n\nВ свёрнутом виде у времени работы появляются подсказки. Задача - помочь пользователю определить работает организация сейчас или нет.\n\nИспользуется цветовое кодирование иконки (зеленая - если организация работает, серая - если организация закрыта) и тестовая подсказка.\n\n**Финальные версии текстов для подсказок**\n<table>\n    <tr>\n        <th>График работы </th>\n        <th>Подсказка</th>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Открыто до 20:00</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Откроется завтра</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Закроется через 15 минут</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Открыто. Меньше 5 минут до закрытия</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Закроется через 5 минут</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00, обед 13:00 – 14:00 </td>\n        <td><b>Закроется через 15 минут</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00, обед 13:00 – 14:00</td>\n        <td><b>Откроется через 15 минут</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня 09:00 – 20:00 </td>\n        <td><b>Откроется через 15 минут</b></td>\n    </tr>\n    <tr>\n        <td>Сегодня выходной</td>\n        <td><b>Откроется в понедельник</b></td>\n    </tr>\n</table>\n\n\n##### Подсказки при использовании фильтра \"Работает сейчас\"\n\nЕсли пользователь отфильтровал результаты поиска по \"Работает сейчас\" подсказка должна отображаться и для скрытой карточки предприятия.&nbsp;\n\n![](./img/open-now.png \"Работает-сейчас\")\n\n### Дополнительные требования и&nbsp;ограничения\n\n1.  Время работы оцениваем по часовому поясу проекта в котором находится организация. Т.е. если человек из Новосибирска в просматривает профиль московской организации - время до закрытия должно считаться по московскому времени.&nbsp;\n2.  Не учитываем переходы на летнее\\зимнее время.\n3.  Не учитываем праздники.\n\n### Примеры карточек\n\n\n![](./img/worktimescreen.png \"worktimescreen.png\")\n"
  },
  {
    "path": "vendors/firmcard/src/Dictionary.js",
    "content": "/*global\n    FirmCard:false\n*/\n// FirmCard.dictionary = {};\n\nFirmCard.prototype.dict = {\n\n    t: function (lang, msg, argument) { // (String, Number) -> String\n        var result,\n            msgIsset = false,\n            dictionaryMsg,\n            exp;\n\n        if (typeof this[lang] === 'undefined') {\n            if (lang === 'ar') {\n                lang = 'en';\n            } else {\n                lang = 'ru';\n            }\n        }\n        dictionaryMsg = this[lang][msg];\n        msgIsset = typeof dictionaryMsg !== 'undefined';\n        if (!msgIsset) {\n            return msg;\n        }\n        result = msgIsset ? dictionaryMsg : msg;\n\n        if (argument !== undefined) {\n            argument = parseInt(argument, 10);\n            argument = isNaN(argument) ? 0 : argument;\n            exp = this[lang].pluralRules(argument);\n            result = argument + ' ' + dictionaryMsg[exp];\n        }\n        return result;\n    },\n\n    ru: {\n        pluralRules: function (n) { // (Number)\n            if (n % 10 === 1 && n % 100 !== 11) { // 1, 21\n                return 0;\n            }\n            if ((n % 10 >= 2 && n % 10 <= 4 && (n % 10) % 1 === 0) && (n % 100 < 12 || n % 100 > 14)) { // 2, 3\n                return 1;\n            }\n\n            if ((n % 10 === 0) || (n % 10 >= 5 && n % 10 <= 9 && (n % 10) % 1 === 0) || (n % 100 >= 11 && (n % 100) <= 14 && (n % 100) % 1 === 0)) { // 13, 17\n                return 2;\n            }\n        },\n\n        btnBack: 'Назад',\n        btnFindWay: 'Проехать сюда',\n        btnEntrance: 'Найти вход',\n        linkReviews: ['отзыв', 'отзыва', 'отзывов'],\n        linkPhoto: ['фото', 'фото', 'фото'],\n        linkBooklet: 'Буклет',\n        tommorow: 'завтра',\n        afterTommorow: 'послезавтра',\n        afterWeek: 'через неделю',\n        nextSun: 'в воскресенье',\n        nextMon: 'в понедельник',\n        nextTue: 'во вторник',\n        nextWed: 'в среду',\n        nextThu: 'в четверг',\n        nextFri: 'в пятницу',\n        nextSat: 'в субботу',\n        willOpen: 'откроется',\n        willClose: 'закроется',\n        isOpen: 'Открыто',\n        openTill: 'Открыто до ',\n        closeIn: 'Закроется через ',\n        openAt: 'Откроется в ',\n        openIn: 'Откроется через ',\n        open: 'Откроется ',\n        nHours: ['час', 'часа', 'часов'],\n        nMins: ['минуту', 'минуты', 'минут'],\n        lunch: 'обед',\n        Lunch: 'Обед. ',\n        workingDays: 'Рабочие дни',\n        weekdays: 'Будние дни',\n        restDay: ['выходной', 'выходные','выходные'],\n        reviewsOnFlamp: 'Отзывы на Флампе',\n        writeReviewOnFlamp: 'Написать отзыв на Флампе',\n        payment: 'оплата',\n        everyday: 'Ежедневно c',\n        worksAroundTheClock: 'Работает круглосуточно',\n        aroundTheClock: 'Круглосуточно',\n        knowMore: 'узнать больше',\n        toClose: 'до закрытия',\n        monday: 'понедельник',\n        tuesday: 'вторник',\n        wednesday: 'среда',\n        thursday: 'четверг',\n        friday: 'пятница',\n        saturday: 'суббота',\n        sunday: 'воскресенье',\n        mon: 'пон',\n        tue: 'втр',\n        wed: 'срд',\n        thu: 'чтв',\n        fri: 'птн',\n        sat: 'сбт',\n        sun: 'вск',\n        toLunch: 'до обеда',\n        today: 'Сегодня',\n        lessThenHour: 'менее часа',\n        youCouldLate: 'вы можете не успеть',\n        workingTime: 'рабочее время',\n        showAllOrgInRubric: 'Показать все организации рубрики',\n        todayIsRestDay: 'Сегодня выходной',\n        internet: 'Оплата через Интернет',\n        noncash: 'Безналичный расчет',\n        goldcrown: 'Золотая Корона',\n        dinersclub: 'Diners Club',\n        mastercard: 'Mastercard',\n        maestrocard: 'MaestroCard',\n        visa: 'Visa',\n        cash: 'Наличный расчет',\n        americanexpress: 'American Express',\n        hour : 'час',\n        less: 'менее',\n        _in : 'Через',\n        isClosingOnDinner : ' закрывается на обед'\n    },\n\n    it: {\n        pluralRules: function (n) { // (Number)\n            if (n === 1) { // 1\n                return 0;\n            } else {\n                return 1; //0, 2, 3, 4 ..\n            }\n        },\n\n        btnBack: 'Indietro',\n        btnFindWay: 'Come arrivare ',\n        btnEntrance: 'Trova l\\'ingresso',\n        linkReviews: ['recensione', 'recensioni'],\n        linkPhoto: ['fotografia', 'fotografie'],\n        linkBooklet: 'Sull\\'azienda',\n        tommorow: 'domani',\n        afterTommorow: 'dopodomani',\n        afterWeek: 'tra una settimana',\n        nextSun: 'la domenica',\n        nextMon: 'il lunedi',\n        nextTue: 'il martedì',\n        nextWed: 'il mercoledì',\n        nextThu: 'il giovedi',\n        nextFri: 'il venerdì',\n        nextSat: 'il sabato',\n        willOpen: 'apre',\n        willClose: 'ciuso',\n        isOpen: 'Aperto',\n        openTill: 'Aperto fino alle ',\n        closeIn: 'Chiude tra ',\n        openAt: 'Apre alle ',\n        openIn: 'Apre tra ',\n        open: 'Apre ',\n        nHours: ['ora', 'ore'],\n        nMins: ['minuto', 'minuti'],\n        lunch: 'pausa pranzo',\n        Lunch: 'Pausa pranzo. ',\n        workingDays: 'Giorni feriali',\n        weekdays: 'Giorni feriali',\n        restDay: ['chiusura','chiusura'],\n        reviewsOnFlamp: 'Recensioni su Flamp',\n        writeReviewOnFlamp: 'Scrivi una recensione su Flamp',\n        payment: 'pagamento',\n        everyday: 'Ogni giorno dalole',\n        worksAroundTheClock: 'Operativo 24 ore su 24',\n        aroundTheClock: '24 ore su 24',\n        knowMore: 'ulteriori informazioni',\n        toClose: 'fino alla chiusura',\n        monday: 'lunedi',\n        tuesday: 'martedì',\n        wednesday: 'mercoledì',\n        thursday: 'giovedi',\n        friday: 'venerdì',\n        saturday: 'sabato',\n        sunday: 'domenica',\n        mon: 'lun',\n        tue: 'mar',\n        wed: 'mer',\n        thu: 'gio',\n        fri: 'ven',\n        sat: 'sab',\n        sun: 'dom',\n        toLunch: 'fino alla pausa pranzo',\n        today: 'Oggi',\n        lessThenHour: 'meno di un\\'ora',\n        youCouldLate: 'affrettarsi, chiusura imminente',\n        workingTime: 'orario di lavoro',\n        showAllOrgInRubric: 'Visualizza tutte le aziende della categoria',\n        todayIsRestDay: 'oggi chiuso',\n        internet: 'Pagamento on-line',\n        noncash: 'Pagamento non in contanti',\n        goldcrown: 'Zolotaja Korona',\n        dinersclub: 'Diners Club',\n        mastercard: 'MasterCard',\n        maestrocard: 'MaestroCard',\n        visa: 'Visa',\n        cash: 'Pagamento in contanti',\n        americanexpress: 'American Express',\n        hour : 'un\\'ora',\n        less: 'meno di',\n        _in : 'Tra',\n        isClosingOnDinner : 'chiude per pausa pranzo'\n    },\n\n    en: {\n        pluralRules: function (n) { // (Number)\n            if (n === 1) { // 1\n                return 0;\n            } else {\n                return 1; //0, 2, 3, 4 ..\n            }\n        },\n\n        btnBack: 'Back',\n        btnFindWay: 'Get here',\n        btnEntrance: 'Find entrance',\n        linkReviews: ['review', 'reviews'],\n        linkPhoto: ['photo', 'photos'],\n        linkBooklet: 'About company',\n        tommorow: 'tomorrow',\n        afterTommorow: 'the day after tomorrow',\n        afterWeek: 'in a week',\n        nextSun: 'on Sunday',\n        nextMon: 'on Monday',\n        nextTue: 'on Tuesday',\n        nextWed: 'on Wednesday',\n        nextThu: 'on Thursday',\n        nextFri: 'on Friday',\n        nextSat: 'on Saturday',\n        willOpen: 'opens ',\n        willClose: 'closes',\n        isOpen: 'Open',\n        openTill: 'Open till ',\n        closeIn: 'Closes in ',\n        openAt: 'Opens at ',\n        openIn: 'Opens in ',\n        open: 'Opens ',\n        nHours: ['hour', 'hours'],\n        nMins: ['minute', 'minutes'],\n        lunch: 'lunch break',\n        Lunch: 'Lunch break. ',\n        workingDays: 'Working days',\n        weekdays: 'Weekdays',\n        restDay: ['day off','days off'],\n        reviewsOnFlamp: 'Reviews on Flamp',\n        writeReviewOnFlamp: 'Write a review on Flamp',\n        payment: 'payment',\n        everyday: 'Daily from',\n        worksAroundTheClock: 'Open 24 hours',\n        aroundTheClock: '24h',\n        knowMore: 'see also',\n        toClose: 'until closing',\n        monday: 'Monday',\n        tuesday: 'Tuesday',\n        wednesday: 'Wednesday',\n        thursday: 'Thursday',\n        friday: 'Friday',\n        saturday: 'Saturday',\n        sunday: 'Sunday',\n        mon: 'Mon',\n        tue: 'Tue',\n        wed: 'Wed',\n        thu: 'Thu',\n        fri: 'Fri',\n        sat: 'Sat',\n        sun: 'Sun',\n        toLunch: 'until lunch',\n        today: 'Today',\n        lessThenHour: 'less then one hour',\n        youCouldLate: 'you might be late',\n        workingTime: 'working hours',\n        showAllOrgInRubric: 'Show all organizations in the category',\n        todayIsRestDay: 'closed today',\n        internet: 'Online',\n        noncash: ' No-cash',\n        goldcrown: 'Golden Crown',\n        dinersclub: 'Diners Club',\n        mastercard: 'Mastercard',\n        maestrocard: 'MaestroCard',\n        visa: 'Visa',\n        cash: 'Cash',\n        americanexpress: 'American Express',\n        hour : 'hour',\n        less: 'less',\n        _in : 'In',\n        isClosingOnDinner : 'will be closing for lunch'\n    },\n\n    cs: {\n        pluralRules: function (n) { // (Number)\n            return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2;\n        },\n\n        btnBack: 'Zpět',\n        btnFindWay: 'Jet sem',\n        btnEntrance: 'Hledat vstup',\n        linkReviews: ['recenze', 'recenze', 'recenzí'],\n        linkPhoto: ['fotografie', 'fotografie', 'fotografií'],\n        linkBooklet: 'Leták',\n        tommorow: 'zítra',\n        afterTommorow: 'pozítří',\n        afterWeek: 'za týden',\n        nextSun: 'v neděli',\n        nextMon: 'v pondělí',\n        nextTue: 'v úterý',\n        nextWed: 've středu',\n        nextThu: 've čtvrtek',\n        nextFri: 'v pátek',\n        nextSat: 'v sobotu',\n        willOpen: 'otevře se',\n        willClose: 'zavře se',\n        isOpen: 'Otevřeno',\n        openTill: 'Otevřeno do ',\n        closeIn: 'Zavře se za ',\n        openAt: 'Otevře se v ',\n        openIn: 'Otevře se za ',\n        open: 'Otevře se ',\n        nHours: [ 'hodinu' , 'hodiny' , 'hodin' ],\n        nMins: [ 'minutu' , 'minuty' , 'minut' ],\n        lunch: 'polední přestávka',\n        Lunch: 'Polední přestávka. ',\n        workingDays: 'Všední dny',\n        weekdays: 'Všední dny',\n        restDay: ['zavřeno', 'zavřeno'],\n        reviewsOnFlamp: 'Recenze na Flampu',\n        writeReviewOnFlamp: 'Napsat recenzi na Flampu',\n        payment: 'platba',\n        everyday: 'Denně od ',\n        worksAroundTheClock: 'Pracuje nonstop',\n        aroundTheClock: 'Nonstop',\n        knowMore: 'dozvědět se více',\n        toClose: 'do uzavření',\n        monday: 'pondělí',\n        tuesday: 'úterý',\n        wednesday: 'středa',\n        thursday: 'čtvrtek',\n        friday: 'pátek',\n        saturday: 'sobota',\n        sunday: 'neděle',\n        mon: 'po',\n        tue: 'út',\n        wed: 'st',\n        thu: 'čt',\n        fri: 'pá',\n        sat: 'so',\n        sun: 'ne',\n        toLunch: 'do polední přestávky',\n        today: 'Dnes',\n        lessThenHour: 'méně než hodinu',\n        youCouldLate: 'nemusíte to stihnout',\n        workingTime: 'pracovní doba',\n        showAllOrgInRubric: 'Zobrazit všechny organizace v rubrice',\n        todayIsRestDay: 'Dnes je zavřeno',\n        internet: 'Platba prostřednictvím Internetu',\n        noncash: 'Bezhotovostní platba',\n        goldcrown: 'Zolotaja Korona',\n        dinersclub: 'Diners Club',\n        mastercard: 'Mastercard',\n        maestrocard: 'MaestroCard',\n        visa: 'Visa',\n        cash: 'Platba hotově',\n        americanexpress: 'American Express',\n        hour : 'hodinu',\n        less: 'méně',\n        _in : 'Za',\n        isClosingOnDinner : 'začíná polední přestávka'\n    },\n\n    es: {\n        pluralRules: function (n) { // (Number)\n          return (n === 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2;\n        },\n\n        btnBack: 'Atrás',\n        btnFindWay: 'Ir para allá',\n        btnEntrance: 'Buscar acceso',\n        linkReviews: ['comentario', 'comentarios', 'comentarios'],\n        linkPhoto: ['foto', 'fotos', 'fotos'],\n        linkBooklet: 'Folleto',\n        tommorow: 'mañana',\n        afterTommorow: 'pasado mañana',\n        afterWeek: 'en una semana más',\n        nextSun: 'el domingo',\n        nextMon: 'el lunes',\n        nextTue: 'el martes',\n        nextWed: 'el miércoles',\n        nextThu: 'el jueves',\n        nextFri: 'el viernes',\n        nextSat: 'el sábado',\n        willOpen: 'se abrirá',\n        willClose: 'se cerrará',\n        isOpen: 'Abierto',\n        openTill: 'Abierto hasta ',\n        closeIn: 'Se cerrará dentro de ',\n        openAt: 'Se abrirá el ',\n        openIn: 'Se abrirá dentro de ',\n        open: 'Se abrirá ',\n        nHours: ['hora', 'horas', 'horas'],\n        nMins: ['minuto', 'minutos', 'minutos'],\n        lunch: 'hora de colación',\n        Lunch: 'Hora de colación. ',\n        workingDays: 'Días laborables',\n        weekdays: 'Días laborables',\n        restDay: ['cerrado','cerrado'],\n        reviewsOnFlamp: 'Comentarios en Flamp',\n        writeReviewOnFlamp: 'Escribir un comentario en Flamp',\n        payment: 'pago',\n        everyday: 'Cada día desde',\n        worksAroundTheClock: 'Abierto las 24 horas',\n        aroundTheClock: '24 horas',\n        knowMore: 'para saber más',\n        toClose: 'hasta el cierre',\n        monday: 'lunes',\n        tuesday: 'martes',\n        wednesday: 'miércoles',\n        thursday: 'jueves',\n        friday: 'viernes',\n        saturday: 'sábado',\n        sunday: 'domingo',\n        mon: 'lun',\n        tue: 'mar',\n        wed: 'mié',\n        thu: 'jue',\n        fri: 'vie',\n        sat: 'sáb',\n        sun: 'dom',\n        toLunch: 'antes de la hora de colación',\n        today: 'Hoy',\n        lessThenHour: 'menos de una hora',\n        youCouldLate: 'puede ser que no alcanzas a llegar',\n        workingTime: 'horario de trabajo',\n        showAllOrgInRubric: 'Mostrar todas las empresas de la categoría',\n        todayIsRestDay: 'Hoy cerrado',\n        internet: 'Pago por Internet',\n        noncash: 'Pago sin efectivo',\n        goldcrown: 'Zolotaya Korona',\n        dinersclub: 'Diners Club',\n        mastercard: 'Mastercard',\n        maestrocard: 'MaestroCard',\n        visa: 'Visa',\n        cash: 'Pago en efectivo',\n        americanexpress: 'American Express',\n        hour : 'hora',\n        less: 'menos de',\n        _in : 'Dentro de',\n        isClosingOnDinner : 'se cierra por hora de colación'\n    }\n};\n"
  },
  {
    "path": "vendors/firmcard/src/FirmCard.DataHelper.js",
    "content": "FirmCard.DataHelper = {\n\tpayMethods : [\n\t\t'americanexpress',\n\t\t'cash',\n\t\t'dinersclub',\n\t\t'goldcrown',\n\t\t'internet',\n\t\t'mastercard',\n\t\t'noncash',\n\t\t'visa'\n\t],\n\n\t_msgs : {},\n\n\tgetFlampUrl : function (id) {\n\t    return DG.config.flampUrl.concat(id, '?', DG.config.flampGoogleAnalytics);\n\t},\n\n\tmsg : function (msg) {\n\t\tif (this._msgs.hasOwnProperty(msg)) {\n\t\t\treturn this._msgs[msg];\n\t\t}\n\t\tconsole && console.log(\"Cant't find translation for '\" + msg + \"'.\");\n\t\treturn msg.toString().replace('_', ' ');\n\t},\n\n\tgetProjectTime: function (timezoneOffset, time) {\n        var now, utc;\n\n        if (time) {\n            now = new Date(time);\n        } else {\n            now = new Date();\n        }\n\n        if (timezoneOffset) {\n            utc = now.getTime() + (now.getTimezoneOffset() * 60000);\n            return new Date(utc + (60000 * timezoneOffset));\n        } else {\n            return now;\n        }\n    }\n};\n"
  },
  {
    "path": "vendors/firmcard/src/FirmCard.js",
    "content": "var FirmCard = function (firm, options) {\n    this._setOptions(options);\n    this._firmContentObject = {};\n    this._schedule = new FirmCard.Schedule({\n        localLang: this.options.lang,\n        dict: this.dict\n    });\n\n    this.render(firm);\n};\n\nFirmCard.prototype = {\n\n    render: function (firmId) {\n        if (!firmId) { return; }\n\n        if (firmId !== this._firmId) {\n            this._firmContentObject = {};\n            this._renderCardById(firmId);\n        } else {\n            this._toggleEventHandlers();\n        }\n\n        return this._firmContentObject;\n    },\n\n    getSchedule: function () {\n        return this._schedule;\n    },\n\n    getContainer: function () {\n        return this._container;\n    },\n\n    _renderCardById: function (firmId) {\n        var self = this;\n\n        this.options.ajax(firmId).then(function (res) {\n            if (!res) { return false; }\n            var data = res.result.items;\n            if (data !== 'undefined') {\n                self._firmData = data[0];\n\n                // Support for old WebAPI format.\n                // TODO: remove this call after WebAPI release\n                self._convertWebsite();\n\n                self._firmId = firmId;\n                self._renderFirmCard();\n                self._toggleEventHandlers();\n            }\n        }, function (error) {\n            self._renderError();\n        });\n    },\n\n    _createFirmContainer: function () {\n        var firm = document.createElement('div');\n        firm.setAttribute('id', 'dg-map-firm-full-' + this._firmId);\n        firm.setAttribute('class', 'dg-map-firm-full');\n\n        return firm;\n    },\n\n    _getPaymentTypes: function (data) {\n        var result = [],\n            groupName = 'general_payment_type';\n\n        if (!data.attribute_groups) {\n            return result;\n        }\n\n        data.attribute_groups.forEach(function (group) {\n            if (group.name) {\n                return;\n            }\n\n            group.attributes.forEach(function (attr) {\n                if (attr.tag.substring(0, groupName.length) === groupName) {\n                    result.push(attr.name);\n                }\n            });\n        });\n\n        return result;\n    },\n\n    _groupRubrics: function (data) {\n        var result = {\n            primary: [],\n            additional: []\n        };\n\n        if (!data.rubrics || !data.rubrics.length) {\n            return result;\n        }\n\n        data.rubrics.forEach(function (rubric) {\n            result[rubric.kind].push(rubric);\n        });\n\n        return result;\n    },\n\n    // Support for old WebAPI format.\n    // TODO: remove this function after WebAPI release\n    _convertWebsite: function () {\n        if (!this._firmData.contact_groups) {\n            return;\n        }\n\n        this._firmData.contact_groups.forEach(function (group) {\n            if (!group.contacts) {\n                return;\n            }\n\n            group.contacts.forEach(function (contact) {\n                if (contact.type != 'website') {\n                    return;\n                }\n\n                if (!contact.url) {\n                    contact.url = contact.value;\n                }\n            });\n        });\n    },\n\n    _renderFirmCard: function () {\n        var firmCardBody, schedule, forecast, links, btns, paymentTypes, rubrics,\n            data = this._firmData,\n            container = this._container = this._createFirmContainer();\n\n        schedule = this._schedule.transform(data.schedule, {\n            zoneOffset: this.options.timezoneOffset,\n            apiLang: this.options.lang,\n            localLang: this.options.lang\n        });\n\n        forecast = this._schedule.forecast(schedule);\n\n        paymentTypes = this._getPaymentTypes(data);\n        rubrics = this._groupRubrics(data);\n\n        firmCardBody = this._buildFirmCardBody(\n            this._getConfigFirmCardBody(data, schedule, forecast, paymentTypes, rubrics)\n        );\n\n        links = this._fillHeaderLinks();\n        btns = this._fillFooterButtons();\n\n        //fill object for view render\n        this._firmContentObject.header = this.options.render('firmCardHeader', {'firmName': data.name, 'links': links});\n        container.innerHTML = firmCardBody;\n        this._firmContentObject.tmpl = container;\n        if (btns.length) {\n            this._footerContainer = document.createElement('div');\n\n            this._footerContainer.innerHTML = this.options.render('popupFooterBtns', {'btns': btns});\n            this._firmContentObject.footer = this._footerContainer;\n        }\n\n        if (this.options.onFirmReady) {\n            this.options.onFirmReady(this._firmContentObject);\n        }\n    },\n\n    _renderError: function() {\n        this._firmContentObject.header = this.options.render('popupHeader', {\n            title: this.options.t('apiErrorTitle')\n        });\n\n        this._firmContentObject.tmpl = this.options.t('apiErrorBody');\n\n        if (this.options.onFirmReady) {\n            this.options.onFirmReady(this._firmContentObject);\n        }\n    },\n\n    _getConfigFirmCardBody: function (data, schedule, forecast, attributes, rubrics) {\n        return [\n            {\n                tmpl: 'firmCardAddr',\n                data: {\n                    address: data.address_name,\n                    comment: data.address_comment\n                }\n            },\n            {\n                tmpl: 'firmCardContacts',\n                data: {\n                    groups: data.contact_groups\n                }\n            },\n            {\n                tmpl: 'firmCardSchedule',\n                data: {\n                    schedule: schedule,\n                    forecast: forecast\n                }\n            },\n            {\n                tmpl: 'frimCardPayments',\n                data: {\n                    payments: attributes\n                }\n            },\n            {\n                tmpl: 'firmCardRubric',\n                data: {\n                    rubrics: rubrics\n                }\n            }\n        ];\n    },\n\n    _buildFirmCardBody: function (parts) {\n        var self = this;\n        return parts.reduce(function (body, item) {\n            var html = self.options.render(item.tmpl, item.data);\n            return body + html;\n        }, '');\n    },\n\n    _fillFooterButtons: function () {\n        var btns = [];\n\n        if (this.options.backBtn) {\n            btns.push({ name: 'firm-card-back',\n                        label: this.dict.t(this.options.lang, 'btnBack'),\n                        icon: true\n            });\n        }\n\n        if (this.options.showRouteSearch) {\n            btns.push({ name: 'goto',\n                        label: this.dict.t(this.options.lang, 'btnFindWay'),\n                        icon: true,\n                        href: this.options.gotoUrl\n            });\n        }\n\n        if (\n            this._firmData.links &&\n                this._firmData.links.entrances &&\n                this.options.showEntrance\n        ) {\n            btns.push({ name: 'show-entrance',\n                        label: this.dict.t(this.options.lang, 'btnEntrance'),\n                        icon: true\n            });\n        }\n\n        return btns;\n    },\n\n    _fillHeaderLinks: function () {\n        var links = [],\n            reviewData = this._firmData.reviews,\n            booklet,\n            link;\n\n        if (this._firmData.external_content) {\n            this._firmData.external_content.forEach(function (el) {\n                if (el && el.type == 'booklet') {\n                    booklet = el;\n                }\n            });\n        }\n\n        if (reviewData && reviewData.is_reviewable) {\n            links.push({\n                name: 'flamp_stars',\n                width: reviewData.rating * 20\n            });\n            links.push({\n                name: 'flamp_reviews',\n                label: this.dict.t(this.options.lang, 'linkReviews', reviewData.review_count ? reviewData.review_count : 0),\n                href: FirmCard.DataHelper.getFlampUrl(this._firmId)\n            });\n        }\n\n        // Retrieve photo data from external content block\n        var photos;\n        var externalContent = this._firmData.external_content;\n\n        for (var i = 0; i < externalContent.length; i++) {\n            if (\n                externalContent[i].type == 'photo_album' &&\n                externalContent[i].subtype == 'common'\n            ) {\n                photos = externalContent[i];\n                break;\n            }\n        }\n\n        if (!this.options.isMobile && photos && photos.count && this.options.showPhotos) {\n            link = L.Util.template(DG.config.photosLink, {\n                'id': this._firmId,\n                'domain': this.options.domain\n            });\n\n            links.push({name: 'photos',\n                href: link,\n                label: this.dict.t(this.options.lang, 'linkPhoto', photos.count)\n            });\n        }\n\n        if (!this.options.isMobile && booklet && booklet.url && this.options.showBooklet) {\n            links.push({\n                name: 'booklet',\n                href:  booklet.url,\n                label: this.dict.t(this.options.lang, 'linkBooklet')\n            });\n        }\n\n\n        return links;\n    },\n\n    _events: {\n        'dg-popup__button_name_firm-card-back': function() {\n            this.options.backBtn();\n            this._toggleEventHandlers(true);\n        },\n        'dg-popup__button_name_show-entrance': function() {\n            var ent = new this.options.showEntrance({'vectors': this._firmData.links.entrances[0].geometry.vectors});\n            ent.addTo(this.options.map);\n            ent.fitBounds();\n            this._toggleEventHandlers(true);\n        },\n        'dg-schedule__today': function() {\n            this._onToggleSchedule();\n        }\n    },\n\n    _toggleEventHandlers: function (flag) {\n        this.options.popup[flag ? 'off' : 'on']('click', this._onClick, this);\n        this.options.map[flag ? 'off' : 'on']('popupclose', this._onClose, this);\n    },\n\n    _onClick: function (e) {\n        var target = e.originalEvent.target;\n\n        for (var eventClass in this._events) {\n            if (this._events.hasOwnProperty(eventClass) && target.className.indexOf(eventClass) > -1) {\n                DG.DomEvent.preventDefault(e.originalEvent);\n                this._events[eventClass].call(this, target);\n                return;\n            }\n        }\n    },\n\n    _onClose: function (e) {\n        this._toggleEventHandlers(true);\n    },\n\n    _onToggleSchedule: function () {\n        var schedule = this._container.querySelector('.dg-schedule__table'),\n            forecast = this._container.querySelector('.dg-schedule__now'),\n            target = this._container.querySelector('.dg-schedule__today'),\n            showClass = ' dg-schedule__today_shown_true';\n\n        if (!schedule) { return; }\n\n        if (schedule.style.display === 'block') {\n            schedule.style.display = 'none';\n            forecast.style.display = 'block';\n            target.className = target.className.replace(showClass, '');\n        } else {\n            forecast.style.display = 'none';\n            schedule.style.display = 'block';\n            target.className += showClass;\n        }\n\n        if (this.options.onToggle) {\n            this.options.onToggle();\n        }\n    },\n\n    _setOptions: function (options) {\n        var option,\n            options = options || {};\n\n        this.options = options;\n        options.lang = options.lang || 'ru';\n\n        for (option in options) {\n            if (options.hasOwnProperty(option)) {\n                this.options[option] = options[option];\n            }\n        }\n    },\n\n    _hasTouch: function () {\n        return (('ontouchstart' in window) ||\n                (navigator.maxTouchPoints > 0) ||\n                (navigator.msMaxTouchPoints > 0));\n    }\n};\n"
  },
  {
    "path": "vendors/firmcard/src/FirmList.js",
    "content": "/* global\n    FirmCard: false\n*/\n(function () {\n    FirmCard.List = function (firms, options) {\n        this._firms = {}; // {'firmID': firmDomObj}\n        this._setOptions(options);\n\n        this._container = options && options.container || document.createElement('ul');\n        this._container.setAttribute('class', 'dg-building-callout__list');\n\n        this._eventHandlersInited = false;\n        this._firmCard = this._createFirm();\n        this.renderList(firms);\n    };\n\n    FirmCard.List.prototype = {\n\n        renderList: function (firms) {\n            if (firms) {\n                this._toggleEventHandlers();\n                this.addFirms(firms);\n            }\n            if (this.options.onListReady) {\n                this.options.onListReady(this._container);\n            }\n\n            return this._container;\n        },\n\n        _processFirms: function (firms, action) {\n            if (!firms) { return; }\n            var method = '_' + action + 'Firm';\n            if (this._isArray(firms)) {\n                for (var i = 0, l = firms.length; i < l; i++) {\n                    this[method](firms[i]);\n                }\n            } else {\n                this[method](firms);\n            }\n\n        },\n\n        addFirms: function(firms) {\n            this._processFirms(firms, 'add');\n        },\n\n        removeFirms: function(firms) {\n            this._processFirms(firms, 'remove');\n        },\n\n        setLang: function (newLang) {\n            this.options.firmCard.lang = newLang;\n        },\n\n        getLang: function () {\n            return this.options.firmCard.lang;\n        },\n\n        getContainer: function () {\n            return this._container;\n        },\n\n        clearList : function () {\n            this._firms = {};\n            this._toggleEventHandlers(true);\n            this._clearContainer();\n        },\n\n        _removeFirm: function (id) {\n            if (!this._firms[id]) { return false; }\n            this._container.removeChild(this._firms[id]);\n            delete this._firms[id];\n        },\n\n        _addFirm: function (firmData) {\n            var tmpl = this.options.firmlistItemTmpl,\n                domFirm, firm, content;\n\n            firm = {\n                name: firmData.name,\n                id: firmData.id.split('_').slice(0, 1)\n            };\n\n            if (!(firm.id in this._firms)) {\n\n                domFirm = this._createListItem();\n\n                content = tmpl ? this.options.firmCard.render(tmpl, {'firm': firm}) : firm.name;\n\n                domFirm.insertAdjacentHTML('beforeend', content);\n\n                this._firms[firm.id] = domFirm;\n                this._container.appendChild(domFirm);\n            }\n        },\n\n        _createListItem: function () {\n            var item = document.createElement('li');\n            item.setAttribute('class', 'dg-building-callout__list-item');\n\n            return item;\n        },\n\n        _isArray: function (obj) {\n            return {}.toString.call(obj) === '[object Array]';\n        },\n\n        _createFirm: function (firmData) {\n            return new FirmCard(firmData, this.options.firmCard);\n        },\n\n        _isEmptyObj: function (obj) {\n            for (var prop in obj) {\n                if (obj.hasOwnProperty(prop)) {\n                    return false;\n                }\n            }\n\n            return true;\n        },\n\n        _events: {\n            'dg-popup__link': function(target) {\n                var s = this._firmCard.render(target.id);\n\n                this.options.firmCard[this._isEmptyObj(s) ? 'pasteLoader' : 'onFirmReady'](s);\n\n                this.options.firmCard.onFirmClick && this.options.firmCard.onFirmClick();\n\n                this._toggleEventHandlers(true);\n            },\n            'dg-building-callout__list-item': function(target) {\n                target = target.children[0];\n\n                this._events['dg-popup__link'].call(this, target);\n            },\n            'dg-popup__button_name_back': function() {\n                this.options.firmCard.onShowLess();\n\n                this._toggleEventHandlers(true);\n            }\n        },\n\n        _toggleEventHandlers : function (flag) {\n            this.options.firmCard.popup[flag ? 'off' : 'on']('click', this._onClick, this);\n        },\n\n        _onClick: function (e) {\n            var target = e.originalEvent.target;\n\n            for (var eventClass in this._events) {\n                if (this._events.hasOwnProperty(eventClass) && target.className.indexOf(eventClass) > -1) {\n                    DG.DomEvent.preventDefault(e.originalEvent);\n                    this._events[eventClass].call(this, target);\n                    return;\n                }\n            }\n        },\n\n        _clearContainer: function () {\n            var container = this._container;\n\n            while (container.hasChildNodes()) {\n                container.removeChild(container.firstChild);\n            }\n        },\n\n        _setOptions: function (options) {\n            options || (options = {});\n            this.options = options;\n            this.options.firmCard || (this.options.firmCard = {});\n\n            if (!options.firmCard.lang) {\n                this.options.firmCard.lang = 'ru';\n            }\n\n            for (var option in options) {\n                if (options.hasOwnProperty(option)) {\n                    this.options[option] = options[option];\n                }\n            }\n        }\n    };\n})();\n"
  },
  {
    "path": "vendors/firmcard/src/Schedule.js",
    "content": "/*global\n    FirmCard:false\n*/\nFirmCard.Schedule = function (options) {\n    options = options || {};\n\n    this.localLang = options.localLang || 'ru';\n    this.dict = options.dict;\n    return this;\n};\n\nFirmCard.Schedule.prototype = {\n\n    setLang: function (lang) {\n        this.localLang = lang || 'ru';\n        return this;\n    },\n\n    transform: function (model, params) {\n        if (!model) {\n            return;\n        }\n        params = params || {};\n\n        function bind(fn, obj) { // (Function, Object) -> Function\n            var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;\n            return function () {\n                return fn.apply(obj, args || arguments);\n            };\n        }\n\n        var todayKey, // Mon, Tue ...\n            today, // Объект модели - текущий день недели\n            from, // Самое раннее время открытия за день\n            to, // Самое позднее время закрытия за день\n            zoneOffset = params.zoneOffset || 0,\n            schedule = {}, // Объект-расписание, формируемый под шаблон\n            now = params.now || FirmCard.DataHelper.getProjectTime(zoneOffset).getTime(), // Current timestamp in milliseconds\n            weekKeys = [], // Ключи дней недели, определяют порядок дней и первый день недели. 0 - первый день недели в регионе (не обязательно Mon)\n            weekKeysLocal = [],\n            weekFullKeysLocal = [],\n            weekKeysShort =  [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ],\n            weekKeysFull = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'],\n            localLang = params.localLang || this.localLang,\n            localWorkingDays = params.localWorkingDays || [0, 1, 1, 1, 1, 1, 0],\n            firstdayOffset = params.firstdayOffset || 1,\n            minHoursToDisplayClosure = params.minHoursToDisplayClosure || 4,\n            t = bind(this.dict.t, this.dict);\n\n\n        function capitaliseFirstLetter(string) {\n            return string.charAt(0).toUpperCase() + string.slice(1);\n        }\n\n        function getHours(str) {\n            return str.substr(0, 2);\n        }\n\n        function getMinutes(str) {\n            return str.substr(3, 2);\n        }\n\n        // Конвертация временной точки формата апи в формат отображения (25:00 -> 01:00)\n        function formatTime(str) {\n            var hours = +getHours(str) % 24 + '';\n\n            if (hours.length === 1) {\n                hours = '0' + hours;\n            }\n\n            return hours + ':' + getMinutes(str);\n        }\n\n        // Конвертация int числа в номер дня недели (диапазон 0-6)\n        // отрицательные чила: -1 вернёт 6, -2 -> 5 и т.д\n        // положительные: 7 -> 0, 8 -> 1\n        function dayNum(n) {\n            return (n + 70) % 7;\n        }\n\n\n        /* jshint ignore:start */\n        // Возвращает последний элемент массива\n        // Взято из Underscore.js http://underscorejs.org/#last\n        function getArrayLast(arr, n) {\n            if ( arr == null ) return void 0;\n            if (   n == null ) return arr[ arr.length - 1 ];\n            return slice.call( arr, Math.max(arr.length - n , 0) );\n        }\n\n\n        // Выполняет глубокое сравнение объектов\n        // Взято из Underscore.js http://underscorejs.org/#isEqual\n        // Упрощено для тех трёх сравнений, которые выполняются в Shedule.js\n        function isEqual(obj1, obj2) {\n            if ( obj1 === obj2 ) return true;\n            if ( ! ( obj1 instanceof Object ) || ! ( obj2 instanceof Object ) ) return false;\n            if ( obj1.constructor !== obj2.constructor ) return false;\n            for ( var prop in obj1 ) {\n                if ( ! obj1.hasOwnProperty( prop ) ) continue;\n                if ( ! obj2.hasOwnProperty( prop ) ) return false;\n                if ( obj1[ prop ] === obj2[ prop ] ) continue;\n                if ( typeof( obj1[ prop ] ) !== \"object\" ) return false;\n                if ( ! isEqual( obj1[ prop ],  obj2[ prop ] ) ) return false;\n            }\n            for ( prop in obj2 ) {\n            if ( obj2.hasOwnProperty( prop ) && ! obj1.hasOwnProperty( prop ) ) return false;\n            }\n\n            return true;\n        }\n\n        // Generate an integer Array containing an arithmetic progression. A port of\n        // the native Python `range()` function. See\n        // [the Python documentation](http://docs.python.org/library/functions.html#range).\n        function range(start, stop, step) {\n        if (arguments.length <= 1) {\n            stop = start || 0;\n            start = 0;\n        }\n        step = arguments[2] || 1;\n\n        var length = Math.max(Math.ceil((stop - start) / step), 0);\n        var idx = 0;\n        var range = new Array(length);\n        while(idx < length) {\n            range[idx++] = start;\n            start += step;\n        }\n\n        return range;\n        }\n\n\n        //Заполняет свойства объекта значениями по умолчанию\n        //Взято из Underscore.js http://underscorejs.org/#defaults\n        function fillDefaults(obj) {\n         var args = Array.prototype.slice.call(arguments, 1);\n         args.forEach(function(source) {\n            if (source) {\n                for (var prop in source) {\n                    if (obj[prop] === void 0) obj[prop] = source[prop];\n                }\n            }\n        });\n        return obj;\n        }\n\n        //Сортирует значения согласно с итератором\n        //Взято с Underscore.js http://underscorejs.org/#sortBy\n        function sortBy(obj, iterator){\n            return pluck(obj.map( function(value, index, list) {\n                return {\n                        value: value,\n                        index: index,\n                        criteria: iterator.call(this, value, index, list)\n                        };\n                }).sort(function(left, right) {\n                        var a = left.criteria;\n                        var b = right.criteria;\n                        if (a !== b) {\n                        if (a > b || a === void 0) return 1;\n                        if (a < b || b === void 0) return -1;\n                        }\n                return left.index - right.index;\n                }), 'value');\n        }\n\n        /* jshint ignore:end */\n\n        function pluck(arr, key){\n            var i, rv = [];\n            for (i = 0; i < arr.length; ++i) {\n            rv[i] = arr[i][key];\n            }\n            return rv;\n        }\n\n\n        // Преобразовать расписание на день в упорядоченный массив временных отсечек (string)\n        // Сейчас полагается, что API уже выдаёт сортированный массив\n        function getSortedTimePoints(day) {\n            var points = [],\n                from, to,\n                deltaHours, deltaMinutes;\n\n            if (!day || !day.working_hours) {\n                return [];\n            }\n\n            for (var i = 0 ; i < day.working_hours.length ; i++) {\n                from = day.working_hours[i].from;\n                to = day.working_hours[i].to;\n\n                deltaHours = getHours(to) - getHours(from);\n                deltaMinutes = getMinutes(to) - getMinutes(from);\n                if (deltaHours < 0 || (deltaHours === 0 && deltaMinutes <= 0)) { // Если \"до\" меньше или равно \"от\" - значит указывает на завтра\n                    to = (+getHours(to) + 24) + ':' + getMinutes(to); // (01:00 -> 25:00)\n                }\n\n                points[i * 2] = {\n                    time: from,\n                    type: 'open'\n                };\n                points[i * 2 + 1] = {\n                    time: to,\n                    type: day.working_hours.length - 1 === i ? 'close' : 'lunch'\n                };\n            }\n\n            return points;\n        }\n\n        // Возвращает массив timestamp всех точек, всех дней недели, от сегодняшнего и в будущее\n        // Например, сегодня среда, отсечки будут взяты для дат со среды (сегодня) по следующий вторник включительно\n        function getTimeStamps(model) {\n            var timestamps = [],\n                out = [],\n                timePoints,\n                num = weekKeys.indexOf(todayKey); // Номер сегодняшнего дня недели (для данного региона)\n\n\n            // Цикл по дням недели начиная с сегодняшнего\n            var j; // Номер текущего дня в массиве weekKeys\n            for (var i = 0 ; i < 7 ; i++) {\n                j = dayNum(num + i);\n                timePoints = getSortedTimePoints(model[weekKeys[j]]);\n                // Цикл по точкам времени с конвертацией в timestamp\n                timePoints.forEach(\n                    /* jshint -W083 */\n                    function (point) {\n                    // now - обязательно! иначе будет браться текущий timestamp что чревато несовпадениями при медленном быстродействии\n                    // Вычислить таймстемп для данного дня недели, часа и минуты, в будущем, но ближайший к now\n                    var tsp = new Date(now);\n                    tsp.setDate(tsp.getDate()+i);\n                    tsp.setHours(getHours(point.time));\n                    tsp.setMinutes(getMinutes(point.time));\n                    var ts = tsp.getTime();\n\n\n\n                    timestamps.push({\n                        ts: ts,\n                        type: point.type\n                    });\n\n                    if (timestamps[timestamps.length - 1] && timestamps[timestamps.length - 2]) {\n                        // Парно удаляем совпадающие точки (они не имеют смысла - это сегодня 24:00 и завтра 00:00)\n                        if (timestamps[timestamps.length - 1].ts === timestamps[timestamps.length - 2].ts) {\n                            timestamps.pop();\n                            timestamps.pop();\n                        }\n                    }\n\n                    if (timestamps[timestamps.length - 1] && timestamps[timestamps.length - 2]) {\n                        // Парно переносим точки в будущее, если они обе в прошлом (первая точка ([0]) должна быть всегда открытием!)\n                        if (timestamps[timestamps.length - 1].ts <= now && timestamps[timestamps.length - 2].ts <= now) {\n                            timestamps[timestamps.length - 1].ts += (7 * 24 * 60 * 60 * 1000);\n                            timestamps[timestamps.length - 2].ts += (7 * 24 * 60 * 60 * 1000);\n                        }\n                    }\n                }\n                /* jshint +W083 */\n                );\n            }\n\n            // Сортируем на возрастание, ведь возможно были переносы в будущее\n            timestamps = sortBy(timestamps, function (timestamp) { return timestamp.ts; });\n\n            // Удаляем попарно совпадающие точки времени\n            i = 0;\n            while (i < timestamps.length) {\n                if (timestamps[i + 1] && timestamps[i].ts === timestamps[i + 1].ts) {\n                    i++;\n                } else {\n                    out.push(timestamps[i].ts);\n                }\n                i++;\n            }\n\n            // Проверка на ежедневно-круглосуточность\n            if (out.length === 2 && (out[1] - out[0]) === (7 * 24 * 60 * 60 * 1000)) {\n                return [];\n            }\n\n            return timestamps;\n        }\n\n        function whenOpenInverse(h, d, num) {\n            if (d === 1 && h > minHoursToDisplayClosure ) {\n                return t(localLang, 'tommorow');\n            } else if (d > 1) {\n                /* jshint -W015 */\n                switch (num) {\n                    case 0: return t(localLang, 'nextSun');\n                    case 1: return t(localLang, 'nextMon');\n                    case 2: return t(localLang, 'nextTue');\n                    case 3: return t(localLang, 'nextWed');\n                    case 4: return t(localLang, 'nextThu');\n                    case 5: return t(localLang, 'nextFri');\n                    case 6: return t(localLang, 'nextSat');\n                }\n                /* jshint +W015 */\n            }\n\n            return;\n        }\n\n\n        //Возвращает интервал в целых днях, с поправкой на смену дня в полночь, между\n        // @param timestampEnd и @param dateStart\n        function dayInterval(timestampEnd, dateStart) {\n\n            var oneDay = 1000 * 60 * 60 * 24,\n                dateEnd = new Date(timestampEnd.ts);\n\n            var diff;\n\n            diff = Math.round((dateEnd - dateStart) / oneDay);\n\n            if( timestampEnd.type==='open' && dateEnd.getHours() < 1 )\n                { diff ++; }\n\n            return diff;\n        }\n\n\n        // Поместить данные в объект для шаблона о сегодняшнем дне\n        function setTodayString(today) {\n\n            var timePoints,\n                periods = [],\n                timestamps;\n\n            schedule.now = {};\n\n            // Timestamps всех отсечек\n            timestamps = getTimeStamps(model);\n\n            if (!timestamps.length) {\n                schedule.always = true; // Работает ежедневно круглосуточно\n                schedule.now.open = true;\n            }\n\n\n            for (var i = 0 ; i < timestamps.length ; i++) {\n                // Попали между точками i-1 и i // Мы находимся заведомо в будущем относительно 1\n                if (now >= (timestamps[i - 1] && timestamps[i - 1].ts || 0) && now < timestamps[i].ts) {\n                    var h = Math.floor((timestamps[i].ts - now) / (1000 * 60 * 60)), // Количество часов до следующего timestamp\n                        m = Math.floor((timestamps[i].ts - now) / (1000 * 60) - h * 60), // Количество минут (без часов) до следующего timestamp\n                        dayNow = new Date(now),\n\n                        // открыто если следующая итерация не открытие\n                        nowIsOpen = timestamps[i].type !== 'open';\n\n                        //var d = dayOfYear(dayTs) - dayOfYear(dayNow);\n                        //var d = dayInterval(dayTs, dayNow, nowIsOpen);\n                        var d = dayInterval(timestamps[i], dayNow);\n\n\n\n                    // округляем минуты до кратных 5\n                    m = Math.floor(m / 10) * 10 ? Math.floor(m / 10) * 10 : 5;\n\n                    schedule.now.open = nowIsOpen;\n                    schedule.now.lunch = !!(timestamps[i - 1] && timestamps[i - 1].type === 'lunch' || getArrayLast(timestamps).type === 'lunch');\n\n                    schedule.will = {\n                        willType: timestamps[i].type,\n                        d: d,\n                        h: h,\n                        m: m\n                    };\n\n                    // Когда закроется или откроется\n                    var willWhen = new Date(timestamps[i].ts);\n                    schedule.will.when = whenOpenInverse(h, d, willWhen.getDay());\n\n\n                    var willTill = new Date(timestamps[i].ts),\n                        strHours = willTill.getHours(),\n                        strMinutes = willTill.getMinutes();\n\n                    if (strHours < 10) { strHours = '0' + strHours; }\n                    if (strMinutes < 10) { strMinutes = '0' + strMinutes; }\n\n                    schedule.will.till = strHours+':'+strMinutes;\n                }\n            }\n\n            if (!today) {\n                return; // На сегодня расписания нет - сейчас закрыто\n            }\n\n            timePoints = pluck(getSortedTimePoints(today), 'time');\n\n            // Цикл по периодам работы за день\n            for (i = 2 ; i < timePoints.length ; i = i + 2) {\n                periods.push({ from: timePoints[i - 1], to: timePoints[i] });\n            }\n\n            from = formatTime(timePoints[0]);\n            to = formatTime(timePoints[timePoints.length - 1]);\n\n            if (from === to) { // Круглосуточно\n                schedule.today = {\n                    alltime: true,\n                    alltimeStr: t(localLang, 'worksAroundTheClock'),\n                    from: '00:00',\n                    to: '24:00'\n                };\n            } else { // От from до to\n                schedule.today = {\n                    from: from,\n                    to: to\n                };\n            }\n\n            if (periods.length > 0) { // Перерывы на обед\n                schedule.lunch = periods;\n                schedule.lunchStr = t(localLang, 'lunch');\n            }\n        }\n\n        // Формирование объекта-таблицы-расписания для шаблона\n        function makeTable() {\n            var column = [],\n                hasLunch = false;\n\n            for (var j = 0 ; j < 7 ; j++) {\n                var dayKey = weekKeys[j],\n                    lunchMaxLength = 0;\n\n                column[j] = {};\n\n                if (model[dayKey]) {\n                    var day = model[dayKey],\n                        timePoints = pluck(getSortedTimePoints(day), 'time'),\n                        lunch = []; // Отрезки времени (отсортированные моменты) на обеды\n\n                    // Цикл по периодам работы за день\n                    for (var i = 2 ; i < timePoints.length ; i = i + 2) {\n                        hasLunch = true;\n                        lunch.push({ from: timePoints[i - 1], to: timePoints[i] });\n                    }\n                    lunchMaxLength = Math.max(timePoints.length / 2, lunchMaxLength);\n\n                    column[j] = {\n                        from: formatTime(timePoints[0]),\n                        to: formatTime(timePoints[timePoints.length - 1]),\n                        lunch: lunch\n                    };\n                }\n\n                if (dayKey === todayKey) { // Сегодняшний день надо подсветить\n                    column[j].active = true;\n                }\n\n                column[j].key = weekKeysLocal[j];\n            }\n\n            // Дополнение пустыми объектами массивов lunch\n            column.forEach( function (col) {\n                if (col.lunch) {\n                    fillDefaults(col.lunch, range(1, lunchMaxLength));\n                }\n            });\n\n            return {\n                table: column,\n                hasLunch: hasLunch\n            };\n        }\n\n        // Сгенерировать строку для всех дней model, совпадающих с day\n        function makeSimpleString(day, model) {\n            var points,\n                out = {\n                    dayList: [],\n                    lunch: []\n                },\n                lunchesTime = [];\n\n            if (day && day.working_hours && day.working_hours.length) {\n                points = pluck(getSortedTimePoints(day), 'time');\n                points.forEach( function (point, key) {\n                    if (key === 0) {\n                        out.from = formatTime(point);\n                    } else if (key === points.length - 1) {\n                        out.to = formatTime(point);\n                    } else {\n                        lunchesTime.push(formatTime(point));\n                    }\n                });\n                for (var i = 0; i < lunchesTime.length; i += 2) {\n                    out.lunch.push({\n                        from: lunchesTime[i],\n                        to: lunchesTime[i + 1],\n                        lunchStr: capitaliseFirstLetter(t(localLang, 'lunch'))\n                    });\n                }\n\n                if (out.from == '00:00' && out.to == '00:00') {\n                    out.to = '24:00';\n                }\n\n                if (day.round_the_clock) {\n                    out.alltime = true;\n                    out.alltimeStr = t(localLang, 'worksAroundTheClock');\n                }\n            } else { // Выходной\n                out.holiday = true;\n            }\n\n            // Формируем список дней на локальном языке\n            var groupWorkingDays = [0, 0, 0, 0, 0, 0, 0]; // Флаги работы фирмы в дни текущей группы\n            var flow = 0;\n\n            weekKeys.forEach( function (dayKey, numKey) { // 'Mon', 0\n                if (isEqual(model[dayKey], day) || (!model[dayKey] && day === null)) {\n                    out.dayList.push(weekFullKeysLocal[numKey]);\n                    groupWorkingDays[dayNum(numKey + firstdayOffset)] = 1;\n                    flow++;\n                } else {\n                    if (flow > 2) { // Более 2 дней подряд\n                        var lastDay = out.dayList.pop();\n\n                        for (var i = 1 ; i < flow - 1 ; i++) {\n                            out.dayList.pop();\n                        }\n\n                        out.dayList[out.dayList.length - 1] += ' — ' + lastDay;\n                    }\n\n                    flow = 0;\n                }\n            });\n\n            // Список дней в данной группе идентичен списку будних дней, значит можно заменить словом \"Будни\"\n            out.budni = isEqual(localWorkingDays, groupWorkingDays);\n            // Список рабочих дней - все дни недели, значит нужно выводить фразу \"Ежедневно\"\n            out.everyday = ( Math.min.apply(Math, groupWorkingDays) === 1 );\n\n            if ( out.holiday ) { out.holidayStr = t(localLang, 'restDay', out.dayList.length).slice(2); }\n\n            // Делаем из массива строку и поднимаем первый символ\n            out.dayList = out.dayList.join(', ');\n            out.dayList = out.dayList.charAt(0).toUpperCase() + out.dayList.slice(1);\n\n\n            return out;\n        }\n\n        // Возвращает массив simple строк на основе массива дней days\n        function makeAdvancedString(days, model) {\n            var out = [];\n\n            for (var i = days.length - 1 ; i >= 0 ; i--) {\n                out.push(makeSimpleString(days[i], model));\n            }\n\n            return out;\n        }\n\n        // Заполняем названия дней недели, 1 - понедельник. В заполненных массивах понедельник это 0\n\n        for (var i = 0 ; i < 7 ; i++) {\n            weekKeys[i] = weekKeysShort[i];\n            weekKeysLocal[i] = this.dict.t(localLang, weekKeysShort[i].toLowerCase());\n            weekFullKeysLocal[i] = this.dict.t(localLang, weekKeysFull[i]);\n        }\n\n        // Вычисляем сегодняшний день недели (ссылку на объект дня в модели)\n        todayKey = weekKeysShort[dayNum(new Date(now).getDay() - firstdayOffset)];\n        today = model[todayKey]; // Объект расписания - текущий день недели\n        setTodayString(today); // Сделать объект для шаблона - строка, которая описывает время работы сегодня\n\n        // Находим количество разных расписаний и сохраняем их в массив\n        var apiDifferentDays = [], // Массив различающихся дней из модели\n            apiScheduleDaysCount = 0, // Количество описанных дней в расписании модели\n            apiDifferentDaysCount = 0, // Количество разных дней в расписании модели\n            differentWorkingHoursCount = []; // Количество рабочих часов в разных днях\n\n        Object.keys(model).forEach( function(day) {\n            if (model[day] && model[day].working_hours) { // Проверяем что это день, а не комментарий или что-то ещё\n                apiScheduleDaysCount++;\n                if (!isEqual(model[day], getArrayLast(apiDifferentDays))) {\n                    apiDifferentDays.push(model[day]);\n                }\n            }\n        });\n\n        apiDifferentDaysCount = apiDifferentDays.length;\n        // Если не все дни описаны в модели, значит есть ещё один тип дней - выходной (отсутствущий в модели)\n        if (apiScheduleDaysCount < 7) {\n            apiDifferentDaysCount++;\n        }\n\n        // Если разных более 2, то упростить не получится - делаем таблицу\n        if (apiDifferentDaysCount > 2) {\n            schedule.week = makeTable(model);\n        } else { // Иначе, составляем комментарий из двух строк\n\n            // Случай, когда все одинаковые\n            if (apiDifferentDaysCount === 1) {\n                schedule.week = {\n                    evently: [makeSimpleString(model[weekKeys[0]], model)]\n                };\n            } else { // Остаётся случай, когда есть два типа дней\n                // Определяем день с наибольшим количеством рабочих часов из числа разных дней\n                for (i = 0 ; i < apiDifferentDaysCount ; i++) {\n                    differentWorkingHoursCount[i] = 0;\n\n                    if (apiDifferentDays[i]) {\n                        var points = pluck(getSortedTimePoints(apiDifferentDays[i]), 'time');\n\n                        for (var j = 0 ; j < points.length ; j = j + 2) {\n                            var hours = (getHours(points[j + 1]) + getMinutes(points[j + 1]) / 60) - (getHours(points[j]) + getMinutes(points[j]) / 60);\n                            differentWorkingHoursCount[i] += hours;\n                        }\n                    } else { // Выходной\n                        apiDifferentDays[i] = null;\n                    }\n                }\n\n                var apiSortedDifferentDays = sortBy(apiDifferentDays, function (day, key) {\n                    return differentWorkingHoursCount[key];\n                });\n\n                schedule.week = {\n                    evently: makeAdvancedString(apiSortedDifferentDays, model)\n                };\n            }\n        }\n\n        schedule.comment = model.comment;\n        if (schedule.week && schedule.week.evently && schedule.week.evently.length === 1) {\n            schedule.everyday = schedule.week.evently[0].everyday;\n        }\n        return schedule;\n    },\n\n    forecast: function (schedule, params) {\n        var interval = '',\n        open,\n        today = {},\n        nowText,\n        maxHours = params && params.maxHours || 1;\n\n        if (!schedule) {\n            return {};\n        }\n\n        if (schedule.always) { // Круглосуточно ежедневно - более ничего выводить не нужно\n            return {\n                today: {\n                    text: this.dict.t(this.localLang, 'aroundTheClock')\n                },\n                open: true\n            };\n        }\n\n        // Формируем строку - через сколько произойдёт следующая инверсия открытости\n        if (schedule.will && schedule.will.h < maxHours) {\n            if (schedule.will.h) {\n                interval += this.dict.t(this.localLang, 'nHours', schedule.will.h) + ' ';\n            }\n\n            if (schedule.will.m) {\n                interval += this.dict.t(this.localLang, 'nMins', schedule.will.m);\n            }\n        }\n\n        // Данные на сегодня\n        if (schedule.today) {\n            today.text = this.dict.t(this.localLang, 'today');\n            if (schedule.everyday) {\n                today.text = this.dict.t(this.localLang, 'everyday');\n            }\n            today.from = schedule.today.from;\n            today.to = schedule.today.to;\n            today.lunch = schedule.lunch;\n            if (today.lunch) {\n                today.lunchStr = this.dict.t(this.localLang, 'lunch');\n            }\n        } else {\n            today.text = this.dict.t(this.localLang, 'todayIsRestDay');\n        }\n\n        // Текущий статус и прогноз\n        if (schedule.always) { // Если круглосуточно, ничего кроме \"Круглосуточно\" выводить не нужно\n            today.text = this.dict.t(this.localLang, 'aroundTheClock');\n            open = true;\n        } else if (schedule.now) {\n            open = schedule.now.open;\n            if (open) { // открыто\n                if (schedule.will && schedule.will.willType === 'lunch') {\n                    // далее - закрытие на обед\n                    if (schedule.will && schedule.will.h < maxHours) {\n                        // менее maxHours до закрытия  на обед\n                        nowText = this.dict.t(this.localLang, '_in') + ' ' + this.dict.t(this.localLang, 'nMins', interval) + this.dict.t(this.localLang, 'isClosingOnDinner');\n                    } else {\n                        // больше maxHours до закрытия  на обед\n                        nowText = this.dict.t(this.localLang, 'isOpen');\n                    }\n\n                } else {\n                    // далее просто закрытие\n                    if (schedule.will.h < maxHours) {\n                        // менее maxHours до закрытия просто\n                        nowText = this.dict.t(this.localLang, 'closeIn') + this.dict.t(this.localLang, 'nMins', interval);\n                    } else {\n                        // больше maxHours до закрытия просто\n                        nowText = this.dict.t(this.localLang, 'isOpen');\n                    }\n                }\n            } else { // закрыто\n                if (schedule.will && schedule.will.when) {\n                    // откроется не сегодня\n                    nowText = this.dict.t(this.localLang, 'open') + schedule.will.when;\n                } else {\n                    // откроется сегодня\n                    if (schedule.now && schedule.now.lunch) {\n                        // сейчас обед\n                        if (schedule.will.h < maxHours) {\n                            // менее maxHours до открытия с обеда\n                            nowText = this.dict.t(this.localLang, 'Lunch') + this.dict.t(this.localLang, 'openIn') + this.dict.t(this.localLang, 'nMins', interval);\n                        } else {\n                            // больше maxHours до открытия с обеда\n                            nowText = this.dict.t(this.localLang, 'Lunch') + this.dict.t(this.localLang, 'openAt') + schedule.will.till;\n                        }\n                    } else {\n                        // просто закрыто\n                        if (schedule.will && schedule.will.h < maxHours) {\n                            // менее maxHours до открытия просто\n                            nowText = this.dict.t(this.localLang, 'openIn') + this.dict.t(this.localLang, 'nMins', interval);\n                        } else {\n                            // больше maxHours до открытия просто\n                            nowText = this.dict.t(this.localLang, 'openAt') + schedule.will.till;\n                        }\n                    }\n                }\n            }\n        }\n\n        return {\n            today: today,\n            now: nowText,\n            open: open,\n            week: schedule.week,\n            comment: schedule.comment,\n            everyday: schedule.everyday\n        };\n    }\n};\n"
  },
  {
    "path": "vendors/firmcard/src/vendors/momentjs/lang/moment.cs.js",
    "content": "// moment.js language configuration\n// language : czech (cs)\n// author : petrbela : https://github.com/petrbela\n!function(){function e(e){function t(e){return e>1&&5>e&&1!==~~(e/10)}function a(e,a,n,_){var s=e+\" \";switch(n){case\"s\":return a||_?\"p\\xe1r vte\\u0159in\":\"p\\xe1r vte\\u0159inami\";case\"m\":return a?\"minuta\":_?\"minutu\":\"minutou\";case\"mm\":return a||_?s+(t(e)?\"minuty\":\"minut\"):s+\"minutami\";break;case\"h\":return a?\"hodina\":_?\"hodinu\":\"hodinou\";case\"hh\":return a||_?s+(t(e)?\"hodiny\":\"hodin\"):s+\"hodinami\";break;case\"d\":return a||_?\"den\":\"dnem\";case\"dd\":return a||_?s+(t(e)?\"dny\":\"dn\\xed\"):s+\"dny\";break;case\"M\":return a||_?\"m\\u011bs\\xedc\":\"m\\u011bs\\xedcem\";case\"MM\":return a||_?s+(t(e)?\"m\\u011bs\\xedce\":\"m\\u011bs\\xedc\\u016f\"):s+\"m\\u011bs\\xedci\";break;case\"y\":return a||_?\"rok\":\"rokem\";case\"yy\":return a||_?s+(t(e)?\"roky\":\"let\"):s+\"lety\"}}var n=\"leden_\\xfanor_b\\u0159ezen_duben_kv\\u011bten_\\u010derven_\\u010dervenec_srpen_z\\xe1\\u0159\\xed_\\u0159\\xedjen_listopad_prosinec\".split(\"_\"),_=\"led_\\xfano_b\\u0159e_dub_kv\\u011b_\\u010dvn_\\u010dvc_srp_z\\xe1\\u0159_\\u0159\\xedj_lis_pro\".split(\"_\");e.lang(\"cs\",{months:n,monthsShort:_,monthsParse:function(e,t){var a,n=[];for(a=0;12>a;a++)n[a]=new RegExp(\"^\"+e[a]+\"$|^\"+t[a]+\"$\",\"i\");return n}(n,_),weekdays:\"ned\\u011ble_pond\\u011bl\\xed_\\xfater\\xfd_st\\u0159eda_\\u010dtvrtek_p\\xe1tek_sobota\".split(\"_\"),weekdaysShort:\"ne_po_\\xfat_st_\\u010dt_p\\xe1_so\".split(\"_\"),weekdaysMin:\"ne_po_\\xfat_st_\\u010dt_p\\xe1_so\".split(\"_\"),longDateFormat:{LT:\"H:mm\",L:\"DD.MM.YYYY\",LL:\"D. MMMM YYYY\",LLL:\"D. MMMM YYYY LT\",LLLL:\"dddd D. MMMM YYYY LT\"},calendar:{sameDay:\"[dnes v] LT\",nextDay:\"[z\\xedtra v] LT\",nextWeek:function(){switch(this.day()){case 0:return\"[v ned\\u011bli v] LT\";case 1:case 2:return\"[v] dddd [v] LT\";case 3:return\"[ve st\\u0159edu v] LT\";case 4:return\"[ve \\u010dtvrtek v] LT\";case 5:return\"[v p\\xe1tek v] LT\";case 6:return\"[v sobotu v] LT\"}},lastDay:\"[v\\u010dera v] LT\",lastWeek:function(){switch(this.day()){case 0:return\"[minulou ned\\u011bli v] LT\";case 1:case 2:return\"[minul\\xe9] dddd [v] LT\";case 3:return\"[minulou st\\u0159edu v] LT\";case 4:case 5:return\"[minul\\xfd] dddd [v] LT\";case 6:return\"[minulou sobotu v] LT\"}},sameElse:\"L\"},relativeTime:{future:\"za %s\",past:\"p\\u0159ed %s\",s:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},ordinal:\"%d.\",week:{dow:1,doy:4}})}\"function\"==typeof define&&define.amd&&define([\"moment\"],e),\"undefined\"!=typeof window&&window.moment&&e(window.moment)}();"
  },
  {
    "path": "vendors/firmcard/src/vendors/momentjs/lang/moment.it.js",
    "content": "// moment.js language configuration\n// language : italian (it)\n// author : Lorenzo : https://github.com/aliem\n// author: Mattia Larentis: https://github.com/nostalgiaz\n!function(){function e(e){e.lang(\"it\",{months:\"Gennaio_Febbraio_Marzo_Aprile_Maggio_Giugno_Luglio_Agosto_Settembre_Ottobre_Novembre_Dicembre\".split(\"_\"),monthsShort:\"Gen_Feb_Mar_Apr_Mag_Giu_Lug_Ago_Set_Ott_Nov_Dic\".split(\"_\"),weekdays:\"Domenica_Luned\\xec_Marted\\xec_Mercoled\\xec_Gioved\\xec_Venerd\\xec_Sabato\".split(\"_\"),weekdaysShort:\"Dom_Lun_Mar_Mer_Gio_Ven_Sab\".split(\"_\"),weekdaysMin:\"D_L_Ma_Me_G_V_S\".split(\"_\"),longDateFormat:{LT:\"HH:mm\",L:\"DD/MM/YYYY\",LL:\"D MMMM YYYY\",LLL:\"D MMMM YYYY LT\",LLLL:\"dddd, D MMMM YYYY LT\"},calendar:{sameDay:\"[Oggi alle] LT\",nextDay:\"[Domani alle] LT\",nextWeek:\"dddd [alle] LT\",lastDay:\"[Ieri alle] LT\",lastWeek:\"[lo scorso] dddd [alle] LT\",sameElse:\"L\"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?\"tra\":\"in\")+\" \"+e},past:\"%s fa\",s:\"secondi\",m:\"un minuto\",mm:\"%d minuti\",h:\"un'ora\",hh:\"%d ore\",d:\"un giorno\",dd:\"%d giorni\",M:\"un mese\",MM:\"%d mesi\",y:\"un anno\",yy:\"%d anni\"},ordinal:\"%d\\xba\",week:{dow:1,doy:4}})}\"function\"==typeof define&&define.amd&&define([\"moment\"],e),\"undefined\"!=typeof window&&window.moment&&e(window.moment)}();"
  },
  {
    "path": "vendors/firmcard/src/vendors/momentjs/lang/moment.ru.js",
    "content": "// moment.js language configuration\n// language : russian (ru)\n// author : Viktorminator : https://github.com/Viktorminator\n// Author : Menelion Elensúle : https://github.com/Oire\n!function(){function e(e){function t(e,t){var n=e.split(\"_\");return 1===t%10&&11!==t%100?n[0]:t%10>=2&&4>=t%10&&(10>t%100||t%100>=20)?n[1]:n[2]}function n(e,n,a){var _={mm:\"\\u043c\\u0438\\u043d\\u0443\\u0442\\u0430_\\u043c\\u0438\\u043d\\u0443\\u0442\\u044b_\\u043c\\u0438\\u043d\\u0443\\u0442\",hh:\"\\u0447\\u0430\\u0441_\\u0447\\u0430\\u0441\\u0430_\\u0447\\u0430\\u0441\\u043e\\u0432\",dd:\"\\u0434\\u0435\\u043d\\u044c_\\u0434\\u043d\\u044f_\\u0434\\u043d\\u0435\\u0439\",MM:\"\\u043c\\u0435\\u0441\\u044f\\u0446_\\u043c\\u0435\\u0441\\u044f\\u0446\\u0430_\\u043c\\u0435\\u0441\\u044f\\u0446\\u0435\\u0432\",yy:\"\\u0433\\u043e\\u0434_\\u0433\\u043e\\u0434\\u0430_\\u043b\\u0435\\u0442\"};return\"m\"===a?n?\"\\u043c\\u0438\\u043d\\u0443\\u0442\\u0430\":\"\\u043c\\u0438\\u043d\\u0443\\u0442\\u0443\":e+\" \"+t(_[a],+e)}function a(e,t){var n={nominative:\"\\u044f\\u043d\\u0432\\u0430\\u0440\\u044c_\\u0444\\u0435\\u0432\\u0440\\u0430\\u043b\\u044c_\\u043c\\u0430\\u0440\\u0442_\\u0430\\u043f\\u0440\\u0435\\u043b\\u044c_\\u043c\\u0430\\u0439_\\u0438\\u044e\\u043d\\u044c_\\u0438\\u044e\\u043b\\u044c_\\u0430\\u0432\\u0433\\u0443\\u0441\\u0442_\\u0441\\u0435\\u043d\\u0442\\u044f\\u0431\\u0440\\u044c_\\u043e\\u043a\\u0442\\u044f\\u0431\\u0440\\u044c_\\u043d\\u043e\\u044f\\u0431\\u0440\\u044c_\\u0434\\u0435\\u043a\\u0430\\u0431\\u0440\\u044c\".split(\"_\"),accusative:\"\\u044f\\u043d\\u0432\\u0430\\u0440\\u044f_\\u0444\\u0435\\u0432\\u0440\\u0430\\u043b\\u044f_\\u043c\\u0430\\u0440\\u0442\\u0430_\\u0430\\u043f\\u0440\\u0435\\u043b\\u044f_\\u043c\\u0430\\u044f_\\u0438\\u044e\\u043d\\u044f_\\u0438\\u044e\\u043b\\u044f_\\u0430\\u0432\\u0433\\u0443\\u0441\\u0442\\u0430_\\u0441\\u0435\\u043d\\u0442\\u044f\\u0431\\u0440\\u044f_\\u043e\\u043a\\u0442\\u044f\\u0431\\u0440\\u044f_\\u043d\\u043e\\u044f\\u0431\\u0440\\u044f_\\u0434\\u0435\\u043a\\u0430\\u0431\\u0440\\u044f\".split(\"_\")},a=/D[oD]? *MMMM?/.test(t)?\"accusative\":\"nominative\";return n[a][e.month()]}function _(e,t){var n={nominative:\"\\u0432\\u043e\\u0441\\u043a\\u0440\\u0435\\u0441\\u0435\\u043d\\u044c\\u0435_\\u043f\\u043e\\u043d\\u0435\\u0434\\u0435\\u043b\\u044c\\u043d\\u0438\\u043a_\\u0432\\u0442\\u043e\\u0440\\u043d\\u0438\\u043a_\\u0441\\u0440\\u0435\\u0434\\u0430_\\u0447\\u0435\\u0442\\u0432\\u0435\\u0440\\u0433_\\u043f\\u044f\\u0442\\u043d\\u0438\\u0446\\u0430_\\u0441\\u0443\\u0431\\u0431\\u043e\\u0442\\u0430\".split(\"_\"),accusative:\"\\u0432\\u043e\\u0441\\u043a\\u0440\\u0435\\u0441\\u0435\\u043d\\u044c\\u0435_\\u043f\\u043e\\u043d\\u0435\\u0434\\u0435\\u043b\\u044c\\u043d\\u0438\\u043a_\\u0432\\u0442\\u043e\\u0440\\u043d\\u0438\\u043a_\\u0441\\u0440\\u0435\\u0434\\u0443_\\u0447\\u0435\\u0442\\u0432\\u0435\\u0440\\u0433_\\u043f\\u044f\\u0442\\u043d\\u0438\\u0446\\u0443_\\u0441\\u0443\\u0431\\u0431\\u043e\\u0442\\u0443\".split(\"_\")},a=/\\[ ?[\\u0412\\u0432] ?(?:\\u043f\\u0440\\u043e\\u0448\\u043b\\u0443\\u044e|\\u0441\\u043b\\u0435\\u0434\\u0443\\u044e\\u0449\\u0443\\u044e)? ?\\] ?dddd/.test(t)?\"accusative\":\"nominative\";return n[a][e.day()]}e.lang(\"ru\",{months:a,monthsShort:\"\\u044f\\u043d\\u0432_\\u0444\\u0435\\u0432_\\u043c\\u0430\\u0440_\\u0430\\u043f\\u0440_\\u043c\\u0430\\u0439_\\u0438\\u044e\\u043d_\\u0438\\u044e\\u043b_\\u0430\\u0432\\u0433_\\u0441\\u0435\\u043d_\\u043e\\u043a\\u0442_\\u043d\\u043e\\u044f_\\u0434\\u0435\\u043a\".split(\"_\"),weekdays:_,weekdaysShort:\"\\u0432\\u0441\\u043a_\\u043f\\u043d\\u0434_\\u0432\\u0442\\u0440_\\u0441\\u0440\\u0434_\\u0447\\u0442\\u0432_\\u043f\\u0442\\u043d_\\u0441\\u0431\\u0442\".split(\"_\"),weekdaysMin:\"\\u0432\\u0441_\\u043f\\u043d_\\u0432\\u0442_\\u0441\\u0440_\\u0447\\u0442_\\u043f\\u0442_\\u0441\\u0431\".split(\"_\"),longDateFormat:{LT:\"HH:mm\",L:\"DD.MM.YYYY\",LL:\"D MMMM YYYY \\u0433.\",LLL:\"D MMMM YYYY \\u0433., LT\",LLLL:\"dddd, D MMMM YYYY \\u0433., LT\"},calendar:{sameDay:\"[\\u0421\\u0435\\u0433\\u043e\\u0434\\u043d\\u044f \\u0432] LT\",nextDay:\"[\\u0417\\u0430\\u0432\\u0442\\u0440\\u0430 \\u0432] LT\",lastDay:\"[\\u0412\\u0447\\u0435\\u0440\\u0430 \\u0432] LT\",nextWeek:function(){return 2===this.day()?\"[\\u0412\\u043e] dddd [\\u0432] LT\":\"[\\u0412] dddd [\\u0432] LT\"},lastWeek:function(){switch(this.day()){case 0:return\"[\\u0412 \\u043f\\u0440\\u043e\\u0448\\u043b\\u043e\\u0435] dddd [\\u0432] LT\";case 1:case 2:case 4:return\"[\\u0412 \\u043f\\u0440\\u043e\\u0448\\u043b\\u044b\\u0439] dddd [\\u0432] LT\";case 3:case 5:case 6:return\"[\\u0412 \\u043f\\u0440\\u043e\\u0448\\u043b\\u0443\\u044e] dddd [\\u0432] LT\"}},sameElse:\"L\"},relativeTime:{future:\"\\u0447\\u0435\\u0440\\u0435\\u0437 %s\",past:\"%s \\u043d\\u0430\\u0437\\u0430\\u0434\",s:\"\\u043d\\u0435\\u0441\\u043a\\u043e\\u043b\\u044c\\u043a\\u043e \\u0441\\u0435\\u043a\\u0443\\u043d\\u0434\",m:n,mm:n,h:\"\\u0447\\u0430\\u0441\",hh:n,d:\"\\u0434\\u0435\\u043d\\u044c\",dd:n,M:\"\\u043c\\u0435\\u0441\\u044f\\u0446\",MM:n,y:\"\\u0433\\u043e\\u0434\",yy:n},ordinal:function(e,t){switch(t){case\"M\":case\"d\":case\"DDD\":return e+\"-\\u0439\";case\"D\":return e+\"-\\u0433\\u043e\";case\"w\":case\"W\":return e+\"-\\u044f\";default:return e}},week:{dow:1,doy:7}})}\"function\"==typeof define&&define.amd&&define([\"moment\"],e),\"undefined\"!=typeof window&&window.moment&&e(window.moment)}();"
  },
  {
    "path": "vendors/firmcard/src/vendors/underscore1.5.1.js",
    "content": "//     Underscore.js 1.5.1\n//     http://underscorejs.org\n//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n//     Underscore may be freely distributed under the MIT license.\n\n(function() {\n\n  // Baseline setup\n  // --------------\n\n  // Establish the root object, `window` in the browser, or `global` on the server.\n  var root = this;\n\n  // Save the previous value of the `_` variable.\n  var previousUnderscore = root._;\n\n  // Establish the object that gets returned to break out of a loop iteration.\n  var breaker = {};\n\n  // Save bytes in the minified (but not gzipped) version:\n  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n  // Create quick reference variables for speed access to core prototypes.\n  var\n    push             = ArrayProto.push,\n    slice            = ArrayProto.slice,\n    concat           = ArrayProto.concat,\n    toString         = ObjProto.toString,\n    hasOwnProperty   = ObjProto.hasOwnProperty;\n\n  // All **ECMAScript 5** native function implementations that we hope to use\n  // are declared here.\n  var\n    nativeForEach      = ArrayProto.forEach,\n    nativeMap          = ArrayProto.map,\n    nativeReduce       = ArrayProto.reduce,\n    nativeReduceRight  = ArrayProto.reduceRight,\n    nativeFilter       = ArrayProto.filter,\n    nativeEvery        = ArrayProto.every,\n    nativeSome         = ArrayProto.some,\n    nativeIndexOf      = ArrayProto.indexOf,\n    nativeLastIndexOf  = ArrayProto.lastIndexOf,\n    nativeIsArray      = Array.isArray,\n    nativeKeys         = Object.keys,\n    nativeBind         = FuncProto.bind;\n\n  // Create a safe reference to the Underscore object for use below.\n  var _ = function(obj) {\n    if (obj instanceof _) return obj;\n    if (!(this instanceof _)) return new _(obj);\n    this._wrapped = obj;\n  };\n\n  // Export the Underscore object for **Node.js**, with\n  // backwards-compatibility for the old `require()` API. If we're in\n  // the browser, add `_` as a global object via a string identifier,\n  // for Closure Compiler \"advanced\" mode.\n  if (typeof exports !== 'undefined') {\n    if (typeof module !== 'undefined' && module.exports) {\n      exports = module.exports = _;\n    }\n    exports._ = _;\n  } else {\n    root._ = _;\n  }\n\n  // Current version.\n  _.VERSION = '1.5.1';\n\n  // Collection Functions\n  // --------------------\n\n  // The cornerstone, an `each` implementation, aka `forEach`.\n  // Handles objects with the built-in `forEach`, arrays, and raw objects.\n  // Delegates to **ECMAScript 5**'s native `forEach` if available.\n  var each = _.each = _.forEach = function(obj, iterator, context) {\n    if (obj == null) return;\n    if (nativeForEach && obj.forEach === nativeForEach) {\n      obj.forEach(iterator, context);\n    } else if (obj.length === +obj.length) {\n      for (var i = 0, l = obj.length; i < l; i++) {\n        if (iterator.call(context, obj[i], i, obj) === breaker) return;\n      }\n    } else {\n      for (var key in obj) {\n        if (_.has(obj, key)) {\n          if (iterator.call(context, obj[key], key, obj) === breaker) return;\n        }\n      }\n    }\n  };\n\n  // Return the results of applying the iterator to each element.\n  // Delegates to **ECMAScript 5**'s native `map` if available.\n  _.map = _.collect = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n    each(obj, function(value, index, list) {\n      results.push(iterator.call(context, value, index, list));\n    });\n    return results;\n  };\n\n  var reduceError = 'Reduce of empty array with no initial value';\n\n  // **Reduce** builds up a single result from a list of values, aka `inject`,\n  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduce && obj.reduce === nativeReduce) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n    }\n    each(obj, function(value, index, list) {\n      if (!initial) {\n        memo = value;\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, value, index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // The right-associative version of reduce, also known as `foldr`.\n  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n    }\n    var length = obj.length;\n    if (length !== +length) {\n      var keys = _.keys(obj);\n      length = keys.length;\n    }\n    each(obj, function(value, index, list) {\n      index = keys ? keys[--length] : --length;\n      if (!initial) {\n        memo = obj[index];\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, obj[index], index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // Return the first value which passes a truth test. Aliased as `detect`.\n  _.find = _.detect = function(obj, iterator, context) {\n    var result;\n    any(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) {\n        result = value;\n        return true;\n      }\n    });\n    return result;\n  };\n\n  // Return all the elements that pass a truth test.\n  // Delegates to **ECMAScript 5**'s native `filter` if available.\n  // Aliased as `select`.\n  _.filter = _.select = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n    each(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) results.push(value);\n    });\n    return results;\n  };\n\n  // Return all the elements for which a truth test fails.\n  _.reject = function(obj, iterator, context) {\n    return _.filter(obj, function(value, index, list) {\n      return !iterator.call(context, value, index, list);\n    }, context);\n  };\n\n  // Determine whether all of the elements match a truth test.\n  // Delegates to **ECMAScript 5**'s native `every` if available.\n  // Aliased as `all`.\n  _.every = _.all = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = true;\n    if (obj == null) return result;\n    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n    each(obj, function(value, index, list) {\n      if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if at least one element in the object matches a truth test.\n  // Delegates to **ECMAScript 5**'s native `some` if available.\n  // Aliased as `any`.\n  var any = _.some = _.any = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = false;\n    if (obj == null) return result;\n    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n    each(obj, function(value, index, list) {\n      if (result || (result = iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if the array or object contains a given value (using `===`).\n  // Aliased as `include`.\n  _.contains = _.include = function(obj, target) {\n    if (obj == null) return false;\n    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n    return any(obj, function(value) {\n      return value === target;\n    });\n  };\n\n  // Invoke a method (with arguments) on every item in a collection.\n  _.invoke = function(obj, method) {\n    var args = slice.call(arguments, 2);\n    var isFunc = _.isFunction(method);\n    return _.map(obj, function(value) {\n      return (isFunc ? method : value[method]).apply(value, args);\n    });\n  };\n\n  // Convenience version of a common use case of `map`: fetching a property.\n  _.pluck = function(obj, key) {\n    return _.map(obj, function(value){ return value[key]; });\n  };\n\n  // Convenience version of a common use case of `filter`: selecting only objects\n  // containing specific `key:value` pairs.\n  _.where = function(obj, attrs, first) {\n    if (_.isEmpty(attrs)) return first ? void 0 : [];\n    return _[first ? 'find' : 'filter'](obj, function(value) {\n      for (var key in attrs) {\n        if (attrs[key] !== value[key]) return false;\n      }\n      return true;\n    });\n  };\n\n  // Convenience version of a common use case of `find`: getting the first object\n  // containing specific `key:value` pairs.\n  _.findWhere = function(obj, attrs) {\n    return _.where(obj, attrs, true);\n  };\n\n  // Return the maximum element or (element-based computation).\n  // Can't optimize arrays of integers longer than 65,535 elements.\n  // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)\n  _.max = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.max.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return -Infinity;\n    var result = {computed : -Infinity, value: -Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed > result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Return the minimum element (or element-based computation).\n  _.min = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.min.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return Infinity;\n    var result = {computed : Infinity, value: Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed < result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Shuffle an array.\n  _.shuffle = function(obj) {\n    var rand;\n    var index = 0;\n    var shuffled = [];\n    each(obj, function(value) {\n      rand = _.random(index++);\n      shuffled[index - 1] = shuffled[rand];\n      shuffled[rand] = value;\n    });\n    return shuffled;\n  };\n\n  // An internal function to generate lookup iterators.\n  var lookupIterator = function(value) {\n    return _.isFunction(value) ? value : function(obj){ return obj[value]; };\n  };\n\n  // Sort the object's values by a criterion produced by an iterator.\n  _.sortBy = function(obj, value, context) {\n    var iterator = lookupIterator(value);\n    return _.pluck(_.map(obj, function(value, index, list) {\n      return {\n        value : value,\n        index : index,\n        criteria : iterator.call(context, value, index, list)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria;\n      var b = right.criteria;\n      if (a !== b) {\n        if (a > b || a === void 0) return 1;\n        if (a < b || b === void 0) return -1;\n      }\n      return left.index < right.index ? -1 : 1;\n    }), 'value');\n  };\n\n  // An internal function used for aggregate \"group by\" operations.\n  var group = function(obj, value, context, behavior) {\n    var result = {};\n    var iterator = lookupIterator(value == null ? _.identity : value);\n    each(obj, function(value, index) {\n      var key = iterator.call(context, value, index, obj);\n      behavior(result, key, value);\n    });\n    return result;\n  };\n\n  // Groups the object's values by a criterion. Pass either a string attribute\n  // to group by, or a function that returns the criterion.\n  _.groupBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key, value) {\n      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);\n    });\n  };\n\n  // Counts instances of an object that group by a certain criterion. Pass\n  // either a string attribute to count by, or a function that returns the\n  // criterion.\n  _.countBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key) {\n      if (!_.has(result, key)) result[key] = 0;\n      result[key]++;\n    });\n  };\n\n  // Use a comparator function to figure out the smallest index at which\n  // an object should be inserted so as to maintain order. Uses binary search.\n  _.sortedIndex = function(array, obj, iterator, context) {\n    iterator = iterator == null ? _.identity : lookupIterator(iterator);\n    var value = iterator.call(context, obj);\n    var low = 0, high = array.length;\n    while (low < high) {\n      var mid = (low + high) >>> 1;\n      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n    }\n    return low;\n  };\n\n  // Safely create a real, live array from anything iterable.\n  _.toArray = function(obj) {\n    if (!obj) return [];\n    if (_.isArray(obj)) return slice.call(obj);\n    if (obj.length === +obj.length) return _.map(obj, _.identity);\n    return _.values(obj);\n  };\n\n  // Return the number of elements in an object.\n  _.size = function(obj) {\n    if (obj == null) return 0;\n    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n  };\n\n  // Array Functions\n  // ---------------\n\n  // Get the first element of an array. Passing **n** will return the first N\n  // values in the array. Aliased as `head` and `take`. The **guard** check\n  // allows it to work with `_.map`.\n  _.first = _.head = _.take = function(array, n, guard) {\n    if (array == null) return void 0;\n    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];\n  };\n\n  // Returns everything but the last entry of the array. Especially useful on\n  // the arguments object. Passing **n** will return all the values in\n  // the array, excluding the last N. The **guard** check allows it to work with\n  // `_.map`.\n  _.initial = function(array, n, guard) {\n    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n  };\n\n  // Get the last element of an array. Passing **n** will return the last N\n  // values in the array. The **guard** check allows it to work with `_.map`.\n  _.last = function(array, n, guard) {\n    if (array == null) return void 0;\n    if ((n != null) && !guard) {\n      return slice.call(array, Math.max(array.length - n, 0));\n    } else {\n      return array[array.length - 1];\n    }\n  };\n\n  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n  // Especially useful on the arguments object. Passing an **n** will return\n  // the rest N values in the array. The **guard**\n  // check allows it to work with `_.map`.\n  _.rest = _.tail = _.drop = function(array, n, guard) {\n    return slice.call(array, (n == null) || guard ? 1 : n);\n  };\n\n  // Trim out all falsy values from an array.\n  _.compact = function(array) {\n    return _.filter(array, _.identity);\n  };\n\n  // Internal implementation of a recursive `flatten` function.\n  var flatten = function(input, shallow, output) {\n    if (shallow && _.every(input, _.isArray)) {\n      return concat.apply(output, input);\n    }\n    each(input, function(value) {\n      if (_.isArray(value) || _.isArguments(value)) {\n        shallow ? push.apply(output, value) : flatten(value, shallow, output);\n      } else {\n        output.push(value);\n      }\n    });\n    return output;\n  };\n\n  // Return a completely flattened version of an array.\n  _.flatten = function(array, shallow) {\n    return flatten(array, shallow, []);\n  };\n\n  // Return a version of the array that does not contain the specified value(s).\n  _.without = function(array) {\n    return _.difference(array, slice.call(arguments, 1));\n  };\n\n  // Produce a duplicate-free version of the array. If the array has already\n  // been sorted, you have the option of using a faster algorithm.\n  // Aliased as `unique`.\n  _.uniq = _.unique = function(array, isSorted, iterator, context) {\n    if (_.isFunction(isSorted)) {\n      context = iterator;\n      iterator = isSorted;\n      isSorted = false;\n    }\n    var initial = iterator ? _.map(array, iterator, context) : array;\n    var results = [];\n    var seen = [];\n    each(initial, function(value, index) {\n      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n        seen.push(value);\n        results.push(array[index]);\n      }\n    });\n    return results;\n  };\n\n  // Produce an array that contains the union: each distinct element from all of\n  // the passed-in arrays.\n  _.union = function() {\n    return _.uniq(_.flatten(arguments, true));\n  };\n\n  // Produce an array that contains every item shared between all the\n  // passed-in arrays.\n  _.intersection = function(array) {\n    var rest = slice.call(arguments, 1);\n    return _.filter(_.uniq(array), function(item) {\n      return _.every(rest, function(other) {\n        return _.indexOf(other, item) >= 0;\n      });\n    });\n  };\n\n  // Take the difference between one array and a number of other arrays.\n  // Only the elements present in just the first array will remain.\n  _.difference = function(array) {\n    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n    return _.filter(array, function(value){ return !_.contains(rest, value); });\n  };\n\n  // Zip together multiple lists into a single array -- elements that share\n  // an index go together.\n  _.zip = function() {\n    var length = _.max(_.pluck(arguments, \"length\").concat(0));\n    var results = new Array(length);\n    for (var i = 0; i < length; i++) {\n      results[i] = _.pluck(arguments, '' + i);\n    }\n    return results;\n  };\n\n  // Converts lists into objects. Pass either a single array of `[key, value]`\n  // pairs, or two parallel arrays of the same length -- one of keys, and one of\n  // the corresponding values.\n  _.object = function(list, values) {\n    if (list == null) return {};\n    var result = {};\n    for (var i = 0, l = list.length; i < l; i++) {\n      if (values) {\n        result[list[i]] = values[i];\n      } else {\n        result[list[i][0]] = list[i][1];\n      }\n    }\n    return result;\n  };\n\n  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n  // we need this function. Return the position of the first occurrence of an\n  // item in an array, or -1 if the item is not included in the array.\n  // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n  // If the array is large and already in sort order, pass `true`\n  // for **isSorted** to use binary search.\n  _.indexOf = function(array, item, isSorted) {\n    if (array == null) return -1;\n    var i = 0, l = array.length;\n    if (isSorted) {\n      if (typeof isSorted == 'number') {\n        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);\n      } else {\n        i = _.sortedIndex(array, item);\n        return array[i] === item ? i : -1;\n      }\n    }\n    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n    for (; i < l; i++) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n  _.lastIndexOf = function(array, item, from) {\n    if (array == null) return -1;\n    var hasIndex = from != null;\n    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n    }\n    var i = (hasIndex ? from : array.length);\n    while (i--) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Generate an integer Array containing an arithmetic progression. A port of\n  // the native Python `range()` function. See\n  // [the Python documentation](http://docs.python.org/library/functions.html#range).\n  _.range = function(start, stop, step) {\n    if (arguments.length <= 1) {\n      stop = start || 0;\n      start = 0;\n    }\n    step = arguments[2] || 1;\n\n    var len = Math.max(Math.ceil((stop - start) / step), 0);\n    var idx = 0;\n    var range = new Array(len);\n\n    while(idx < len) {\n      range[idx++] = start;\n      start += step;\n    }\n\n    return range;\n  };\n\n  // Function (ahem) Functions\n  // ------------------\n\n  // Reusable constructor function for prototype setting.\n  var ctor = function(){};\n\n  // Create a function bound to a given object (assigning `this`, and arguments,\n  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n  // available.\n  _.bind = function(func, context) {\n    var args, bound;\n    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n    if (!_.isFunction(func)) throw new TypeError;\n    args = slice.call(arguments, 2);\n    return bound = function() {\n      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));\n      ctor.prototype = func.prototype;\n      var self = new ctor;\n      ctor.prototype = null;\n      var result = func.apply(self, args.concat(slice.call(arguments)));\n      if (Object(result) === result) return result;\n      return self;\n    };\n  };\n\n  // Partially apply a function by creating a version that has had some of its\n  // arguments pre-filled, without changing its dynamic `this` context.\n  _.partial = function(func) {\n    var args = slice.call(arguments, 1);\n    return function() {\n      return func.apply(this, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Bind all of an object's methods to that object. Useful for ensuring that\n  // all callbacks defined on an object belong to it.\n  _.bindAll = function(obj) {\n    var funcs = slice.call(arguments, 1);\n    if (funcs.length === 0) throw new Error(\"bindAll must be passed function names\");\n    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n    return obj;\n  };\n\n  // Memoize an expensive function by storing its results.\n  _.memoize = function(func, hasher) {\n    var memo = {};\n    hasher || (hasher = _.identity);\n    return function() {\n      var key = hasher.apply(this, arguments);\n      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n    };\n  };\n\n  // Delays a function for the given number of milliseconds, and then calls\n  // it with the arguments supplied.\n  _.delay = function(func, wait) {\n    var args = slice.call(arguments, 2);\n    return setTimeout(function(){ return func.apply(null, args); }, wait);\n  };\n\n  // Defers a function, scheduling it to run after the current call stack has\n  // cleared.\n  _.defer = function(func) {\n    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n  };\n\n  // Returns a function, that, when invoked, will only be triggered at most once\n  // during a given window of time. Normally, the throttled function will run\n  // as much as it can, without ever going more than once per `wait` duration;\n  // but if you'd like to disable the execution on the leading edge, pass\n  // `{leading: false}`. To disable execution on the trailing edge, ditto.\n  _.throttle = function(func, wait, options) {\n    var context, args, result;\n    var timeout = null;\n    var previous = 0;\n    options || (options = {});\n    var later = function() {\n      previous = options.leading === false ? 0 : new Date;\n      timeout = null;\n      result = func.apply(context, args);\n    };\n    return function() {\n      var now = new Date;\n      if (!previous && options.leading === false) previous = now;\n      var remaining = wait - (now - previous);\n      context = this;\n      args = arguments;\n      if (remaining <= 0) {\n        clearTimeout(timeout);\n        timeout = null;\n        previous = now;\n        result = func.apply(context, args);\n      } else if (!timeout && options.trailing !== false) {\n        timeout = setTimeout(later, remaining);\n      }\n      return result;\n    };\n  };\n\n  // Returns a function, that, as long as it continues to be invoked, will not\n  // be triggered. The function will be called after it stops being called for\n  // N milliseconds. If `immediate` is passed, trigger the function on the\n  // leading edge, instead of the trailing.\n  _.debounce = function(func, wait, immediate) {\n    var result;\n    var timeout = null;\n    return function() {\n      var context = this, args = arguments;\n      var later = function() {\n        timeout = null;\n        if (!immediate) result = func.apply(context, args);\n      };\n      var callNow = immediate && !timeout;\n      clearTimeout(timeout);\n      timeout = setTimeout(later, wait);\n      if (callNow) result = func.apply(context, args);\n      return result;\n    };\n  };\n\n  // Returns a function that will be executed at most one time, no matter how\n  // often you call it. Useful for lazy initialization.\n  _.once = function(func) {\n    var ran = false, memo;\n    return function() {\n      if (ran) return memo;\n      ran = true;\n      memo = func.apply(this, arguments);\n      func = null;\n      return memo;\n    };\n  };\n\n  // Returns the first function passed as an argument to the second,\n  // allowing you to adjust arguments, run code before and after, and\n  // conditionally execute the original function.\n  _.wrap = function(func, wrapper) {\n    return function() {\n      var args = [func];\n      push.apply(args, arguments);\n      return wrapper.apply(this, args);\n    };\n  };\n\n  // Returns a function that is the composition of a list of functions, each\n  // consuming the return value of the function that follows.\n  _.compose = function() {\n    var funcs = arguments;\n    return function() {\n      var args = arguments;\n      for (var i = funcs.length - 1; i >= 0; i--) {\n        args = [funcs[i].apply(this, args)];\n      }\n      return args[0];\n    };\n  };\n\n  // Returns a function that will only be executed after being called N times.\n  _.after = function(times, func) {\n    return function() {\n      if (--times < 1) {\n        return func.apply(this, arguments);\n      }\n    };\n  };\n\n  // Object Functions\n  // ----------------\n\n  // Retrieve the names of an object's properties.\n  // Delegates to **ECMAScript 5**'s native `Object.keys`\n  _.keys = nativeKeys || function(obj) {\n    if (obj !== Object(obj)) throw new TypeError('Invalid object');\n    var keys = [];\n    for (var key in obj) if (_.has(obj, key)) keys.push(key);\n    return keys;\n  };\n\n  // Retrieve the values of an object's properties.\n  _.values = function(obj) {\n    var values = [];\n    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);\n    return values;\n  };\n\n  // Convert an object into a list of `[key, value]` pairs.\n  _.pairs = function(obj) {\n    var pairs = [];\n    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);\n    return pairs;\n  };\n\n  // Invert the keys and values of an object. The values must be serializable.\n  _.invert = function(obj) {\n    var result = {};\n    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;\n    return result;\n  };\n\n  // Return a sorted list of the function names available on the object.\n  // Aliased as `methods`\n  _.functions = _.methods = function(obj) {\n    var names = [];\n    for (var key in obj) {\n      if (_.isFunction(obj[key])) names.push(key);\n    }\n    return names.sort();\n  };\n\n  // Extend a given object with all the properties in passed-in object(s).\n  _.extend = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Return a copy of the object only containing the whitelisted properties.\n  _.pick = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    each(keys, function(key) {\n      if (key in obj) copy[key] = obj[key];\n    });\n    return copy;\n  };\n\n   // Return a copy of the object without the blacklisted properties.\n  _.omit = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    for (var key in obj) {\n      if (!_.contains(keys, key)) copy[key] = obj[key];\n    }\n    return copy;\n  };\n\n  // Fill in a given object with default properties.\n  _.defaults = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          if (obj[prop] === void 0) obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Create a (shallow-cloned) duplicate of an object.\n  _.clone = function(obj) {\n    if (!_.isObject(obj)) return obj;\n    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n  };\n\n  // Invokes interceptor with the obj, and then returns obj.\n  // The primary purpose of this method is to \"tap into\" a method chain, in\n  // order to perform operations on intermediate results within the chain.\n  _.tap = function(obj, interceptor) {\n    interceptor(obj);\n    return obj;\n  };\n\n  // Internal recursive comparison function for `isEqual`.\n  var eq = function(a, b, aStack, bStack) {\n    // Identical objects are equal. `0 === -0`, but they aren't identical.\n    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).\n    if (a === b) return a !== 0 || 1 / a == 1 / b;\n    // A strict comparison is necessary because `null == undefined`.\n    if (a == null || b == null) return a === b;\n    // Unwrap any wrapped objects.\n    if (a instanceof _) a = a._wrapped;\n    if (b instanceof _) b = b._wrapped;\n    // Compare `[[Class]]` names.\n    var className = toString.call(a);\n    if (className != toString.call(b)) return false;\n    switch (className) {\n      // Strings, numbers, dates, and booleans are compared by value.\n      case '[object String]':\n        // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n        // equivalent to `new String(\"5\")`.\n        return a == String(b);\n      case '[object Number]':\n        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n        // other numeric values.\n        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n      case '[object Date]':\n      case '[object Boolean]':\n        // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n        // millisecond representations. Note that invalid dates with millisecond representations\n        // of `NaN` are not equivalent.\n        return +a == +b;\n      // RegExps are compared by their source patterns and flags.\n      case '[object RegExp]':\n        return a.source == b.source &&\n               a.global == b.global &&\n               a.multiline == b.multiline &&\n               a.ignoreCase == b.ignoreCase;\n    }\n    if (typeof a != 'object' || typeof b != 'object') return false;\n    // Assume equality for cyclic structures. The algorithm for detecting cyclic\n    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n    var length = aStack.length;\n    while (length--) {\n      // Linear search. Performance is inversely proportional to the number of\n      // unique nested structures.\n      if (aStack[length] == a) return bStack[length] == b;\n    }\n    // Objects with different constructors are not equivalent, but `Object`s\n    // from different frames are.\n    var aCtor = a.constructor, bCtor = b.constructor;\n    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n                             _.isFunction(bCtor) && (bCtor instanceof bCtor))) {\n      return false;\n    }\n    // Add the first object to the stack of traversed objects.\n    aStack.push(a);\n    bStack.push(b);\n    var size = 0, result = true;\n    // Recursively compare objects and arrays.\n    if (className == '[object Array]') {\n      // Compare array lengths to determine if a deep comparison is necessary.\n      size = a.length;\n      result = size == b.length;\n      if (result) {\n        // Deep compare the contents, ignoring non-numeric properties.\n        while (size--) {\n          if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n        }\n      }\n    } else {\n      // Deep compare objects.\n      for (var key in a) {\n        if (_.has(a, key)) {\n          // Count the expected number of properties.\n          size++;\n          // Deep compare each member.\n          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n        }\n      }\n      // Ensure that both objects contain the same number of properties.\n      if (result) {\n        for (key in b) {\n          if (_.has(b, key) && !(size--)) break;\n        }\n        result = !size;\n      }\n    }\n    // Remove the first object from the stack of traversed objects.\n    aStack.pop();\n    bStack.pop();\n    return result;\n  };\n\n  // Perform a deep comparison to check if two objects are equal.\n  _.isEqual = function(a, b) {\n    return eq(a, b, [], []);\n  };\n\n  // Is a given array, string, or object empty?\n  // An \"empty\" object has no enumerable own-properties.\n  _.isEmpty = function(obj) {\n    if (obj == null) return true;\n    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n    for (var key in obj) if (_.has(obj, key)) return false;\n    return true;\n  };\n\n  // Is a given value a DOM element?\n  _.isElement = function(obj) {\n    return !!(obj && obj.nodeType === 1);\n  };\n\n  // Is a given value an array?\n  // Delegates to ECMA5's native Array.isArray\n  _.isArray = nativeIsArray || function(obj) {\n    return toString.call(obj) == '[object Array]';\n  };\n\n  // Is a given variable an object?\n  _.isObject = function(obj) {\n    return obj === Object(obj);\n  };\n\n  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n    _['is' + name] = function(obj) {\n      return toString.call(obj) == '[object ' + name + ']';\n    };\n  });\n\n  // Define a fallback version of the method in browsers (ahem, IE), where\n  // there isn't any inspectable \"Arguments\" type.\n  if (!_.isArguments(arguments)) {\n    _.isArguments = function(obj) {\n      return !!(obj && _.has(obj, 'callee'));\n    };\n  }\n\n  // Optimize `isFunction` if appropriate.\n  if (typeof (/./) !== 'function') {\n    _.isFunction = function(obj) {\n      return typeof obj === 'function';\n    };\n  }\n\n  // Is a given object a finite number?\n  _.isFinite = function(obj) {\n    return isFinite(obj) && !isNaN(parseFloat(obj));\n  };\n\n  // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n  _.isNaN = function(obj) {\n    return _.isNumber(obj) && obj != +obj;\n  };\n\n  // Is a given value a boolean?\n  _.isBoolean = function(obj) {\n    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n  };\n\n  // Is a given value equal to null?\n  _.isNull = function(obj) {\n    return obj === null;\n  };\n\n  // Is a given variable undefined?\n  _.isUndefined = function(obj) {\n    return obj === void 0;\n  };\n\n  // Shortcut function for checking if an object has a given property directly\n  // on itself (in other words, not on a prototype).\n  _.has = function(obj, key) {\n    return hasOwnProperty.call(obj, key);\n  };\n\n  // Utility Functions\n  // -----------------\n\n  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n  // previous owner. Returns a reference to the Underscore object.\n  _.noConflict = function() {\n    root._ = previousUnderscore;\n    return this;\n  };\n\n  // Keep the identity function around for default iterators.\n  _.identity = function(value) {\n    return value;\n  };\n\n  // Run a function **n** times.\n  _.times = function(n, iterator, context) {\n    var accum = Array(Math.max(0, n));\n    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n    return accum;\n  };\n\n  // Return a random integer between min and max (inclusive).\n  _.random = function(min, max) {\n    if (max == null) {\n      max = min;\n      min = 0;\n    }\n    return min + Math.floor(Math.random() * (max - min + 1));\n  };\n\n  // List of HTML entities for escaping.\n  var entityMap = {\n    escape: {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      \"'\": '&#x27;',\n      '/': '&#x2F;'\n    }\n  };\n  entityMap.unescape = _.invert(entityMap.escape);\n\n  // Regexes containing the keys and values listed immediately above.\n  var entityRegexes = {\n    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n  };\n\n  // Functions for escaping and unescaping strings to/from HTML interpolation.\n  _.each(['escape', 'unescape'], function(method) {\n    _[method] = function(string) {\n      if (string == null) return '';\n      return ('' + string).replace(entityRegexes[method], function(match) {\n        return entityMap[method][match];\n      });\n    };\n  });\n\n  // If the value of the named `property` is a function then invoke it with the\n  // `object` as context; otherwise, return it.\n  _.result = function(object, property) {\n    if (object == null) return void 0;\n    var value = object[property];\n    return _.isFunction(value) ? value.call(object) : value;\n  };\n\n  // Add your own custom functions to the Underscore object.\n  _.mixin = function(obj) {\n    each(_.functions(obj), function(name){\n      var func = _[name] = obj[name];\n      _.prototype[name] = function() {\n        var args = [this._wrapped];\n        push.apply(args, arguments);\n        return result.call(this, func.apply(_, args));\n      };\n    });\n  };\n\n  // Generate a unique integer id (unique within the entire client session).\n  // Useful for temporary DOM ids.\n  var idCounter = 0;\n  _.uniqueId = function(prefix) {\n    var id = ++idCounter + '';\n    return prefix ? prefix + id : id;\n  };\n\n  // By default, Underscore uses ERB-style template delimiters, change the\n  // following template settings to use alternative delimiters.\n  _.templateSettings = {\n    evaluate    : /<%([\\s\\S]+?)%>/g,\n    interpolate : /<%=([\\s\\S]+?)%>/g,\n    escape      : /<%-([\\s\\S]+?)%>/g\n  };\n\n  // When customizing `templateSettings`, if you don't want to define an\n  // interpolation, evaluation or escaping regex, we need one that is\n  // guaranteed not to match.\n  var noMatch = /(.)^/;\n\n  // Certain characters need to be escaped so that they can be put into a\n  // string literal.\n  var escapes = {\n    \"'\":      \"'\",\n    '\\\\':     '\\\\',\n    '\\r':     'r',\n    '\\n':     'n',\n    '\\t':     't',\n    '\\u2028': 'u2028',\n    '\\u2029': 'u2029'\n  };\n\n  var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n  // JavaScript micro-templating, similar to John Resig's implementation.\n  // Underscore templating handles arbitrary delimiters, preserves whitespace,\n  // and correctly escapes quotes within interpolated code.\n  _.template = function(text, data, settings) {\n    var render;\n    settings = _.defaults({}, settings, _.templateSettings);\n\n    // Combine delimiters into one regular expression via alternation.\n    var matcher = new RegExp([\n      (settings.escape || noMatch).source,\n      (settings.interpolate || noMatch).source,\n      (settings.evaluate || noMatch).source\n    ].join('|') + '|$', 'g');\n\n    // Compile the template source, escaping string literals appropriately.\n    var index = 0;\n    var source = \"__p+='\";\n    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n      source += text.slice(index, offset)\n        .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n      if (escape) {\n        source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n      }\n      if (interpolate) {\n        source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n      }\n      if (evaluate) {\n        source += \"';\\n\" + evaluate + \"\\n__p+='\";\n      }\n      index = offset + match.length;\n      return match;\n    });\n    source += \"';\\n\";\n\n    // If a variable is not specified, place data values in local scope.\n    if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n    source = \"var __t,__p='',__j=Array.prototype.join,\" +\n      \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n      source + \"return __p;\\n\";\n\n    try {\n      render = new Function(settings.variable || 'obj', '_', source);\n    } catch (e) {\n      e.source = source;\n      throw e;\n    }\n\n    if (data) return render(data, _);\n    var template = function(data) {\n      return render.call(this, data, _);\n    };\n\n    // Provide the compiled function source as a convenience for precompilation.\n    template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n    return template;\n  };\n\n  // Add a \"chain\" function, which will delegate to the wrapper.\n  _.chain = function(obj) {\n    return _(obj).chain();\n  };\n\n  // OOP\n  // ---------------\n  // If Underscore is called as a function, it returns a wrapped object that\n  // can be used OO-style. This wrapper holds altered versions of all the\n  // underscore functions. Wrapped objects may be chained.\n\n  // Helper function to continue chaining intermediate results.\n  var result = function(obj) {\n    return this._chain ? _(obj).chain() : obj;\n  };\n\n  // Add all of the Underscore functions to the wrapper object.\n  _.mixin(_);\n\n  // Add all mutator Array functions to the wrapper.\n  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      var obj = this._wrapped;\n      method.apply(obj, arguments);\n      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n      return result.call(this, obj);\n    };\n  });\n\n  // Add all accessor Array functions to the wrapper.\n  each(['concat', 'join', 'slice'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      return result.call(this, method.apply(this._wrapped, arguments));\n    };\n  });\n\n  _.extend(_.prototype, {\n\n    // Start chaining a wrapped Underscore object.\n    chain: function() {\n      this._chain = true;\n      return this;\n    },\n\n    // Extracts the result from a wrapped and chained object.\n    value: function() {\n      return this._wrapped;\n    }\n\n  });\n\n}).call(this);\n"
  },
  {
    "path": "vendors/firmcard/test/FirmCardSpec.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n\n<body>\n    <script src=\"sinon.js\"></script>\n    <script src=\"mocha.js\"></script>\n    <script src=\"../src/vendors/underscore1.5.1.js\"></script>\n    <script src=\"expect.js\"></script>\n\n\n    <script src=\"../src/FirmCard.js\"></script>\n    <script src=\"../src/FirmCard.DataHelper.js\"></script>\n\n    <script src=\"../src/Schedule.js\"></script>\n    <script src=\"../src/Dictionary.js\"></script>\n\n    <script type=\"text/javascript\">\n        mocha.setup('bdd');\n        mocha.ignoreLeaks();\n    </script>\n\n    <div id=\"mocha\"></div>\n\n    <script src=\"demoData.js\"></script>\n    <script src=\"FirmCardSpec.js\"></script>\n    <script type=\"text/javascript\">\n        mocha.run();\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "vendors/firmcard/test/FirmCardSpec.js",
    "content": "describe('Расписание работы организации', function () {\n\n    function mockTime(timestamp) {\n        //rid of magic 6 (local time)\n        return timestamp + (7 + new Date().getTimezoneOffset() / 60) * 60 * 60 * 1000;\n    }\n    var d = new FirmCard(null, {\n        localLang: 'ru'\n    });\n\n    it('!model', function () {\n        var result =  d.getSchedule().transform();\n\n        expect(result).to.not.be.ok();\n    });\n\n    it('!params', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData['default'].model);\n\n        expect(result).to.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Comment', function () {\n        var result =  d.getSchedule().transform({\n            comment: 'comment'\n        });\n\n        expect(result.comment).to.be('comment');\n        expect(result.everyday).to.be.ok(); // Ежедневно закрыто, Ха!\n\n    });\n\n    it('Будни одинаково, выходные выходные', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData['default'].model, {\n            now: mockTime(1366610753162),\n\n        }); // 13:06 пн 22 апреля 2013\n        expect(result.now.open).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(4);\n        expect(result.will.m).to.be(50);\n        expect(result.will.till).to.be('18:00');\n        expect(result.today.from).to.be('10:00');\n        expect(result.today.to).to.be('18:00');\n        expect(result.week.evently[0].dayList).to.be('Понедельник–пятница');\n        expect(result.week.evently[0].budni).to.be.ok();\n        expect(result.week.evently[0].everyday).to.not.be.ok();\n        expect(result.week.evently[1].dayList).to.be('Суббота, воскресенье');\n        expect(result.week.evently[1].budni).to.not.be.ok();\n        expect(result.week.evently[1].everyday).to.not.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Будни одинаково, выходные выходные, до нуля', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.evently.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n\n        expect(result.now.open).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(10);\n        expect(result.will.m).to.be(50);\n        expect(result.will.till).to.be('00:00');\n        expect(result.today.from).to.be('10:00');\n        expect(result.today.to).to.be('00:00');\n        expect(result.week.evently[0].dayList).to.be('Понедельник–пятница');\n        expect(result.week.evently[0].budni).to.be.ok();\n        expect(result.week.evently[0].holiday).to.not.be.ok();\n        expect(result.week.evently[0].everyday).to.not.be.ok();\n        expect(result.week.evently[1].dayList).to.be('Суббота, воскресенье');\n        expect(result.week.evently[1].budni).to.not.be.ok();\n        expect(result.week.evently[1].holiday).to.be.ok();\n        expect(result.week.evently[1].everyday).to.not.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Будни одинаково, суббота сокращённо', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.eventlySat.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(4);\n        expect(result.will.m).to.be(50);\n        expect(result.will.till).to.be('18:00');\n        expect(result.today.from).to.be('10:00');\n        expect(result.today.to).to.be('18:00');\n        expect(result.week.evently).to.not.be.ok;\n        expect(_.isEqual(result.week.table, [\n            { from: '10:00', to: '18:00', lunch: [], active: true, key: 'пнд' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'втр' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'срд' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'чтв' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'птн' },\n            { from: '10:00', to: '17:00', lunch: [], key: 'сбт' },\n            { key: 'вск' }\n        ])).to.be.ok;\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Будни одинаково, суббота сокращённо, максимум часов в субботу', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.eventlySatMax.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(4);\n        expect(result.will.m).to.be(50);\n        expect(result.will.till).to.be('18:00');\n        expect(result.today.from).to.be('10:00');\n        expect(result.today.to).to.be('18:00');\n        expect(result.week.evently).to.not.be.ok;\n        expect(_.isEqual(result.week.table, [\n            { from: '10:00', to: '18:00', lunch: [], active: true, key: 'пнд' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'втр' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'срд' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'чтв' },\n            { from: '10:00', to: '18:00', lunch: [], key: 'птн' },\n            { from: '10:00', to: '19:00', lunch: [], key: 'сбт' },\n            { key: 'вск' }\n        ])).to.be.ok;\n        expect(result.everyday).to.not.be.ok();\n    });\n\n    it('Круглосуточно без выходных', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.alltime.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.be.ok();\n        expect(result.always).to.be.ok();\n        expect(result.today.alltime).to.be.ok();\n        expect(result.will).to.not.be.ok();\n        expect(result.week.hasLunch).to.not.be.ok();\n        expect(result.week.evently[0].dayList).to.be('Понедельник, вторник, среда, четверг, пятница, суббота, воскресенье');\n        expect(result.week.evently[0].alltime).to.be.ok();\n        expect(result.week.evently[0].budni).to.not.be.ok();\n        expect(result.week.evently[0].everyday).to.be.ok();\n        expect(result.everyday).to.be.ok();\n\n    });\n\n    it('Круглосуточно кроме выходных среды и воскресенья', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.thuHol.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today.alltime).to.be.ok();\n        expect(result.will.d).to.be(2);\n        expect(result.will.h).to.be(58);\n        expect(result.will.m).to.be(50);\n        expect(result.will.till).to.be('00:00');\n        expect(result.week.hasLunch).to.not.be.ok();\n        expect(result.week.evently[0].dayList).to.be('Понедельник–среда, пятница, суббота');\n        expect(result.week.evently[0].alltime).to.be.ok();\n        expect(result.week.evently[0].budni).to.not.be.ok();\n        expect(result.week.evently[0].everyday).to.not.be.ok();\n        expect(result.week.evently[1].dayList).to.be('Четверг, воскресенье');\n        expect(result.week.evently[1].alltime).to.not.be.ok();\n        expect(result.week.evently[1].budni).to.not.be.ok();\n        expect(result.week.evently[1].everyday).to.not.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Среда–пятница', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.strangeWeek.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.not.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today).to.be(undefined);\n        expect(result.will.d).to.be(2);\n        expect(result.will.h).to.be(34);\n        expect(result.will.m).to.be(50);\n        expect(result.will.when).to.be('в среду');\n        expect(result.will.till).to.be('00:00');\n        expect(result.week.hasLunch).to.not.be.ok();\n        expect(result.week.evently[0].dayList).to.be('Среда–пятница');\n        expect(result.week.evently[0].alltime).to.be(undefined);\n        expect(result.week.evently[0].everyday).to.not.be.ok();\n        expect(result.week.evently[0].budni).to.not.be.ok();\n        expect(result.week.evently[1].dayList).to.be('Понедельник, вторник, суббота, воскресенье');\n        expect(result.week.evently[1].alltime).to.not.be.ok();\n        expect(result.week.evently[1].everyday).to.not.be.ok();\n        expect(result.week.evently[1].budni).to.not.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Работает только в воскресенье с обедом', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.periods3.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.not.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today).to.be(undefined);\n        expect(result.will.d).to.be(6);\n        expect(result.will.h).to.be(140);\n        expect(result.will.m).to.be(50);\n        expect(result.will.when).to.be('в воскресенье');\n        expect(result.will.till).to.be('10:00');\n        expect(result.week.hasLunch).to.not.be.ok();\n        expect(result.week.evently[0].dayList).to.be('Воскресенье');\n        expect(result.week.evently[0].alltime).to.be(undefined);\n        expect(result.week.evently[0].everyday).to.not.be.ok();\n        expect(result.week.evently[0].budni).to.not.be.ok();\n        expect(result.week.evently[1].dayList).to.be('Понедельник–суббота');\n        expect(result.week.evently[1].alltime).to.not.be.ok();\n        expect(result.week.evently[1].everyday).to.not.be.ok();\n        expect(result.week.evently[1].budni).to.not.be.ok();\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Закроется через 1 минуту', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.oneMinuteLeft.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(0);\n        expect(result.will.m).to.be(5);\n\n    });\n\n    it('Сегодня уже закрыто, откроется через неделю', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.foraWeek.model, {\n            now: mockTime(1366610753162)\n        }); // 13:06 пн 22 апреля 2013\n\n        expect(result.now.open).to.not.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today).to.be.ok();\n        expect(result.will.d).to.be(7);\n        expect(result.will.h).to.be(165);\n        expect(result.will.m).to.be(20);\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Ещё закрыто, откроется через час с лишним', function () {\n        var result =  d.getSchedule().transform(scheduleDemoData.tooEarly.model, {\n            now: mockTime(1366773607003)\n        }); // 10:20 ср 24 апреля 2013\n\n        expect(result.now.open).to.not.be.ok();\n        expect(result.always).to.be(undefined);\n        expect(result.today).to.be.ok();\n        expect(result.will.d).to.be(0);\n        expect(result.will.h).to.be(1);\n        expect(result.will.m).to.be(40);\n        expect(result.will.when).to.be(undefined);\n        expect(result.comment).to.ok('до последнего клиента');\n\n    });\n\n    it('Откроется завтра если сегодня воскресенье', function () { // Баг сбербанка\n        var result =  d.getSchedule().transform(scheduleDemoData.sberBank.model, {\n            now: mockTime(1367138129777)\n        }); // Воскресенье, 28 апреля 2013\n\n        expect(result.will.d).to.be(1);\n        expect(result.will.when).to.be('завтра');\n        expect(result.everyday).to.not.be.ok();\n\n    });\n\n    it('Ежедневно одинаково, откроется завтра', function () { // Баг с неправильной сортировкой timestamps\n        var result =  d.getSchedule().transform(scheduleDemoData.everyday.model, {\n            now: mockTime(1368015897543)\n        }); // Среда, 8 мая 2013, 19+\n\n        expect(result.will.d).to.be(1);\n    });\n\n    it('Timespamp совпадает с открытием – должен быть объект will', function () { // Баг с неправильной сортировкой timestamps\n        var result =  d.getSchedule().transform(scheduleDemoData.everyday.model, {\n            now: mockTime(1368015897543 + 52560000)\n        }); // Точно совпадает с временем открытия\n\n        expect(result.will).to.be.ok();\n    });\n});\n\ndescribe('FirmCard', function () {\n\n    it('При повторном render ajax не вызывается', function () {\n        var render = sinon.stub(FirmCard.prototype, '_renderCardById', function (firmId) {\n                this._firmId = firmId;\n                this.options.ajax();\n            }),\n            ajaxSpy = sinon.spy(function () {\n                firmCard._fullFirmEl = document.createElement('div');\n            }),\n            firmCard = new FirmCard(undefined,\n            {\n                ajax: ajaxSpy,\n                tmpls: {\n                    loader: ''\n                },\n                render: function () {return ''; }\n            });\n\n        firmCard.render('141265770546806');\n        firmCard.render('141265770546806');\n\n       expect(ajaxSpy.callCount).to.be.eql(1);\n\n       render.restore();\n\n    });\n\n    it('#getSchedule возвращает объект типа FirmCard.Schedule', function () {\n        var firmCard = new FirmCard();\n\n        expect(firmCard.getSchedule()).to.be.a(FirmCard.Schedule);\n    });\n\n});\n"
  },
  {
    "path": "vendors/firmcard/test/FirmListSpec.html",
    "content": "<!doctype html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n\n<body>\n    <script src=\"mocha.js\"></script>\n    <script src=\"sinon.js\"></script>\n    <script src=\"expect.js\"></script>\n\n    <script src=\"../src/FirmCard.js\"></script>\n    <script src=\"../src/FirmCard.DataHelper.js\"></script>\n    <script src=\"../src/FirmList.js\"></script>\n\n    <script src=\"../src/Schedule.js\"></script>\n    <script src=\"../src/Dictionary.js\"></script>\n\n    <script type=\"text/javascript\">\n        mocha.setup('bdd');\n        mocha.ignoreLeaks();\n    </script>\n\n    <div id=\"mocha\"></div>\n\n    <script src=\"FirmListSpec.js\"></script>\n    <script type=\"text/javascript\">\n        mocha.run();\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "vendors/firmcard/test/FirmListSpec.js",
    "content": "describe('DGFirmList', function () {\n    var render, results, addFirms, alreadyInList, defaultFirm;\n    beforeEach(function () {\n        results =\n        [{\"id\":\"141265769760312_7f48jh2915H23H8he2g3uvDn5A6AG45842cB44287906231J5b6d19G4H3G38495\",\"name\":\"Спарк-Авто, ООО\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359477657\",\"filials_count\":3,\"name\":\"Спарк-Авто, ООО\"},\"ads\":{\"warning\":null,\"micro_comment\":\"Оригинальные и дубликатные запчасти на авто европейского производства\"},\"rubrics\":{\"primary\":[{\"name\":\"Автозапчасти для иномарок\"},{\"name\":\"Автохимия / Масла\"},{\"name\":\"Автоаксессуары\"}],\"additional\":[]}},{\"id\":\"141265769349900_71B8jh2903H33H75e5BguvDn5A6AG45842cB4428379C231J546A19G4H3G28495\",\"name\":\"Автозапчасти, ООО Невис ПТ\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359268956\",\"filials_count\":1,\"name\":\"Автозапчасти, ООО Невис ПТ\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Автозапчасти для иномарок\"},{\"name\":\"Автоаксессуары\"}],\"additional\":[]}},{\"id\":\"141265769369916_77A8jh2919H43H6ee45BuvDn5A6AG4584AcB4428399C231J556719G4H3G28495\",\"name\":\"Детская поликлиника, Детская городская клиническая больница №1, Отделение №2\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359278970\",\"filials_count\":2,\"name\":\"Детская поликлиника, Детская городская клиническая больница №1\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Поликлиники детские\"}],\"additional\":[]}},{\"id\":\"141265770849956_7A88jh2959H53H78e9g9uvDn5A71G4584ecB4428879C231J5b6919G4H3G28495\",\"name\":\"Магазин автозапчастей для Peugeot, Citroen, Fiat, ООО Меркурий Авто\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359990712\",\"filials_count\":1,\"name\":\"Магазин автозапчастей для Peugeot, Citroen, Fiat, ООО Меркурий Авто\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Автозапчасти для иномарок\"}],\"additional\":[]}}];\n        addFirms = [{\"id\":\"141265770537261_gb48jh2964H43HA6b42guvDn5A71G4584gh744285675535JA18g19G4H3G28816\",\"name\":\"Семицветик, АНО, центр развития ребенка\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359781129\",\"filials_count\":4,\"name\":\"Семицветик, АНО, центр развития ребенка\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Центры раннего развития / дошкольного образования детей\"}],\"additional\":[]}},{\"id\":\"141265771201116_eb4Cjh2919H53HA5b66guvDn5A72G45876g744282314535JA18g19G4H3G28816\",\"name\":\"СибТайм, лингвистический центр\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359311404\",\"filials_count\":4,\"name\":\"СибТайм, лингвистический центр\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Школы иностранных языков\"}],\"additional\":[{\"name\":\"Перевод с иностранных языков\"},{\"name\":\"Обучение за рубежом\"}]}},{\"id\":\"141265770296136_2b49jh2939H63H87beeguvDn5A71G458b87744282C64535J918g19G4H3G28816\",\"name\":\"Пеликан, центр психолого-педагогической поддержки молодежи\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359390966\",\"filials_count\":2,\"name\":\"Пеликан, центр психолого-педагогической поддержки молодежи\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Услуги психолога\"}],\"additional\":[]}},{\"id\":\"141265770029779_1b4hjh297CH73H95b6cguvDn5A71G4583A574428059A535J218g19G4H3G28816\",\"name\":\"Следственный отдел по Кировскому району\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359738445\",\"filials_count\":1,\"name\":\"Следственный отдел по Кировскому району\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Следственный комитет\"}],\"additional\":[]}}];\n        alreadyInList = [{\"id\":\"141265769760312_7f48jh2915H23H8he2g3uvDn5A6AG45842cB44287906231J5b6d19G4H3G38495\",\"name\":\"Спарк-Авто, ООО\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359477657\",\"filials_count\":3,\"name\":\"Спарк-Авто, ООО\"},\"ads\":{\"warning\":null,\"micro_comment\":\"Оригинальные и дубликатные запчасти на авто европейского производства\"},\"rubrics\":{\"primary\":[{\"name\":\"Автозапчасти для иномарок\"},{\"name\":\"Автохимия / Масла\"},{\"name\":\"Автоаксессуары\"}],\"additional\":[]}}];\n        defaultFirm = {\"id\":\"141265769358463_1b4ijh2966H23H97b37guvDn5A6AG4589d9744283887535JB18g19G4H3G28816\",\"name\":\"Железобетонспецстрой, ЗАО, строительная компания\",\"type\":\"filial\",\"firm\":{\"id\":\"141274359275268\",\"filials_count\":1,\"name\":\"Железобетонспецстрой, ЗАО, строительная компания\"},\"ads\":null,\"rubrics\":{\"primary\":[{\"name\":\"Реконструкция и капремонт зданий\"},{\"name\":\"Промышленное строительство\"},{\"name\":\"Жилищное строительство\"}],\"additional\":[]}};\n    });\n\n    afterEach(function () {\n        results = addFirms = alreadyInList = defaultFirm = null;\n    });\n\n    describe('#should set correct default options:', function () {\n        it(\"default container\", function() {\n            var firmList = new FirmCard.List(results, {});\n\n            expect(firmList.getContainer().className).to.be('dg-building-callout__list');\n        });\n\n        it(\"default lang = ru\", function() {\n            var firmList = new FirmCard.List(results, {});\n\n            expect(firmList.getLang()).to.be('ru');\n        });\n    })\n\n    describe('#should manage FirmCards in correct way:', function () {\n        it(\"render results and return FirmList container\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n\n            expect(customContainer.className).to.be('dg-building-callout__list');\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(4);\n        });\n\n        it(\"add firm\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.addFirms(defaultFirm);\n            firmList.renderList();\n\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(5);\n        });\n\n        it(\"add firms array\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.addFirms(addFirms);\n            firmList.renderList();\n\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(8);\n        });\n\n        it(\"remove firm\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.removeFirms('141265769760312');\n\n            expect(customContainer.querySelector('#firm-141265769760312')).not.to.be.ok();\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(3);\n        });\n\n        it(\"remove firms array\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.renderList();\n            firmList.removeFirms(['141265769760312', '141265769349900', '141265770849956']);\n\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(1);\n        });\n\n        it(\"remove firms if List was cleared\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.renderList();\n            firmList.clearList();\n\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(0);\n        });\n\n        it(\"ignore firm if it already in list\", function() {\n            var customContainer = document.createElement('div'),\n                firmList = new FirmCard.List(results, {container: customContainer});\n            firmList.renderList();\n            firmList.addFirms(alreadyInList);\n            firmList.renderList();\n\n            expect(customContainer.querySelectorAll('.dg-building-callout__list-item').length).to.be(4);\n        });\n    })\n\n    describe('#should support localization:', function () {\n        it(\"setLang method\", function() {\n            var firmList = new FirmCard.List(results, {});\n            firmList.setLang('en');\n            expect(firmList.getLang()).to.be('en');\n        });\n    })\n});\n"
  },
  {
    "path": "vendors/firmcard/test/demoData.js",
    "content": "var scheduleDemoData = {\n\n    // Будни одинаково, выходные выходные\n    default: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Ежедневно одинаково\n    everyday: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sun\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // До нуля\n    evently: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Будни одинаково, суббота сокращённо\n    eventlySat: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"17:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Максимум часов в субботу\n    eventlySatMax: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"19:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Круглосуточно без выходных\n    alltime: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Sun\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Круглосуточно кроме выходных среды и воскресенья\n    thuHol: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": true,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"00:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Будни, начало недели во вторник, рабочая среда-пятница\n    strangeWeek: {\n        model: {\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"23:00\"\n                }]\n            },\n            \"Thu\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"23:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"00:00\",\n                    \"to\": \"23:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Пон-среда, пятница-воскресенье больше часов\n    periods2: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"19:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"19:00\"\n                }]\n            },\n            \"Sun\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"19:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    //\n    periods3: {\n        model: {\n            \"Sun\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"19:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    oneMinuteLeft: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:06\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    foraWeek: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:31\",\n                    \"to\": \"13:05\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    // Много обедов\n    lunches: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"15:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"15:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"15:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"15:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"Sun\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"13:00\"\n                }, {\n                    \"from\": \"14:00\",\n                    \"to\": \"15:00\"\n                }, {\n                    \"from\": \"16:00\",\n                    \"to\": \"18:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    night: {\n        model: {\n            \"Mon\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"05:00\"\n                }]\n            },\n            \"Tue\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"01:00\"\n                }]\n            },\n            \"Wed\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"02:00\"\n                }]\n            },\n            \"Fri\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"04:00\"\n                }]\n            },\n            \"Sat\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"17:00\"\n                }, {\n                    \"from\": \"18:00\",\n                    \"to\": \"04:00\"\n                }]\n            },\n            \"Sun\": {\n                \"round_the_clock\": false,\n                \"working_hours\": [{\n                    \"from\": \"10:00\",\n                    \"to\": \"04:00\"\n                }]\n            },\n            \"comment\": null\n        }\n    },\n\n    tooEarly: {\n        model: {\n            Mon: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Tue: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Wed: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Thu: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Fri: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Sat: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            Sun: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"12:00\",\n                    to: \"00:00\"\n                }]\n            },\n            comment: \"до последнего клиента\"\n        }\n    },\n\n    sberBank: {\n        model: {\n            Mon: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"09:00\",\n                    to: \"19:00\"\n                }]\n            },\n            Tue: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"09:00\",\n                    to: \"19:00\"\n                }]\n            },\n            Wed: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"09:00\",\n                    to: \"19:00\"\n                }]\n            },\n            Thu: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"09:00\",\n                    to: \"19:00\"\n                }]\n            },\n            Fri: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"09:00\",\n                    to: \"19:00\"\n                }]\n            },\n            Sat: {\n                round_the_clock: false,\n                working_hours: [{\n                    from: \"10:00\",\n                    to: \"16:00\"\n                }]\n            },\n            Sun: null,\n            comment: null\n        }\n    }\n};\n"
  },
  {
    "path": "vendors/firmcard/test/expect.js",
    "content": "\n(function (global, module) {\n\n  if ('undefined' == typeof module) {\n    var module = { exports: {} }\n      , exports = module.exports\n  }\n\n  /**\n   * Exports.\n   */\n\n  module.exports = expect;\n  expect.Assertion = Assertion;\n\n  /**\n   * Exports version.\n   */\n\n  expect.version = '0.1.2';\n\n  /**\n   * Possible assertion flags.\n   */\n\n  var flags = {\n      not: ['to', 'be', 'have', 'include', 'only']\n    , to: ['be', 'have', 'include', 'only', 'not']\n    , only: ['have']\n    , have: ['own']\n    , be: ['an']\n  };\n\n  function expect (obj) {\n    return new Assertion(obj);\n  }\n\n  /**\n   * Constructor\n   *\n   * @api private\n   */\n\n  function Assertion (obj, flag, parent) {\n    this.obj = obj;\n    this.flags = {};\n\n    if (undefined != parent) {\n      this.flags[flag] = true;\n\n      for (var i in parent.flags) {\n        if (parent.flags.hasOwnProperty(i)) {\n          this.flags[i] = true;\n        }\n      }\n    }\n\n    var $flags = flag ? flags[flag] : keys(flags)\n      , self = this\n\n    if ($flags) {\n      for (var i = 0, l = $flags.length; i < l; i++) {\n        // avoid recursion\n        if (this.flags[$flags[i]]) continue;\n\n        var name = $flags[i]\n          , assertion = new Assertion(this.obj, name, this)\n\n        if ('function' == typeof Assertion.prototype[name]) {\n          // clone the function, make sure we dont touch the prot reference\n          var old = this[name];\n          this[name] = function () {\n            return old.apply(self, arguments);\n          }\n\n          for (var fn in Assertion.prototype) {\n            if (Assertion.prototype.hasOwnProperty(fn) && fn != name) {\n              this[name][fn] = bind(assertion[fn], assertion);\n            }\n          }\n        } else {\n          this[name] = assertion;\n        }\n      }\n    }\n  };\n\n  /**\n   * Performs an assertion\n   *\n   * @api private\n   */\n\n  Assertion.prototype.assert = function (truth, msg, error) {\n    var msg = this.flags.not ? error : msg\n      , ok = this.flags.not ? !truth : truth;\n\n    if (!ok) {\n      throw new Error(msg.call(this));\n    }\n\n    this.and = new Assertion(this.obj);\n  };\n\n  /**\n   * Check if the value is truthy\n   *\n   * @api public\n   */\n\n  Assertion.prototype.ok = function () {\n    this.assert(\n        !!this.obj\n      , function(){ return 'expected ' + i(this.obj) + ' to be truthy' }\n      , function(){ return 'expected ' + i(this.obj) + ' to be falsy' });\n  };\n\n  /**\n   * Assert that the function throws.\n   *\n   * @param {Function|RegExp} callback, or regexp to match error string against\n   * @api public\n   */\n\n  Assertion.prototype.throwError =\n  Assertion.prototype.throwException = function (fn) {\n    expect(this.obj).to.be.a('function');\n\n    var thrown = false\n      , not = this.flags.not\n\n    try {\n      this.obj();\n    } catch (e) {\n      if ('function' == typeof fn) {\n        fn(e);\n      } else if ('object' == typeof fn) {\n        var subject = 'string' == typeof e ? e : e.message;\n        if (not) {\n          expect(subject).to.not.match(fn);\n        } else {\n          expect(subject).to.match(fn);\n        }\n      }\n      thrown = true;\n    }\n\n    if ('object' == typeof fn && not) {\n      // in the presence of a matcher, ensure the `not` only applies to\n      // the matching.\n      this.flags.not = false;\n    }\n\n    var name = this.obj.name || 'fn';\n    this.assert(\n        thrown\n      , function(){ return 'expected ' + name + ' to throw an exception' }\n      , function(){ return 'expected ' + name + ' not to throw an exception' });\n  };\n\n  /**\n   * Checks if the array is empty.\n   *\n   * @api public\n   */\n\n  Assertion.prototype.empty = function () {\n    var expectation;\n\n    if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) {\n      if ('number' == typeof this.obj.length) {\n        expectation = !this.obj.length;\n      } else {\n        expectation = !keys(this.obj).length;\n      }\n    } else {\n      if ('string' != typeof this.obj) {\n        expect(this.obj).to.be.an('object');\n      }\n\n      expect(this.obj).to.have.property('length');\n      expectation = !this.obj.length;\n    }\n\n    this.assert(\n        expectation\n      , function(){ return 'expected ' + i(this.obj) + ' to be empty' }\n      , function(){ return 'expected ' + i(this.obj) + ' to not be empty' });\n    return this;\n  };\n\n  /**\n   * Checks if the obj exactly equals another.\n   *\n   * @api public\n   */\n\n  Assertion.prototype.be =\n  Assertion.prototype.equal = function (obj) {\n    this.assert(\n        obj === this.obj\n      , function(){ return 'expected ' + i(this.obj) + ' to equal ' + i(obj) }\n      , function(){ return 'expected ' + i(this.obj) + ' to not equal ' + i(obj) });\n    return this;\n  };\n\n  /**\n   * Checks if the obj sortof equals another.\n   *\n   * @api public\n   */\n\n  Assertion.prototype.eql = function (obj) {\n    this.assert(\n        expect.eql(obj, this.obj)\n      , function(){ return 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) }\n      , function(){ return 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj) });\n    return this;\n  };\n\n  /**\n   * Assert within start to finish (inclusive).\n   *\n   * @param {Number} start\n   * @param {Number} finish\n   * @api public\n   */\n\n  Assertion.prototype.within = function (start, finish) {\n    var range = start + '..' + finish;\n    this.assert(\n        this.obj >= start && this.obj <= finish\n      , function(){ return 'expected ' + i(this.obj) + ' to be within ' + range }\n      , function(){ return 'expected ' + i(this.obj) + ' to not be within ' + range });\n    return this;\n  };\n\n  /**\n   * Assert typeof / instance of\n   *\n   * @api public\n   */\n\n  Assertion.prototype.a =\n  Assertion.prototype.an = function (type) {\n    if ('string' == typeof type) {\n      // proper english in error msg\n      var n = /^[aeiou]/.test(type) ? 'n' : '';\n\n      // typeof with support for 'array'\n      this.assert(\n          'array' == type ? isArray(this.obj) :\n            'object' == type\n              ? 'object' == typeof this.obj && null !== this.obj\n              : type == typeof this.obj\n        , function(){ return 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type }\n        , function(){ return 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type });\n    } else {\n      // instanceof\n      var name = type.name || 'supplied constructor';\n      this.assert(\n          this.obj instanceof type\n        , function(){ return 'expected ' + i(this.obj) + ' to be an instance of ' + name }\n        , function(){ return 'expected ' + i(this.obj) + ' not to be an instance of ' + name });\n    }\n\n    return this;\n  };\n\n  /**\n   * Assert numeric value above _n_.\n   *\n   * @param {Number} n\n   * @api public\n   */\n\n  Assertion.prototype.greaterThan =\n  Assertion.prototype.above = function (n) {\n    this.assert(\n        this.obj > n\n      , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n }\n      , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n });\n    return this;\n  };\n\n  /**\n   * Assert numeric value below _n_.\n   *\n   * @param {Number} n\n   * @api public\n   */\n\n  Assertion.prototype.lessThan =\n  Assertion.prototype.below = function (n) {\n    this.assert(\n        this.obj < n\n      , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n }\n      , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n });\n    return this;\n  };\n\n  /**\n   * Assert string value matches _regexp_.\n   *\n   * @param {RegExp} regexp\n   * @api public\n   */\n\n  Assertion.prototype.match = function (regexp) {\n    this.assert(\n        regexp.exec(this.obj)\n      , function(){ return 'expected ' + i(this.obj) + ' to match ' + regexp }\n      , function(){ return 'expected ' + i(this.obj) + ' not to match ' + regexp });\n    return this;\n  };\n\n  /**\n   * Assert property \"length\" exists and has value of _n_.\n   *\n   * @param {Number} n\n   * @api public\n   */\n\n  Assertion.prototype.length = function (n) {\n    expect(this.obj).to.have.property('length');\n    var len = this.obj.length;\n    this.assert(\n        n == len\n      , function(){ return 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len }\n      , function(){ return 'expected ' + i(this.obj) + ' to not have a length of ' + len });\n    return this;\n  };\n\n  /**\n   * Assert property _name_ exists, with optional _val_.\n   *\n   * @param {String} name\n   * @param {Mixed} val\n   * @api public\n   */\n\n  Assertion.prototype.property = function (name, val) {\n    if (this.flags.own) {\n      this.assert(\n          Object.prototype.hasOwnProperty.call(this.obj, name)\n        , function(){ return 'expected ' + i(this.obj) + ' to have own property ' + i(name) }\n        , function(){ return 'expected ' + i(this.obj) + ' to not have own property ' + i(name) });\n      return this;\n    }\n\n    if (this.flags.not && undefined !== val) {\n      if (undefined === this.obj[name]) {\n        throw new Error(i(this.obj) + ' has no property ' + i(name));\n      }\n    } else {\n      var hasProp;\n      try {\n        hasProp = name in this.obj\n      } catch (e) {\n        hasProp = undefined !== this.obj[name]\n      }\n\n      this.assert(\n          hasProp\n        , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) }\n        , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) });\n    }\n\n    if (undefined !== val) {\n      this.assert(\n          val === this.obj[name]\n        , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name)\n          + ' of ' + i(val) + ', but got ' + i(this.obj[name]) }\n        , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name)\n          + ' of ' + i(val) });\n    }\n\n    this.obj = this.obj[name];\n    return this;\n  };\n\n  /**\n   * Assert that the array contains _obj_ or string contains _obj_.\n   *\n   * @param {Mixed} obj|string\n   * @api public\n   */\n\n  Assertion.prototype.string =\n  Assertion.prototype.contain = function (obj) {\n    if ('string' == typeof this.obj) {\n      this.assert(\n          ~this.obj.indexOf(obj)\n        , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }\n        , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });\n    } else {\n      this.assert(\n          ~indexOf(this.obj, obj)\n        , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }\n        , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });\n    }\n    return this;\n  };\n\n  /**\n   * Assert exact keys or inclusion of keys by using\n   * the `.own` modifier.\n   *\n   * @param {Array|String ...} keys\n   * @api public\n   */\n\n  Assertion.prototype.key =\n  Assertion.prototype.keys = function ($keys) {\n    var str\n      , ok = true;\n\n    $keys = isArray($keys)\n      ? $keys\n      : Array.prototype.slice.call(arguments);\n\n    if (!$keys.length) throw new Error('keys required');\n\n    var actual = keys(this.obj)\n      , len = $keys.length;\n\n    // Inclusion\n    ok = every($keys, function (key) {\n      return ~indexOf(actual, key);\n    });\n\n    // Strict\n    if (!this.flags.not && this.flags.only) {\n      ok = ok && $keys.length == actual.length;\n    }\n\n    // Key string\n    if (len > 1) {\n      $keys = map($keys, function (key) {\n        return i(key);\n      });\n      var last = $keys.pop();\n      str = $keys.join(', ') + ', and ' + last;\n    } else {\n      str = i($keys[0]);\n    }\n\n    // Form\n    str = (len > 1 ? 'keys ' : 'key ') + str;\n\n    // Have / include\n    str = (!this.flags.only ? 'include ' : 'only have ') + str;\n\n    // Assertion\n    this.assert(\n        ok\n      , function(){ return 'expected ' + i(this.obj) + ' to ' + str }\n      , function(){ return 'expected ' + i(this.obj) + ' to not ' + str });\n\n    return this;\n  };\n  /**\n   * Assert a failure.\n   *\n   * @param {String ...} custom message\n   * @api public\n   */\n  Assertion.prototype.fail = function (msg) {\n    msg = msg || \"explicit failure\";\n    this.assert(false, msg, msg);\n    return this;\n  };\n\n  /**\n   * Function bind implementation.\n   */\n\n  function bind (fn, scope) {\n    return function () {\n      return fn.apply(scope, arguments);\n    }\n  }\n\n  /**\n   * Array every compatibility\n   *\n   * @see bit.ly/5Fq1N2\n   * @api public\n   */\n\n  function every (arr, fn, thisObj) {\n    var scope = thisObj || global;\n    for (var i = 0, j = arr.length; i < j; ++i) {\n      if (!fn.call(scope, arr[i], i, arr)) {\n        return false;\n      }\n    }\n    return true;\n  };\n\n  /**\n   * Array indexOf compatibility.\n   *\n   * @see bit.ly/a5Dxa2\n   * @api public\n   */\n\n  function indexOf (arr, o, i) {\n    if (Array.prototype.indexOf) {\n      return Array.prototype.indexOf.call(arr, o, i);\n    }\n\n    if (arr.length === undefined) {\n      return -1;\n    }\n\n    for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0\n        ; i < j && arr[i] !== o; i++);\n\n    return j <= i ? -1 : i;\n  };\n\n  // https://gist.github.com/1044128/\n  var getOuterHTML = function(element) {\n    if ('outerHTML' in element) return element.outerHTML;\n    var ns = \"http://www.w3.org/1999/xhtml\";\n    var container = document.createElementNS(ns, '_');\n    var elemProto = (window.HTMLElement || window.Element).prototype;\n    var xmlSerializer = new XMLSerializer();\n    var html;\n    if (document.xmlVersion) {\n      return xmlSerializer.serializeToString(element);\n    } else {\n      container.appendChild(element.cloneNode(false));\n      html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');\n      container.innerHTML = '';\n      return html;\n    }\n  };\n\n  // Returns true if object is a DOM element.\n  var isDOMElement = function (object) {\n    if (typeof HTMLElement === 'object') {\n      return object instanceof HTMLElement;\n    } else {\n      return object &&\n        typeof object === 'object' &&\n        object.nodeType === 1 &&\n        typeof object.nodeName === 'string';\n    }\n  };\n\n  /**\n   * Inspects an object.\n   *\n   * @see taken from node.js `util` module (copyright Joyent, MIT license)\n   * @api private\n   */\n\n  function i (obj, showHidden, depth) {\n    var seen = [];\n\n    function stylize (str) {\n      return str;\n    };\n\n    function format (value, recurseTimes) {\n      // Provide a hook for user-specified inspect functions.\n      // Check that value is an object with an inspect function on it\n      if (value && typeof value.inspect === 'function' &&\n          // Filter out the util module, it's inspect function is special\n          value !== exports &&\n          // Also filter out any prototype objects using the circular check.\n          !(value.constructor && value.constructor.prototype === value)) {\n        return value.inspect(recurseTimes);\n      }\n\n      // Primitive types cannot have properties\n      switch (typeof value) {\n        case 'undefined':\n          return stylize('undefined', 'undefined');\n\n        case 'string':\n          var simple = '\\'' + json.stringify(value).replace(/^\"|\"$/g, '')\n                                                   .replace(/'/g, \"\\\\'\")\n                                                   .replace(/\\\\\"/g, '\"') + '\\'';\n          return stylize(simple, 'string');\n\n        case 'number':\n          return stylize('' + value, 'number');\n\n        case 'boolean':\n          return stylize('' + value, 'boolean');\n      }\n      // For some reason typeof null is \"object\", so special case here.\n      if (value === null) {\n        return stylize('null', 'null');\n      }\n\n      if (isDOMElement(value)) {\n        return getOuterHTML(value);\n      }\n\n      // Look up the keys of the object.\n      var visible_keys = keys(value);\n      var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys;\n\n      // Functions without properties can be shortcutted.\n      if (typeof value === 'function' && $keys.length === 0) {\n        if (isRegExp(value)) {\n          return stylize('' + value, 'regexp');\n        } else {\n          var name = value.name ? ': ' + value.name : '';\n          return stylize('[Function' + name + ']', 'special');\n        }\n      }\n\n      // Dates without properties can be shortcutted\n      if (isDate(value) && $keys.length === 0) {\n        return stylize(value.toUTCString(), 'date');\n      }\n\n      var base, type, braces;\n      // Determine the object type\n      if (isArray(value)) {\n        type = 'Array';\n        braces = ['[', ']'];\n      } else {\n        type = 'Object';\n        braces = ['{', '}'];\n      }\n\n      // Make functions say that they are functions\n      if (typeof value === 'function') {\n        var n = value.name ? ': ' + value.name : '';\n        base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';\n      } else {\n        base = '';\n      }\n\n      // Make dates with properties first say the date\n      if (isDate(value)) {\n        base = ' ' + value.toUTCString();\n      }\n\n      if ($keys.length === 0) {\n        return braces[0] + base + braces[1];\n      }\n\n      if (recurseTimes < 0) {\n        if (isRegExp(value)) {\n          return stylize('' + value, 'regexp');\n        } else {\n          return stylize('[Object]', 'special');\n        }\n      }\n\n      seen.push(value);\n\n      var output = map($keys, function (key) {\n        var name, str;\n        if (value.__lookupGetter__) {\n          if (value.__lookupGetter__(key)) {\n            if (value.__lookupSetter__(key)) {\n              str = stylize('[Getter/Setter]', 'special');\n            } else {\n              str = stylize('[Getter]', 'special');\n            }\n          } else {\n            if (value.__lookupSetter__(key)) {\n              str = stylize('[Setter]', 'special');\n            }\n          }\n        }\n        if (indexOf(visible_keys, key) < 0) {\n          name = '[' + key + ']';\n        }\n        if (!str) {\n          if (indexOf(seen, value[key]) < 0) {\n            if (recurseTimes === null) {\n              str = format(value[key]);\n            } else {\n              str = format(value[key], recurseTimes - 1);\n            }\n            if (str.indexOf('\\n') > -1) {\n              if (isArray(value)) {\n                str = map(str.split('\\n'), function (line) {\n                  return '  ' + line;\n                }).join('\\n').substr(2);\n              } else {\n                str = '\\n' + map(str.split('\\n'), function (line) {\n                  return '   ' + line;\n                }).join('\\n');\n              }\n            }\n          } else {\n            str = stylize('[Circular]', 'special');\n          }\n        }\n        if (typeof name === 'undefined') {\n          if (type === 'Array' && key.match(/^\\d+$/)) {\n            return str;\n          }\n          name = json.stringify('' + key);\n          if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n            name = name.substr(1, name.length - 2);\n            name = stylize(name, 'name');\n          } else {\n            name = name.replace(/'/g, \"\\\\'\")\n                       .replace(/\\\\\"/g, '\"')\n                       .replace(/(^\"|\"$)/g, \"'\");\n            name = stylize(name, 'string');\n          }\n        }\n\n        return name + ': ' + str;\n      });\n\n      seen.pop();\n\n      var numLinesEst = 0;\n      var length = reduce(output, function (prev, cur) {\n        numLinesEst++;\n        if (indexOf(cur, '\\n') >= 0) numLinesEst++;\n        return prev + cur.length + 1;\n      }, 0);\n\n      if (length > 50) {\n        output = braces[0] +\n                 (base === '' ? '' : base + '\\n ') +\n                 ' ' +\n                 output.join(',\\n  ') +\n                 ' ' +\n                 braces[1];\n\n      } else {\n        output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n      }\n\n      return output;\n    }\n    return format(obj, (typeof depth === 'undefined' ? 2 : depth));\n  };\n\n  function isArray (ar) {\n    return Object.prototype.toString.call(ar) == '[object Array]';\n  };\n\n  function isRegExp(re) {\n    var s;\n    try {\n      s = '' + re;\n    } catch (e) {\n      return false;\n    }\n\n    return re instanceof RegExp || // easy case\n           // duck-type for context-switching evalcx case\n           typeof(re) === 'function' &&\n           re.constructor.name === 'RegExp' &&\n           re.compile &&\n           re.test &&\n           re.exec &&\n           s.match(/^\\/.*\\/[gim]{0,3}$/);\n  };\n\n  function isDate(d) {\n    if (d instanceof Date) return true;\n    return false;\n  };\n\n  function keys (obj) {\n    if (Object.keys) {\n      return Object.keys(obj);\n    }\n\n    var keys = [];\n\n    for (var i in obj) {\n      if (Object.prototype.hasOwnProperty.call(obj, i)) {\n        keys.push(i);\n      }\n    }\n\n    return keys;\n  }\n\n  function map (arr, mapper, that) {\n    if (Array.prototype.map) {\n      return Array.prototype.map.call(arr, mapper, that);\n    }\n\n    var other= new Array(arr.length);\n\n    for (var i= 0, n = arr.length; i<n; i++)\n      if (i in arr)\n        other[i] = mapper.call(that, arr[i], i, arr);\n\n    return other;\n  };\n\n  function reduce (arr, fun) {\n    if (Array.prototype.reduce) {\n      return Array.prototype.reduce.apply(\n          arr\n        , Array.prototype.slice.call(arguments, 1)\n      );\n    }\n\n    var len = +this.length;\n\n    if (typeof fun !== \"function\")\n      throw new TypeError();\n\n    // no value to return if no initial value and an empty array\n    if (len === 0 && arguments.length === 1)\n      throw new TypeError();\n\n    var i = 0;\n    if (arguments.length >= 2) {\n      var rv = arguments[1];\n    } else {\n      do {\n        if (i in this) {\n          rv = this[i++];\n          break;\n        }\n\n        // if array contains no values, no initial value to return\n        if (++i >= len)\n          throw new TypeError();\n      } while (true);\n    }\n\n    for (; i < len; i++) {\n      if (i in this)\n        rv = fun.call(null, rv, this[i], i, this);\n    }\n\n    return rv;\n  };\n\n  /**\n   * Asserts deep equality\n   *\n   * @see taken from node.js `assert` module (copyright Joyent, MIT license)\n   * @api private\n   */\n\n  expect.eql = function eql (actual, expected) {\n    // 7.1. All identical values are equivalent, as determined by ===.\n    if (actual === expected) {\n      return true;\n    } else if ('undefined' != typeof Buffer\n        && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {\n      if (actual.length != expected.length) return false;\n\n      for (var i = 0; i < actual.length; i++) {\n        if (actual[i] !== expected[i]) return false;\n      }\n\n      return true;\n\n    // 7.2. If the expected value is a Date object, the actual value is\n    // equivalent if it is also a Date object that refers to the same time.\n    } else if (actual instanceof Date && expected instanceof Date) {\n      return actual.getTime() === expected.getTime();\n\n    // 7.3. Other pairs that do not both pass typeof value == \"object\",\n    // equivalence is determined by ==.\n    } else if (typeof actual != 'object' && typeof expected != 'object') {\n      return actual == expected;\n\n    // 7.4. For all other Object pairs, including Array objects, equivalence is\n    // determined by having the same number of owned properties (as verified\n    // with Object.prototype.hasOwnProperty.call), the same set of keys\n    // (although not necessarily the same order), equivalent values for every\n    // corresponding key, and an identical \"prototype\" property. Note: this\n    // accounts for both named and indexed properties on Arrays.\n    } else {\n      return objEquiv(actual, expected);\n    }\n  }\n\n  function isUndefinedOrNull (value) {\n    return value === null || value === undefined;\n  }\n\n  function isArguments (object) {\n    return Object.prototype.toString.call(object) == '[object Arguments]';\n  }\n\n  function objEquiv (a, b) {\n    if (isUndefinedOrNull(a) || isUndefinedOrNull(b))\n      return false;\n    // an identical \"prototype\" property.\n    if (a.prototype !== b.prototype) return false;\n    //~~~I've managed to break Object.keys through screwy arguments passing.\n    //   Converting to array solves the problem.\n    if (isArguments(a)) {\n      if (!isArguments(b)) {\n        return false;\n      }\n      a = pSlice.call(a);\n      b = pSlice.call(b);\n      return expect.eql(a, b);\n    }\n    try{\n      var ka = keys(a),\n        kb = keys(b),\n        key, i;\n    } catch (e) {//happens when one is a string literal and the other isn't\n      return false;\n    }\n    // having the same number of owned properties (keys incorporates hasOwnProperty)\n    if (ka.length != kb.length)\n      return false;\n    //the same set of keys (although not necessarily the same order),\n    ka.sort();\n    kb.sort();\n    //~~~cheap key test\n    for (i = ka.length - 1; i >= 0; i--) {\n      if (ka[i] != kb[i])\n        return false;\n    }\n    //equivalent values for every corresponding key, and\n    //~~~possibly expensive deep test\n    for (i = ka.length - 1; i >= 0; i--) {\n      key = ka[i];\n      if (!expect.eql(a[key], b[key]))\n         return false;\n    }\n    return true;\n  }\n\n  var json = (function () {\n    \"use strict\";\n\n    if ('object' == typeof JSON && JSON.parse && JSON.stringify) {\n      return {\n          parse: nativeJSON.parse\n        , stringify: nativeJSON.stringify\n      }\n    }\n\n    var JSON = {};\n\n    function f(n) {\n        // Format integers to have at least two digits.\n        return n < 10 ? '0' + n : n;\n    }\n\n    function date(d, key) {\n      return isFinite(d.valueOf()) ?\n          d.getUTCFullYear()     + '-' +\n          f(d.getUTCMonth() + 1) + '-' +\n          f(d.getUTCDate())      + 'T' +\n          f(d.getUTCHours())     + ':' +\n          f(d.getUTCMinutes())   + ':' +\n          f(d.getUTCSeconds())   + 'Z' : null;\n    };\n\n    var cx = /[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n        escapable = /[\\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,\n        gap,\n        indent,\n        meta = {    // table of character substitutions\n            '\\b': '\\\\b',\n            '\\t': '\\\\t',\n            '\\n': '\\\\n',\n            '\\f': '\\\\f',\n            '\\r': '\\\\r',\n            '\"' : '\\\\\"',\n            '\\\\': '\\\\\\\\'\n        },\n        rep;\n\n\n    function quote(string) {\n\n  // If the string contains no control characters, no quote characters, and no\n  // backslash characters, then we can safely slap some quotes around it.\n  // Otherwise we must also replace the offending characters with safe escape\n  // sequences.\n\n        escapable.lastIndex = 0;\n        return escapable.test(string) ? '\"' + string.replace(escapable, function (a) {\n            var c = meta[a];\n            return typeof c === 'string' ? c :\n                '\\\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n        }) + '\"' : '\"' + string + '\"';\n    }\n\n\n    function str(key, holder) {\n\n  // Produce a string from holder[key].\n\n        var i,          // The loop counter.\n            k,          // The member key.\n            v,          // The member value.\n            length,\n            mind = gap,\n            partial,\n            value = holder[key];\n\n  // If the value has a toJSON method, call it to obtain a replacement value.\n\n        if (value instanceof Date) {\n            value = date(key);\n        }\n\n  // If we were called with a replacer function, then call the replacer to\n  // obtain a replacement value.\n\n        if (typeof rep === 'function') {\n            value = rep.call(holder, key, value);\n        }\n\n  // What happens next depends on the value's type.\n\n        switch (typeof value) {\n        case 'string':\n            return quote(value);\n\n        case 'number':\n\n  // JSON numbers must be finite. Encode non-finite numbers as null.\n\n            return isFinite(value) ? String(value) : 'null';\n\n        case 'boolean':\n        case 'null':\n\n  // If the value is a boolean or null, convert it to a string. Note:\n  // typeof null does not produce 'null'. The case is included here in\n  // the remote chance that this gets fixed someday.\n\n            return String(value);\n\n  // If the type is 'object', we might be dealing with an object or an array or\n  // null.\n\n        case 'object':\n\n  // Due to a specification blunder in ECMAScript, typeof null is 'object',\n  // so watch out for that case.\n\n            if (!value) {\n                return 'null';\n            }\n\n  // Make an array to hold the partial results of stringifying this object value.\n\n            gap += indent;\n            partial = [];\n\n  // Is the value an array?\n\n            if (Object.prototype.toString.apply(value) === '[object Array]') {\n\n  // The value is an array. Stringify every element. Use null as a placeholder\n  // for non-JSON values.\n\n                length = value.length;\n                for (i = 0; i < length; i += 1) {\n                    partial[i] = str(i, value) || 'null';\n                }\n\n  // Join all of the elements together, separated with commas, and wrap them in\n  // brackets.\n\n                v = partial.length === 0 ? '[]' : gap ?\n                    '[\\n' + gap + partial.join(',\\n' + gap) + '\\n' + mind + ']' :\n                    '[' + partial.join(',') + ']';\n                gap = mind;\n                return v;\n            }\n\n  // If the replacer is an array, use it to select the members to be stringified.\n\n            if (rep && typeof rep === 'object') {\n                length = rep.length;\n                for (i = 0; i < length; i += 1) {\n                    if (typeof rep[i] === 'string') {\n                        k = rep[i];\n                        v = str(k, value);\n                        if (v) {\n                            partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                        }\n                    }\n                }\n            } else {\n\n  // Otherwise, iterate through all of the keys in the object.\n\n                for (k in value) {\n                    if (Object.prototype.hasOwnProperty.call(value, k)) {\n                        v = str(k, value);\n                        if (v) {\n                            partial.push(quote(k) + (gap ? ': ' : ':') + v);\n                        }\n                    }\n                }\n            }\n\n  // Join all of the member texts together, separated with commas,\n  // and wrap them in braces.\n\n            v = partial.length === 0 ? '{}' : gap ?\n                '{\\n' + gap + partial.join(',\\n' + gap) + '\\n' + mind + '}' :\n                '{' + partial.join(',') + '}';\n            gap = mind;\n            return v;\n        }\n    }\n\n  // If the JSON object does not yet have a stringify method, give it one.\n\n    JSON.stringify = function (value, replacer, space) {\n\n  // The stringify method takes a value and an optional replacer, and an optional\n  // space parameter, and returns a JSON text. The replacer can be a function\n  // that can replace values, or an array of strings that will select the keys.\n  // A default replacer method can be provided. Use of the space parameter can\n  // produce text that is more easily readable.\n\n        var i;\n        gap = '';\n        indent = '';\n\n  // If the space parameter is a number, make an indent string containing that\n  // many spaces.\n\n        if (typeof space === 'number') {\n            for (i = 0; i < space; i += 1) {\n                indent += ' ';\n            }\n\n  // If the space parameter is a string, it will be used as the indent string.\n\n        } else if (typeof space === 'string') {\n            indent = space;\n        }\n\n  // If there is a replacer, it must be a function or an array.\n  // Otherwise, throw an error.\n\n        rep = replacer;\n        if (replacer && typeof replacer !== 'function' &&\n                (typeof replacer !== 'object' ||\n                typeof replacer.length !== 'number')) {\n            throw new Error('JSON.stringify');\n        }\n\n  // Make a fake root object containing our value under the key of ''.\n  // Return the result of stringifying the value.\n\n        return str('', {'': value});\n    };\n\n  // If the JSON object does not yet have a parse method, give it one.\n\n    JSON.parse = function (text, reviver) {\n    // The parse method takes a text and an optional reviver function, and returns\n    // a JavaScript value if the text is a valid JSON text.\n\n        var j;\n\n        function walk(holder, key) {\n\n    // The walk method is used to recursively walk the resulting structure so\n    // that modifications can be made.\n\n            var k, v, value = holder[key];\n            if (value && typeof value === 'object') {\n                for (k in value) {\n                    if (Object.prototype.hasOwnProperty.call(value, k)) {\n                        v = walk(value, k);\n                        if (v !== undefined) {\n                            value[k] = v;\n                        } else {\n                            delete value[k];\n                        }\n                    }\n                }\n            }\n            return reviver.call(holder, key, value);\n        }\n\n\n    // Parsing happens in four stages. In the first stage, we replace certain\n    // Unicode characters with escape sequences. JavaScript handles many characters\n    // incorrectly, either silently deleting them, or treating them as line endings.\n\n        text = String(text);\n        cx.lastIndex = 0;\n        if (cx.test(text)) {\n            text = text.replace(cx, function (a) {\n                return '\\\\u' +\n                    ('0000' + a.charCodeAt(0).toString(16)).slice(-4);\n            });\n        }\n\n    // In the second stage, we run the text against regular expressions that look\n    // for non-JSON patterns. We are especially concerned with '()' and 'new'\n    // because they can cause invocation, and '=' because it can cause mutation.\n    // But just to be safe, we want to reject all unexpected forms.\n\n    // We split the second stage into 4 regexp operations in order to work around\n    // crippling inefficiencies in IE's and Safari's regexp engines. First we\n    // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we\n    // replace all simple value tokens with ']' characters. Third, we delete all\n    // open brackets that follow a colon or comma or that begin the text. Finally,\n    // we look to see that the remaining characters are only whitespace or ']' or\n    // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.\n\n        if (/^[\\],:{}\\s]*$/\n                .test(text.replace(/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')\n                    .replace(/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g, ']')\n                    .replace(/(?:^|:|,)(?:\\s*\\[)+/g, ''))) {\n\n    // In the third stage we use the eval function to compile the text into a\n    // JavaScript structure. The '{' operator is subject to a syntactic ambiguity\n    // in JavaScript: it can begin a block or an object literal. We wrap the text\n    // in parens to eliminate the ambiguity.\n\n            j = eval('(' + text + ')');\n\n    // In the optional fourth stage, we recursively walk the new structure, passing\n    // each name/value pair to a reviver function for possible transformation.\n\n            return typeof reviver === 'function' ?\n                walk({'': j}, '') : j;\n        }\n\n    // If the text is not JSON parseable, then a SyntaxError is thrown.\n\n        throw new SyntaxError('JSON.parse');\n    };\n\n    return JSON;\n  })();\n\n  if ('undefined' != typeof window) {\n    window.expect = module.exports;\n  }\n\n})(\n    this\n  , 'undefined' != typeof module ? module : {}\n  , 'undefined' != typeof exports ? exports : {}\n);\n"
  },
  {
    "path": "vendors/firmcard/test/mocha.css",
    "content": "@charset \"utf-8\";\n\nbody {\n  font: 20px/1.5 \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  padding: 60px 50px;\n}\n\n#mocha ul, #mocha li {\n  margin: 0;\n  padding: 0;\n}\n\n#mocha ul {\n  list-style: none;\n}\n\n#mocha h1, #mocha h2 {\n  margin: 0;\n}\n\n#mocha h1 {\n  margin-top: 15px;\n  font-size: 1em;\n  font-weight: 200;\n}\n\n#mocha h1 a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha h1 a:hover {\n  text-decoration: underline;\n}\n\n#mocha .suite .suite h1 {\n  margin-top: 0;\n  font-size: .8em;\n}\n\n.hidden {\n  display: none;\n}\n\n#mocha h2 {\n  font-size: 12px;\n  font-weight: normal;\n  cursor: pointer;\n}\n\n#mocha .suite {\n  margin-left: 15px;\n}\n\n#mocha .test {\n  margin-left: 15px;\n  overflow: hidden;\n}\n\n#mocha .test.pending:hover h2::after {\n  content: '(pending)';\n  font-family: arial;\n}\n\n#mocha .test.pass.medium .duration {\n  background: #C09853;\n}\n\n#mocha .test.pass.slow .duration {\n  background: #B94A48;\n}\n\n#mocha .test.pass::before {\n  content: '✓';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #00d6b2;\n}\n\n#mocha .test.pass .duration {\n  font-size: 9px;\n  margin-left: 5px;\n  padding: 2px 5px;\n  color: white;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  -ms-border-radius: 5px;\n  -o-border-radius: 5px;\n  border-radius: 5px;\n}\n\n#mocha .test.pass.fast .duration {\n  display: none;\n}\n\n#mocha .test.pending {\n  color: #0b97c4;\n}\n\n#mocha .test.pending::before {\n  content: '◦';\n  color: #0b97c4;\n}\n\n#mocha .test.fail {\n  color: #c00;\n}\n\n#mocha .test.fail pre {\n  color: black;\n}\n\n#mocha .test.fail::before {\n  content: '✖';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #c00;\n}\n\n#mocha .test pre.error {\n  color: #c00;\n  max-height: 300px;\n  overflow: auto;\n}\n\n#mocha .test pre {\n  display: block;\n  float: left;\n  clear: left;\n  font: 12px/1.5 monaco, monospace;\n  margin: 5px;\n  padding: 15px;\n  border: 1px solid #eee;\n  border-bottom-color: #ddd;\n  -webkit-border-radius: 3px;\n  -webkit-box-shadow: 0 1px 3px #eee;\n  -moz-border-radius: 3px;\n  -moz-box-shadow: 0 1px 3px #eee;\n}\n\n#mocha .test h2 {\n  position: relative;\n}\n\n#mocha .test a.replay {\n  position: absolute;\n  top: 3px;\n  right: 0;\n  text-decoration: none;\n  vertical-align: middle;\n  display: block;\n  width: 15px;\n  height: 15px;\n  line-height: 15px;\n  text-align: center;\n  background: #eee;\n  font-size: 15px;\n  -moz-border-radius: 15px;\n  border-radius: 15px;\n  -webkit-transition: opacity 200ms;\n  -moz-transition: opacity 200ms;\n  transition: opacity 200ms;\n  opacity: 0.3;\n  color: #888;\n}\n\n#mocha .test:hover a.replay {\n  opacity: 1;\n}\n\n#mocha-report.pass .test.fail {\n  display: none;\n}\n\n#mocha-report.fail .test.pass {\n  display: none;\n}\n\n#mocha-error {\n  color: #c00;\n  font-size: 1.5  em;\n  font-weight: 100;\n  letter-spacing: 1px;\n}\n\n#mocha-stats {\n  position: fixed;\n  top: 15px;\n  right: 10px;\n  font-size: 12px;\n  margin: 0;\n  color: #888;\n}\n\n#mocha-stats .progress {\n  float: right;\n  padding-top: 0;\n}\n\n#mocha-stats em {\n  color: black;\n}\n\n#mocha-stats a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha-stats a:hover {\n  border-bottom: 1px solid #eee;\n}\n\n#mocha-stats li {\n  display: inline-block;\n  margin: 0 5px;\n  list-style: none;\n  padding-top: 11px;\n}\n\n#mocha-stats canvas {\n  width: 40px;\n  height: 40px;\n}\n\ncode .comment { color: #ddd }\ncode .init { color: #2F6FAD }\ncode .string { color: #5890AD }\ncode .keyword { color: #8A6343 }\ncode .number { color: #2F6FAD }\n\n@media screen and (max-device-width: 480px) {\n  body {\n    padding: 60px 0px;\n  }\n\n  #stats {\n    position: absolute;\n  }\n}"
  },
  {
    "path": "vendors/firmcard/test/mocha.js",
    "content": ";(function(){\n\n// CommonJS require()\n\nfunction require(p){\n    var path = require.resolve(p)\n      , mod = require.modules[path];\n    if (!mod) throw new Error('failed to require \"' + p + '\"');\n    if (!mod.exports) {\n      mod.exports = {};\n      mod.call(mod.exports, mod, mod.exports, require.relative(path));\n    }\n    return mod.exports;\n  }\n\nrequire.modules = {};\n\nrequire.resolve = function (path){\n    var orig = path\n      , reg = path + '.js'\n      , index = path + '/index.js';\n    return require.modules[reg] && reg\n      || require.modules[index] && index\n      || orig;\n  };\n\nrequire.register = function (path, fn){\n    require.modules[path] = fn;\n  };\n\nrequire.relative = function (parent) {\n    return function(p){\n      if ('.' != p.charAt(0)) return require(p);\n\n      var path = parent.split('/')\n        , segs = p.split('/');\n      path.pop();\n\n      for (var i = 0; i < segs.length; i++) {\n        var seg = segs[i];\n        if ('..' == seg) path.pop();\n        else if ('.' != seg) path.push(seg);\n      }\n\n      return require(path.join('/'));\n    };\n  };\n\n\nrequire.register(\"browser/debug.js\", function(module, exports, require){\n\nmodule.exports = function(type){\n  return function(){\n  }\n};\n\n}); // module: browser/debug.js\n\nrequire.register(\"browser/diff.js\", function(module, exports, require){\n/* See license.txt for terms of usage */\n\n/*\n * Text diff implementation.\n * \n * This library supports the following APIS:\n * JsDiff.diffChars: Character by character diff\n * JsDiff.diffWords: Word (as defined by \\b regex) diff which ignores whitespace\n * JsDiff.diffLines: Line based diff\n * \n * JsDiff.diffCss: Diff targeted at CSS content\n * \n * These methods are based on the implementation proposed in\n * \"An O(ND) Difference Algorithm and its Variations\" (Myers, 1986).\n * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927\n */\nvar JsDiff = (function() {\n  function clonePath(path) {\n    return { newPos: path.newPos, components: path.components.slice(0) };\n  }\n  function removeEmpty(array) {\n    var ret = [];\n    for (var i = 0; i < array.length; i++) {\n      if (array[i]) {\n        ret.push(array[i]);\n      }\n    }\n    return ret;\n  }\n  function escapeHTML(s) {\n    var n = s;\n    n = n.replace(/&/g, \"&amp;\");\n    n = n.replace(/</g, \"&lt;\");\n    n = n.replace(/>/g, \"&gt;\");\n    n = n.replace(/\"/g, \"&quot;\");\n\n    return n;\n  }\n\n\n  var fbDiff = function(ignoreWhitespace) {\n    this.ignoreWhitespace = ignoreWhitespace;\n  };\n  fbDiff.prototype = {\n      diff: function(oldString, newString) {\n        // Handle the identity case (this is due to unrolling editLength == 0\n        if (newString == oldString) {\n          return [{ value: newString }];\n        }\n        if (!newString) {\n          return [{ value: oldString, removed: true }];\n        }\n        if (!oldString) {\n          return [{ value: newString, added: true }];\n        }\n\n        newString = this.tokenize(newString);\n        oldString = this.tokenize(oldString);\n\n        var newLen = newString.length, oldLen = oldString.length;\n        var maxEditLength = newLen + oldLen;\n        var bestPath = [{ newPos: -1, components: [] }];\n\n        // Seed editLength = 0\n        var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);\n        if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {\n          return bestPath[0].components;\n        }\n\n        for (var editLength = 1; editLength <= maxEditLength; editLength++) {\n          for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {\n            var basePath;\n            var addPath = bestPath[diagonalPath-1],\n                removePath = bestPath[diagonalPath+1];\n            oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;\n            if (addPath) {\n              // No one else is going to attempt to use this value, clear it\n              bestPath[diagonalPath-1] = undefined;\n            }\n\n            var canAdd = addPath && addPath.newPos+1 < newLen;\n            var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;\n            if (!canAdd && !canRemove) {\n              bestPath[diagonalPath] = undefined;\n              continue;\n            }\n\n            // Select the diagonal that we want to branch from. We select the prior\n            // path whose position in the new string is the farthest from the origin\n            // and does not pass the bounds of the diff graph\n            if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {\n              basePath = clonePath(removePath);\n              this.pushComponent(basePath.components, oldString[oldPos], undefined, true);\n            } else {\n              basePath = clonePath(addPath);\n              basePath.newPos++;\n              this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);\n            }\n\n            var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);\n\n            if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {\n              return basePath.components;\n            } else {\n              bestPath[diagonalPath] = basePath;\n            }\n          }\n        }\n      },\n\n      pushComponent: function(components, value, added, removed) {\n        var last = components[components.length-1];\n        if (last && last.added === added && last.removed === removed) {\n          // We need to clone here as the component clone operation is just\n          // as shallow array clone\n          components[components.length-1] =\n            {value: this.join(last.value, value), added: added, removed: removed };\n        } else {\n          components.push({value: value, added: added, removed: removed });\n        }\n      },\n      extractCommon: function(basePath, newString, oldString, diagonalPath) {\n        var newLen = newString.length,\n            oldLen = oldString.length,\n            newPos = basePath.newPos,\n            oldPos = newPos - diagonalPath;\n        while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {\n          newPos++;\n          oldPos++;\n          \n          this.pushComponent(basePath.components, newString[newPos], undefined, undefined);\n        }\n        basePath.newPos = newPos;\n        return oldPos;\n      },\n\n      equals: function(left, right) {\n        var reWhitespace = /\\S/;\n        if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {\n          return true;\n        } else {\n          return left == right;\n        }\n      },\n      join: function(left, right) {\n        return left + right;\n      },\n      tokenize: function(value) {\n        return value;\n      }\n  };\n  \n  var CharDiff = new fbDiff();\n  \n  var WordDiff = new fbDiff(true);\n  WordDiff.tokenize = function(value) {\n    return removeEmpty(value.split(/(\\s+|\\b)/));\n  };\n  \n  var CssDiff = new fbDiff(true);\n  CssDiff.tokenize = function(value) {\n    return removeEmpty(value.split(/([{}:;,]|\\s+)/));\n  };\n  \n  var LineDiff = new fbDiff();\n  LineDiff.tokenize = function(value) {\n    return value.split(/^/m);\n  };\n  \n  return {\n    diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },\n    diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },\n    diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },\n\n    diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },\n\n    createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {\n      var ret = [];\n\n      ret.push(\"Index: \" + fileName);\n      ret.push(\"===================================================================\");\n      ret.push(\"--- \" + fileName + (typeof oldHeader === \"undefined\" ? \"\" : \"\\t\" + oldHeader));\n      ret.push(\"+++ \" + fileName + (typeof newHeader === \"undefined\" ? \"\" : \"\\t\" + newHeader));\n\n      var diff = LineDiff.diff(oldStr, newStr);\n      if (!diff[diff.length-1].value) {\n        diff.pop();   // Remove trailing newline add\n      }\n      diff.push({value: \"\", lines: []});   // Append an empty value to make cleanup easier\n\n      function contextLines(lines) {\n        return lines.map(function(entry) { return ' ' + entry; });\n      }\n      function eofNL(curRange, i, current) {\n        var last = diff[diff.length-2],\n            isLast = i === diff.length-2,\n            isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);\n\n        // Figure out if this is the last line for the given file and missing NL\n        if (!/\\n$/.test(current.value) && (isLast || isLastOfType)) {\n          curRange.push('\\\\ No newline at end of file');\n        }\n      }\n\n      var oldRangeStart = 0, newRangeStart = 0, curRange = [],\n          oldLine = 1, newLine = 1;\n      for (var i = 0; i < diff.length; i++) {\n        var current = diff[i],\n            lines = current.lines || current.value.replace(/\\n$/, \"\").split(\"\\n\");\n        current.lines = lines;\n\n        if (current.added || current.removed) {\n          if (!oldRangeStart) {\n            var prev = diff[i-1];\n            oldRangeStart = oldLine;\n            newRangeStart = newLine;\n            \n            if (prev) {\n              curRange = contextLines(prev.lines.slice(-4));\n              oldRangeStart -= curRange.length;\n              newRangeStart -= curRange.length;\n            }\n          }\n          curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?\"+\":\"-\") + entry; }));\n          eofNL(curRange, i, current);\n\n          if (current.added) {\n            newLine += lines.length;\n          } else {\n            oldLine += lines.length;\n          }\n        } else {\n          if (oldRangeStart) {\n            // Close out any changes that have been output (or join overlapping)\n            if (lines.length <= 8 && i < diff.length-2) {\n              // Overlapping\n              curRange.push.apply(curRange, contextLines(lines));\n            } else {\n              // end the range and output\n              var contextSize = Math.min(lines.length, 4);\n              ret.push(\n                  \"@@ -\" + oldRangeStart + \",\" + (oldLine-oldRangeStart+contextSize)\n                  + \" +\" + newRangeStart + \",\" + (newLine-newRangeStart+contextSize)\n                  + \" @@\");\n              ret.push.apply(ret, curRange);\n              ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));\n              if (lines.length <= 4) {\n                eofNL(ret, i, current);\n              }\n\n              oldRangeStart = 0;  newRangeStart = 0; curRange = [];\n            }\n          }\n          oldLine += lines.length;\n          newLine += lines.length;\n        }\n      }\n\n      return ret.join('\\n') + '\\n';\n    },\n\n    convertChangesToXML: function(changes){\n      var ret = [];\n      for ( var i = 0; i < changes.length; i++) {\n        var change = changes[i];\n        if (change.added) {\n          ret.push(\"<ins>\");\n        } else if (change.removed) {\n          ret.push(\"<del>\");\n        }\n\n        ret.push(escapeHTML(change.value));\n\n        if (change.added) {\n          ret.push(\"</ins>\");\n        } else if (change.removed) {\n          ret.push(\"</del>\");\n        }\n      }\n      return ret.join(\"\");\n    }\n  };\n})();\n\nif (typeof module !== \"undefined\") {\n    module.exports = JsDiff;\n}\n\n}); // module: browser/diff.js\n\nrequire.register(\"browser/events.js\", function(module, exports, require){\n\n/**\n * Module exports.\n */\n\nexports.EventEmitter = EventEmitter;\n\n/**\n * Check if `obj` is an array.\n */\n\nfunction isArray(obj) {\n  return '[object Array]' == {}.toString.call(obj);\n}\n\n/**\n * Event emitter constructor.\n *\n * @api public\n */\n\nfunction EventEmitter(){};\n\n/**\n * Adds a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.on = function (name, fn) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = fn;\n  } else if (isArray(this.$events[name])) {\n    this.$events[name].push(fn);\n  } else {\n    this.$events[name] = [this.$events[name], fn];\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n/**\n * Adds a volatile listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.once = function (name, fn) {\n  var self = this;\n\n  function on () {\n    self.removeListener(name, on);\n    fn.apply(this, arguments);\n  };\n\n  on.listener = fn;\n  this.on(name, on);\n\n  return this;\n};\n\n/**\n * Removes a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeListener = function (name, fn) {\n  if (this.$events && this.$events[name]) {\n    var list = this.$events[name];\n\n    if (isArray(list)) {\n      var pos = -1;\n\n      for (var i = 0, l = list.length; i < l; i++) {\n        if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {\n          pos = i;\n          break;\n        }\n      }\n\n      if (pos < 0) {\n        return this;\n      }\n\n      list.splice(pos, 1);\n\n      if (!list.length) {\n        delete this.$events[name];\n      }\n    } else if (list === fn || (list.listener && list.listener === fn)) {\n      delete this.$events[name];\n    }\n  }\n\n  return this;\n};\n\n/**\n * Removes all listeners for an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeAllListeners = function (name) {\n  if (name === undefined) {\n    this.$events = {};\n    return this;\n  }\n\n  if (this.$events && this.$events[name]) {\n    this.$events[name] = null;\n  }\n\n  return this;\n};\n\n/**\n * Gets all listeners for a certain event.\n *\n * @api public\n */\n\nEventEmitter.prototype.listeners = function (name) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = [];\n  }\n\n  if (!isArray(this.$events[name])) {\n    this.$events[name] = [this.$events[name]];\n  }\n\n  return this.$events[name];\n};\n\n/**\n * Emits an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.emit = function (name) {\n  if (!this.$events) {\n    return false;\n  }\n\n  var handler = this.$events[name];\n\n  if (!handler) {\n    return false;\n  }\n\n  var args = [].slice.call(arguments, 1);\n\n  if ('function' == typeof handler) {\n    handler.apply(this, args);\n  } else if (isArray(handler)) {\n    var listeners = handler.slice();\n\n    for (var i = 0, l = listeners.length; i < l; i++) {\n      listeners[i].apply(this, args);\n    }\n  } else {\n    return false;\n  }\n\n  return true;\n};\n}); // module: browser/events.js\n\nrequire.register(\"browser/fs.js\", function(module, exports, require){\n\n}); // module: browser/fs.js\n\nrequire.register(\"browser/path.js\", function(module, exports, require){\n\n}); // module: browser/path.js\n\nrequire.register(\"browser/progress.js\", function(module, exports, require){\n\n/**\n * Expose `Progress`.\n */\n\nmodule.exports = Progress;\n\n/**\n * Initialize a new `Progress` indicator.\n */\n\nfunction Progress() {\n  this.percent = 0;\n  this.size(0);\n  this.fontSize(11);\n  this.font('helvetica, arial, sans-serif');\n}\n\n/**\n * Set progress size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.size = function(n){\n  this._size = n;\n  return this;\n};\n\n/**\n * Set text to `str`.\n *\n * @param {String} str\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.text = function(str){\n  this._text = str;\n  return this;\n};\n\n/**\n * Set font size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.fontSize = function(n){\n  this._fontSize = n;\n  return this;\n};\n\n/**\n * Set font `family`.\n *\n * @param {String} family\n * @return {Progress} for chaining\n */\n\nProgress.prototype.font = function(family){\n  this._font = family;\n  return this;\n};\n\n/**\n * Update percentage to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n */\n\nProgress.prototype.update = function(n){\n  this.percent = n;\n  return this;\n};\n\n/**\n * Draw on `ctx`.\n *\n * @param {CanvasRenderingContext2d} ctx\n * @return {Progress} for chaining\n */\n\nProgress.prototype.draw = function(ctx){\n  var percent = Math.min(this.percent, 100)\n    , size = this._size\n    , half = size / 2\n    , x = half\n    , y = half\n    , rad = half - 1\n    , fontSize = this._fontSize;\n\n  ctx.font = fontSize + 'px ' + this._font;\n\n  var angle = Math.PI * 2 * (percent / 100);\n  ctx.clearRect(0, 0, size, size);\n\n  // outer circle\n  ctx.strokeStyle = '#9f9f9f';\n  ctx.beginPath();\n  ctx.arc(x, y, rad, 0, angle, false);\n  ctx.stroke();\n\n  // inner circle\n  ctx.strokeStyle = '#eee';\n  ctx.beginPath();\n  ctx.arc(x, y, rad - 1, 0, angle, true);\n  ctx.stroke();\n\n  // text\n  var text = this._text || (percent | 0) + '%'\n    , w = ctx.measureText(text).width;\n\n  ctx.fillText(\n      text\n    , x - w / 2 + 1\n    , y + fontSize / 2 - 1);\n\n  return this;\n};\n\n}); // module: browser/progress.js\n\nrequire.register(\"browser/tty.js\", function(module, exports, require){\n\nexports.isatty = function(){\n  return true;\n};\n\nexports.getWindowSize = function(){\n  return [window.innerHeight, window.innerWidth];\n};\n}); // module: browser/tty.js\n\nrequire.register(\"context.js\", function(module, exports, require){\n\n/**\n * Expose `Context`.\n */\n\nmodule.exports = Context;\n\n/**\n * Initialize a new `Context`.\n *\n * @api private\n */\n\nfunction Context(){}\n\n/**\n * Set or get the context `Runnable` to `runnable`.\n *\n * @param {Runnable} runnable\n * @return {Context}\n * @api private\n */\n\nContext.prototype.runnable = function(runnable){\n  if (0 == arguments.length) return this._runnable;\n  this.test = this._runnable = runnable;\n  return this;\n};\n\n/**\n * Set test timeout `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.timeout = function(ms){\n  this.runnable().timeout(ms);\n  return this;\n};\n\n/**\n * Set test slowness threshold `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.slow = function(ms){\n  this.runnable().slow(ms);\n  return this;\n};\n\n/**\n * Inspect the context void of `._runnable`.\n *\n * @return {String}\n * @api private\n */\n\nContext.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_runnable' == key) return;\n    if ('test' == key) return;\n    return val;\n  }, 2);\n};\n\n}); // module: context.js\n\nrequire.register(\"hook.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Hook`.\n */\n\nmodule.exports = Hook;\n\n/**\n * Initialize a new `Hook` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Hook(title, fn) {\n  Runnable.call(this, title, fn);\n  this.type = 'hook';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nfunction F(){};\nF.prototype = Runnable.prototype;\nHook.prototype = new F;\nHook.prototype.constructor = Hook;\n\n\n/**\n * Get or set the test `err`.\n *\n * @param {Error} err\n * @return {Error}\n * @api public\n */\n\nHook.prototype.error = function(err){\n  if (0 == arguments.length) {\n    var err = this._error;\n    this._error = null;\n    return err;\n  }\n\n  this._error = err;\n};\n\n}); // module: hook.js\n\nrequire.register(\"interfaces/bdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * BDD-style interface:\n *\n *      describe('Array', function(){\n *        describe('#indexOf()', function(){\n *          it('should return -1 when not present', function(){\n *\n *          });\n *\n *          it('should return the index when present', function(){\n *\n *          });\n *        });\n *      });\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n\n    context.describe = context.context = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Pending describe.\n     */\n\n    context.xdescribe =\n    context.xcontext =\n    context.describe.skip = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suite.pending = true;\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n    };\n\n    /**\n     * Exclusive suite.\n     */\n\n    context.describe.only = function(title, fn){\n      var suite = context.describe(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.it = context.specify = function(title, fn){\n      var suite = suites[0];\n      if (suite.pending) var fn = null;\n      var test = new Test(title, fn);\n      suite.addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.it.only = function(title, fn){\n      var test = context.it(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n\n    /**\n     * Pending test case.\n     */\n\n    context.xit =\n    context.xspecify =\n    context.it.skip = function(title){\n      context.it(title);\n    };\n  });\n};\n\n}); // module: interfaces/bdd.js\n\nrequire.register(\"interfaces/exports.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n *\n *     exports.Array = {\n *       '#indexOf()': {\n *         'should return -1 when the value is not present': function(){\n *\n *         },\n *\n *         'should return the correct index when the value is present': function(){\n *\n *         }\n *       }\n *     };\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('require', visit);\n\n  function visit(obj) {\n    var suite;\n    for (var key in obj) {\n      if ('function' == typeof obj[key]) {\n        var fn = obj[key];\n        switch (key) {\n          case 'before':\n            suites[0].beforeAll(fn);\n            break;\n          case 'after':\n            suites[0].afterAll(fn);\n            break;\n          case 'beforeEach':\n            suites[0].beforeEach(fn);\n            break;\n          case 'afterEach':\n            suites[0].afterEach(fn);\n            break;\n          default:\n            suites[0].addTest(new Test(key, fn));\n        }\n      } else {\n        var suite = Suite.create(suites[0], key);\n        suites.unshift(suite);\n        visit(obj[key]);\n        suites.shift();\n      }\n    }\n  }\n};\n\n}); // module: interfaces/exports.js\n\nrequire.register(\"interfaces/index.js\", function(module, exports, require){\n\nexports.bdd = require('./bdd');\nexports.tdd = require('./tdd');\nexports.qunit = require('./qunit');\nexports.exports = require('./exports');\n\n}); // module: interfaces/index.js\n\nrequire.register(\"interfaces/qunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * QUnit-style interface:\n *\n *     suite('Array');\n *\n *     test('#length', function(){\n *       var arr = [1,2,3];\n *       ok(arr.length == 3);\n *     });\n *\n *     test('#indexOf()', function(){\n *       var arr = [1,2,3];\n *       ok(arr.indexOf(1) == 0);\n *       ok(arr.indexOf(2) == 1);\n *       ok(arr.indexOf(3) == 2);\n *     });\n *\n *     suite('String');\n *\n *     test('#length', function(){\n *       ok('foo'.length == 3);\n *     });\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`.\n     */\n\n    context.suite = function(title){\n      if (suites.length > 1) suites.shift();\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      suites[0].addTest(new Test(title, fn));\n    };\n  });\n};\n\n}); // module: interfaces/qunit.js\n\nrequire.register(\"interfaces/tdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n *\n *      suite('Array', function(){\n *        suite('#indexOf()', function(){\n *          suiteSetup(function(){\n *\n *          });\n *\n *          test('should return -1 when not present', function(){\n *\n *          });\n *\n *          test('should return the index when present', function(){\n *\n *          });\n *\n *          suiteTeardown(function(){\n *\n *          });\n *        });\n *      });\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.setup = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.teardown = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Execute before the suite.\n     */\n\n    context.suiteSetup = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after the suite.\n     */\n\n    context.suiteTeardown = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n\n    context.suite = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn.call(suite);\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.suite.only = function(title, fn){\n      var suite = context.suite(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      var test = new Test(title, fn);\n      suites[0].addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.test.only = function(title, fn){\n      var test = context.test(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n\n    /**\n     * Pending test case.\n     */\n\n    context.test.skip = function(title){\n      context.test(title);\n    };\n  });\n};\n\n}); // module: interfaces/tdd.js\n\nrequire.register(\"mocha.js\", function(module, exports, require){\n/*!\n * mocha\n * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar path = require('browser/path')\n  , utils = require('./utils');\n\n/**\n * Expose `Mocha`.\n */\n\nexports = module.exports = Mocha;\n\n/**\n * Expose internals.\n */\n\nexports.utils = utils;\nexports.interfaces = require('./interfaces');\nexports.reporters = require('./reporters');\nexports.Runnable = require('./runnable');\nexports.Context = require('./context');\nexports.Runner = require('./runner');\nexports.Suite = require('./suite');\nexports.Hook = require('./hook');\nexports.Test = require('./test');\n\n/**\n * Return image `name` path.\n *\n * @param {String} name\n * @return {String}\n * @api private\n */\n\nfunction image(name) {\n  return __dirname + '/../images/' + name + '.png';\n}\n\n/**\n * Setup mocha with `options`.\n *\n * Options:\n *\n *   - `ui` name \"bdd\", \"tdd\", \"exports\" etc\n *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`\n *   - `globals` array of accepted globals\n *   - `timeout` timeout in milliseconds\n *   - `bail` bail on the first test failure\n *   - `slow` milliseconds to wait before considering a test slow\n *   - `ignoreLeaks` ignore global leaks\n *   - `grep` string or regexp to filter tests with\n *\n * @param {Object} options\n * @api public\n */\n\nfunction Mocha(options) {\n  options = options || {};\n  this.files = [];\n  this.options = options;\n  this.grep(options.grep);\n  this.suite = new exports.Suite('', new exports.Context);\n  this.ui(options.ui);\n  this.bail(options.bail);\n  this.reporter(options.reporter);\n  if (options.timeout) this.timeout(options.timeout);\n  if (options.slow) this.slow(options.slow);\n}\n\n/**\n * Enable or disable bailing on the first failure.\n *\n * @param {Boolean} [bail]\n * @api public\n */\n\nMocha.prototype.bail = function(bail){\n  if (0 == arguments.length) bail = true;\n  this.suite.bail(bail);\n  return this;\n};\n\n/**\n * Add test `file`.\n *\n * @param {String} file\n * @api public\n */\n\nMocha.prototype.addFile = function(file){\n  this.files.push(file);\n  return this;\n};\n\n/**\n * Set reporter to `reporter`, defaults to \"dot\".\n *\n * @param {String|Function} reporter name or constructor\n * @api public\n */\n\nMocha.prototype.reporter = function(reporter){\n  if ('function' == typeof reporter) {\n    this._reporter = reporter;\n  } else {\n    reporter = reporter || 'dot';\n    try {\n      this._reporter = require('./reporters/' + reporter);\n    } catch (err) {\n      this._reporter = require(reporter);\n    }\n    if (!this._reporter) throw new Error('invalid reporter \"' + reporter + '\"');\n  }\n  return this;\n};\n\n/**\n * Set test UI `name`, defaults to \"bdd\".\n *\n * @param {String} bdd\n * @api public\n */\n\nMocha.prototype.ui = function(name){\n  name = name || 'bdd';\n  this._ui = exports.interfaces[name];\n  if (!this._ui) throw new Error('invalid interface \"' + name + '\"');\n  this._ui = this._ui(this.suite);\n  return this;\n};\n\n/**\n * Load registered files.\n *\n * @api private\n */\n\nMocha.prototype.loadFiles = function(fn){\n  var self = this;\n  var suite = this.suite;\n  var pending = this.files.length;\n  this.files.forEach(function(file){\n    file = path.resolve(file);\n    suite.emit('pre-require', global, file, self);\n    suite.emit('require', require(file), file, self);\n    suite.emit('post-require', global, file, self);\n    --pending || (fn && fn());\n  });\n};\n\n/**\n * Enable growl support.\n *\n * @api private\n */\n\nMocha.prototype._growl = function(runner, reporter) {\n  var notify = require('growl');\n\n  runner.on('end', function(){\n    var stats = reporter.stats;\n    if (stats.failures) {\n      var msg = stats.failures + ' of ' + runner.total + ' tests failed';\n      notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });\n    } else {\n      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {\n          name: 'mocha'\n        , title: 'Passed'\n        , image: image('ok')\n      });\n    }\n  });\n};\n\n/**\n * Add regexp to grep, if `re` is a string it is escaped.\n *\n * @param {RegExp|String} re\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.grep = function(re){\n  this.options.grep = 'string' == typeof re\n    ? new RegExp(utils.escapeRegexp(re))\n    : re;\n  return this;\n};\n\n/**\n * Invert `.grep()` matches.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.invert = function(){\n  this.options.invert = true;\n  return this;\n};\n\n/**\n * Ignore global leaks.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.ignoreLeaks = function(){\n  this.options.ignoreLeaks = true;\n  return this;\n};\n\n/**\n * Enable global leak checking.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.checkLeaks = function(){\n  this.options.ignoreLeaks = false;\n  return this;\n};\n\n/**\n * Enable growl support.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.growl = function(){\n  this.options.growl = true;\n  return this;\n};\n\n/**\n * Ignore `globals` array or string.\n *\n * @param {Array|String} globals\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.globals = function(globals){\n  this.options.globals = (this.options.globals || []).concat(globals);\n  return this;\n};\n\n/**\n * Set the timeout in milliseconds.\n *\n * @param {Number} timeout\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.timeout = function(timeout){\n  this.suite.timeout(timeout);\n  return this;\n};\n\n/**\n * Set slowness threshold in milliseconds.\n *\n * @param {Number} slow\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.slow = function(slow){\n  this.suite.slow(slow);\n  return this;\n};\n\n/**\n * Makes all tests async (accepting a callback)\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.asyncOnly = function(){\n  this.options.asyncOnly = true;\n  return this;\n};\n\n/**\n * Run tests and invoke `fn()` when complete.\n *\n * @param {Function} fn\n * @return {Runner}\n * @api public\n */\n\nMocha.prototype.run = function(fn){\n  if (this.files.length) this.loadFiles();\n  var suite = this.suite;\n  var options = this.options;\n  var runner = new exports.Runner(suite);\n  var reporter = new this._reporter(runner);\n  runner.ignoreLeaks = false !== options.ignoreLeaks;\n  runner.asyncOnly = options.asyncOnly;\n  if (options.grep) runner.grep(options.grep, options.invert);\n  if (options.globals) runner.globals(options.globals);\n  if (options.growl) this._growl(runner, reporter);\n  return runner.run(fn);\n};\n\n}); // module: mocha.js\n\nrequire.register(\"ms.js\", function(module, exports, require){\n\n/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\n\n/**\n * Parse or format the given `val`.\n *\n * @param {String|Number} val\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val){\n  if ('string' == typeof val) return parse(val);\n  return format(val);\n}\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n  var m = /^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);\n  if (!m) return;\n  var n = parseFloat(m[1]);\n  var type = (m[2] || 'ms').toLowerCase();\n  switch (type) {\n    case 'years':\n    case 'year':\n    case 'y':\n      return n * 31557600000;\n    case 'days':\n    case 'day':\n    case 'd':\n      return n * 86400000;\n    case 'hours':\n    case 'hour':\n    case 'h':\n      return n * 3600000;\n    case 'minutes':\n    case 'minute':\n    case 'm':\n      return n * 60000;\n    case 'seconds':\n    case 'second':\n    case 's':\n      return n * 1000;\n    case 'ms':\n      return n;\n  }\n}\n\n/**\n * Format the given `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api public\n */\n\nfunction format(ms) {\n  if (ms == d) return Math.round(ms / d) + ' day';\n  if (ms > d) return Math.round(ms / d) + ' days';\n  if (ms == h) return Math.round(ms / h) + ' hour';\n  if (ms > h) return Math.round(ms / h) + ' hours';\n  if (ms == m) return Math.round(ms / m) + ' minute';\n  if (ms > m) return Math.round(ms / m) + ' minutes';\n  if (ms == s) return Math.round(ms / s) + ' second';\n  if (ms > s) return Math.round(ms / s) + ' seconds';\n  return ms + ' ms';\n}\n}); // module: ms.js\n\nrequire.register(\"reporters/base.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar tty = require('browser/tty')\n  , diff = require('browser/diff')\n  , ms = require('../ms');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Check if both stdio streams are associated with a tty.\n */\n\nvar isatty = tty.isatty(1) && tty.isatty(2);\n\n/**\n * Expose `Base`.\n */\n\nexports = module.exports = Base;\n\n/**\n * Enable coloring by default.\n */\n\nexports.useColors = isatty;\n\n/**\n * Default color map.\n */\n\nexports.colors = {\n    'pass': 90\n  , 'fail': 31\n  , 'bright pass': 92\n  , 'bright fail': 91\n  , 'bright yellow': 93\n  , 'pending': 36\n  , 'suite': 0\n  , 'error title': 0\n  , 'error message': 31\n  , 'error stack': 90\n  , 'checkmark': 32\n  , 'fast': 90\n  , 'medium': 33\n  , 'slow': 31\n  , 'green': 32\n  , 'light': 90\n  , 'diff gutter': 90\n  , 'diff added': 42\n  , 'diff removed': 41\n};\n\n/**\n * Default symbol map.\n */\n\nexports.symbols = {\n  ok: '✓',\n  err: '✖',\n  dot: '․'\n};\n\n// With node.js on Windows: use symbols available in terminal default fonts\nif ('win32' == process.platform) {\n  exports.symbols.ok = '\\u221A';\n  exports.symbols.err = '\\u00D7';\n  exports.symbols.dot = '.';\n}\n\n/**\n * Color `str` with the given `type`,\n * allowing colors to be disabled,\n * as well as user-defined color\n * schemes.\n *\n * @param {String} type\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nvar color = exports.color = function(type, str) {\n  if (!exports.useColors) return str;\n  return '\\u001b[' + exports.colors[type] + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Expose term window size, with some\n * defaults for when stderr is not a tty.\n */\n\nexports.window = {\n  width: isatty\n    ? process.stdout.getWindowSize\n      ? process.stdout.getWindowSize(1)[0]\n      : tty.getWindowSize()[1]\n    : 75\n};\n\n/**\n * Expose some basic cursor interactions\n * that are common among reporters.\n */\n\nexports.cursor = {\n  hide: function(){\n    process.stdout.write('\\u001b[?25l');\n  },\n\n  show: function(){\n    process.stdout.write('\\u001b[?25h');\n  },\n\n  deleteLine: function(){\n    process.stdout.write('\\u001b[2K');\n  },\n\n  beginningOfLine: function(){\n    process.stdout.write('\\u001b[0G');\n  },\n\n  CR: function(){\n    exports.cursor.deleteLine();\n    exports.cursor.beginningOfLine();\n  }\n};\n\n/**\n * Outut the given `failures` as a list.\n *\n * @param {Array} failures\n * @api public\n */\n\nexports.list = function(failures){\n  console.error();\n  failures.forEach(function(test, i){\n    // format\n    var fmt = color('error title', '  %s) %s:\\n')\n      + color('error message', '     %s')\n      + color('error stack', '\\n%s\\n');\n\n    // msg\n    var err = test.err\n      , message = err.message || ''\n      , stack = err.stack || message\n      , index = stack.indexOf(message) + message.length\n      , msg = stack.slice(0, index)\n      , actual = err.actual\n      , expected = err.expected\n      , escape = true;\n\n    // explicitly show diff\n    if (err.showDiff) {\n      escape = false;\n      err.actual = actual = JSON.stringify(actual, null, 2);\n      err.expected = expected = JSON.stringify(expected, null, 2);\n    }\n\n    // actual / expected diff\n    if ('string' == typeof actual && 'string' == typeof expected) {\n      var len = Math.max(actual.length, expected.length);\n\n      if (len < 20) msg = errorDiff(err, 'Chars', escape);\n      else msg = errorDiff(err, 'Words', escape);\n\n      // linenos\n      var lines = msg.split('\\n');\n      if (lines.length > 4) {\n        var width = String(lines.length).length;\n        msg = lines.map(function(str, i){\n          return pad(++i, width) + ' |' + ' ' + str;\n        }).join('\\n');\n      }\n\n      // legend\n      msg = '\\n'\n        + color('diff removed', 'actual')\n        + ' '\n        + color('diff added', 'expected')\n        + '\\n\\n'\n        + msg\n        + '\\n';\n\n      // indent\n      msg = msg.replace(/^/gm, '      ');\n\n      fmt = color('error title', '  %s) %s:\\n%s')\n        + color('error stack', '\\n%s\\n');\n    }\n\n    // indent stack trace without msg\n    stack = stack.slice(index ? index + 1 : index)\n      .replace(/^/gm, '  ');\n\n    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);\n  });\n};\n\n/**\n * Initialize a new `Base` reporter.\n *\n * All other reporters generally\n * inherit from this reporter, providing\n * stats such as test duration, number\n * of tests passed / failed etc.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Base(runner) {\n  var self = this\n    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }\n    , failures = this.failures = [];\n\n  if (!runner) return;\n  this.runner = runner;\n\n  runner.stats = stats;\n\n  runner.on('start', function(){\n    stats.start = new Date;\n  });\n\n  runner.on('suite', function(suite){\n    stats.suites = stats.suites || 0;\n    suite.root || stats.suites++;\n  });\n\n  runner.on('test end', function(test){\n    stats.tests = stats.tests || 0;\n    stats.tests++;\n  });\n\n  runner.on('pass', function(test){\n    stats.passes = stats.passes || 0;\n\n    var medium = test.slow() / 2;\n    test.speed = test.duration > test.slow()\n      ? 'slow'\n      : test.duration > medium\n        ? 'medium'\n        : 'fast';\n\n    stats.passes++;\n  });\n\n  runner.on('fail', function(test, err){\n    stats.failures = stats.failures || 0;\n    stats.failures++;\n    test.err = err;\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    stats.end = new Date;\n    stats.duration = new Date - stats.start;\n  });\n\n  runner.on('pending', function(){\n    stats.pending++;\n  });\n}\n\n/**\n * Output common epilogue used by many of\n * the bundled reporters.\n *\n * @api public\n */\n\nBase.prototype.epilogue = function(){\n  var stats = this.stats\n    , fmt\n    , tests;\n\n  console.log();\n\n  function pluralize(n) {\n    return 1 == n ? 'test' : 'tests';\n  }\n\n  // failure\n  if (stats.failures) {\n    fmt = color('bright fail', '  ' + exports.symbols.err)\n      + color('fail', ' %d of %d %s failed')\n      + color('light', ':')\n\n    console.error(fmt,\n      stats.failures,\n      this.runner.total,\n      pluralize(this.runner.total));\n\n    Base.list(this.failures);\n    console.error();\n    return;\n  }\n\n  // pass\n  fmt = color('bright pass', ' ')\n    + color('green', ' %d %s complete')\n    + color('light', ' (%s)');\n\n  console.log(fmt,\n    stats.tests || 0,\n    pluralize(stats.tests),\n    ms(stats.duration));\n\n  // pending\n  if (stats.pending) {\n    fmt = color('pending', ' ')\n      + color('pending', ' %d %s pending');\n\n    console.log(fmt, stats.pending, pluralize(stats.pending));\n  }\n\n  console.log();\n};\n\n/**\n * Pad the given `str` to `len`.\n *\n * @param {String} str\n * @param {String} len\n * @return {String}\n * @api private\n */\n\nfunction pad(str, len) {\n  str = String(str);\n  return Array(len - str.length + 1).join(' ') + str;\n}\n\n/**\n * Return a character diff for `err`.\n *\n * @param {Error} err\n * @return {String}\n * @api private\n */\n\nfunction errorDiff(err, type, escape) {\n  return diff['diff' + type](err.actual, err.expected).map(function(str){\n    if (escape) {\n      str.value = str.value\n        .replace(/\\t/g, '<tab>')\n        .replace(/\\r/g, '<CR>')\n        .replace(/\\n/g, '<LF>\\n');\n    }\n    if (str.added) return colorLines('diff added', str.value);\n    if (str.removed) return colorLines('diff removed', str.value);\n    return str.value;\n  }).join('');\n}\n\n/**\n * Color lines for `str`, using the color `name`.\n *\n * @param {String} name\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nfunction colorLines(name, str) {\n  return str.split('\\n').map(function(str){\n    return color(name, str);\n  }).join('\\n');\n}\n\n}); // module: reporters/base.js\n\nrequire.register(\"reporters/doc.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = Doc;\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Doc(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , indents = 2;\n\n  function indent() {\n    return Array(indents).join('  ');\n  }\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n    ++indents;\n    console.log('%s<section class=\"suite\">', indent());\n    ++indents;\n    console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));\n    console.log('%s<dl>', indent());\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    console.log('%s</dl>', indent());\n    --indents;\n    console.log('%s</section>', indent());\n    --indents;\n  });\n\n  runner.on('pass', function(test){\n    console.log('%s  <dt>%s</dt>', indent(), utils.escape(test.title));\n    var code = utils.escape(utils.clean(test.fn.toString()));\n    console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);\n  });\n}\n\n}); // module: reporters/doc.js\n\nrequire.register(\"reporters/dot.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = Dot;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Dot(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , n = 0;\n\n  runner.on('start', function(){\n    process.stdout.write('\\n  ');\n  });\n\n  runner.on('pending', function(test){\n    process.stdout.write(color('pending', Base.symbols.dot));\n  });\n\n  runner.on('pass', function(test){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    if ('slow' == test.speed) {\n      process.stdout.write(color('bright yellow', Base.symbols.dot));\n    } else {\n      process.stdout.write(color(test.speed, Base.symbols.dot));\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    process.stdout.write(color('fail', Base.symbols.dot));\n  });\n\n  runner.on('end', function(){\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nDot.prototype = new F;\nDot.prototype.constructor = Dot;\n\n}); // module: reporters/dot.js\n\nrequire.register(\"reporters/html-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar JSONCov = require('./json-cov')\n  , fs = require('browser/fs');\n\n/**\n * Expose `HTMLCov`.\n */\n\nexports = module.exports = HTMLCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTMLCov(runner) {\n  var jade = require('jade')\n    , file = __dirname + '/templates/coverage.jade'\n    , str = fs.readFileSync(file, 'utf8')\n    , fn = jade.compile(str, { filename: file })\n    , self = this;\n\n  JSONCov.call(this, runner, false);\n\n  runner.on('end', function(){\n    process.stdout.write(fn({\n        cov: self.cov\n      , coverageClass: coverageClass\n    }));\n  });\n}\n\n/**\n * Return coverage class for `n`.\n *\n * @return {String}\n * @api private\n */\n\nfunction coverageClass(n) {\n  if (n >= 75) return 'high';\n  if (n >= 50) return 'medium';\n  if (n >= 25) return 'low';\n  return 'terrible';\n}\n}); // module: reporters/html-cov.js\n\nrequire.register(\"reporters/html.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , Progress = require('../browser/progress')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = HTML;\n\n/**\n * Stats template.\n */\n\nvar statsTemplate = '<ul id=\"mocha-stats\">'\n  + '<li class=\"progress\"><canvas width=\"40\" height=\"40\"></canvas></li>'\n  + '<li class=\"passes\"><a href=\"#\">passes:</a> <em>0</em></li>'\n  + '<li class=\"failures\"><a href=\"#\">failures:</a> <em>0</em></li>'\n  + '<li class=\"duration\">duration: <em>0</em>s</li>'\n  + '</ul>';\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTML(runner, root) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , stat = fragment(statsTemplate)\n    , items = stat.getElementsByTagName('li')\n    , passes = items[1].getElementsByTagName('em')[0]\n    , passesLink = items[1].getElementsByTagName('a')[0]\n    , failures = items[2].getElementsByTagName('em')[0]\n    , failuresLink = items[2].getElementsByTagName('a')[0]\n    , duration = items[3].getElementsByTagName('em')[0]\n    , canvas = stat.getElementsByTagName('canvas')[0]\n    , report = fragment('<ul id=\"mocha-report\"></ul>')\n    , stack = [report]\n    , progress\n    , ctx\n\n  root = root || document.getElementById('mocha');\n\n  if (canvas.getContext) {\n    var ratio = window.devicePixelRatio || 1;\n    canvas.style.width = canvas.width;\n    canvas.style.height = canvas.height;\n    canvas.width *= ratio;\n    canvas.height *= ratio;\n    ctx = canvas.getContext('2d');\n    ctx.scale(ratio, ratio);\n    progress = new Progress;\n  }\n\n  if (!root) return error('#mocha div missing, add it to your document');\n\n  // pass toggle\n  on(passesLink, 'click', function(){\n    unhide();\n    var name = /pass/.test(report.className) ? '' : ' pass';\n    report.className = report.className.replace(/fail|pass/g, '') + name;\n    if (report.className.trim()) hideSuitesWithout('test pass');\n  });\n\n  // failure toggle\n  on(failuresLink, 'click', function(){\n    unhide();\n    var name = /fail/.test(report.className) ? '' : ' fail';\n    report.className = report.className.replace(/fail|pass/g, '') + name;\n    if (report.className.trim()) hideSuitesWithout('test fail');\n  });\n\n  root.appendChild(stat);\n  root.appendChild(report);\n\n  if (progress) progress.size(40);\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n\n    // suite\n    var url = '?grep=' + encodeURIComponent(suite.fullTitle());\n    var el = fragment('<li class=\"suite\"><h1><a href=\"%s\">%s</a></h1></li>', url, escape(suite.title));\n\n    // container\n    stack[0].appendChild(el);\n    stack.unshift(document.createElement('ul'));\n    el.appendChild(stack[0]);\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    stack.shift();\n  });\n\n  runner.on('fail', function(test, err){\n    if ('hook' == test.type) runner.emit('test end', test);\n  });\n\n  runner.on('test end', function(test){\n    // TODO: add to stats\n    var percent = stats.tests / this.total * 100 | 0;\n    if (progress) progress.update(percent).draw(ctx);\n\n    // update stats\n    var ms = new Date - stats.start;\n    text(passes, stats.passes);\n    text(failures, stats.failures);\n    text(duration, (ms / 1000).toFixed(2));\n\n    // test\n    if ('passed' == test.state) {\n      var el = fragment('<li class=\"test pass %e\"><h2>%e<span class=\"duration\">%ems</span> <a href=\"?grep=%e\" class=\"replay\">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));\n    } else if (test.pending) {\n      var el = fragment('<li class=\"test pass pending\"><h2>%e</h2></li>', test.title);\n    } else {\n      var el = fragment('<li class=\"test fail\"><h2>%e <a href=\"?grep=%e\" class=\"replay\">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));\n      var str = test.err.stack || test.err.toString();\n\n      // FF / Opera do not add the message\n      if (!~str.indexOf(test.err.message)) {\n        str = test.err.message + '\\n' + str;\n      }\n\n      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we\n      // check for the result of the stringifying.\n      if ('[object Error]' == str) str = test.err.message;\n\n      // Safari doesn't give you a stack. Let's at least provide a source line.\n      if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {\n        str += \"\\n(\" + test.err.sourceURL + \":\" + test.err.line + \")\";\n      }\n\n      el.appendChild(fragment('<pre class=\"error\">%e</pre>', str));\n    }\n\n    // toggle code\n    // TODO: defer\n    if (!test.pending) {\n      var h2 = el.getElementsByTagName('h2')[0];\n\n      on(h2, 'click', function(){\n        pre.style.display = 'none' == pre.style.display\n          ? 'block'\n          : 'none';\n      });\n\n      var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));\n      el.appendChild(pre);\n      pre.style.display = 'none';\n    }\n\n    // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.\n    if (stack[0]) stack[0].appendChild(el);\n  });\n}\n\n/**\n * Display error `msg`.\n */\n\nfunction error(msg) {\n  document.body.appendChild(fragment('<div id=\"mocha-error\">%s</div>', msg));\n}\n\n/**\n * Return a DOM fragment from `html`.\n */\n\nfunction fragment(html) {\n  var args = arguments\n    , div = document.createElement('div')\n    , i = 1;\n\n  div.innerHTML = html.replace(/%([se])/g, function(_, type){\n    switch (type) {\n      case 's': return String(args[i++]);\n      case 'e': return escape(args[i++]);\n    }\n  });\n\n  return div.firstChild;\n}\n\n/**\n * Check for suites that do not have elements\n * with `classname`, and hide them.\n */\n\nfunction hideSuitesWithout(classname) {\n  var suites = document.getElementsByClassName('suite');\n  for (var i = 0; i < suites.length; i++) {\n    var els = suites[i].getElementsByClassName(classname);\n    if (0 == els.length) suites[i].className += ' hidden';\n  }\n}\n\n/**\n * Unhide .hidden suites.\n */\n\nfunction unhide() {\n  var els = document.getElementsByClassName('suite hidden');\n  for (var i = 0; i < els.length; ++i) {\n    els[i].className = els[i].className.replace('suite hidden', 'suite');\n  }\n}\n\n/**\n * Set `el` text to `str`.\n */\n\nfunction text(el, str) {\n  if (el.textContent) {\n    el.textContent = str;\n  } else {\n    el.innerText = str;\n  }\n}\n\n/**\n * Listen on `event` with callback `fn`.\n */\n\nfunction on(el, event, fn) {\n  if (el.addEventListener) {\n    el.addEventListener(event, fn, false);\n  } else {\n    el.attachEvent('on' + event, fn);\n  }\n}\n\n}); // module: reporters/html.js\n\nrequire.register(\"reporters/index.js\", function(module, exports, require){\n\nexports.Base = require('./base');\nexports.Dot = require('./dot');\nexports.Doc = require('./doc');\nexports.TAP = require('./tap');\nexports.JSON = require('./json');\nexports.HTML = require('./html');\nexports.List = require('./list');\nexports.Min = require('./min');\nexports.Spec = require('./spec');\nexports.Nyan = require('./nyan');\nexports.XUnit = require('./xunit');\nexports.Markdown = require('./markdown');\nexports.Progress = require('./progress');\nexports.Landing = require('./landing');\nexports.JSONCov = require('./json-cov');\nexports.HTMLCov = require('./html-cov');\nexports.JSONStream = require('./json-stream');\nexports.Teamcity = require('./teamcity');\n\n}); // module: reporters/index.js\n\nrequire.register(\"reporters/json-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `JSONCov`.\n */\n\nexports = module.exports = JSONCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @param {Boolean} output\n * @api public\n */\n\nfunction JSONCov(runner, output) {\n  var self = this\n    , output = 1 == arguments.length ? true : output;\n\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var cov = global._$jscoverage || {};\n    var result = self.cov = map(cov);\n    result.stats = self.stats;\n    result.tests = tests.map(clean);\n    result.failures = failures.map(clean);\n    result.passes = passes.map(clean);\n    if (!output) return;\n    process.stdout.write(JSON.stringify(result, null, 2 ));\n  });\n}\n\n/**\n * Map jscoverage data to a JSON structure\n * suitable for reporting.\n *\n * @param {Object} cov\n * @return {Object}\n * @api private\n */\n\nfunction map(cov) {\n  var ret = {\n      instrumentation: 'node-jscoverage'\n    , sloc: 0\n    , hits: 0\n    , misses: 0\n    , coverage: 0\n    , files: []\n  };\n\n  for (var filename in cov) {\n    var data = coverage(filename, cov[filename]);\n    ret.files.push(data);\n    ret.hits += data.hits;\n    ret.misses += data.misses;\n    ret.sloc += data.sloc;\n  }\n\n  ret.files.sort(function(a, b) {\n    return a.filename.localeCompare(b.filename);\n  });\n\n  if (ret.sloc > 0) {\n    ret.coverage = (ret.hits / ret.sloc) * 100;\n  }\n\n  return ret;\n};\n\n/**\n * Map jscoverage data for a single source file\n * to a JSON structure suitable for reporting.\n *\n * @param {String} filename name of the source file\n * @param {Object} data jscoverage coverage data\n * @return {Object}\n * @api private\n */\n\nfunction coverage(filename, data) {\n  var ret = {\n    filename: filename,\n    coverage: 0,\n    hits: 0,\n    misses: 0,\n    sloc: 0,\n    source: {}\n  };\n\n  data.source.forEach(function(line, num){\n    num++;\n\n    if (data[num] === 0) {\n      ret.misses++;\n      ret.sloc++;\n    } else if (data[num] !== undefined) {\n      ret.hits++;\n      ret.sloc++;\n    }\n\n    ret.source[num] = {\n        source: line\n      , coverage: data[num] === undefined\n        ? ''\n        : data[num]\n    };\n  });\n\n  ret.coverage = ret.hits / ret.sloc * 100;\n\n  return ret;\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n\n}); // module: reporters/json-cov.js\n\nrequire.register(\"reporters/json-stream.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total;\n\n  runner.on('start', function(){\n    console.log(JSON.stringify(['start', { total: total }]));\n  });\n\n  runner.on('pass', function(test){\n    console.log(JSON.stringify(['pass', clean(test)]));\n  });\n\n  runner.on('fail', function(test, err){\n    console.log(JSON.stringify(['fail', clean(test)]));\n  });\n\n  runner.on('end', function(){\n    process.stdout.write(JSON.stringify(['end', self.stats]));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json-stream.js\n\nrequire.register(\"reporters/json.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `JSON`.\n */\n\nexports = module.exports = JSONReporter;\n\n/**\n * Initialize a new `JSON` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction JSONReporter(runner) {\n  var self = this;\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var obj = {\n        stats: self.stats\n      , tests: tests.map(clean)\n      , failures: failures.map(clean)\n      , passes: passes.map(clean)\n    };\n\n    process.stdout.write(JSON.stringify(obj, null, 2));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json.js\n\nrequire.register(\"reporters/landing.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Landing`.\n */\n\nexports = module.exports = Landing;\n\n/**\n * Airplane color.\n */\n\nBase.colors.plane = 0;\n\n/**\n * Airplane crash color.\n */\n\nBase.colors['plane crash'] = 31;\n\n/**\n * Runway color.\n */\n\nBase.colors.runway = 90;\n\n/**\n * Initialize a new `Landing` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Landing(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , total = runner.total\n    , stream = process.stdout\n    , plane = color('plane', '✈')\n    , crashed = -1\n    , n = 0;\n\n  function runway() {\n    var buf = Array(width).join('-');\n    return '  ' + color('runway', buf);\n  }\n\n  runner.on('start', function(){\n    stream.write('\\n  ');\n    cursor.hide();\n  });\n\n  runner.on('test end', function(test){\n    // check if the plane crashed\n    var col = -1 == crashed\n      ? width * ++n / total | 0\n      : crashed;\n\n    // show the crash\n    if ('failed' == test.state) {\n      plane = color('plane crash', '✈');\n      crashed = col;\n    }\n\n    // render landing strip\n    stream.write('\\u001b[4F\\n\\n');\n    stream.write(runway());\n    stream.write('\\n  ');\n    stream.write(color('runway', Array(col).join('⋅')));\n    stream.write(plane)\n    stream.write(color('runway', Array(width - col).join('⋅') + '\\n'));\n    stream.write(runway());\n    stream.write('\\u001b[0m');\n  });\n\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nLanding.prototype = new F;\nLanding.prototype.constructor = Landing;\n\n}); // module: reporters/landing.js\n\nrequire.register(\"reporters/list.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 0;\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = color('checkmark', '  -')\n      + color('pending', ' %s');\n    console.log(fmt, test.fullTitle());\n  });\n\n  runner.on('pass', function(test){\n    var fmt = color('checkmark', '  '+Base.symbols.dot)\n      + color('pass', ' %s: ')\n      + color(test.speed, '%dms');\n    cursor.CR();\n    console.log(fmt, test.fullTitle(), test.duration);\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(color('fail', '  %d) %s'), ++n, test.fullTitle());\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nList.prototype = new F;\nList.prototype.constructor = List;\n\n\n}); // module: reporters/list.js\n\nrequire.register(\"reporters/markdown.js\", function(module, exports, require){\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Markdown`.\n */\n\nexports = module.exports = Markdown;\n\n/**\n * Initialize a new `Markdown` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Markdown(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , level = 0\n    , buf = '';\n\n  function title(str) {\n    return Array(level).join('#') + ' ' + str;\n  }\n\n  function indent() {\n    return Array(level).join('  ');\n  }\n\n  function mapTOC(suite, obj) {\n    var ret = obj;\n    obj = obj[suite.title] = obj[suite.title] || { suite: suite };\n    suite.suites.forEach(function(suite){\n      mapTOC(suite, obj);\n    });\n    return ret;\n  }\n\n  function stringifyTOC(obj, level) {\n    ++level;\n    var buf = '';\n    var link;\n    for (var key in obj) {\n      if ('suite' == key) continue;\n      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\\n';\n      if (key) buf += Array(level).join('  ') + link;\n      buf += stringifyTOC(obj[key], level);\n    }\n    --level;\n    return buf;\n  }\n\n  function generateTOC(suite) {\n    var obj = mapTOC(suite, {});\n    return stringifyTOC(obj, 0);\n  }\n\n  generateTOC(runner.suite);\n\n  runner.on('suite', function(suite){\n    ++level;\n    var slug = utils.slug(suite.fullTitle());\n    buf += '<a name=\"' + slug + '\"></a>' + '\\n';\n    buf += title(suite.title) + '\\n';\n  });\n\n  runner.on('suite end', function(suite){\n    --level;\n  });\n\n  runner.on('pass', function(test){\n    var code = utils.clean(test.fn.toString());\n    buf += test.title + '.\\n';\n    buf += '\\n```js\\n';\n    buf += code + '\\n';\n    buf += '```\\n\\n';\n  });\n\n  runner.on('end', function(){\n    process.stdout.write('# TOC\\n');\n    process.stdout.write(generateTOC(runner.suite));\n    process.stdout.write(buf);\n  });\n}\n}); // module: reporters/markdown.js\n\nrequire.register(\"reporters/min.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Min`.\n */\n\nexports = module.exports = Min;\n\n/**\n * Initialize a new `Min` minimal test reporter (best used with --watch).\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Min(runner) {\n  Base.call(this, runner);\n\n  runner.on('start', function(){\n    // clear screen\n    process.stdout.write('\\u001b[2J');\n    // set cursor position\n    process.stdout.write('\\u001b[1;3H');\n  });\n\n  runner.on('end', this.epilogue.bind(this));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nMin.prototype = new F;\nMin.prototype.constructor = Min;\n\n\n}); // module: reporters/min.js\n\nrequire.register(\"reporters/nyan.js\", function(module, exports, require){\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = NyanCat;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction NyanCat(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , rainbowColors = this.rainbowColors = self.generateColors()\n    , colorIndex = this.colorIndex = 0\n    , numerOfLines = this.numberOfLines = 4\n    , trajectories = this.trajectories = [[], [], [], []]\n    , nyanCatWidth = this.nyanCatWidth = 11\n    , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)\n    , scoreboardWidth = this.scoreboardWidth = 5\n    , tick = this.tick = 0\n    , n = 0;\n\n  runner.on('start', function(){\n    Base.cursor.hide();\n    self.draw('start');\n  });\n\n  runner.on('pending', function(test){\n    self.draw('pending');\n  });\n\n  runner.on('pass', function(test){\n    self.draw('pass');\n  });\n\n  runner.on('fail', function(test, err){\n    self.draw('fail');\n  });\n\n  runner.on('end', function(){\n    Base.cursor.show();\n    for (var i = 0; i < self.numberOfLines; i++) write('\\n');\n    self.epilogue();\n  });\n}\n\n/**\n * Draw the nyan cat with runner `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.draw = function(status){\n  this.appendRainbow();\n  this.drawScoreboard();\n  this.drawRainbow();\n  this.drawNyanCat(status);\n  this.tick = !this.tick;\n};\n\n/**\n * Draw the \"scoreboard\" showing the number\n * of passes, failures and pending tests.\n *\n * @api private\n */\n\nNyanCat.prototype.drawScoreboard = function(){\n  var stats = this.stats;\n  var colors = Base.colors;\n\n  function draw(color, n) {\n    write(' ');\n    write('\\u001b[' + color + 'm' + n + '\\u001b[0m');\n    write('\\n');\n  }\n\n  draw(colors.green, stats.passes);\n  draw(colors.fail, stats.failures);\n  draw(colors.pending, stats.pending);\n  write('\\n');\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Append the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.appendRainbow = function(){\n  var segment = this.tick ? '_' : '-';\n  var rainbowified = this.rainbowify(segment);\n\n  for (var index = 0; index < this.numberOfLines; index++) {\n    var trajectory = this.trajectories[index];\n    if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();\n    trajectory.push(rainbowified);\n  }\n};\n\n/**\n * Draw the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.drawRainbow = function(){\n  var self = this;\n\n  this.trajectories.forEach(function(line, index) {\n    write('\\u001b[' + self.scoreboardWidth + 'C');\n    write(line.join(''));\n    write('\\n');\n  });\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Draw the nyan cat with `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.drawNyanCat = function(status) {\n  var self = this;\n  var startWidth = this.scoreboardWidth + this.trajectories[0].length;\n  var color = '\\u001b[' + startWidth + 'C';\n  var padding = '';\n  \n  write(color);\n  write('_,------,');\n  write('\\n');\n  \n  write(color);\n  padding = self.tick ? '  ' : '   ';\n  write('_|' + padding + '/\\\\_/\\\\ ');\n  write('\\n');\n  \n  write(color);\n  padding = self.tick ? '_' : '__';\n  var tail = self.tick ? '~' : '^';\n  var face;\n  switch (status) {\n    case 'pass':\n      face = '( ^ .^)';\n      break;\n    case 'fail':\n      face = '( o .o)';\n      break;\n    default:\n      face = '( - .-)';\n  }\n  write(tail + '|' + padding + face + ' ');\n  write('\\n');\n  \n  write(color);\n  padding = self.tick ? ' ' : '  ';\n  write(padding + '\"\"  \"\" ');\n  write('\\n');\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Move cursor up `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorUp = function(n) {\n  write('\\u001b[' + n + 'A');\n};\n\n/**\n * Move cursor down `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorDown = function(n) {\n  write('\\u001b[' + n + 'B');\n};\n\n/**\n * Generate rainbow colors.\n *\n * @return {Array}\n * @api private\n */\n\nNyanCat.prototype.generateColors = function(){\n  var colors = [];\n\n  for (var i = 0; i < (6 * 7); i++) {\n    var pi3 = Math.floor(Math.PI / 3);\n    var n = (i * (1.0 / 6));\n    var r = Math.floor(3 * Math.sin(n) + 3);\n    var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);\n    var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);\n    colors.push(36 * r + 6 * g + b + 16);\n  }\n\n  return colors;\n};\n\n/**\n * Apply rainbow to the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nNyanCat.prototype.rainbowify = function(str){\n  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];\n  this.colorIndex += 1;\n  return '\\u001b[38;5;' + color + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Stdout helper.\n */\n\nfunction write(string) {\n  process.stdout.write(string);\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nNyanCat.prototype = new F;\nNyanCat.prototype.constructor = NyanCat;\n\n\n}); // module: reporters/nyan.js\n\nrequire.register(\"reporters/progress.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Progress`.\n */\n\nexports = module.exports = Progress;\n\n/**\n * General progress bar color.\n */\n\nBase.colors.progress = 90;\n\n/**\n * Initialize a new `Progress` bar test reporter.\n *\n * @param {Runner} runner\n * @param {Object} options\n * @api public\n */\n\nfunction Progress(runner, options) {\n  Base.call(this, runner);\n\n  var self = this\n    , options = options || {}\n    , stats = this.stats\n    , width = Base.window.width * .50 | 0\n    , total = runner.total\n    , complete = 0\n    , max = Math.max;\n\n  // default chars\n  options.open = options.open || '[';\n  options.complete = options.complete || '▬';\n  options.incomplete = options.incomplete || Base.symbols.dot;\n  options.close = options.close || ']';\n  options.verbose = false;\n\n  // tests started\n  runner.on('start', function(){\n    console.log();\n    cursor.hide();\n  });\n\n  // tests complete\n  runner.on('test end', function(){\n    complete++;\n    var incomplete = total - complete\n      , percent = complete / total\n      , n = width * percent | 0\n      , i = width - n;\n\n    cursor.CR();\n    process.stdout.write('\\u001b[J');\n    process.stdout.write(color('progress', '  ' + options.open));\n    process.stdout.write(Array(n).join(options.complete));\n    process.stdout.write(Array(i).join(options.incomplete));\n    process.stdout.write(color('progress', options.close));\n    if (options.verbose) {\n      process.stdout.write(color('progress', ' ' + complete + ' of ' + total));\n    }\n  });\n\n  // tests are complete, output some stats\n  // and the failures if any\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nProgress.prototype = new F;\nProgress.prototype.constructor = Progress;\n\n\n}); // module: reporters/progress.js\n\nrequire.register(\"reporters/spec.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Spec`.\n */\n\nexports = module.exports = Spec;\n\n/**\n * Initialize a new `Spec` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Spec(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , indents = 0\n    , n = 0;\n\n  function indent() {\n    return Array(indents).join('  ')\n  }\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('suite', function(suite){\n    ++indents;\n    console.log(color('suite', '%s%s'), indent(), suite.title);\n  });\n\n  runner.on('suite end', function(suite){\n    --indents;\n    if (1 == indents) console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(indent() + color('pass', '  ◦ ' + test.title + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = indent() + color('pending', '  - %s');\n    console.log(fmt, test.title);\n  });\n\n  runner.on('pass', function(test){\n    if ('fast' == test.speed) {\n      var fmt = indent()\n        + color('checkmark', '  ' + Base.symbols.ok)\n        + color('pass', ' %s ');\n      cursor.CR();\n      console.log(fmt, test.title);\n    } else {\n      var fmt = indent()\n        + color('checkmark', '  ' + Base.symbols.ok)\n        + color('pass', ' %s ')\n        + color(test.speed, '(%dms)');\n      cursor.CR();\n      console.log(fmt, test.title, test.duration);\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(indent() + color('fail', '  %d) %s'), ++n, test.title);\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nSpec.prototype = new F;\nSpec.prototype.constructor = Spec;\n\n\n}); // module: reporters/spec.js\n\nrequire.register(\"reporters/tap.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `TAP`.\n */\n\nexports = module.exports = TAP;\n\n/**\n * Initialize a new `TAP` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction TAP(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 1\n    , passes = 0\n    , failures = 0;\n\n  runner.on('start', function(){\n    var total = runner.grepTotal(runner.suite);\n    console.log('%d..%d', 1, total);\n  });\n\n  runner.on('test end', function(){\n    ++n;\n  });\n\n  runner.on('pending', function(test){\n    console.log('ok %d %s # SKIP -', n, title(test));\n  });\n\n  runner.on('pass', function(test){\n    passes++;\n    console.log('ok %d %s', n, title(test));\n  });\n\n  runner.on('fail', function(test, err){\n    failures++;\n    console.log('not ok %d %s', n, title(test));\n    if (err.stack) console.log(err.stack.replace(/^/gm, '  '));\n  });\n\n  runner.on('end', function(){\n    console.log('# tests ' + (passes + failures));\n    console.log('# pass ' + passes);\n    console.log('# fail ' + failures);\n  });\n}\n\n/**\n * Return a TAP-safe title of `test`\n *\n * @param {Object} test\n * @return {String}\n * @api private\n */\n\nfunction title(test) {\n  return test.fullTitle().replace(/#/g, '');\n}\n\n}); // module: reporters/tap.js\n\nrequire.register(\"reporters/teamcity.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Teamcity`.\n */\n\nexports = module.exports = Teamcity;\n\n/**\n * Initialize a new `Teamcity` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Teamcity(runner) {\n  Base.call(this, runner);\n  var stats = this.stats;\n\n  runner.on('start', function() {\n    console.log(\"##teamcity[testSuiteStarted name='mocha.suite']\");\n  });\n\n  runner.on('test', function(test) {\n    console.log(\"##teamcity[testStarted name='\" + escape(test.fullTitle()) + \"']\");\n  });\n\n  runner.on('fail', function(test, err) {\n    console.log(\"##teamcity[testFailed name='\" + escape(test.fullTitle()) + \"' message='\" + escape(err.message) + \"']\");\n  });\n\n  runner.on('pending', function(test) {\n    console.log(\"##teamcity[testIgnored name='\" + escape(test.fullTitle()) + \"' message='pending']\");\n  });\n\n  runner.on('test end', function(test) {\n    console.log(\"##teamcity[testFinished name='\" + escape(test.fullTitle()) + \"' duration='\" + test.duration + \"']\");\n  });\n\n  runner.on('end', function() {\n    console.log(\"##teamcity[testSuiteFinished name='mocha.suite' duration='\" + stats.duration + \"']\");\n  });\n}\n\n/**\n * Escape the given `str`.\n */\n\nfunction escape(str) {\n  return str\n    .replace(/\\|/g, \"||\")\n    .replace(/\\n/g, \"|n\")\n    .replace(/\\r/g, \"|r\")\n    .replace(/\\[/g, \"|[\")\n    .replace(/\\]/g, \"|]\")\n    .replace(/\\u0085/g, \"|x\")\n    .replace(/\\u2028/g, \"|l\")\n    .replace(/\\u2029/g, \"|p\")\n    .replace(/'/g, \"|'\");\n}\n\n}); // module: reporters/teamcity.js\n\nrequire.register(\"reporters/xunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `XUnit`.\n */\n\nexports = module.exports = XUnit;\n\n/**\n * Initialize a new `XUnit` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction XUnit(runner) {\n  Base.call(this, runner);\n  var stats = this.stats\n    , tests = []\n    , self = this;\n\n  runner.on('pass', function(test){\n    tests.push(test);\n  });\n\n  runner.on('fail', function(test){\n    tests.push(test);\n  });\n\n  runner.on('end', function(){\n    console.log(tag('testsuite', {\n        name: 'Mocha Tests'\n      , tests: stats.tests\n      , failures: stats.failures\n      , errors: stats.failures\n      , skip: stats.tests - stats.failures - stats.passes\n      , timestamp: (new Date).toUTCString()\n      , time: stats.duration / 1000\n    }, false));\n\n    tests.forEach(test);\n    console.log('</testsuite>');\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nfunction F(){};\nF.prototype = Base.prototype;\nXUnit.prototype = new F;\nXUnit.prototype.constructor = XUnit;\n\n\n/**\n * Output tag for the given `test.`\n */\n\nfunction test(test) {\n  var attrs = {\n      classname: test.parent.fullTitle()\n    , name: test.title\n    , time: test.duration / 1000\n  };\n\n  if ('failed' == test.state) {\n    var err = test.err;\n    attrs.message = escape(err.message);\n    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));\n  } else if (test.pending) {\n    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));\n  } else {\n    console.log(tag('testcase', attrs, true) );\n  }\n}\n\n/**\n * HTML tag helper.\n */\n\nfunction tag(name, attrs, close, content) {\n  var end = close ? '/>' : '>'\n    , pairs = []\n    , tag;\n\n  for (var key in attrs) {\n    pairs.push(key + '=\"' + escape(attrs[key]) + '\"');\n  }\n\n  tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;\n  if (content) tag += content + '</' + name + end;\n  return tag;\n}\n\n/**\n * Return cdata escaped CDATA `str`.\n */\n\nfunction cdata(str) {\n  return '<![CDATA[' + escape(str) + ']]>';\n}\n\n}); // module: reporters/xunit.js\n\nrequire.register(\"runnable.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runnable')\n  , milliseconds = require('./ms');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Object#toString().\n */\n\nvar toString = Object.prototype.toString;\n\n/**\n * Expose `Runnable`.\n */\n\nmodule.exports = Runnable;\n\n/**\n * Initialize a new `Runnable` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Runnable(title, fn) {\n  this.title = title;\n  this.fn = fn;\n  this.async = fn && fn.length;\n  this.sync = ! this.async;\n  this._timeout = 2000;\n  this._slow = 75;\n  this.timedOut = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nRunnable.prototype = new F;\nRunnable.prototype.constructor = Runnable;\n\n\n/**\n * Set & get timeout `ms`.\n *\n * @param {Number|String} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._timeout = ms;\n  if (this.timer) this.resetTimeout();\n  return this;\n};\n\n/**\n * Set & get slow `ms`.\n *\n * @param {Number|String} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nRunnable.prototype.fullTitle = function(){\n  return this.parent.fullTitle() + ' ' + this.title;\n};\n\n/**\n * Clear the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.clearTimeout = function(){\n  clearTimeout(this.timer);\n};\n\n/**\n * Inspect the runnable void of private properties.\n *\n * @return {String}\n * @api private\n */\n\nRunnable.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_' == key[0]) return;\n    if ('parent' == key) return '#<Suite>';\n    if ('ctx' == key) return '#<Context>';\n    return val;\n  }, 2);\n};\n\n/**\n * Reset the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.resetTimeout = function(){\n  var self = this\n    , ms = this.timeout();\n\n  this.clearTimeout();\n  if (ms) {\n    this.timer = setTimeout(function(){\n      self.callback(new Error('timeout of ' + ms + 'ms exceeded'));\n      self.timedOut = true;\n    }, ms);\n  }\n};\n\n/**\n * Run the test and invoke `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunnable.prototype.run = function(fn){\n  var self = this\n    , ms = this.timeout()\n    , start = new Date\n    , ctx = this.ctx\n    , finished\n    , emitted;\n\n  if (ctx) ctx.runnable(this);\n\n  // timeout\n  if (this.async) {\n    if (ms) {\n      this.timer = setTimeout(function(){\n        done(new Error('timeout of ' + ms + 'ms exceeded'));\n        self.timedOut = true;\n      }, ms);\n    }\n  }\n\n  // called multiple times\n  function multiple(err) {\n    if (emitted) return;\n    emitted = true;\n    self.emit('error', err || new Error('done() called multiple times'));\n  }\n\n  // finished\n  function done(err) {\n    if (self.timedOut) return;\n    if (finished) return multiple(err);\n    self.clearTimeout();\n    self.duration = new Date - start;\n    finished = true;\n    fn(err);\n  }\n\n  // for .resetTimeout()\n  this.callback = done;\n\n  // async\n  if (this.async) {\n    try {\n      this.fn.call(ctx, function(err){\n        if (err instanceof Error || toString.call(err) === \"[object Error]\") return done(err);\n        if (null != err) return done(new Error('done() invoked with non-Error: ' + err));\n        done();\n      });\n    } catch (err) {\n      done(err);\n    }\n    return;\n  }\n\n  if (this.asyncOnly) {\n    return done(new Error('--async-only option in use without declaring `done()`'));\n  }\n\n  // sync\n  try {\n    if (!this.pending) this.fn.call(ctx);\n    this.duration = new Date - start;\n    fn();\n  } catch (err) {\n    fn(err);\n  }\n};\n\n}); // module: runnable.js\n\nrequire.register(\"runner.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runner')\n  , Test = require('./test')\n  , utils = require('./utils')\n  , filter = utils.filter\n  , keys = utils.keys;\n\n/**\n * Non-enumerable globals.\n */\n\nvar globals = [\n  'setTimeout',\n  'clearTimeout',\n  'setInterval',\n  'clearInterval',\n  'XMLHttpRequest',\n  'Date'\n];\n\n/**\n * Expose `Runner`.\n */\n\nmodule.exports = Runner;\n\n/**\n * Initialize a `Runner` for the given `suite`.\n *\n * Events:\n *\n *   - `start`  execution started\n *   - `end`  execution complete\n *   - `suite`  (suite) test suite execution started\n *   - `suite end`  (suite) all tests (and sub-suites) have finished\n *   - `test`  (test) test execution started\n *   - `test end`  (test) test completed\n *   - `hook`  (hook) hook execution started\n *   - `hook end`  (hook) hook complete\n *   - `pass`  (test) test passed\n *   - `fail`  (test, err) test failed\n *\n * @api public\n */\n\nfunction Runner(suite) {\n  var self = this;\n  this._globals = [];\n  this.suite = suite;\n  this.total = suite.total();\n  this.failures = 0;\n  this.on('test end', function(test){ self.checkGlobals(test); });\n  this.on('hook end', function(hook){ self.checkGlobals(hook); });\n  this.grep(/.*/);\n  this.globals(this.globalProps().concat(['errno']));\n}\n\n/**\n * Wrapper for setImmediate, process.nextTick, or browser polyfill.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunner.immediately = global.setImmediate || process.nextTick;\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nRunner.prototype = new F;\nRunner.prototype.constructor = Runner;\n\n\n/**\n * Run tests with full titles matching `re`. Updates runner.total\n * with number of tests matched.\n *\n * @param {RegExp} re\n * @param {Boolean} invert\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.grep = function(re, invert){\n  debug('grep %s', re);\n  this._grep = re;\n  this._invert = invert;\n  this.total = this.grepTotal(this.suite);\n  return this;\n};\n\n/**\n * Returns the number of tests matching the grep search for the\n * given suite.\n *\n * @param {Suite} suite\n * @return {Number}\n * @api public\n */\n\nRunner.prototype.grepTotal = function(suite) {\n  var self = this;\n  var total = 0;\n\n  suite.eachTest(function(test){\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (match) total++;\n  });\n\n  return total;\n};\n\n/**\n * Return a list of global properties.\n *\n * @return {Array}\n * @api private\n */\n\nRunner.prototype.globalProps = function() {\n  var props = utils.keys(global);\n\n  // non-enumerables\n  for (var i = 0; i < globals.length; ++i) {\n    if (~utils.indexOf(props, globals[i])) continue;\n    props.push(globals[i]);\n  }\n\n  return props;\n};\n\n/**\n * Allow the given `arr` of globals.\n *\n * @param {Array} arr\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.globals = function(arr){\n  if (0 == arguments.length) return this._globals;\n  debug('globals %j', arr);\n  utils.forEach(arr, function(arr){\n    this._globals.push(arr);\n  }, this);\n  return this;\n};\n\n/**\n * Check for global variable leaks.\n *\n * @api private\n */\n\nRunner.prototype.checkGlobals = function(test){\n  if (this.ignoreLeaks) return;\n  var ok = this._globals;\n  var globals = this.globalProps();\n  var isNode = process.kill;\n  var leaks;\n\n  // check length - 2 ('errno' and 'location' globals)\n  if (isNode && 1 == ok.length - globals.length) return\n  else if (2 == ok.length - globals.length) return;\n\n  leaks = filterLeaks(ok, globals);\n  this._globals = this._globals.concat(leaks);\n\n  if (leaks.length > 1) {\n    this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));\n  } else if (leaks.length) {\n    this.fail(test, new Error('global leak detected: ' + leaks[0]));\n  }\n};\n\n/**\n * Fail the given `test`.\n *\n * @param {Test} test\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.fail = function(test, err){\n  ++this.failures;\n  test.state = 'failed';\n\n  if ('string' == typeof err) {\n    err = new Error('the string \"' + err + '\" was thrown, throw an Error :)');\n  }\n\n  this.emit('fail', test, err);\n};\n\n/**\n * Fail the given `hook` with `err`.\n *\n * Hook failures (currently) hard-end due\n * to that fact that a failing hook will\n * surely cause subsequent tests to fail,\n * causing jumbled reporting.\n *\n * @param {Hook} hook\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.failHook = function(hook, err){\n  this.fail(hook, err);\n  this.emit('end');\n};\n\n/**\n * Run hook `name` callbacks and then invoke `fn()`.\n *\n * @param {String} name\n * @param {Function} function\n * @api private\n */\n\nRunner.prototype.hook = function(name, fn){\n  var suite = this.suite\n    , hooks = suite['_' + name]\n    , self = this\n    , timer;\n\n  function next(i) {\n    var hook = hooks[i];\n    if (!hook) return fn();\n    self.currentRunnable = hook;\n\n    self.emit('hook', hook);\n\n    hook.on('error', function(err){\n      self.failHook(hook, err);\n    });\n\n    hook.run(function(err){\n      hook.removeAllListeners('error');\n      var testError = hook.error();\n      if (testError) self.fail(self.test, testError);\n      if (err) return self.failHook(hook, err);\n      self.emit('hook end', hook);\n      next(++i);\n    });\n  }\n\n  Runner.immediately(function(){\n    next(0);\n  });\n};\n\n/**\n * Run hook `name` for the given array of `suites`\n * in order, and callback `fn(err)`.\n *\n * @param {String} name\n * @param {Array} suites\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hooks = function(name, suites, fn){\n  var self = this\n    , orig = this.suite;\n\n  function next(suite) {\n    self.suite = suite;\n\n    if (!suite) {\n      self.suite = orig;\n      return fn();\n    }\n\n    self.hook(name, function(err){\n      if (err) {\n        self.suite = orig;\n        return fn(err);\n      }\n\n      next(suites.pop());\n    });\n  }\n\n  next(suites.pop());\n};\n\n/**\n * Run hooks from the top level down.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookUp = function(name, fn){\n  var suites = [this.suite].concat(this.parents()).reverse();\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Run hooks from the bottom up.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookDown = function(name, fn){\n  var suites = [this.suite].concat(this.parents());\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Return an array of parent Suites from\n * closest to furthest.\n *\n * @return {Array}\n * @api private\n */\n\nRunner.prototype.parents = function(){\n  var suite = this.suite\n    , suites = [];\n  while (suite = suite.parent) suites.push(suite);\n  return suites;\n};\n\n/**\n * Run the current test and callback `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTest = function(fn){\n  var test = this.test\n    , self = this;\n\n  if (this.asyncOnly) test.asyncOnly = true;\n\n  try {\n    test.on('error', function(err){\n      self.fail(test, err);\n    });\n    test.run(fn);\n  } catch (err) {\n    fn(err);\n  }\n};\n\n/**\n * Run tests in the given `suite` and invoke\n * the callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTests = function(suite, fn){\n  var self = this\n    , tests = suite.tests.slice()\n    , test;\n\n  function next(err) {\n    // if we bail after first err\n    if (self.failures && suite._bail) return fn();\n\n    // next test\n    test = tests.shift();\n\n    // all done\n    if (!test) return fn();\n\n    // grep\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (!match) return next();\n\n    // pending\n    if (test.pending) {\n      self.emit('pending', test);\n      self.emit('test end', test);\n      return next();\n    }\n\n    // execute test and hook(s)\n    self.emit('test', self.test = test);\n    self.hookDown('beforeEach', function(){\n      self.currentRunnable = self.test;\n      self.runTest(function(err){\n        test = self.test;\n\n        if (err) {\n          self.fail(test, err);\n          self.emit('test end', test);\n          return self.hookUp('afterEach', next);\n        }\n\n        test.state = 'passed';\n        self.emit('pass', test);\n        self.emit('test end', test);\n        self.hookUp('afterEach', next);\n      });\n    });\n  }\n\n  this.next = next;\n  next();\n};\n\n/**\n * Run the given `suite` and invoke the\n * callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runSuite = function(suite, fn){\n  var total = this.grepTotal(suite)\n    , self = this\n    , i = 0;\n\n  debug('run suite %s', suite.fullTitle());\n\n  if (!total) return fn();\n\n  this.emit('suite', this.suite = suite);\n\n  function next() {\n    var curr = suite.suites[i++];\n    if (!curr) return done();\n    self.runSuite(curr, next);\n  }\n\n  function done() {\n    self.suite = suite;\n    self.hook('afterAll', function(){\n      self.emit('suite end', suite);\n      fn();\n    });\n  }\n\n  this.hook('beforeAll', function(){\n    self.runTests(suite, next);\n  });\n};\n\n/**\n * Handle uncaught exceptions.\n *\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.uncaught = function(err){\n  debug('uncaught exception %s', err.message);\n  var runnable = this.currentRunnable;\n  if (!runnable || 'failed' == runnable.state) return;\n  runnable.clearTimeout();\n  err.uncaught = true;\n  this.fail(runnable, err);\n\n  // recover from test\n  if ('test' == runnable.type) {\n    this.emit('test end', runnable);\n    this.hookUp('afterEach', this.next);\n    return;\n  }\n\n  // bail on hooks\n  this.emit('end');\n};\n\n/**\n * Run the root suite and invoke `fn(failures)`\n * on completion.\n *\n * @param {Function} fn\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.run = function(fn){\n  var self = this\n    , fn = fn || function(){};\n\n  function uncaught(err){\n    self.uncaught(err);\n  }\n\n  debug('start');\n\n  // callback\n  this.on('end', function(){\n    debug('end');\n    process.removeListener('uncaughtException', uncaught);\n    fn(self.failures);\n  });\n\n  // run suites\n  this.emit('start');\n  this.runSuite(this.suite, function(){\n    debug('finished running');\n    self.emit('end');\n  });\n\n  // uncaught exception\n  process.on('uncaughtException', uncaught);\n\n  return this;\n};\n\n/**\n * Filter leaks with the given globals flagged as `ok`.\n *\n * @param {Array} ok\n * @param {Array} globals\n * @return {Array}\n * @api private\n */\n\nfunction filterLeaks(ok, globals) {\n  return filter(globals, function(key){\n    var matched = filter(ok, function(ok){\n      if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);\n      // Opera and IE expose global variables for HTML element IDs (issue #243)\n      if (/^mocha-/.test(key)) return true;\n      return key == ok;\n    });\n    return matched.length == 0 && (!global.navigator || 'onerror' !== key);\n  });\n}\n\n}); // module: runner.js\n\nrequire.register(\"suite.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:suite')\n  , milliseconds = require('./ms')\n  , utils = require('./utils')\n  , Hook = require('./hook');\n\n/**\n * Expose `Suite`.\n */\n\nexports = module.exports = Suite;\n\n/**\n * Create a new `Suite` with the given `title`\n * and parent `Suite`. When a suite with the\n * same title is already present, that suite\n * is returned to provide nicer reporter\n * and more flexible meta-testing.\n *\n * @param {Suite} parent\n * @param {String} title\n * @return {Suite}\n * @api public\n */\n\nexports.create = function(parent, title){\n  var suite = new Suite(title, parent.ctx);\n  suite.parent = parent;\n  if (parent.pending) suite.pending = true;\n  title = suite.fullTitle();\n  parent.addSuite(suite);\n  return suite;\n};\n\n/**\n * Initialize a new `Suite` with the given\n * `title` and `ctx`.\n *\n * @param {String} title\n * @param {Context} ctx\n * @api private\n */\n\nfunction Suite(title, ctx) {\n  this.title = title;\n  this.ctx = ctx;\n  this.suites = [];\n  this.tests = [];\n  this.pending = false;\n  this._beforeEach = [];\n  this._beforeAll = [];\n  this._afterEach = [];\n  this._afterAll = [];\n  this.root = !title;\n  this._timeout = 2000;\n  this._slow = 75;\n  this._bail = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nfunction F(){};\nF.prototype = EventEmitter.prototype;\nSuite.prototype = new F;\nSuite.prototype.constructor = Suite;\n\n\n/**\n * Return a clone of this `Suite`.\n *\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.clone = function(){\n  var suite = new Suite(this.title);\n  debug('clone');\n  suite.ctx = this.ctx;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  return suite;\n};\n\n/**\n * Set timeout `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._timeout = parseInt(ms, 10);\n  return this;\n};\n\n/**\n * Set slow `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('slow %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Sets whether to bail after first error.\n *\n * @parma {Boolean} bail\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.bail = function(bail){\n  if (0 == arguments.length) return this._bail;\n  debug('bail %s', bail);\n  this._bail = bail;\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeAll.push(hook);\n  this.emit('beforeAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterAll.push(hook);\n  this.emit('afterAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeEach.push(hook);\n  this.emit('beforeEach', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterEach.push(hook);\n  this.emit('afterEach', hook);\n  return this;\n};\n\n/**\n * Add a test `suite`.\n *\n * @param {Suite} suite\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addSuite = function(suite){\n  suite.parent = this;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  this.suites.push(suite);\n  this.emit('suite', suite);\n  return this;\n};\n\n/**\n * Add a `test` to this suite.\n *\n * @param {Test} test\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addTest = function(test){\n  test.parent = this;\n  test.timeout(this.timeout());\n  test.slow(this.slow());\n  test.ctx = this.ctx;\n  this.tests.push(test);\n  this.emit('test', test);\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nSuite.prototype.fullTitle = function(){\n  if (this.parent) {\n    var full = this.parent.fullTitle();\n    if (full) return full + ' ' + this.title;\n  }\n  return this.title;\n};\n\n/**\n * Return the total number of tests.\n *\n * @return {Number}\n * @api public\n */\n\nSuite.prototype.total = function(){\n  return utils.reduce(this.suites, function(sum, suite){\n    return sum + suite.total();\n  }, 0) + this.tests.length;\n};\n\n/**\n * Iterates through each suite recursively to find\n * all tests. Applies a function in the format\n * `fn(test)`.\n *\n * @param {Function} fn\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.eachTest = function(fn){\n  utils.forEach(this.tests, fn);\n  utils.forEach(this.suites, function(suite){\n    suite.eachTest(fn);\n  });\n  return this;\n};\n\n}); // module: suite.js\n\nrequire.register(\"test.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Test`.\n */\n\nmodule.exports = Test;\n\n/**\n * Initialize a new `Test` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Test(title, fn) {\n  Runnable.call(this, title, fn);\n  this.pending = !fn;\n  this.type = 'test';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nfunction F(){};\nF.prototype = Runnable.prototype;\nTest.prototype = new F;\nTest.prototype.constructor = Test;\n\n\n}); // module: test.js\n\nrequire.register(\"utils.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar fs = require('browser/fs')\n  , path = require('browser/path')\n  , join = path.join\n  , debug = require('browser/debug')('mocha:watch');\n\n/**\n * Ignored directories.\n */\n\nvar ignore = ['node_modules', '.git'];\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param  {String} html\n * @return {String}\n * @api private\n */\n\nexports.escape = function(html){\n  return String(html)\n    .replace(/&/g, '&amp;')\n    .replace(/\"/g, '&quot;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;');\n};\n\n/**\n * Array#forEach (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @param {Object} scope\n * @api private\n */\n\nexports.forEach = function(arr, fn, scope){\n  for (var i = 0, l = arr.length; i < l; i++)\n    fn.call(scope, arr[i], i);\n};\n\n/**\n * Array#indexOf (<=IE8)\n *\n * @parma {Array} arr\n * @param {Object} obj to find index of\n * @param {Number} start\n * @api private\n */\n\nexports.indexOf = function(arr, obj, start){\n  for (var i = start || 0, l = arr.length; i < l; i++) {\n    if (arr[i] === obj)\n      return i;\n  }\n  return -1;\n};\n\n/**\n * Array#reduce (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @param {Object} initial value\n * @api private\n */\n\nexports.reduce = function(arr, fn, val){\n  var rval = val;\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    rval = fn(rval, arr[i], i, arr);\n  }\n\n  return rval;\n};\n\n/**\n * Array#filter (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @api private\n */\n\nexports.filter = function(arr, fn){\n  var ret = [];\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    var val = arr[i];\n    if (fn(val, i, arr)) ret.push(val);\n  }\n\n  return ret;\n};\n\n/**\n * Object.keys (<=IE8)\n *\n * @param {Object} obj\n * @return {Array} keys\n * @api private\n */\n\nexports.keys = Object.keys || function(obj) {\n  var keys = []\n    , has = Object.prototype.hasOwnProperty // for `window` on <=IE8\n\n  for (var key in obj) {\n    if (has.call(obj, key)) {\n      keys.push(key);\n    }\n  }\n\n  return keys;\n};\n\n/**\n * Watch the given `files` for changes\n * and invoke `fn(file)` on modification.\n *\n * @param {Array} files\n * @param {Function} fn\n * @api private\n */\n\nexports.watch = function(files, fn){\n  var options = { interval: 100 };\n  files.forEach(function(file){\n    debug('file %s', file);\n    fs.watchFile(file, options, function(curr, prev){\n      if (prev.mtime < curr.mtime) fn(file);\n    });\n  });\n};\n\n/**\n * Ignored files.\n */\n\nfunction ignored(path){\n  return !~ignore.indexOf(path);\n}\n\n/**\n * Lookup files in the given `dir`.\n *\n * @return {Array}\n * @api private\n */\n\nexports.files = function(dir, ret){\n  ret = ret || [];\n\n  fs.readdirSync(dir)\n  .filter(ignored)\n  .forEach(function(path){\n    path = join(dir, path);\n    if (fs.statSync(path).isDirectory()) {\n      exports.files(path, ret);\n    } else if (path.match(/\\.(js|coffee)$/)) {\n      ret.push(path);\n    }\n  });\n\n  return ret;\n};\n\n/**\n * Compute a slug from the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.slug = function(str){\n  return str\n    .toLowerCase()\n    .replace(/ +/g, '-')\n    .replace(/[^-\\w]/g, '');\n};\n\n/**\n * Strip the function definition from `str`,\n * and re-indent for pre whitespace.\n */\n\nexports.clean = function(str) {\n  str = str\n    .replace(/^function *\\(.*\\) *{/, '')\n    .replace(/\\s+\\}$/, '');\n\n  var spaces = str.match(/^\\n?( *)/)[1].length\n    , re = new RegExp('^ {' + spaces + '}', 'gm');\n\n  str = str.replace(re, '');\n\n  return exports.trim(str);\n};\n\n/**\n * Escape regular expression characters in `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.escapeRegexp = function(str){\n  return str.replace(/[-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n};\n\n/**\n * Trim the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.trim = function(str){\n  return str.replace(/^\\s+|\\s+$/g, '');\n};\n\n/**\n * Parse the given `qs`.\n *\n * @param {String} qs\n * @return {Object}\n * @api private\n */\n\nexports.parseQuery = function(qs){\n  return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){\n    var i = pair.indexOf('=')\n      , key = pair.slice(0, i)\n      , val = pair.slice(++i);\n\n    obj[key] = decodeURIComponent(val);\n    return obj;\n  }, {});\n};\n\n/**\n * Highlight the given string of `js`.\n *\n * @param {String} js\n * @return {String}\n * @api private\n */\n\nfunction highlight(js) {\n  return js\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\\/\\/(.*)/gm, '<span class=\"comment\">//$1</span>')\n    .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n    .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n    .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n}\n\n/**\n * Highlight the contents of tag `name`.\n *\n * @param {String} name\n * @api private\n */\n\nexports.highlightTags = function(name) {\n  var code = document.getElementsByTagName(name);\n  for (var i = 0, len = code.length; i < len; ++i) {\n    code[i].innerHTML = highlight(code[i].innerHTML);\n  }\n};\n\n}); // module: utils.js\n/**\n * Node shims.\n *\n * These are meant only to allow\n * mocha.js to run untouched, not\n * to allow running node code in\n * the browser.\n */\n\nprocess = {};\nprocess.exit = function(status){};\nprocess.stdout = {};\nglobal = window;\n\n/**\n * Remove uncaughtException listener.\n */\n\nprocess.removeListener = function(e){\n  if ('uncaughtException' == e) {\n    window.onerror = null;\n  }\n};\n\n/**\n * Implements uncaughtException listener.\n */\n\nprocess.on = function(e, fn){\n  if ('uncaughtException' == e) {\n    window.onerror = function(err, url, line){\n      fn(new Error(err + ' (' + url + ':' + line + ')'));\n    };\n  }\n};\n\n// boot\n;(function(){\n\n  /**\n   * Expose mocha.\n   */\n\n  var Mocha = window.Mocha = require('mocha'),\n      mocha = window.mocha = new Mocha({ reporter: 'html' });\n\n  var immediateQueue = []\n    , immediateTimeout;\n\n  function timeslice() {\n    var immediateStart = new Date().getTime();\n    while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) {\n      immediateQueue.shift()();\n    }\n    if (immediateQueue.length) {\n      immediateTimeout = setTimeout(timeslice, 0);\n    } else {\n      immediateTimeout = null;\n    }\n  }\n\n  /**\n   * High-performance override of Runner.immediately.\n   */\n\n  Mocha.Runner.immediately = function(callback) {\n    immediateQueue.push(callback);\n    if (!immediateTimeout) {\n      immediateTimeout = setTimeout(timeslice, 0);\n    }\n  };\n\n  /**\n   * Override ui to ensure that the ui functions are initialized.\n   * Normally this would happen in Mocha.prototype.loadFiles.\n   */\n\n  mocha.ui = function(ui){\n    Mocha.prototype.ui.call(this, ui);\n    this.suite.emit('pre-require', window, null, this);\n    return this;\n  };\n\n  /**\n   * Setup mocha with the given setting options.\n   */\n\n  mocha.setup = function(opts){\n    if ('string' == typeof opts) opts = { ui: opts };\n    for (var opt in opts) this[opt](opts[opt]);\n    return this;\n  };\n\n  /**\n   * Run mocha, returning the Runner.\n   */\n\n  mocha.run = function(fn){\n    var options = mocha.options;\n    mocha.globals('location');\n\n    var query = Mocha.utils.parseQuery(window.location.search || '');\n    if (query.grep) mocha.grep(query.grep);\n    if (query.invert) mocha.invert();\n\n    return Mocha.prototype.run.call(mocha, function(){\n      Mocha.utils.highlightTags('code');\n      if (fn) fn();\n    });\n  };\n})();\n})();"
  },
  {
    "path": "vendors/firmcard/test/sinon.js",
    "content": "/**\n * Sinon.JS 1.7.1, 2013/05/07\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS\n *\n * (The BSD License)\n * \n * Copyright (c) 2010-2013, Christian Johansen, christian@cjohansen.no\n * All rights reserved.\n * \n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n *     * Redistributions of source code must retain the above copyright notice,\n *       this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright notice,\n *       this list of conditions and the following disclaimer in the documentation\n *       and/or other materials provided with the distribution.\n *     * Neither the name of Christian Johansen nor the names of his contributors\n *       may be used to endorse or promote products derived from this software\n *       without specific prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nthis.sinon = (function () {\nvar buster = (function (setTimeout, B) {\n    var isNode = typeof require == \"function\" && typeof module == \"object\";\n    var div = typeof document != \"undefined\" && document.createElement(\"div\");\n    var F = function () {};\n\n    var buster = {\n        bind: function bind(obj, methOrProp) {\n            var method = typeof methOrProp == \"string\" ? obj[methOrProp] : methOrProp;\n            var args = Array.prototype.slice.call(arguments, 2);\n            return function () {\n                var allArgs = args.concat(Array.prototype.slice.call(arguments));\n                return method.apply(obj, allArgs);\n            };\n        },\n\n        partial: function partial(fn) {\n            var args = [].slice.call(arguments, 1);\n            return function () {\n                return fn.apply(this, args.concat([].slice.call(arguments)));\n            };\n        },\n\n        create: function create(object) {\n            F.prototype = object;\n            return new F();\n        },\n\n        extend: function extend(target) {\n            if (!target) { return; }\n            for (var i = 1, l = arguments.length, prop; i < l; ++i) {\n                for (prop in arguments[i]) {\n                    target[prop] = arguments[i][prop];\n                }\n            }\n            return target;\n        },\n\n        nextTick: function nextTick(callback) {\n            if (typeof process != \"undefined\" && process.nextTick) {\n                return process.nextTick(callback);\n            }\n            setTimeout(callback, 0);\n        },\n\n        functionName: function functionName(func) {\n            if (!func) return \"\";\n            if (func.displayName) return func.displayName;\n            if (func.name) return func.name;\n            var matches = func.toString().match(/function\\s+([^\\(]+)/m);\n            return matches && matches[1] || \"\";\n        },\n\n        isNode: function isNode(obj) {\n            if (!div) return false;\n            try {\n                obj.appendChild(div);\n                obj.removeChild(div);\n            } catch (e) {\n                return false;\n            }\n            return true;\n        },\n\n        isElement: function isElement(obj) {\n            return obj && obj.nodeType === 1 && buster.isNode(obj);\n        },\n\n        isArray: function isArray(arr) {\n            return Object.prototype.toString.call(arr) == \"[object Array]\";\n        },\n\n        flatten: function flatten(arr) {\n            var result = [], arr = arr || [];\n            for (var i = 0, l = arr.length; i < l; ++i) {\n                result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]);\n            }\n            return result;\n        },\n\n        each: function each(arr, callback) {\n            for (var i = 0, l = arr.length; i < l; ++i) {\n                callback(arr[i]);\n            }\n        },\n\n        map: function map(arr, callback) {\n            var results = [];\n            for (var i = 0, l = arr.length; i < l; ++i) {\n                results.push(callback(arr[i]));\n            }\n            return results;\n        },\n\n        parallel: function parallel(fns, callback) {\n            function cb(err, res) {\n                if (typeof callback == \"function\") {\n                    callback(err, res);\n                    callback = null;\n                }\n            }\n            if (fns.length == 0) { return cb(null, []); }\n            var remaining = fns.length, results = [];\n            function makeDone(num) {\n                return function done(err, result) {\n                    if (err) { return cb(err); }\n                    results[num] = result;\n                    if (--remaining == 0) { cb(null, results); }\n                };\n            }\n            for (var i = 0, l = fns.length; i < l; ++i) {\n                fns[i](makeDone(i));\n            }\n        },\n\n        series: function series(fns, callback) {\n            function cb(err, res) {\n                if (typeof callback == \"function\") {\n                    callback(err, res);\n                }\n            }\n            var remaining = fns.slice();\n            var results = [];\n            function callNext() {\n                if (remaining.length == 0) return cb(null, results);\n                var promise = remaining.shift()(next);\n                if (promise && typeof promise.then == \"function\") {\n                    promise.then(buster.partial(next, null), next);\n                }\n            }\n            function next(err, result) {\n                if (err) return cb(err);\n                results.push(result);\n                callNext();\n            }\n            callNext();\n        },\n\n        countdown: function countdown(num, done) {\n            return function () {\n                if (--num == 0) done();\n            };\n        }\n    };\n\n    if (typeof process === \"object\" &&\n        typeof require === \"function\" && typeof module === \"object\") {\n        var crypto = require(\"crypto\");\n        var path = require(\"path\");\n\n        buster.tmpFile = function (fileName) {\n            var hashed = crypto.createHash(\"sha1\");\n            hashed.update(fileName);\n            var tmpfileName = hashed.digest(\"hex\");\n\n            if (process.platform == \"win32\") {\n                return path.join(process.env[\"TEMP\"], tmpfileName);\n            } else {\n                return path.join(\"/tmp\", tmpfileName);\n            }\n        };\n    }\n\n    if (Array.prototype.some) {\n        buster.some = function (arr, fn, thisp) {\n            return arr.some(fn, thisp);\n        };\n    } else {\n        // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some\n        buster.some = function (arr, fun, thisp) {\n                        if (arr == null) { throw new TypeError(); }\n            arr = Object(arr);\n            var len = arr.length >>> 0;\n            if (typeof fun !== \"function\") { throw new TypeError(); }\n\n            for (var i = 0; i < len; i++) {\n                if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) {\n                    return true;\n                }\n            }\n\n            return false;\n        };\n    }\n\n    if (Array.prototype.filter) {\n        buster.filter = function (arr, fn, thisp) {\n            return arr.filter(fn, thisp);\n        };\n    } else {\n        // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter\n        buster.filter = function (fn, thisp) {\n                        if (this == null) { throw new TypeError(); }\n\n            var t = Object(this);\n            var len = t.length >>> 0;\n            if (typeof fn != \"function\") { throw new TypeError(); }\n\n            var res = [];\n            for (var i = 0; i < len; i++) {\n                if (i in t) {\n                    var val = t[i]; // in case fun mutates this\n                    if (fn.call(thisp, val, i, t)) { res.push(val); }\n                }\n            }\n\n            return res;\n        };\n    }\n\n    if (isNode) {\n        module.exports = buster;\n        buster.eventEmitter = require(\"./buster-event-emitter\");\n        Object.defineProperty(buster, \"defineVersionGetter\", {\n            get: function () {\n                return require(\"./define-version-getter\");\n            }\n        });\n    }\n\n    return buster.extend(B || {}, buster);\n}(setTimeout, buster));\nif (typeof buster === \"undefined\") {\n    var buster = {};\n}\n\nif (typeof module === \"object\" && typeof require === \"function\") {\n    buster = require(\"buster-core\");\n}\n\nbuster.format = buster.format || {};\nbuster.format.excludeConstructors = [\"Object\", /^.$/];\nbuster.format.quoteStrings = true;\n\nbuster.format.ascii = (function () {\n    \n    var hasOwn = Object.prototype.hasOwnProperty;\n\n    var specialObjects = [];\n    if (typeof global != \"undefined\") {\n        specialObjects.push({ obj: global, value: \"[object global]\" });\n    }\n    if (typeof document != \"undefined\") {\n        specialObjects.push({ obj: document, value: \"[object HTMLDocument]\" });\n    }\n    if (typeof window != \"undefined\") {\n        specialObjects.push({ obj: window, value: \"[object Window]\" });\n    }\n\n    function keys(object) {\n        var k = Object.keys && Object.keys(object) || [];\n\n        if (k.length == 0) {\n            for (var prop in object) {\n                if (hasOwn.call(object, prop)) {\n                    k.push(prop);\n                }\n            }\n        }\n\n        return k.sort();\n    }\n\n    function isCircular(object, objects) {\n        if (typeof object != \"object\") {\n            return false;\n        }\n\n        for (var i = 0, l = objects.length; i < l; ++i) {\n            if (objects[i] === object) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    function ascii(object, processed, indent) {\n        if (typeof object == \"string\") {\n            var quote = typeof this.quoteStrings != \"boolean\" || this.quoteStrings;\n            return processed || quote ? '\"' + object + '\"' : object;\n        }\n\n        if (typeof object == \"function\" && !(object instanceof RegExp)) {\n            return ascii.func(object);\n        }\n\n        processed = processed || [];\n\n        if (isCircular(object, processed)) {\n            return \"[Circular]\";\n        }\n\n        if (Object.prototype.toString.call(object) == \"[object Array]\") {\n            return ascii.array.call(this, object, processed);\n        }\n\n        if (!object) {\n            return \"\" + object;\n        }\n\n        if (buster.isElement(object)) {\n            return ascii.element(object);\n        }\n\n        if (typeof object.toString == \"function\" &&\n            object.toString !== Object.prototype.toString) {\n            return object.toString();\n        }\n\n        for (var i = 0, l = specialObjects.length; i < l; i++) {\n            if (object === specialObjects[i].obj) {\n                return specialObjects[i].value;\n            }\n        }\n\n        return ascii.object.call(this, object, processed, indent);\n    }\n\n    ascii.func = function (func) {\n        return \"function \" + buster.functionName(func) + \"() {}\";\n    };\n\n    ascii.array = function (array, processed) {\n        processed = processed || [];\n        processed.push(array);\n        var pieces = [];\n\n        for (var i = 0, l = array.length; i < l; ++i) {\n            pieces.push(ascii.call(this, array[i], processed));\n        }\n\n        return \"[\" + pieces.join(\", \") + \"]\";\n    };\n\n    ascii.object = function (object, processed, indent) {\n        processed = processed || [];\n        processed.push(object);\n        indent = indent || 0;\n        var pieces = [], properties = keys(object), prop, str, obj;\n        var is = \"\";\n        var length = 3;\n\n        for (var i = 0, l = indent; i < l; ++i) {\n            is += \" \";\n        }\n\n        for (i = 0, l = properties.length; i < l; ++i) {\n            prop = properties[i];\n            obj = object[prop];\n\n            if (isCircular(obj, processed)) {\n                str = \"[Circular]\";\n            } else {\n                str = ascii.call(this, obj, processed, indent + 2);\n            }\n\n            str = (/\\s/.test(prop) ? '\"' + prop + '\"' : prop) + \": \" + str;\n            length += str.length;\n            pieces.push(str);\n        }\n\n        var cons = ascii.constructorName.call(this, object);\n        var prefix = cons ? \"[\" + cons + \"] \" : \"\"\n\n        return (length + indent) > 80 ?\n            prefix + \"{\\n  \" + is + pieces.join(\",\\n  \" + is) + \"\\n\" + is + \"}\" :\n            prefix + \"{ \" + pieces.join(\", \") + \" }\";\n    };\n\n    ascii.element = function (element) {\n        var tagName = element.tagName.toLowerCase();\n        var attrs = element.attributes, attribute, pairs = [], attrName;\n\n        for (var i = 0, l = attrs.length; i < l; ++i) {\n            attribute = attrs.item(i);\n            attrName = attribute.nodeName.toLowerCase().replace(\"html:\", \"\");\n\n            if (attrName == \"contenteditable\" && attribute.nodeValue == \"inherit\") {\n                continue;\n            }\n\n            if (!!attribute.nodeValue) {\n                pairs.push(attrName + \"=\\\"\" + attribute.nodeValue + \"\\\"\");\n            }\n        }\n\n        var formatted = \"<\" + tagName + (pairs.length > 0 ? \" \" : \"\");\n        var content = element.innerHTML;\n\n        if (content.length > 20) {\n            content = content.substr(0, 20) + \"[...]\";\n        }\n\n        var res = formatted + pairs.join(\" \") + \">\" + content + \"</\" + tagName + \">\";\n\n        return res.replace(/ contentEditable=\"inherit\"/, \"\");\n    };\n\n    ascii.constructorName = function (object) {\n        var name = buster.functionName(object && object.constructor);\n        var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];\n\n        for (var i = 0, l = excludes.length; i < l; ++i) {\n            if (typeof excludes[i] == \"string\" && excludes[i] == name) {\n                return \"\";\n            } else if (excludes[i].test && excludes[i].test(name)) {\n                return \"\";\n            }\n        }\n\n        return name;\n    };\n\n    return ascii;\n}());\n\nif (typeof module != \"undefined\") {\n    module.exports = buster.format;\n}\n/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/\n/*global module, require, __dirname, document*/\n/**\n * Sinon core utilities. For internal use only.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\nvar sinon = (function (buster) {\n    var div = typeof document != \"undefined\" && document.createElement(\"div\");\n    var hasOwn = Object.prototype.hasOwnProperty;\n\n    function isDOMNode(obj) {\n        var success = false;\n\n        try {\n            obj.appendChild(div);\n            success = div.parentNode == obj;\n        } catch (e) {\n            return false;\n        } finally {\n            try {\n                obj.removeChild(div);\n            } catch (e) {\n                // Remove failed, not much we can do about that\n            }\n        }\n\n        return success;\n    }\n\n    function isElement(obj) {\n        return div && obj && obj.nodeType === 1 && isDOMNode(obj);\n    }\n\n    function isFunction(obj) {\n        return typeof obj === \"function\" || !!(obj && obj.constructor && obj.call && obj.apply);\n    }\n\n    function mirrorProperties(target, source) {\n        for (var prop in source) {\n            if (!hasOwn.call(target, prop)) {\n                target[prop] = source[prop];\n            }\n        }\n    }\n\n    function isRestorable (obj) {\n        return typeof obj === \"function\" && typeof obj.restore === \"function\" && obj.restore.sinon;\n    }\n\n    var sinon = {\n        wrapMethod: function wrapMethod(object, property, method) {\n            if (!object) {\n                throw new TypeError(\"Should wrap property of object\");\n            }\n\n            if (typeof method != \"function\") {\n                throw new TypeError(\"Method wrapper should be function\");\n            }\n\n            var wrappedMethod = object[property];\n\n            if (!isFunction(wrappedMethod)) {\n                throw new TypeError(\"Attempted to wrap \" + (typeof wrappedMethod) + \" property \" +\n                                    property + \" as function\");\n            }\n\n            if (wrappedMethod.restore && wrappedMethod.restore.sinon) {\n                throw new TypeError(\"Attempted to wrap \" + property + \" which is already wrapped\");\n            }\n\n            if (wrappedMethod.calledBefore) {\n                var verb = !!wrappedMethod.returns ? \"stubbed\" : \"spied on\";\n                throw new TypeError(\"Attempted to wrap \" + property + \" which is already \" + verb);\n            }\n\n            // IE 8 does not support hasOwnProperty on the window object.\n            var owned = hasOwn.call(object, property);\n            object[property] = method;\n            method.displayName = property;\n\n            method.restore = function () {\n                // For prototype properties try to reset by delete first.\n                // If this fails (ex: localStorage on mobile safari) then force a reset\n                // via direct assignment.\n                if (!owned) {\n                    delete object[property];\n                }\n                if (object[property] === method) {\n                    object[property] = wrappedMethod;\n                }\n            };\n\n            method.restore.sinon = true;\n            mirrorProperties(method, wrappedMethod);\n\n            return method;\n        },\n\n        extend: function extend(target) {\n            for (var i = 1, l = arguments.length; i < l; i += 1) {\n                for (var prop in arguments[i]) {\n                    if (arguments[i].hasOwnProperty(prop)) {\n                        target[prop] = arguments[i][prop];\n                    }\n\n                    // DONT ENUM bug, only care about toString\n                    if (arguments[i].hasOwnProperty(\"toString\") &&\n                        arguments[i].toString != target.toString) {\n                        target.toString = arguments[i].toString;\n                    }\n                }\n            }\n\n            return target;\n        },\n\n        create: function create(proto) {\n            var F = function () {};\n            F.prototype = proto;\n            return new F();\n        },\n\n        deepEqual: function deepEqual(a, b) {\n            if (sinon.match && sinon.match.isMatcher(a)) {\n                return a.test(b);\n            }\n            if (typeof a != \"object\" || typeof b != \"object\") {\n                return a === b;\n            }\n\n            if (isElement(a) || isElement(b)) {\n                return a === b;\n            }\n\n            if (a === b) {\n                return true;\n            }\n\n            if ((a === null && b !== null) || (a !== null && b === null)) {\n                return false;\n            }\n\n            var aString = Object.prototype.toString.call(a);\n            if (aString != Object.prototype.toString.call(b)) {\n                return false;\n            }\n\n            if (aString == \"[object Array]\") {\n                if (a.length !== b.length) {\n                    return false;\n                }\n\n                for (var i = 0, l = a.length; i < l; i += 1) {\n                    if (!deepEqual(a[i], b[i])) {\n                        return false;\n                    }\n                }\n\n                return true;\n            }\n\n            var prop, aLength = 0, bLength = 0;\n\n            for (prop in a) {\n                aLength += 1;\n\n                if (!deepEqual(a[prop], b[prop])) {\n                    return false;\n                }\n            }\n\n            for (prop in b) {\n                bLength += 1;\n            }\n\n            return aLength == bLength;\n        },\n\n        functionName: function functionName(func) {\n            var name = func.displayName || func.name;\n\n            // Use function decomposition as a last resort to get function\n            // name. Does not rely on function decomposition to work - if it\n            // doesn't debugging will be slightly less informative\n            // (i.e. toString will say 'spy' rather than 'myFunc').\n            if (!name) {\n                var matches = func.toString().match(/function ([^\\s\\(]+)/);\n                name = matches && matches[1];\n            }\n\n            return name;\n        },\n\n        functionToString: function toString() {\n            if (this.getCall && this.callCount) {\n                var thisValue, prop, i = this.callCount;\n\n                while (i--) {\n                    thisValue = this.getCall(i).thisValue;\n\n                    for (prop in thisValue) {\n                        if (thisValue[prop] === this) {\n                            return prop;\n                        }\n                    }\n                }\n            }\n\n            return this.displayName || \"sinon fake\";\n        },\n\n        getConfig: function (custom) {\n            var config = {};\n            custom = custom || {};\n            var defaults = sinon.defaultConfig;\n\n            for (var prop in defaults) {\n                if (defaults.hasOwnProperty(prop)) {\n                    config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];\n                }\n            }\n\n            return config;\n        },\n\n        format: function (val) {\n            return \"\" + val;\n        },\n\n        defaultConfig: {\n            injectIntoThis: true,\n            injectInto: null,\n            properties: [\"spy\", \"stub\", \"mock\", \"clock\", \"server\", \"requests\"],\n            useFakeTimers: true,\n            useFakeServer: true\n        },\n\n        timesInWords: function timesInWords(count) {\n            return count == 1 && \"once\" ||\n                count == 2 && \"twice\" ||\n                count == 3 && \"thrice\" ||\n                (count || 0) + \" times\";\n        },\n\n        calledInOrder: function (spies) {\n            for (var i = 1, l = spies.length; i < l; i++) {\n                if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {\n                    return false;\n                }\n            }\n\n            return true;\n        },\n\n        orderByFirstCall: function (spies) {\n            return spies.sort(function (a, b) {\n                // uuid, won't ever be equal\n                var aCall = a.getCall(0);\n                var bCall = b.getCall(0);\n                var aId = aCall && aCall.callId || -1;\n                var bId = bCall && bCall.callId || -1;\n\n                return aId < bId ? -1 : 1;\n            });\n        },\n\n        log: function () {},\n\n        logError: function (label, err) {\n            var msg = label + \" threw exception: \"\n            sinon.log(msg + \"[\" + err.name + \"] \" + err.message);\n            if (err.stack) { sinon.log(err.stack); }\n\n            setTimeout(function () {\n                err.message = msg + err.message;\n                throw err;\n            }, 0);\n        },\n\n        typeOf: function (value) {\n            if (value === null) {\n                return \"null\";\n            }\n            else if (value === undefined) {\n                return \"undefined\";\n            }\n            var string = Object.prototype.toString.call(value);\n            return string.substring(8, string.length - 1).toLowerCase();\n        },\n\n        createStubInstance: function (constructor) {\n            if (typeof constructor !== \"function\") {\n                throw new TypeError(\"The constructor should be a function.\");\n            }\n            return sinon.stub(sinon.create(constructor.prototype));\n        },\n\n        restore: function (object) {\n            if (object !== null && typeof object === \"object\") {\n                for (var prop in object) {\n                    if (isRestorable(object[prop])) {\n                        object[prop].restore();\n                    }\n                }\n            }\n            else if (isRestorable(object)) {\n                object.restore();\n            }\n        }\n    };\n\n    var isNode = typeof module == \"object\" && typeof require == \"function\";\n\n    if (isNode) {\n        try {\n            buster = { format: require(\"buster-format\") };\n        } catch (e) {}\n        module.exports = sinon;\n        module.exports.spy = require(\"./sinon/spy\");\n        module.exports.spyCall = require(\"./sinon/call\");\n        module.exports.stub = require(\"./sinon/stub\");\n        module.exports.mock = require(\"./sinon/mock\");\n        module.exports.collection = require(\"./sinon/collection\");\n        module.exports.assert = require(\"./sinon/assert\");\n        module.exports.sandbox = require(\"./sinon/sandbox\");\n        module.exports.test = require(\"./sinon/test\");\n        module.exports.testCase = require(\"./sinon/test_case\");\n        module.exports.assert = require(\"./sinon/assert\");\n        module.exports.match = require(\"./sinon/match\");\n    }\n\n    if (buster) {\n        var formatter = sinon.create(buster.format);\n        formatter.quoteStrings = false;\n        sinon.format = function () {\n            return formatter.ascii.apply(formatter, arguments);\n        };\n    } else if (isNode) {\n        try {\n            var util = require(\"util\");\n            sinon.format = function (value) {\n                return typeof value == \"object\" && value.toString === Object.prototype.toString ? util.inspect(value) : value;\n            };\n        } catch (e) {\n            /* Node, but no util module - would be very old, but better safe than\n             sorry */\n        }\n    }\n\n    return sinon;\n}(typeof buster == \"object\" && buster));\n\n/* @depend ../sinon.js */\n/*jslint eqeqeq: false, onevar: false, plusplus: false*/\n/*global module, require, sinon*/\n/**\n * Match functions\n *\n * @author Maximilian Antoni (mail@maxantoni.de)\n * @license BSD\n *\n * Copyright (c) 2012 Maximilian Antoni\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function assertType(value, type, name) {\n        var actual = sinon.typeOf(value);\n        if (actual !== type) {\n            throw new TypeError(\"Expected type of \" + name + \" to be \" +\n                type + \", but was \" + actual);\n        }\n    }\n\n    var matcher = {\n        toString: function () {\n            return this.message;\n        }\n    };\n\n    function isMatcher(object) {\n        return matcher.isPrototypeOf(object);\n    }\n\n    function matchObject(expectation, actual) {\n        if (actual === null || actual === undefined) {\n            return false;\n        }\n        for (var key in expectation) {\n            if (expectation.hasOwnProperty(key)) {\n                var exp = expectation[key];\n                var act = actual[key];\n                if (match.isMatcher(exp)) {\n                    if (!exp.test(act)) {\n                        return false;\n                    }\n                } else if (sinon.typeOf(exp) === \"object\") {\n                    if (!matchObject(exp, act)) {\n                        return false;\n                    }\n                } else if (!sinon.deepEqual(exp, act)) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    matcher.or = function (m2) {\n        if (!isMatcher(m2)) {\n            throw new TypeError(\"Matcher expected\");\n        }\n        var m1 = this;\n        var or = sinon.create(matcher);\n        or.test = function (actual) {\n            return m1.test(actual) || m2.test(actual);\n        };\n        or.message = m1.message + \".or(\" + m2.message + \")\";\n        return or;\n    };\n\n    matcher.and = function (m2) {\n        if (!isMatcher(m2)) {\n            throw new TypeError(\"Matcher expected\");\n        }\n        var m1 = this;\n        var and = sinon.create(matcher);\n        and.test = function (actual) {\n            return m1.test(actual) && m2.test(actual);\n        };\n        and.message = m1.message + \".and(\" + m2.message + \")\";\n        return and;\n    };\n\n    var match = function (expectation, message) {\n        var m = sinon.create(matcher);\n        var type = sinon.typeOf(expectation);\n        switch (type) {\n        case \"object\":\n            if (typeof expectation.test === \"function\") {\n                m.test = function (actual) {\n                    return expectation.test(actual) === true;\n                };\n                m.message = \"match(\" + sinon.functionName(expectation.test) + \")\";\n                return m;\n            }\n            var str = [];\n            for (var key in expectation) {\n                if (expectation.hasOwnProperty(key)) {\n                    str.push(key + \": \" + expectation[key]);\n                }\n            }\n            m.test = function (actual) {\n                return matchObject(expectation, actual);\n            };\n            m.message = \"match(\" + str.join(\", \") + \")\";\n            break;\n        case \"number\":\n            m.test = function (actual) {\n                return expectation == actual;\n            };\n            break;\n        case \"string\":\n            m.test = function (actual) {\n                if (typeof actual !== \"string\") {\n                    return false;\n                }\n                return actual.indexOf(expectation) !== -1;\n            };\n            m.message = \"match(\\\"\" + expectation + \"\\\")\";\n            break;\n        case \"regexp\":\n            m.test = function (actual) {\n                if (typeof actual !== \"string\") {\n                    return false;\n                }\n                return expectation.test(actual);\n            };\n            break;\n        case \"function\":\n            m.test = expectation;\n            if (message) {\n                m.message = message;\n            } else {\n                m.message = \"match(\" + sinon.functionName(expectation) + \")\";\n            }\n            break;\n        default:\n            m.test = function (actual) {\n              return sinon.deepEqual(expectation, actual);\n            };\n        }\n        if (!m.message) {\n            m.message = \"match(\" + expectation + \")\";\n        }\n        return m;\n    };\n\n    match.isMatcher = isMatcher;\n\n    match.any = match(function () {\n        return true;\n    }, \"any\");\n\n    match.defined = match(function (actual) {\n        return actual !== null && actual !== undefined;\n    }, \"defined\");\n\n    match.truthy = match(function (actual) {\n        return !!actual;\n    }, \"truthy\");\n\n    match.falsy = match(function (actual) {\n        return !actual;\n    }, \"falsy\");\n\n    match.same = function (expectation) {\n        return match(function (actual) {\n            return expectation === actual;\n        }, \"same(\" + expectation + \")\");\n    };\n\n    match.typeOf = function (type) {\n        assertType(type, \"string\", \"type\");\n        return match(function (actual) {\n            return sinon.typeOf(actual) === type;\n        }, \"typeOf(\\\"\" + type + \"\\\")\");\n    };\n\n    match.instanceOf = function (type) {\n        assertType(type, \"function\", \"type\");\n        return match(function (actual) {\n            return actual instanceof type;\n        }, \"instanceOf(\" + sinon.functionName(type) + \")\");\n    };\n\n    function createPropertyMatcher(propertyTest, messagePrefix) {\n        return function (property, value) {\n            assertType(property, \"string\", \"property\");\n            var onlyProperty = arguments.length === 1;\n            var message = messagePrefix + \"(\\\"\" + property + \"\\\"\";\n            if (!onlyProperty) {\n                message += \", \" + value;\n            }\n            message += \")\";\n            return match(function (actual) {\n                if (actual === undefined || actual === null ||\n                        !propertyTest(actual, property)) {\n                    return false;\n                }\n                return onlyProperty || sinon.deepEqual(value, actual[property]);\n            }, message);\n        };\n    }\n\n    match.has = createPropertyMatcher(function (actual, property) {\n        if (typeof actual === \"object\") {\n            return property in actual;\n        }\n        return actual[property] !== undefined;\n    }, \"has\");\n\n    match.hasOwn = createPropertyMatcher(function (actual, property) {\n        return actual.hasOwnProperty(property);\n    }, \"hasOwn\");\n\n    match.bool = match.typeOf(\"boolean\");\n    match.number = match.typeOf(\"number\");\n    match.string = match.typeOf(\"string\");\n    match.object = match.typeOf(\"object\");\n    match.func = match.typeOf(\"function\");\n    match.array = match.typeOf(\"array\");\n    match.regexp = match.typeOf(\"regexp\");\n    match.date = match.typeOf(\"date\");\n\n    if (commonJSModule) {\n        module.exports = match;\n    } else {\n        sinon.match = match;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n  * @depend ../sinon.js\n  * @depend match.js\n  */\n/*jslint eqeqeq: false, onevar: false, plusplus: false*/\n/*global module, require, sinon*/\n/**\n  * Spy calls\n  *\n  * @author Christian Johansen (christian@cjohansen.no)\n  * @author Maximilian Antoni (mail@maxantoni.de)\n  * @license BSD\n  *\n  * Copyright (c) 2010-2013 Christian Johansen\n  * Copyright (c) 2013 Maximilian Antoni\n  */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function throwYieldError(proxy, text, args) {\n        var msg = sinon.functionName(proxy) + text;\n        if (args.length) {\n            msg += \" Received [\" + slice.call(args).join(\", \") + \"]\";\n        }\n        throw new Error(msg);\n    }\n\n    var slice = Array.prototype.slice;\n\n    var callProto = {\n        calledOn: function calledOn(thisValue) {\n            if (sinon.match && sinon.match.isMatcher(thisValue)) {\n                return thisValue.test(this.thisValue);\n            }\n            return this.thisValue === thisValue;\n        },\n\n        calledWith: function calledWith() {\n            for (var i = 0, l = arguments.length; i < l; i += 1) {\n                if (!sinon.deepEqual(arguments[i], this.args[i])) {\n                    return false;\n                }\n            }\n\n            return true;\n        },\n\n        calledWithMatch: function calledWithMatch() {\n            for (var i = 0, l = arguments.length; i < l; i += 1) {\n                var actual = this.args[i];\n                var expectation = arguments[i];\n                if (!sinon.match || !sinon.match(expectation).test(actual)) {\n                    return false;\n                }\n            }\n            return true;\n        },\n\n        calledWithExactly: function calledWithExactly() {\n            return arguments.length == this.args.length &&\n                this.calledWith.apply(this, arguments);\n        },\n\n        notCalledWith: function notCalledWith() {\n            return !this.calledWith.apply(this, arguments);\n        },\n\n        notCalledWithMatch: function notCalledWithMatch() {\n            return !this.calledWithMatch.apply(this, arguments);\n        },\n\n        returned: function returned(value) {\n            return sinon.deepEqual(value, this.returnValue);\n        },\n\n        threw: function threw(error) {\n            if (typeof error === \"undefined\" || !this.exception) {\n                return !!this.exception;\n            }\n\n            return this.exception === error || this.exception.name === error;\n        },\n\n        calledWithNew: function calledWithNew(thisValue) {\n            return this.thisValue instanceof this.proxy;\n        },\n\n        calledBefore: function (other) {\n            return this.callId < other.callId;\n        },\n\n        calledAfter: function (other) {\n            return this.callId > other.callId;\n        },\n\n        callArg: function (pos) {\n            this.args[pos]();\n        },\n\n        callArgOn: function (pos, thisValue) {\n            this.args[pos].apply(thisValue);\n        },\n\n        callArgWith: function (pos) {\n            this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));\n        },\n\n        callArgOnWith: function (pos, thisValue) {\n            var args = slice.call(arguments, 2);\n            this.args[pos].apply(thisValue, args);\n        },\n\n        \"yield\": function () {\n            this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));\n        },\n\n        yieldOn: function (thisValue) {\n            var args = this.args;\n            for (var i = 0, l = args.length; i < l; ++i) {\n                if (typeof args[i] === \"function\") {\n                    args[i].apply(thisValue, slice.call(arguments, 1));\n                    return;\n                }\n            }\n            throwYieldError(this.proxy, \" cannot yield since no callback was passed.\", args);\n        },\n\n        yieldTo: function (prop) {\n            this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));\n        },\n\n        yieldToOn: function (prop, thisValue) {\n            var args = this.args;\n            for (var i = 0, l = args.length; i < l; ++i) {\n                if (args[i] && typeof args[i][prop] === \"function\") {\n                    args[i][prop].apply(thisValue, slice.call(arguments, 2));\n                    return;\n                }\n            }\n            throwYieldError(this.proxy, \" cannot yield to '\" + prop +\n                \"' since no callback was passed.\", args);\n        },\n\n        toString: function () {\n            var callStr = this.proxy.toString() + \"(\";\n            var args = [];\n\n            for (var i = 0, l = this.args.length; i < l; ++i) {\n                args.push(sinon.format(this.args[i]));\n            }\n\n            callStr = callStr + args.join(\", \") + \")\";\n\n            if (typeof this.returnValue != \"undefined\") {\n                callStr += \" => \" + sinon.format(this.returnValue);\n            }\n\n            if (this.exception) {\n                callStr += \" !\" + this.exception.name;\n\n                if (this.exception.message) {\n                    callStr += \"(\" + this.exception.message + \")\";\n                }\n            }\n\n            return callStr;\n        }\n    };\n\n    callProto.invokeCallback = callProto.yield;\n\n    function createSpyCall(spy, thisValue, args, returnValue, exception, id) {\n        if (typeof id !== \"number\") {\n            throw new TypeError(\"Call id is not a number\");\n        }\n        var proxyCall = sinon.create(callProto);\n        proxyCall.proxy = spy;\n        proxyCall.thisValue = thisValue;\n        proxyCall.args = args;\n        proxyCall.returnValue = returnValue;\n        proxyCall.exception = exception;\n        proxyCall.callId = id;\n\n        return proxyCall;\n    };\n    createSpyCall.toString = callProto.toString; // used by mocks\n\n    if (commonJSModule) {\n        module.exports = createSpyCall;\n    } else {\n        sinon.spyCall = createSpyCall;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n\n/**\n  * @depend ../sinon.js\n  * @depend call.js\n  */\n/*jslint eqeqeq: false, onevar: false, plusplus: false*/\n/*global module, require, sinon*/\n/**\n  * Spy functions\n  *\n  * @author Christian Johansen (christian@cjohansen.no)\n  * @license BSD\n  *\n  * Copyright (c) 2010-2013 Christian Johansen\n  */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n    var push = Array.prototype.push;\n    var slice = Array.prototype.slice;\n    var callId = 0;\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function spy(object, property) {\n        if (!property && typeof object == \"function\") {\n            return spy.create(object);\n        }\n\n        if (!object && !property) {\n            return spy.create(function () { });\n        }\n\n        var method = object[property];\n        return sinon.wrapMethod(object, property, spy.create(method));\n    }\n\n    function matchingFake(fakes, args, strict) {\n        if (!fakes) {\n            return;\n        }\n\n        var alen = args.length;\n\n        for (var i = 0, l = fakes.length; i < l; i++) {\n            if (fakes[i].matches(args, strict)) {\n                return fakes[i];\n            }\n        }\n    }\n\n    function incrementCallCount() {\n        this.called = true;\n        this.callCount += 1;\n        this.notCalled = false;\n        this.calledOnce = this.callCount == 1;\n        this.calledTwice = this.callCount == 2;\n        this.calledThrice = this.callCount == 3;\n    }\n\n    function createCallProperties() {\n        this.firstCall = this.getCall(0);\n        this.secondCall = this.getCall(1);\n        this.thirdCall = this.getCall(2);\n        this.lastCall = this.getCall(this.callCount - 1);\n    }\n\n    var vars = \"a,b,c,d,e,f,g,h,i,j,k,l\";\n    function createProxy(func) {\n        // Retain the function length:\n        var p;\n        if (func.length) {\n            eval(\"p = (function proxy(\" + vars.substring(0, func.length * 2 - 1) +\n                \") { return p.invoke(func, this, slice.call(arguments)); });\");\n        }\n        else {\n            p = function proxy() {\n                return p.invoke(func, this, slice.call(arguments));\n            };\n        }\n        return p;\n    }\n\n    var uuid = 0;\n\n    // Public API\n    var spyApi = {\n        reset: function () {\n            this.called = false;\n            this.notCalled = true;\n            this.calledOnce = false;\n            this.calledTwice = false;\n            this.calledThrice = false;\n            this.callCount = 0;\n            this.firstCall = null;\n            this.secondCall = null;\n            this.thirdCall = null;\n            this.lastCall = null;\n            this.args = [];\n            this.returnValues = [];\n            this.thisValues = [];\n            this.exceptions = [];\n            this.callIds = [];\n            if (this.fakes) {\n                for (var i = 0; i < this.fakes.length; i++) {\n                    this.fakes[i].reset();\n                }\n            }\n        },\n\n        create: function create(func) {\n            var name;\n\n            if (typeof func != \"function\") {\n                func = function () { };\n            } else {\n                name = sinon.functionName(func);\n            }\n\n            var proxy = createProxy(func);\n\n            sinon.extend(proxy, spy);\n            delete proxy.create;\n            sinon.extend(proxy, func);\n\n            proxy.reset();\n            proxy.prototype = func.prototype;\n            proxy.displayName = name || \"spy\";\n            proxy.toString = sinon.functionToString;\n            proxy._create = sinon.spy.create;\n            proxy.id = \"spy#\" + uuid++;\n\n            return proxy;\n        },\n\n        invoke: function invoke(func, thisValue, args) {\n            var matching = matchingFake(this.fakes, args);\n            var exception, returnValue;\n\n            incrementCallCount.call(this);\n            push.call(this.thisValues, thisValue);\n            push.call(this.args, args);\n            push.call(this.callIds, callId++);\n\n            try {\n                if (matching) {\n                    returnValue = matching.invoke(func, thisValue, args);\n                } else {\n                    returnValue = (this.func || func).apply(thisValue, args);\n                }\n            } catch (e) {\n                push.call(this.returnValues, undefined);\n                exception = e;\n                throw e;\n            } finally {\n                push.call(this.exceptions, exception);\n            }\n\n            push.call(this.returnValues, returnValue);\n\n            createCallProperties.call(this);\n\n            return returnValue;\n        },\n\n        getCall: function getCall(i) {\n            if (i < 0 || i >= this.callCount) {\n                return null;\n            }\n\n            return sinon.spyCall(this, this.thisValues[i], this.args[i],\n                                    this.returnValues[i], this.exceptions[i],\n                                    this.callIds[i]);\n        },\n\n        calledBefore: function calledBefore(spyFn) {\n            if (!this.called) {\n                return false;\n            }\n\n            if (!spyFn.called) {\n                return true;\n            }\n\n            return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];\n        },\n\n        calledAfter: function calledAfter(spyFn) {\n            if (!this.called || !spyFn.called) {\n                return false;\n            }\n\n            return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];\n        },\n\n        withArgs: function () {\n            var args = slice.call(arguments);\n\n            if (this.fakes) {\n                var match = matchingFake(this.fakes, args, true);\n\n                if (match) {\n                    return match;\n                }\n            } else {\n                this.fakes = [];\n            }\n\n            var original = this;\n            var fake = this._create();\n            fake.matchingAguments = args;\n            push.call(this.fakes, fake);\n\n            fake.withArgs = function () {\n                return original.withArgs.apply(original, arguments);\n            };\n\n            for (var i = 0; i < this.args.length; i++) {\n                if (fake.matches(this.args[i])) {\n                    incrementCallCount.call(fake);\n                    push.call(fake.thisValues, this.thisValues[i]);\n                    push.call(fake.args, this.args[i]);\n                    push.call(fake.returnValues, this.returnValues[i]);\n                    push.call(fake.exceptions, this.exceptions[i]);\n                    push.call(fake.callIds, this.callIds[i]);\n                }\n            }\n            createCallProperties.call(fake);\n\n            return fake;\n        },\n\n        matches: function (args, strict) {\n            var margs = this.matchingAguments;\n\n            if (margs.length <= args.length &&\n                sinon.deepEqual(margs, args.slice(0, margs.length))) {\n                return !strict || margs.length == args.length;\n            }\n        },\n\n        printf: function (format) {\n            var spy = this;\n            var args = slice.call(arguments, 1);\n            var formatter;\n\n            return (format || \"\").replace(/%(.)/g, function (match, specifyer) {\n                formatter = spyApi.formatters[specifyer];\n\n                if (typeof formatter == \"function\") {\n                    return formatter.call(null, spy, args);\n                } else if (!isNaN(parseInt(specifyer), 10)) {\n                    return sinon.format(args[specifyer - 1]);\n                }\n\n                return \"%\" + specifyer;\n            });\n        }\n    };\n\n    function delegateToCalls(method, matchAny, actual, notCalled) {\n        spyApi[method] = function () {\n            if (!this.called) {\n                if (notCalled) {\n                    return notCalled.apply(this, arguments);\n                }\n                return false;\n            }\n\n            var currentCall;\n            var matches = 0;\n\n            for (var i = 0, l = this.callCount; i < l; i += 1) {\n                currentCall = this.getCall(i);\n\n                if (currentCall[actual || method].apply(currentCall, arguments)) {\n                    matches += 1;\n\n                    if (matchAny) {\n                        return true;\n                    }\n                }\n            }\n\n            return matches === this.callCount;\n        };\n    }\n\n    delegateToCalls(\"calledOn\", true);\n    delegateToCalls(\"alwaysCalledOn\", false, \"calledOn\");\n    delegateToCalls(\"calledWith\", true);\n    delegateToCalls(\"calledWithMatch\", true);\n    delegateToCalls(\"alwaysCalledWith\", false, \"calledWith\");\n    delegateToCalls(\"alwaysCalledWithMatch\", false, \"calledWithMatch\");\n    delegateToCalls(\"calledWithExactly\", true);\n    delegateToCalls(\"alwaysCalledWithExactly\", false, \"calledWithExactly\");\n    delegateToCalls(\"neverCalledWith\", false, \"notCalledWith\",\n        function () { return true; });\n    delegateToCalls(\"neverCalledWithMatch\", false, \"notCalledWithMatch\",\n        function () { return true; });\n    delegateToCalls(\"threw\", true);\n    delegateToCalls(\"alwaysThrew\", false, \"threw\");\n    delegateToCalls(\"returned\", true);\n    delegateToCalls(\"alwaysReturned\", false, \"returned\");\n    delegateToCalls(\"calledWithNew\", true);\n    delegateToCalls(\"alwaysCalledWithNew\", false, \"calledWithNew\");\n    delegateToCalls(\"callArg\", false, \"callArgWith\", function () {\n        throw new Error(this.toString() + \" cannot call arg since it was not yet invoked.\");\n    });\n    spyApi.callArgWith = spyApi.callArg;\n    delegateToCalls(\"callArgOn\", false, \"callArgOnWith\", function () {\n        throw new Error(this.toString() + \" cannot call arg since it was not yet invoked.\");\n    });\n    spyApi.callArgOnWith = spyApi.callArgOn;\n    delegateToCalls(\"yield\", false, \"yield\", function () {\n        throw new Error(this.toString() + \" cannot yield since it was not yet invoked.\");\n    });\n    // \"invokeCallback\" is an alias for \"yield\" since \"yield\" is invalid in strict mode.\n    spyApi.invokeCallback = spyApi.yield;\n    delegateToCalls(\"yieldOn\", false, \"yieldOn\", function () {\n        throw new Error(this.toString() + \" cannot yield since it was not yet invoked.\");\n    });\n    delegateToCalls(\"yieldTo\", false, \"yieldTo\", function (property) {\n        throw new Error(this.toString() + \" cannot yield to '\" + property +\n            \"' since it was not yet invoked.\");\n    });\n    delegateToCalls(\"yieldToOn\", false, \"yieldToOn\", function (property) {\n        throw new Error(this.toString() + \" cannot yield to '\" + property +\n            \"' since it was not yet invoked.\");\n    });\n\n    spyApi.formatters = {\n        \"c\": function (spy) {\n            return sinon.timesInWords(spy.callCount);\n        },\n\n        \"n\": function (spy) {\n            return spy.toString();\n        },\n\n        \"C\": function (spy) {\n            var calls = [];\n\n            for (var i = 0, l = spy.callCount; i < l; ++i) {\n                var stringifiedCall = \"    \" + spy.getCall(i).toString();\n                if (/\\n/.test(calls[i - 1])) {\n                    stringifiedCall = \"\\n\" + stringifiedCall;\n                }\n                push.call(calls, stringifiedCall);\n            }\n\n            return calls.length > 0 ? \"\\n\" + calls.join(\"\\n\") : \"\";\n        },\n\n        \"t\": function (spy) {\n            var objects = [];\n\n            for (var i = 0, l = spy.callCount; i < l; ++i) {\n                push.call(objects, sinon.format(spy.thisValues[i]));\n            }\n\n            return objects.join(\", \");\n        },\n\n        \"*\": function (spy, args) {\n            var formatted = [];\n\n            for (var i = 0, l = args.length; i < l; ++i) {\n                push.call(formatted, sinon.format(args[i]));\n            }\n\n            return formatted.join(\", \");\n        }\n    };\n\n    sinon.extend(spy, spyApi);\n\n    spy.spyCall = sinon.spyCall;\n\n    if (commonJSModule) {\n        module.exports = spy;\n    } else {\n        sinon.spy = spy;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n * @depend ../sinon.js\n * @depend spy.js\n */\n/*jslint eqeqeq: false, onevar: false*/\n/*global module, require, sinon*/\n/**\n * Stub functions\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function stub(object, property, func) {\n        if (!!func && typeof func != \"function\") {\n            throw new TypeError(\"Custom stub should be function\");\n        }\n\n        var wrapper;\n\n        if (func) {\n            wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;\n        } else {\n            wrapper = stub.create();\n        }\n\n        if (!object && !property) {\n            return sinon.stub.create();\n        }\n\n        if (!property && !!object && typeof object == \"object\") {\n            for (var prop in object) {\n                if (typeof object[prop] === \"function\") {\n                    stub(object, prop);\n                }\n            }\n\n            return object;\n        }\n\n        return sinon.wrapMethod(object, property, wrapper);\n    }\n\n    function getChangingValue(stub, property) {\n        var index = stub.callCount - 1;\n        var values = stub[property];\n        var prop = index in values ? values[index] : values[values.length - 1];\n        stub[property + \"Last\"] = prop;\n\n        return prop;\n    }\n\n    function getCallback(stub, args) {\n        var callArgAt = getChangingValue(stub, \"callArgAts\");\n\n        if (callArgAt < 0) {\n            var callArgProp = getChangingValue(stub, \"callArgProps\");\n\n            for (var i = 0, l = args.length; i < l; ++i) {\n                if (!callArgProp && typeof args[i] == \"function\") {\n                    return args[i];\n                }\n\n                if (callArgProp && args[i] &&\n                    typeof args[i][callArgProp] == \"function\") {\n                    return args[i][callArgProp];\n                }\n            }\n\n            return null;\n        }\n\n        return args[callArgAt];\n    }\n\n    var join = Array.prototype.join;\n\n    function getCallbackError(stub, func, args) {\n        if (stub.callArgAtsLast < 0) {\n            var msg;\n\n            if (stub.callArgPropsLast) {\n                msg = sinon.functionName(stub) +\n                    \" expected to yield to '\" + stub.callArgPropsLast +\n                    \"', but no object with such a property was passed.\"\n            } else {\n                msg = sinon.functionName(stub) +\n                            \" expected to yield, but no callback was passed.\"\n            }\n\n            if (args.length > 0) {\n                msg += \" Received [\" + join.call(args, \", \") + \"]\";\n            }\n\n            return msg;\n        }\n\n        return \"argument at index \" + stub.callArgAtsLast + \" is not a function: \" + func;\n    }\n\n    var nextTick = (function () {\n        if (typeof process === \"object\" && typeof process.nextTick === \"function\") {\n            return process.nextTick;\n        } else if (typeof setImmediate === \"function\") {\n            return setImmediate;\n        } else {\n            return function (callback) {\n                setTimeout(callback, 0);\n            };\n        }\n    })();\n\n    function callCallback(stub, args) {\n        if (stub.callArgAts.length > 0) {\n            var func = getCallback(stub, args);\n\n            if (typeof func != \"function\") {\n                throw new TypeError(getCallbackError(stub, func, args));\n            }\n\n            var callbackArguments = getChangingValue(stub, \"callbackArguments\");\n            var callbackContext = getChangingValue(stub, \"callbackContexts\");\n\n            if (stub.callbackAsync) {\n                nextTick(function() {\n                    func.apply(callbackContext, callbackArguments);\n                });\n            } else {\n                func.apply(callbackContext, callbackArguments);\n            }\n        }\n    }\n\n    var uuid = 0;\n\n    sinon.extend(stub, (function () {\n        var slice = Array.prototype.slice, proto;\n\n        function throwsException(error, message) {\n            if (typeof error == \"string\") {\n                this.exception = new Error(message || \"\");\n                this.exception.name = error;\n            } else if (!error) {\n                this.exception = new Error(\"Error\");\n            } else {\n                this.exception = error;\n            }\n\n            return this;\n        }\n\n        proto = {\n            create: function create() {\n                var functionStub = function () {\n\n                    callCallback(functionStub, arguments);\n\n                    if (functionStub.exception) {\n                        throw functionStub.exception;\n                    } else if (typeof functionStub.returnArgAt == 'number') {\n                        return arguments[functionStub.returnArgAt];\n                    } else if (functionStub.returnThis) {\n                        return this;\n                    }\n                    return functionStub.returnValue;\n                };\n\n                functionStub.id = \"stub#\" + uuid++;\n                var orig = functionStub;\n                functionStub = sinon.spy.create(functionStub);\n                functionStub.func = orig;\n\n                functionStub.callArgAts = [];\n                functionStub.callbackArguments = [];\n                functionStub.callbackContexts = [];\n                functionStub.callArgProps = [];\n\n                sinon.extend(functionStub, stub);\n                functionStub._create = sinon.stub.create;\n                functionStub.displayName = \"stub\";\n                functionStub.toString = sinon.functionToString;\n\n                return functionStub;\n            },\n\n            resetBehavior: function () {\n                var i;\n\n                this.callArgAts = [];\n                this.callbackArguments = [];\n                this.callbackContexts = [];\n                this.callArgProps = [];\n\n                delete this.returnValue;\n                delete this.returnArgAt;\n                this.returnThis = false;\n\n                if (this.fakes) {\n                    for (i = 0; i < this.fakes.length; i++) {\n                        this.fakes[i].resetBehavior();\n                    }\n                }\n            },\n\n            returns: function returns(value) {\n                this.returnValue = value;\n\n                return this;\n            },\n\n            returnsArg: function returnsArg(pos) {\n                if (typeof pos != \"number\") {\n                    throw new TypeError(\"argument index is not number\");\n                }\n\n                this.returnArgAt = pos;\n\n                return this;\n            },\n\n            returnsThis: function returnsThis() {\n                this.returnThis = true;\n\n                return this;\n            },\n\n            \"throws\": throwsException,\n            throwsException: throwsException,\n\n            callsArg: function callsArg(pos) {\n                if (typeof pos != \"number\") {\n                    throw new TypeError(\"argument index is not number\");\n                }\n\n                this.callArgAts.push(pos);\n                this.callbackArguments.push([]);\n                this.callbackContexts.push(undefined);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            callsArgOn: function callsArgOn(pos, context) {\n                if (typeof pos != \"number\") {\n                    throw new TypeError(\"argument index is not number\");\n                }\n                if (typeof context != \"object\") {\n                    throw new TypeError(\"argument context is not an object\");\n                }\n\n                this.callArgAts.push(pos);\n                this.callbackArguments.push([]);\n                this.callbackContexts.push(context);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            callsArgWith: function callsArgWith(pos) {\n                if (typeof pos != \"number\") {\n                    throw new TypeError(\"argument index is not number\");\n                }\n\n                this.callArgAts.push(pos);\n                this.callbackArguments.push(slice.call(arguments, 1));\n                this.callbackContexts.push(undefined);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            callsArgOnWith: function callsArgWith(pos, context) {\n                if (typeof pos != \"number\") {\n                    throw new TypeError(\"argument index is not number\");\n                }\n                if (typeof context != \"object\") {\n                    throw new TypeError(\"argument context is not an object\");\n                }\n\n                this.callArgAts.push(pos);\n                this.callbackArguments.push(slice.call(arguments, 2));\n                this.callbackContexts.push(context);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            yields: function () {\n                this.callArgAts.push(-1);\n                this.callbackArguments.push(slice.call(arguments, 0));\n                this.callbackContexts.push(undefined);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            yieldsOn: function (context) {\n                if (typeof context != \"object\") {\n                    throw new TypeError(\"argument context is not an object\");\n                }\n\n                this.callArgAts.push(-1);\n                this.callbackArguments.push(slice.call(arguments, 1));\n                this.callbackContexts.push(context);\n                this.callArgProps.push(undefined);\n\n                return this;\n            },\n\n            yieldsTo: function (prop) {\n                this.callArgAts.push(-1);\n                this.callbackArguments.push(slice.call(arguments, 1));\n                this.callbackContexts.push(undefined);\n                this.callArgProps.push(prop);\n\n                return this;\n            },\n\n            yieldsToOn: function (prop, context) {\n                if (typeof context != \"object\") {\n                    throw new TypeError(\"argument context is not an object\");\n                }\n\n                this.callArgAts.push(-1);\n                this.callbackArguments.push(slice.call(arguments, 2));\n                this.callbackContexts.push(context);\n                this.callArgProps.push(prop);\n\n                return this;\n            }\n        };\n\n        // create asynchronous versions of callsArg* and yields* methods\n        for (var method in proto) {\n            // need to avoid creating anotherasync versions of the newly added async methods\n            if (proto.hasOwnProperty(method) &&\n                method.match(/^(callsArg|yields|thenYields$)/) &&\n                !method.match(/Async/)) {\n                proto[method + 'Async'] = (function (syncFnName) {\n                    return function () {\n                        this.callbackAsync = true;\n                        return this[syncFnName].apply(this, arguments);\n                    };\n                })(method);\n            }\n        }\n\n        return proto;\n\n    }()));\n\n    if (commonJSModule) {\n        module.exports = stub;\n    } else {\n        sinon.stub = stub;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n * @depend ../sinon.js\n * @depend stub.js\n */\n/*jslint eqeqeq: false, onevar: false, nomen: false*/\n/*global module, require, sinon*/\n/**\n * Mock functions.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n    var push = [].push;\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function mock(object) {\n        if (!object) {\n            return sinon.expectation.create(\"Anonymous mock\");\n        }\n\n        return mock.create(object);\n    }\n\n    sinon.mock = mock;\n\n    sinon.extend(mock, (function () {\n        function each(collection, callback) {\n            if (!collection) {\n                return;\n            }\n\n            for (var i = 0, l = collection.length; i < l; i += 1) {\n                callback(collection[i]);\n            }\n        }\n\n        return {\n            create: function create(object) {\n                if (!object) {\n                    throw new TypeError(\"object is null\");\n                }\n\n                var mockObject = sinon.extend({}, mock);\n                mockObject.object = object;\n                delete mockObject.create;\n\n                return mockObject;\n            },\n\n            expects: function expects(method) {\n                if (!method) {\n                    throw new TypeError(\"method is falsy\");\n                }\n\n                if (!this.expectations) {\n                    this.expectations = {};\n                    this.proxies = [];\n                }\n\n                if (!this.expectations[method]) {\n                    this.expectations[method] = [];\n                    var mockObject = this;\n\n                    sinon.wrapMethod(this.object, method, function () {\n                        return mockObject.invokeMethod(method, this, arguments);\n                    });\n\n                    push.call(this.proxies, method);\n                }\n\n                var expectation = sinon.expectation.create(method);\n                push.call(this.expectations[method], expectation);\n\n                return expectation;\n            },\n\n            restore: function restore() {\n                var object = this.object;\n\n                each(this.proxies, function (proxy) {\n                    if (typeof object[proxy].restore == \"function\") {\n                        object[proxy].restore();\n                    }\n                });\n            },\n\n            verify: function verify() {\n                var expectations = this.expectations || {};\n                var messages = [], met = [];\n\n                each(this.proxies, function (proxy) {\n                    each(expectations[proxy], function (expectation) {\n                        if (!expectation.met()) {\n                            push.call(messages, expectation.toString());\n                        } else {\n                            push.call(met, expectation.toString());\n                        }\n                    });\n                });\n\n                this.restore();\n\n                if (messages.length > 0) {\n                    sinon.expectation.fail(messages.concat(met).join(\"\\n\"));\n                } else {\n                    sinon.expectation.pass(messages.concat(met).join(\"\\n\"));\n                }\n\n                return true;\n            },\n\n            invokeMethod: function invokeMethod(method, thisValue, args) {\n                var expectations = this.expectations && this.expectations[method];\n                var length = expectations && expectations.length || 0, i;\n\n                for (i = 0; i < length; i += 1) {\n                    if (!expectations[i].met() &&\n                        expectations[i].allowsCall(thisValue, args)) {\n                        return expectations[i].apply(thisValue, args);\n                    }\n                }\n\n                var messages = [], available, exhausted = 0;\n\n                for (i = 0; i < length; i += 1) {\n                    if (expectations[i].allowsCall(thisValue, args)) {\n                        available = available || expectations[i];\n                    } else {\n                        exhausted += 1;\n                    }\n                    push.call(messages, \"    \" + expectations[i].toString());\n                }\n\n                if (exhausted === 0) {\n                    return available.apply(thisValue, args);\n                }\n\n                messages.unshift(\"Unexpected call: \" + sinon.spyCall.toString.call({\n                    proxy: method,\n                    args: args\n                }));\n\n                sinon.expectation.fail(messages.join(\"\\n\"));\n            }\n        };\n    }()));\n\n    var times = sinon.timesInWords;\n\n    sinon.expectation = (function () {\n        var slice = Array.prototype.slice;\n        var _invoke = sinon.spy.invoke;\n\n        function callCountInWords(callCount) {\n            if (callCount == 0) {\n                return \"never called\";\n            } else {\n                return \"called \" + times(callCount);\n            }\n        }\n\n        function expectedCallCountInWords(expectation) {\n            var min = expectation.minCalls;\n            var max = expectation.maxCalls;\n\n            if (typeof min == \"number\" && typeof max == \"number\") {\n                var str = times(min);\n\n                if (min != max) {\n                    str = \"at least \" + str + \" and at most \" + times(max);\n                }\n\n                return str;\n            }\n\n            if (typeof min == \"number\") {\n                return \"at least \" + times(min);\n            }\n\n            return \"at most \" + times(max);\n        }\n\n        function receivedMinCalls(expectation) {\n            var hasMinLimit = typeof expectation.minCalls == \"number\";\n            return !hasMinLimit || expectation.callCount >= expectation.minCalls;\n        }\n\n        function receivedMaxCalls(expectation) {\n            if (typeof expectation.maxCalls != \"number\") {\n                return false;\n            }\n\n            return expectation.callCount == expectation.maxCalls;\n        }\n\n        return {\n            minCalls: 1,\n            maxCalls: 1,\n\n            create: function create(methodName) {\n                var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);\n                delete expectation.create;\n                expectation.method = methodName;\n\n                return expectation;\n            },\n\n            invoke: function invoke(func, thisValue, args) {\n                this.verifyCallAllowed(thisValue, args);\n\n                return _invoke.apply(this, arguments);\n            },\n\n            atLeast: function atLeast(num) {\n                if (typeof num != \"number\") {\n                    throw new TypeError(\"'\" + num + \"' is not number\");\n                }\n\n                if (!this.limitsSet) {\n                    this.maxCalls = null;\n                    this.limitsSet = true;\n                }\n\n                this.minCalls = num;\n\n                return this;\n            },\n\n            atMost: function atMost(num) {\n                if (typeof num != \"number\") {\n                    throw new TypeError(\"'\" + num + \"' is not number\");\n                }\n\n                if (!this.limitsSet) {\n                    this.minCalls = null;\n                    this.limitsSet = true;\n                }\n\n                this.maxCalls = num;\n\n                return this;\n            },\n\n            never: function never() {\n                return this.exactly(0);\n            },\n\n            once: function once() {\n                return this.exactly(1);\n            },\n\n            twice: function twice() {\n                return this.exactly(2);\n            },\n\n            thrice: function thrice() {\n                return this.exactly(3);\n            },\n\n            exactly: function exactly(num) {\n                if (typeof num != \"number\") {\n                    throw new TypeError(\"'\" + num + \"' is not a number\");\n                }\n\n                this.atLeast(num);\n                return this.atMost(num);\n            },\n\n            met: function met() {\n                return !this.failed && receivedMinCalls(this);\n            },\n\n            verifyCallAllowed: function verifyCallAllowed(thisValue, args) {\n                if (receivedMaxCalls(this)) {\n                    this.failed = true;\n                    sinon.expectation.fail(this.method + \" already called \" + times(this.maxCalls));\n                }\n\n                if (\"expectedThis\" in this && this.expectedThis !== thisValue) {\n                    sinon.expectation.fail(this.method + \" called with \" + thisValue + \" as thisValue, expected \" +\n                        this.expectedThis);\n                }\n\n                if (!(\"expectedArguments\" in this)) {\n                    return;\n                }\n\n                if (!args) {\n                    sinon.expectation.fail(this.method + \" received no arguments, expected \" +\n                        sinon.format(this.expectedArguments));\n                }\n\n                if (args.length < this.expectedArguments.length) {\n                    sinon.expectation.fail(this.method + \" received too few arguments (\" + sinon.format(args) +\n                        \"), expected \" + sinon.format(this.expectedArguments));\n                }\n\n                if (this.expectsExactArgCount &&\n                    args.length != this.expectedArguments.length) {\n                    sinon.expectation.fail(this.method + \" received too many arguments (\" + sinon.format(args) +\n                        \"), expected \" + sinon.format(this.expectedArguments));\n                }\n\n                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {\n                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {\n                        sinon.expectation.fail(this.method + \" received wrong arguments \" + sinon.format(args) +\n                            \", expected \" + sinon.format(this.expectedArguments));\n                    }\n                }\n            },\n\n            allowsCall: function allowsCall(thisValue, args) {\n                if (this.met() && receivedMaxCalls(this)) {\n                    return false;\n                }\n\n                if (\"expectedThis\" in this && this.expectedThis !== thisValue) {\n                    return false;\n                }\n\n                if (!(\"expectedArguments\" in this)) {\n                    return true;\n                }\n\n                args = args || [];\n\n                if (args.length < this.expectedArguments.length) {\n                    return false;\n                }\n\n                if (this.expectsExactArgCount &&\n                    args.length != this.expectedArguments.length) {\n                    return false;\n                }\n\n                for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {\n                    if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {\n                        return false;\n                    }\n                }\n\n                return true;\n            },\n\n            withArgs: function withArgs() {\n                this.expectedArguments = slice.call(arguments);\n                return this;\n            },\n\n            withExactArgs: function withExactArgs() {\n                this.withArgs.apply(this, arguments);\n                this.expectsExactArgCount = true;\n                return this;\n            },\n\n            on: function on(thisValue) {\n                this.expectedThis = thisValue;\n                return this;\n            },\n\n            toString: function () {\n                var args = (this.expectedArguments || []).slice();\n\n                if (!this.expectsExactArgCount) {\n                    push.call(args, \"[...]\");\n                }\n\n                var callStr = sinon.spyCall.toString.call({\n                    proxy: this.method || \"anonymous mock expectation\",\n                    args: args\n                });\n\n                var message = callStr.replace(\", [...\", \"[, ...\") + \" \" +\n                    expectedCallCountInWords(this);\n\n                if (this.met()) {\n                    return \"Expectation met: \" + message;\n                }\n\n                return \"Expected \" + message + \" (\" +\n                    callCountInWords(this.callCount) + \")\";\n            },\n\n            verify: function verify() {\n                if (!this.met()) {\n                    sinon.expectation.fail(this.toString());\n                } else {\n                    sinon.expectation.pass(this.toString());\n                }\n\n                return true;\n            },\n\n            pass: function(message) {\n              sinon.assert.pass(message);\n            },\n            fail: function (message) {\n                var exception = new Error(message);\n                exception.name = \"ExpectationError\";\n\n                throw exception;\n            }\n        };\n    }());\n\n    if (commonJSModule) {\n        module.exports = mock;\n    } else {\n        sinon.mock = mock;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n * @depend ../sinon.js\n * @depend stub.js\n * @depend mock.js\n */\n/*jslint eqeqeq: false, onevar: false, forin: true*/\n/*global module, require, sinon*/\n/**\n * Collections of stubs, spies and mocks.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n    var push = [].push;\n    var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function getFakes(fakeCollection) {\n        if (!fakeCollection.fakes) {\n            fakeCollection.fakes = [];\n        }\n\n        return fakeCollection.fakes;\n    }\n\n    function each(fakeCollection, method) {\n        var fakes = getFakes(fakeCollection);\n\n        for (var i = 0, l = fakes.length; i < l; i += 1) {\n            if (typeof fakes[i][method] == \"function\") {\n                fakes[i][method]();\n            }\n        }\n    }\n\n    function compact(fakeCollection) {\n        var fakes = getFakes(fakeCollection);\n        var i = 0;\n        while (i < fakes.length) {\n          fakes.splice(i, 1);\n        }\n    }\n\n    var collection = {\n        verify: function resolve() {\n            each(this, \"verify\");\n        },\n\n        restore: function restore() {\n            each(this, \"restore\");\n            compact(this);\n        },\n\n        verifyAndRestore: function verifyAndRestore() {\n            var exception;\n\n            try {\n                this.verify();\n            } catch (e) {\n                exception = e;\n            }\n\n            this.restore();\n\n            if (exception) {\n                throw exception;\n            }\n        },\n\n        add: function add(fake) {\n            push.call(getFakes(this), fake);\n            return fake;\n        },\n\n        spy: function spy() {\n            return this.add(sinon.spy.apply(sinon, arguments));\n        },\n\n        stub: function stub(object, property, value) {\n            if (property) {\n                var original = object[property];\n\n                if (typeof original != \"function\") {\n                    if (!hasOwnProperty.call(object, property)) {\n                        throw new TypeError(\"Cannot stub non-existent own property \" + property);\n                    }\n\n                    object[property] = value;\n\n                    return this.add({\n                        restore: function () {\n                            object[property] = original;\n                        }\n                    });\n                }\n            }\n            if (!property && !!object && typeof object == \"object\") {\n                var stubbedObj = sinon.stub.apply(sinon, arguments);\n\n                for (var prop in stubbedObj) {\n                    if (typeof stubbedObj[prop] === \"function\") {\n                        this.add(stubbedObj[prop]);\n                    }\n                }\n\n                return stubbedObj;\n            }\n\n            return this.add(sinon.stub.apply(sinon, arguments));\n        },\n\n        mock: function mock() {\n            return this.add(sinon.mock.apply(sinon, arguments));\n        },\n\n        inject: function inject(obj) {\n            var col = this;\n\n            obj.spy = function () {\n                return col.spy.apply(col, arguments);\n            };\n\n            obj.stub = function () {\n                return col.stub.apply(col, arguments);\n            };\n\n            obj.mock = function () {\n                return col.mock.apply(col, arguments);\n            };\n\n            return obj;\n        }\n    };\n\n    if (commonJSModule) {\n        module.exports = collection;\n    } else {\n        sinon.collection = collection;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/\n/*global module, require, window*/\n/**\n * Fake timer API\n * setTimeout\n * setInterval\n * clearTimeout\n * clearInterval\n * tick\n * reset\n * Date\n *\n * Inspired by jsUnitMockTimeOut from JsUnit\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\nif (typeof sinon == \"undefined\") {\n    var sinon = {};\n}\n\n(function (global) {\n    var id = 1;\n\n    function addTimer(args, recurring) {\n        if (args.length === 0) {\n            throw new Error(\"Function requires at least 1 parameter\");\n        }\n\n        var toId = id++;\n        var delay = args[1] || 0;\n\n        if (!this.timeouts) {\n            this.timeouts = {};\n        }\n\n        this.timeouts[toId] = {\n            id: toId,\n            func: args[0],\n            callAt: this.now + delay,\n            invokeArgs: Array.prototype.slice.call(args, 2)\n        };\n\n        if (recurring === true) {\n            this.timeouts[toId].interval = delay;\n        }\n\n        return toId;\n    }\n\n    function parseTime(str) {\n        if (!str) {\n            return 0;\n        }\n\n        var strings = str.split(\":\");\n        var l = strings.length, i = l;\n        var ms = 0, parsed;\n\n        if (l > 3 || !/^(\\d\\d:){0,2}\\d\\d?$/.test(str)) {\n            throw new Error(\"tick only understands numbers and 'h:m:s'\");\n        }\n\n        while (i--) {\n            parsed = parseInt(strings[i], 10);\n\n            if (parsed >= 60) {\n                throw new Error(\"Invalid time \" + str);\n            }\n\n            ms += parsed * Math.pow(60, (l - i - 1));\n        }\n\n        return ms * 1000;\n    }\n\n    function createObject(object) {\n        var newObject;\n\n        if (Object.create) {\n            newObject = Object.create(object);\n        } else {\n            var F = function () {};\n            F.prototype = object;\n            newObject = new F();\n        }\n\n        newObject.Date.clock = newObject;\n        return newObject;\n    }\n\n    sinon.clock = {\n        now: 0,\n\n        create: function create(now) {\n            var clock = createObject(this);\n\n            if (typeof now == \"number\") {\n                clock.now = now;\n            }\n\n            if (!!now && typeof now == \"object\") {\n                throw new TypeError(\"now should be milliseconds since UNIX epoch\");\n            }\n\n            return clock;\n        },\n\n        setTimeout: function setTimeout(callback, timeout) {\n            return addTimer.call(this, arguments, false);\n        },\n\n        clearTimeout: function clearTimeout(timerId) {\n            if (!this.timeouts) {\n                this.timeouts = [];\n            }\n\n            if (timerId in this.timeouts) {\n                delete this.timeouts[timerId];\n            }\n        },\n\n        setInterval: function setInterval(callback, timeout) {\n            return addTimer.call(this, arguments, true);\n        },\n\n        clearInterval: function clearInterval(timerId) {\n            this.clearTimeout(timerId);\n        },\n\n        tick: function tick(ms) {\n            ms = typeof ms == \"number\" ? ms : parseTime(ms);\n            var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;\n            var timer = this.firstTimerInRange(tickFrom, tickTo);\n\n            var firstException;\n            while (timer && tickFrom <= tickTo) {\n                if (this.timeouts[timer.id]) {\n                    tickFrom = this.now = timer.callAt;\n                    try {\n                      this.callTimer(timer);\n                    } catch (e) {\n                      firstException = firstException || e;\n                    }\n                }\n\n                timer = this.firstTimerInRange(previous, tickTo);\n                previous = tickFrom;\n            }\n\n            this.now = tickTo;\n\n            if (firstException) {\n              throw firstException;\n            }\n\n            return this.now;\n        },\n\n        firstTimerInRange: function (from, to) {\n            var timer, smallest, originalTimer;\n\n            for (var id in this.timeouts) {\n                if (this.timeouts.hasOwnProperty(id)) {\n                    if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {\n                        continue;\n                    }\n\n                    if (!smallest || this.timeouts[id].callAt < smallest) {\n                        originalTimer = this.timeouts[id];\n                        smallest = this.timeouts[id].callAt;\n\n                        timer = {\n                            func: this.timeouts[id].func,\n                            callAt: this.timeouts[id].callAt,\n                            interval: this.timeouts[id].interval,\n                            id: this.timeouts[id].id,\n                            invokeArgs: this.timeouts[id].invokeArgs\n                        };\n                    }\n                }\n            }\n\n            return timer || null;\n        },\n\n        callTimer: function (timer) {\n            if (typeof timer.interval == \"number\") {\n                this.timeouts[timer.id].callAt += timer.interval;\n            } else {\n                delete this.timeouts[timer.id];\n            }\n\n            try {\n                if (typeof timer.func == \"function\") {\n                    timer.func.apply(null, timer.invokeArgs);\n                } else {\n                    eval(timer.func);\n                }\n            } catch (e) {\n              var exception = e;\n            }\n\n            if (!this.timeouts[timer.id]) {\n                if (exception) {\n                  throw exception;\n                }\n                return;\n            }\n\n            if (exception) {\n              throw exception;\n            }\n        },\n\n        reset: function reset() {\n            this.timeouts = {};\n        },\n\n        Date: (function () {\n            var NativeDate = Date;\n\n            function ClockDate(year, month, date, hour, minute, second, ms) {\n                // Defensive and verbose to avoid potential harm in passing\n                // explicit undefined when user does not pass argument\n                switch (arguments.length) {\n                case 0:\n                    return new NativeDate(ClockDate.clock.now);\n                case 1:\n                    return new NativeDate(year);\n                case 2:\n                    return new NativeDate(year, month);\n                case 3:\n                    return new NativeDate(year, month, date);\n                case 4:\n                    return new NativeDate(year, month, date, hour);\n                case 5:\n                    return new NativeDate(year, month, date, hour, minute);\n                case 6:\n                    return new NativeDate(year, month, date, hour, minute, second);\n                default:\n                    return new NativeDate(year, month, date, hour, minute, second, ms);\n                }\n            }\n\n            return mirrorDateProperties(ClockDate, NativeDate);\n        }())\n    };\n\n    function mirrorDateProperties(target, source) {\n        if (source.now) {\n            target.now = function now() {\n                return target.clock.now;\n            };\n        } else {\n            delete target.now;\n        }\n\n        if (source.toSource) {\n            target.toSource = function toSource() {\n                return source.toSource();\n            };\n        } else {\n            delete target.toSource;\n        }\n\n        target.toString = function toString() {\n            return source.toString();\n        };\n\n        target.prototype = source.prototype;\n        target.parse = source.parse;\n        target.UTC = source.UTC;\n        target.prototype.toUTCString = source.prototype.toUTCString;\n        return target;\n    }\n\n    var methods = [\"Date\", \"setTimeout\", \"setInterval\",\n                   \"clearTimeout\", \"clearInterval\"];\n\n    function restore() {\n        var method;\n\n        for (var i = 0, l = this.methods.length; i < l; i++) {\n            method = this.methods[i];\n            if (global[method].hadOwnProperty) {\n                global[method] = this[\"_\" + method];\n            } else {\n                delete global[method];\n            }\n        }\n\n        // Prevent multiple executions which will completely remove these props\n        this.methods = [];\n    }\n\n    function stubGlobal(method, clock) {\n        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);\n        clock[\"_\" + method] = global[method];\n\n        if (method == \"Date\") {\n            var date = mirrorDateProperties(clock[method], global[method]);\n            global[method] = date;\n        } else {\n            global[method] = function () {\n                return clock[method].apply(clock, arguments);\n            };\n\n            for (var prop in clock[method]) {\n                if (clock[method].hasOwnProperty(prop)) {\n                    global[method][prop] = clock[method][prop];\n                }\n            }\n        }\n\n        global[method].clock = clock;\n    }\n\n    sinon.useFakeTimers = function useFakeTimers(now) {\n        var clock = sinon.clock.create(now);\n        clock.restore = restore;\n        clock.methods = Array.prototype.slice.call(arguments,\n                                                   typeof now == \"number\" ? 1 : 0);\n\n        if (clock.methods.length === 0) {\n            clock.methods = methods;\n        }\n\n        for (var i = 0, l = clock.methods.length; i < l; i++) {\n            stubGlobal(clock.methods[i], clock);\n        }\n\n        return clock;\n    };\n}(typeof global != \"undefined\" && typeof global !== \"function\" ? global : this));\n\nsinon.timers = {\n    setTimeout: setTimeout,\n    clearTimeout: clearTimeout,\n    setInterval: setInterval,\n    clearInterval: clearInterval,\n    Date: Date\n};\n\nif (typeof module == \"object\" && typeof require == \"function\") {\n    module.exports = sinon;\n}\n\n/*jslint eqeqeq: false, onevar: false*/\n/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/\n/**\n * Minimal Event interface implementation\n *\n * Original implementation by Sven Fuchs: https://gist.github.com/995028\n * Modifications and tests by Christian Johansen.\n *\n * @author Sven Fuchs (svenfuchs@artweb-design.de)\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2011 Sven Fuchs, Christian Johansen\n */\n\nif (typeof sinon == \"undefined\") {\n    this.sinon = {};\n}\n\n(function () {\n    var push = [].push;\n\n    sinon.Event = function Event(type, bubbles, cancelable, target) {\n        this.initEvent(type, bubbles, cancelable, target);\n    };\n\n    sinon.Event.prototype = {\n        initEvent: function(type, bubbles, cancelable, target) {\n            this.type = type;\n            this.bubbles = bubbles;\n            this.cancelable = cancelable;\n            this.target = target;\n        },\n\n        stopPropagation: function () {},\n\n        preventDefault: function () {\n            this.defaultPrevented = true;\n        }\n    };\n\n    sinon.EventTarget = {\n        addEventListener: function addEventListener(event, listener, useCapture) {\n            this.eventListeners = this.eventListeners || {};\n            this.eventListeners[event] = this.eventListeners[event] || [];\n            push.call(this.eventListeners[event], listener);\n        },\n\n        removeEventListener: function removeEventListener(event, listener, useCapture) {\n            var listeners = this.eventListeners && this.eventListeners[event] || [];\n\n            for (var i = 0, l = listeners.length; i < l; ++i) {\n                if (listeners[i] == listener) {\n                    return listeners.splice(i, 1);\n                }\n            }\n        },\n\n        dispatchEvent: function dispatchEvent(event) {\n            var type = event.type;\n            var listeners = this.eventListeners && this.eventListeners[type] || [];\n\n            for (var i = 0; i < listeners.length; i++) {\n                if (typeof listeners[i] == \"function\") {\n                    listeners[i].call(this, event);\n                } else {\n                    listeners[i].handleEvent(event);\n                }\n            }\n\n            return !!event.defaultPrevented;\n        }\n    };\n}());\n\n/**\n * @depend ../../sinon.js\n * @depend event.js\n */\n/*jslint eqeqeq: false, onevar: false*/\n/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/\n/**\n * Fake XMLHttpRequest object\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\nif (typeof sinon == \"undefined\") {\n    this.sinon = {};\n}\nsinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };\n\n// wrapper for global\n(function(global) {\n    var xhr = sinon.xhr;\n    xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;\n    xhr.GlobalActiveXObject = global.ActiveXObject;\n    xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != \"undefined\";\n    xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != \"undefined\";\n    xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX\n                                     ? function() { return new xhr.GlobalActiveXObject(\"MSXML2.XMLHTTP.3.0\") } : false;\n\n    /*jsl:ignore*/\n    var unsafeHeaders = {\n        \"Accept-Charset\": true,\n        \"Accept-Encoding\": true,\n        \"Connection\": true,\n        \"Content-Length\": true,\n        \"Cookie\": true,\n        \"Cookie2\": true,\n        \"Content-Transfer-Encoding\": true,\n        \"Date\": true,\n        \"Expect\": true,\n        \"Host\": true,\n        \"Keep-Alive\": true,\n        \"Referer\": true,\n        \"TE\": true,\n        \"Trailer\": true,\n        \"Transfer-Encoding\": true,\n        \"Upgrade\": true,\n        \"User-Agent\": true,\n        \"Via\": true\n    };\n    /*jsl:end*/\n\n    function FakeXMLHttpRequest() {\n        this.readyState = FakeXMLHttpRequest.UNSENT;\n        this.requestHeaders = {};\n        this.requestBody = null;\n        this.status = 0;\n        this.statusText = \"\";\n\n        var xhr = this;\n\n        [\"loadstart\", \"load\", \"abort\", \"loadend\"].forEach(function (eventName) {\n            xhr.addEventListener(eventName, function (event) {\n                var listener = xhr[\"on\" + eventName];\n\n                if (listener && typeof listener == \"function\") {\n                    listener(event);\n                }\n            });\n        });\n\n        if (typeof FakeXMLHttpRequest.onCreate == \"function\") {\n            FakeXMLHttpRequest.onCreate(this);\n        }\n    }\n\n    function verifyState(xhr) {\n        if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {\n            throw new Error(\"INVALID_STATE_ERR\");\n        }\n\n        if (xhr.sendFlag) {\n            throw new Error(\"INVALID_STATE_ERR\");\n        }\n    }\n\n    // filtering to enable a white-list version of Sinon FakeXhr,\n    // where whitelisted requests are passed through to real XHR\n    function each(collection, callback) {\n        if (!collection) return;\n        for (var i = 0, l = collection.length; i < l; i += 1) {\n            callback(collection[i]);\n        }\n    }\n    function some(collection, callback) {\n        for (var index = 0; index < collection.length; index++) {\n            if(callback(collection[index]) === true) return true;\n        };\n        return false;\n    }\n    // largest arity in XHR is 5 - XHR#open\n    var apply = function(obj,method,args) {\n        switch(args.length) {\n        case 0: return obj[method]();\n        case 1: return obj[method](args[0]);\n        case 2: return obj[method](args[0],args[1]);\n        case 3: return obj[method](args[0],args[1],args[2]);\n        case 4: return obj[method](args[0],args[1],args[2],args[3]);\n        case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);\n        };\n    };\n\n    FakeXMLHttpRequest.filters = [];\n    FakeXMLHttpRequest.addFilter = function(fn) {\n        this.filters.push(fn)\n    };\n    var IE6Re = /MSIE 6/;\n    FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {\n        var xhr = new sinon.xhr.workingXHR();\n        each([\"open\",\"setRequestHeader\",\"send\",\"abort\",\"getResponseHeader\",\n              \"getAllResponseHeaders\",\"addEventListener\",\"overrideMimeType\",\"removeEventListener\"],\n             function(method) {\n                 fakeXhr[method] = function() {\n                   return apply(xhr,method,arguments);\n                 };\n             });\n\n        var copyAttrs = function(args) {\n            each(args, function(attr) {\n              try {\n                fakeXhr[attr] = xhr[attr]\n              } catch(e) {\n                if(!IE6Re.test(navigator.userAgent)) throw e;\n              }\n            });\n        };\n\n        var stateChange = function() {\n            fakeXhr.readyState = xhr.readyState;\n            if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {\n                copyAttrs([\"status\",\"statusText\"]);\n            }\n            if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {\n                copyAttrs([\"responseText\"]);\n            }\n            if(xhr.readyState === FakeXMLHttpRequest.DONE) {\n                copyAttrs([\"responseXML\"]);\n            }\n            if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);\n        };\n        if(xhr.addEventListener) {\n          for(var event in fakeXhr.eventListeners) {\n              if(fakeXhr.eventListeners.hasOwnProperty(event)) {\n                  each(fakeXhr.eventListeners[event],function(handler) {\n                      xhr.addEventListener(event, handler);\n                  });\n              }\n          }\n          xhr.addEventListener(\"readystatechange\",stateChange);\n        } else {\n          xhr.onreadystatechange = stateChange;\n        }\n        apply(xhr,\"open\",xhrArgs);\n    };\n    FakeXMLHttpRequest.useFilters = false;\n\n    function verifyRequestSent(xhr) {\n        if (xhr.readyState == FakeXMLHttpRequest.DONE) {\n            throw new Error(\"Request done\");\n        }\n    }\n\n    function verifyHeadersReceived(xhr) {\n        if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {\n            throw new Error(\"No headers received\");\n        }\n    }\n\n    function verifyResponseBodyType(body) {\n        if (typeof body != \"string\") {\n            var error = new Error(\"Attempted to respond to fake XMLHttpRequest with \" +\n                                 body + \", which is not a string.\");\n            error.name = \"InvalidBodyException\";\n            throw error;\n        }\n    }\n\n    sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {\n        async: true,\n\n        open: function open(method, url, async, username, password) {\n            this.method = method;\n            this.url = url;\n            this.async = typeof async == \"boolean\" ? async : true;\n            this.username = username;\n            this.password = password;\n            this.responseText = null;\n            this.responseXML = null;\n            this.requestHeaders = {};\n            this.sendFlag = false;\n            if(sinon.FakeXMLHttpRequest.useFilters === true) {\n                var xhrArgs = arguments;\n                var defake = some(FakeXMLHttpRequest.filters,function(filter) {\n                    return filter.apply(this,xhrArgs)\n                });\n                if (defake) {\n                  return sinon.FakeXMLHttpRequest.defake(this,arguments);\n                }\n            }\n            this.readyStateChange(FakeXMLHttpRequest.OPENED);\n        },\n\n        readyStateChange: function readyStateChange(state) {\n            this.readyState = state;\n\n            if (typeof this.onreadystatechange == \"function\") {\n                try {\n                    this.onreadystatechange();\n                } catch (e) {\n                    sinon.logError(\"Fake XHR onreadystatechange handler\", e);\n                }\n            }\n\n            this.dispatchEvent(new sinon.Event(\"readystatechange\"));\n\n            switch (this.readyState) {\n                case FakeXMLHttpRequest.DONE:\n                    this.dispatchEvent(new sinon.Event(\"load\", false, false, this));\n                    this.dispatchEvent(new sinon.Event(\"loadend\", false, false, this));\n                    break;\n            }\n        },\n\n        setRequestHeader: function setRequestHeader(header, value) {\n            verifyState(this);\n\n            if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {\n                throw new Error(\"Refused to set unsafe header \\\"\" + header + \"\\\"\");\n            }\n\n            if (this.requestHeaders[header]) {\n                this.requestHeaders[header] += \",\" + value;\n            } else {\n                this.requestHeaders[header] = value;\n            }\n        },\n\n        // Helps testing\n        setResponseHeaders: function setResponseHeaders(headers) {\n            this.responseHeaders = {};\n\n            for (var header in headers) {\n                if (headers.hasOwnProperty(header)) {\n                    this.responseHeaders[header] = headers[header];\n                }\n            }\n\n            if (this.async) {\n                this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);\n            } else {\n                this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;\n            }\n        },\n\n        // Currently treats ALL data as a DOMString (i.e. no Document)\n        send: function send(data) {\n            verifyState(this);\n\n            if (!/^(get|head)$/i.test(this.method)) {\n                if (this.requestHeaders[\"Content-Type\"]) {\n                    var value = this.requestHeaders[\"Content-Type\"].split(\";\");\n                    this.requestHeaders[\"Content-Type\"] = value[0] + \";charset=utf-8\";\n                } else {\n                    this.requestHeaders[\"Content-Type\"] = \"text/plain;charset=utf-8\";\n                }\n\n                this.requestBody = data;\n            }\n\n            this.errorFlag = false;\n            this.sendFlag = this.async;\n            this.readyStateChange(FakeXMLHttpRequest.OPENED);\n\n            if (typeof this.onSend == \"function\") {\n                this.onSend(this);\n            }\n\n            this.dispatchEvent(new sinon.Event(\"loadstart\", false, false, this));\n        },\n\n        abort: function abort() {\n            this.aborted = true;\n            this.responseText = null;\n            this.errorFlag = true;\n            this.requestHeaders = {};\n\n            if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {\n                this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);\n                this.sendFlag = false;\n            }\n\n            this.readyState = sinon.FakeXMLHttpRequest.UNSENT;\n\n            this.dispatchEvent(new sinon.Event(\"abort\", false, false, this));\n            if (typeof this.onerror === \"function\") {\n                this.onerror();\n            }\n        },\n\n        getResponseHeader: function getResponseHeader(header) {\n            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {\n                return null;\n            }\n\n            if (/^Set-Cookie2?$/i.test(header)) {\n                return null;\n            }\n\n            header = header.toLowerCase();\n\n            for (var h in this.responseHeaders) {\n                if (h.toLowerCase() == header) {\n                    return this.responseHeaders[h];\n                }\n            }\n\n            return null;\n        },\n\n        getAllResponseHeaders: function getAllResponseHeaders() {\n            if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {\n                return \"\";\n            }\n\n            var headers = \"\";\n\n            for (var header in this.responseHeaders) {\n                if (this.responseHeaders.hasOwnProperty(header) &&\n                    !/^Set-Cookie2?$/i.test(header)) {\n                    headers += header + \": \" + this.responseHeaders[header] + \"\\r\\n\";\n                }\n            }\n\n            return headers;\n        },\n\n        setResponseBody: function setResponseBody(body) {\n            verifyRequestSent(this);\n            verifyHeadersReceived(this);\n            verifyResponseBodyType(body);\n\n            var chunkSize = this.chunkSize || 10;\n            var index = 0;\n            this.responseText = \"\";\n\n            do {\n                if (this.async) {\n                    this.readyStateChange(FakeXMLHttpRequest.LOADING);\n                }\n\n                this.responseText += body.substring(index, index + chunkSize);\n                index += chunkSize;\n            } while (index < body.length);\n\n            var type = this.getResponseHeader(\"Content-Type\");\n\n            if (this.responseText &&\n                (!type || /(text\\/xml)|(application\\/xml)|(\\+xml)/.test(type))) {\n                try {\n                    this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);\n                } catch (e) {\n                    // Unable to parse XML - no biggie\n                }\n            }\n\n            if (this.async) {\n                this.readyStateChange(FakeXMLHttpRequest.DONE);\n            } else {\n                this.readyState = FakeXMLHttpRequest.DONE;\n            }\n        },\n\n        respond: function respond(status, headers, body) {\n            this.setResponseHeaders(headers || {});\n            this.status = typeof status == \"number\" ? status : 200;\n            this.statusText = FakeXMLHttpRequest.statusCodes[this.status];\n            this.setResponseBody(body || \"\");\n            if (typeof this.onload === \"function\"){\n                this.onload();\n            }\n            \n        }\n    });\n\n    sinon.extend(FakeXMLHttpRequest, {\n        UNSENT: 0,\n        OPENED: 1,\n        HEADERS_RECEIVED: 2,\n        LOADING: 3,\n        DONE: 4\n    });\n\n    // Borrowed from JSpec\n    FakeXMLHttpRequest.parseXML = function parseXML(text) {\n        var xmlDoc;\n\n        if (typeof DOMParser != \"undefined\") {\n            var parser = new DOMParser();\n            xmlDoc = parser.parseFromString(text, \"text/xml\");\n        } else {\n            xmlDoc = new ActiveXObject(\"Microsoft.XMLDOM\");\n            xmlDoc.async = \"false\";\n            xmlDoc.loadXML(text);\n        }\n\n        return xmlDoc;\n    };\n\n    FakeXMLHttpRequest.statusCodes = {\n        100: \"Continue\",\n        101: \"Switching Protocols\",\n        200: \"OK\",\n        201: \"Created\",\n        202: \"Accepted\",\n        203: \"Non-Authoritative Information\",\n        204: \"No Content\",\n        205: \"Reset Content\",\n        206: \"Partial Content\",\n        300: \"Multiple Choice\",\n        301: \"Moved Permanently\",\n        302: \"Found\",\n        303: \"See Other\",\n        304: \"Not Modified\",\n        305: \"Use Proxy\",\n        307: \"Temporary Redirect\",\n        400: \"Bad Request\",\n        401: \"Unauthorized\",\n        402: \"Payment Required\",\n        403: \"Forbidden\",\n        404: \"Not Found\",\n        405: \"Method Not Allowed\",\n        406: \"Not Acceptable\",\n        407: \"Proxy Authentication Required\",\n        408: \"Request Timeout\",\n        409: \"Conflict\",\n        410: \"Gone\",\n        411: \"Length Required\",\n        412: \"Precondition Failed\",\n        413: \"Request Entity Too Large\",\n        414: \"Request-URI Too Long\",\n        415: \"Unsupported Media Type\",\n        416: \"Requested Range Not Satisfiable\",\n        417: \"Expectation Failed\",\n        422: \"Unprocessable Entity\",\n        500: \"Internal Server Error\",\n        501: \"Not Implemented\",\n        502: \"Bad Gateway\",\n        503: \"Service Unavailable\",\n        504: \"Gateway Timeout\",\n        505: \"HTTP Version Not Supported\"\n    };\n\n    sinon.useFakeXMLHttpRequest = function () {\n        sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {\n            if (xhr.supportsXHR) {\n                global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;\n            }\n\n            if (xhr.supportsActiveX) {\n                global.ActiveXObject = xhr.GlobalActiveXObject;\n            }\n\n            delete sinon.FakeXMLHttpRequest.restore;\n\n            if (keepOnCreate !== true) {\n                delete sinon.FakeXMLHttpRequest.onCreate;\n            }\n        };\n        if (xhr.supportsXHR) {\n            global.XMLHttpRequest = sinon.FakeXMLHttpRequest;\n        }\n\n        if (xhr.supportsActiveX) {\n            global.ActiveXObject = function ActiveXObject(objId) {\n                if (objId == \"Microsoft.XMLHTTP\" || /^Msxml2\\.XMLHTTP/i.test(objId)) {\n\n                    return new sinon.FakeXMLHttpRequest();\n                }\n\n                return new xhr.GlobalActiveXObject(objId);\n            };\n        }\n\n        return sinon.FakeXMLHttpRequest;\n    };\n\n    sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;\n})(this);\n\nif (typeof module == \"object\" && typeof require == \"function\") {\n    module.exports = sinon;\n}\n\n/**\n * @depend fake_xml_http_request.js\n */\n/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/\n/*global module, require, window*/\n/**\n * The Sinon \"server\" mimics a web server that receives requests from\n * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,\n * both synchronously and asynchronously. To respond synchronuously, canned\n * answers have to be provided upfront.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\nif (typeof sinon == \"undefined\") {\n    var sinon = {};\n}\n\nsinon.fakeServer = (function () {\n    var push = [].push;\n    function F() {}\n\n    function create(proto) {\n        F.prototype = proto;\n        return new F();\n    }\n\n    function responseArray(handler) {\n        var response = handler;\n\n        if (Object.prototype.toString.call(handler) != \"[object Array]\") {\n            response = [200, {}, handler];\n        }\n\n        if (typeof response[2] != \"string\") {\n            throw new TypeError(\"Fake server response body should be string, but was \" +\n                                typeof response[2]);\n        }\n\n        return response;\n    }\n\n    var wloc = typeof window !== \"undefined\" ? window.location : {};\n    var rCurrLoc = new RegExp(\"^\" + wloc.protocol + \"//\" + wloc.host);\n\n    function matchOne(response, reqMethod, reqUrl) {\n        var rmeth = response.method;\n        var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();\n        var url = response.url;\n        var matchUrl = !url || url == reqUrl || (typeof url.test == \"function\" && url.test(reqUrl));\n\n        return matchMethod && matchUrl;\n    }\n\n    function match(response, request) {\n        var requestMethod = this.getHTTPMethod(request);\n        var requestUrl = request.url;\n\n        if (!/^https?:\\/\\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {\n            requestUrl = requestUrl.replace(rCurrLoc, \"\");\n        }\n\n        if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {\n            if (typeof response.response == \"function\") {\n                var ru = response.url;\n                var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));\n                return response.response.apply(response, args);\n            }\n\n            return true;\n        }\n\n        return false;\n    }\n\n    function log(response, request) {\n        var str;\n\n        str =  \"Request:\\n\"  + sinon.format(request)  + \"\\n\\n\";\n        str += \"Response:\\n\" + sinon.format(response) + \"\\n\\n\";\n\n        sinon.log(str);\n    }\n\n    return {\n        create: function () {\n            var server = create(this);\n            this.xhr = sinon.useFakeXMLHttpRequest();\n            server.requests = [];\n\n            this.xhr.onCreate = function (xhrObj) {\n                server.addRequest(xhrObj);\n            };\n\n            return server;\n        },\n\n        addRequest: function addRequest(xhrObj) {\n            var server = this;\n            push.call(this.requests, xhrObj);\n\n            xhrObj.onSend = function () {\n                server.handleRequest(this);\n            };\n\n            if (this.autoRespond && !this.responding) {\n                setTimeout(function () {\n                    server.responding = false;\n                    server.respond();\n                }, this.autoRespondAfter || 10);\n\n                this.responding = true;\n            }\n        },\n\n        getHTTPMethod: function getHTTPMethod(request) {\n            if (this.fakeHTTPMethods && /post/i.test(request.method)) {\n                var matches = (request.requestBody || \"\").match(/_method=([^\\b;]+)/);\n                return !!matches ? matches[1] : request.method;\n            }\n\n            return request.method;\n        },\n\n        handleRequest: function handleRequest(xhr) {\n            if (xhr.async) {\n                if (!this.queue) {\n                    this.queue = [];\n                }\n\n                push.call(this.queue, xhr);\n            } else {\n                this.processRequest(xhr);\n            }\n        },\n\n        respondWith: function respondWith(method, url, body) {\n            if (arguments.length == 1 && typeof method != \"function\") {\n                this.response = responseArray(method);\n                return;\n            }\n\n            if (!this.responses) { this.responses = []; }\n\n            if (arguments.length == 1) {\n                body = method;\n                url = method = null;\n            }\n\n            if (arguments.length == 2) {\n                body = url;\n                url = method;\n                method = null;\n            }\n\n            push.call(this.responses, {\n                method: method,\n                url: url,\n                response: typeof body == \"function\" ? body : responseArray(body)\n            });\n        },\n\n        respond: function respond() {\n            if (arguments.length > 0) this.respondWith.apply(this, arguments);\n            var queue = this.queue || [];\n            var request;\n\n            while(request = queue.shift()) {\n                this.processRequest(request);\n            }\n        },\n\n        processRequest: function processRequest(request) {\n            try {\n                if (request.aborted) {\n                    return;\n                }\n\n                var response = this.response || [404, {}, \"\"];\n\n                if (this.responses) {\n                    for (var i = 0, l = this.responses.length; i < l; i++) {\n                        if (match.call(this, this.responses[i], request)) {\n                            response = this.responses[i].response;\n                            break;\n                        }\n                    }\n                }\n\n                if (request.readyState != 4) {\n                    log(response, request);\n\n                    request.respond(response[0], response[1], response[2]);\n                }\n            } catch (e) {\n                sinon.logError(\"Fake server request processing\", e);\n            }\n        },\n\n        restore: function restore() {\n            return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);\n        }\n    };\n}());\n\nif (typeof module == \"object\" && typeof require == \"function\") {\n    module.exports = sinon;\n}\n\n/**\n * @depend fake_server.js\n * @depend fake_timers.js\n */\n/*jslint browser: true, eqeqeq: false, onevar: false*/\n/*global sinon*/\n/**\n * Add-on for sinon.fakeServer that automatically handles a fake timer along with\n * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery\n * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,\n * it polls the object for completion with setInterval. Dispite the direct\n * motivation, there is nothing jQuery-specific in this file, so it can be used\n * in any environment where the ajax implementation depends on setInterval or\n * setTimeout.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function () {\n    function Server() {}\n    Server.prototype = sinon.fakeServer;\n\n    sinon.fakeServerWithClock = new Server();\n\n    sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {\n        if (xhr.async) {\n            if (typeof setTimeout.clock == \"object\") {\n                this.clock = setTimeout.clock;\n            } else {\n                this.clock = sinon.useFakeTimers();\n                this.resetClock = true;\n            }\n\n            if (!this.longestTimeout) {\n                var clockSetTimeout = this.clock.setTimeout;\n                var clockSetInterval = this.clock.setInterval;\n                var server = this;\n\n                this.clock.setTimeout = function (fn, timeout) {\n                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);\n\n                    return clockSetTimeout.apply(this, arguments);\n                };\n\n                this.clock.setInterval = function (fn, timeout) {\n                    server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);\n\n                    return clockSetInterval.apply(this, arguments);\n                };\n            }\n        }\n\n        return sinon.fakeServer.addRequest.call(this, xhr);\n    };\n\n    sinon.fakeServerWithClock.respond = function respond() {\n        var returnVal = sinon.fakeServer.respond.apply(this, arguments);\n\n        if (this.clock) {\n            this.clock.tick(this.longestTimeout || 0);\n            this.longestTimeout = 0;\n\n            if (this.resetClock) {\n                this.clock.restore();\n                this.resetClock = false;\n            }\n        }\n\n        return returnVal;\n    };\n\n    sinon.fakeServerWithClock.restore = function restore() {\n        if (this.clock) {\n            this.clock.restore();\n        }\n\n        return sinon.fakeServer.restore.apply(this, arguments);\n    };\n}());\n\n/**\n * @depend ../sinon.js\n * @depend collection.js\n * @depend util/fake_timers.js\n * @depend util/fake_server_with_clock.js\n */\n/*jslint eqeqeq: false, onevar: false, plusplus: false*/\n/*global require, module*/\n/**\n * Manages fake collections as well as fake utilities such as Sinon's\n * timers and fake XHR implementation in one convenient object.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\nif (typeof module == \"object\" && typeof require == \"function\") {\n    var sinon = require(\"../sinon\");\n    sinon.extend(sinon, require(\"./util/fake_timers\"));\n}\n\n(function () {\n    var push = [].push;\n\n    function exposeValue(sandbox, config, key, value) {\n        if (!value) {\n            return;\n        }\n\n        if (config.injectInto) {\n            config.injectInto[key] = value;\n        } else {\n            push.call(sandbox.args, value);\n        }\n    }\n\n    function prepareSandboxFromConfig(config) {\n        var sandbox = sinon.create(sinon.sandbox);\n\n        if (config.useFakeServer) {\n            if (typeof config.useFakeServer == \"object\") {\n                sandbox.serverPrototype = config.useFakeServer;\n            }\n\n            sandbox.useFakeServer();\n        }\n\n        if (config.useFakeTimers) {\n            if (typeof config.useFakeTimers == \"object\") {\n                sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);\n            } else {\n                sandbox.useFakeTimers();\n            }\n        }\n\n        return sandbox;\n    }\n\n    sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {\n        useFakeTimers: function useFakeTimers() {\n            this.clock = sinon.useFakeTimers.apply(sinon, arguments);\n\n            return this.add(this.clock);\n        },\n\n        serverPrototype: sinon.fakeServer,\n\n        useFakeServer: function useFakeServer() {\n            var proto = this.serverPrototype || sinon.fakeServer;\n\n            if (!proto || !proto.create) {\n                return null;\n            }\n\n            this.server = proto.create();\n            return this.add(this.server);\n        },\n\n        inject: function (obj) {\n            sinon.collection.inject.call(this, obj);\n\n            if (this.clock) {\n                obj.clock = this.clock;\n            }\n\n            if (this.server) {\n                obj.server = this.server;\n                obj.requests = this.server.requests;\n            }\n\n            return obj;\n        },\n\n        create: function (config) {\n            if (!config) {\n                return sinon.create(sinon.sandbox);\n            }\n\n            var sandbox = prepareSandboxFromConfig(config);\n            sandbox.args = sandbox.args || [];\n            var prop, value, exposed = sandbox.inject({});\n\n            if (config.properties) {\n                for (var i = 0, l = config.properties.length; i < l; i++) {\n                    prop = config.properties[i];\n                    value = exposed[prop] || prop == \"sandbox\" && sandbox;\n                    exposeValue(sandbox, config, prop, value);\n                }\n            } else {\n                exposeValue(sandbox, config, \"sandbox\", value);\n            }\n\n            return sandbox;\n        }\n    });\n\n    sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;\n\n    if (typeof module == \"object\" && typeof require == \"function\") {\n        module.exports = sinon.sandbox;\n    }\n}());\n\n/**\n * @depend ../sinon.js\n * @depend stub.js\n * @depend mock.js\n * @depend sandbox.js\n */\n/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/\n/*global module, require, sinon*/\n/**\n * Test function, sandboxes fakes\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function test(callback) {\n        var type = typeof callback;\n\n        if (type != \"function\") {\n            throw new TypeError(\"sinon.test needs to wrap a test function, got \" + type);\n        }\n\n        return function () {\n            var config = sinon.getConfig(sinon.config);\n            config.injectInto = config.injectIntoThis && this || config.injectInto;\n            var sandbox = sinon.sandbox.create(config);\n            var exception, result;\n            var args = Array.prototype.slice.call(arguments).concat(sandbox.args);\n\n            try {\n                result = callback.apply(this, args);\n            } catch (e) {\n                exception = e;\n            }\n\n            if (typeof exception !== \"undefined\") {\n                sandbox.restore();\n                throw exception;\n            }\n            else {\n                sandbox.verifyAndRestore();\n            }\n\n            return result;\n        };\n    }\n\n    test.config = {\n        injectIntoThis: true,\n        injectInto: null,\n        properties: [\"spy\", \"stub\", \"mock\", \"clock\", \"server\", \"requests\"],\n        useFakeTimers: true,\n        useFakeServer: true\n    };\n\n    if (commonJSModule) {\n        module.exports = test;\n    } else {\n        sinon.test = test;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n * @depend ../sinon.js\n * @depend test.js\n */\n/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/\n/*global module, require, sinon*/\n/**\n * Test case, sandboxes all test functions\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon || !Object.prototype.hasOwnProperty) {\n        return;\n    }\n\n    function createTest(property, setUp, tearDown) {\n        return function () {\n            if (setUp) {\n                setUp.apply(this, arguments);\n            }\n\n            var exception, result;\n\n            try {\n                result = property.apply(this, arguments);\n            } catch (e) {\n                exception = e;\n            }\n\n            if (tearDown) {\n                tearDown.apply(this, arguments);\n            }\n\n            if (exception) {\n                throw exception;\n            }\n\n            return result;\n        };\n    }\n\n    function testCase(tests, prefix) {\n        /*jsl:ignore*/\n        if (!tests || typeof tests != \"object\") {\n            throw new TypeError(\"sinon.testCase needs an object with test functions\");\n        }\n        /*jsl:end*/\n\n        prefix = prefix || \"test\";\n        var rPrefix = new RegExp(\"^\" + prefix);\n        var methods = {}, testName, property, method;\n        var setUp = tests.setUp;\n        var tearDown = tests.tearDown;\n\n        for (testName in tests) {\n            if (tests.hasOwnProperty(testName)) {\n                property = tests[testName];\n\n                if (/^(setUp|tearDown)$/.test(testName)) {\n                    continue;\n                }\n\n                if (typeof property == \"function\" && rPrefix.test(testName)) {\n                    method = property;\n\n                    if (setUp || tearDown) {\n                        method = createTest(property, setUp, tearDown);\n                    }\n\n                    methods[testName] = sinon.test(method);\n                } else {\n                    methods[testName] = tests[testName];\n                }\n            }\n        }\n\n        return methods;\n    }\n\n    if (commonJSModule) {\n        module.exports = testCase;\n    } else {\n        sinon.testCase = testCase;\n    }\n}(typeof sinon == \"object\" && sinon || null));\n\n/**\n * @depend ../sinon.js\n * @depend stub.js\n */\n/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/\n/*global module, require, sinon*/\n/**\n * Assertions matching the test spy retrieval interface.\n *\n * @author Christian Johansen (christian@cjohansen.no)\n * @license BSD\n *\n * Copyright (c) 2010-2013 Christian Johansen\n */\n\n(function (sinon, global) {\n    var commonJSModule = typeof module == \"object\" && typeof require == \"function\";\n    var slice = Array.prototype.slice;\n    var assert;\n\n    if (!sinon && commonJSModule) {\n        sinon = require(\"../sinon\");\n    }\n\n    if (!sinon) {\n        return;\n    }\n\n    function verifyIsStub() {\n        var method;\n\n        for (var i = 0, l = arguments.length; i < l; ++i) {\n            method = arguments[i];\n\n            if (!method) {\n                assert.fail(\"fake is not a spy\");\n            }\n\n            if (typeof method != \"function\") {\n                assert.fail(method + \" is not a function\");\n            }\n\n            if (typeof method.getCall != \"function\") {\n                assert.fail(method + \" is not stubbed\");\n            }\n        }\n    }\n\n    function failAssertion(object, msg) {\n        object = object || global;\n        var failMethod = object.fail || assert.fail;\n        failMethod.call(object, msg);\n    }\n\n    function mirrorPropAsAssertion(name, method, message) {\n        if (arguments.length == 2) {\n            message = method;\n            method = name;\n        }\n\n        assert[name] = function (fake) {\n            verifyIsStub(fake);\n\n            var args = slice.call(arguments, 1);\n            var failed = false;\n\n            if (typeof method == \"function\") {\n                failed = !method(fake);\n            } else {\n                failed = typeof fake[method] == \"function\" ?\n                    !fake[method].apply(fake, args) : !fake[method];\n            }\n\n            if (failed) {\n                failAssertion(this, fake.printf.apply(fake, [message].concat(args)));\n            } else {\n                assert.pass(name);\n            }\n        };\n    }\n\n    function exposedName(prefix, prop) {\n        return !prefix || /^fail/.test(prop) ? prop :\n            prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);\n    };\n\n    assert = {\n        failException: \"AssertError\",\n\n        fail: function fail(message) {\n            var error = new Error(message);\n            error.name = this.failException || assert.failException;\n\n            throw error;\n        },\n\n        pass: function pass(assertion) {},\n\n        callOrder: function assertCallOrder() {\n            verifyIsStub.apply(null, arguments);\n            var expected = \"\", actual = \"\";\n\n            if (!sinon.calledInOrder(arguments)) {\n                try {\n                    expected = [].join.call(arguments, \", \");\n                    var calls = slice.call(arguments);\n                    var i = calls.length;\n                    while (i) {\n                        if (!calls[--i].called) {\n                            calls.splice(i, 1);\n                        }\n                    }\n                    actual = sinon.orderByFirstCall(calls).join(\", \");\n                } catch (e) {\n                    // If this fails, we'll just fall back to the blank string\n                }\n\n                failAssertion(this, \"expected \" + expected + \" to be \" +\n                              \"called in order but were called as \" + actual);\n            } else {\n                assert.pass(\"callOrder\");\n            }\n        },\n\n        callCount: function assertCallCount(method, count) {\n            verifyIsStub(method);\n\n            if (method.callCount != count) {\n                var msg = \"expected %n to be called \" + sinon.timesInWords(count) +\n                    \" but was called %c%C\";\n                failAssertion(this, method.printf(msg));\n            } else {\n                assert.pass(\"callCount\");\n            }\n        },\n\n        expose: function expose(target, options) {\n            if (!target) {\n                throw new TypeError(\"target is null or undefined\");\n            }\n\n            var o = options || {};\n            var prefix = typeof o.prefix == \"undefined\" && \"assert\" || o.prefix;\n            var includeFail = typeof o.includeFail == \"undefined\" || !!o.includeFail;\n\n            for (var method in this) {\n                if (method != \"export\" && (includeFail || !/^(fail)/.test(method))) {\n                    target[exposedName(prefix, method)] = this[method];\n                }\n            }\n\n            return target;\n        }\n    };\n\n    mirrorPropAsAssertion(\"called\", \"expected %n to have been called at least once but was never called\");\n    mirrorPropAsAssertion(\"notCalled\", function (spy) { return !spy.called; },\n                          \"expected %n to not have been called but was called %c%C\");\n    mirrorPropAsAssertion(\"calledOnce\", \"expected %n to be called once but was called %c%C\");\n    mirrorPropAsAssertion(\"calledTwice\", \"expected %n to be called twice but was called %c%C\");\n    mirrorPropAsAssertion(\"calledThrice\", \"expected %n to be called thrice but was called %c%C\");\n    mirrorPropAsAssertion(\"calledOn\", \"expected %n to be called with %1 as this but was called with %t\");\n    mirrorPropAsAssertion(\"alwaysCalledOn\", \"expected %n to always be called with %1 as this but was called with %t\");\n    mirrorPropAsAssertion(\"calledWithNew\", \"expected %n to be called with new\");\n    mirrorPropAsAssertion(\"alwaysCalledWithNew\", \"expected %n to always be called with new\");\n    mirrorPropAsAssertion(\"calledWith\", \"expected %n to be called with arguments %*%C\");\n    mirrorPropAsAssertion(\"calledWithMatch\", \"expected %n to be called with match %*%C\");\n    mirrorPropAsAssertion(\"alwaysCalledWith\", \"expected %n to always be called with arguments %*%C\");\n    mirrorPropAsAssertion(\"alwaysCalledWithMatch\", \"expected %n to always be called with match %*%C\");\n    mirrorPropAsAssertion(\"calledWithExactly\", \"expected %n to be called with exact arguments %*%C\");\n    mirrorPropAsAssertion(\"alwaysCalledWithExactly\", \"expected %n to always be called with exact arguments %*%C\");\n    mirrorPropAsAssertion(\"neverCalledWith\", \"expected %n to never be called with arguments %*%C\");\n    mirrorPropAsAssertion(\"neverCalledWithMatch\", \"expected %n to never be called with match %*%C\");\n    mirrorPropAsAssertion(\"threw\", \"%n did not throw exception%C\");\n    mirrorPropAsAssertion(\"alwaysThrew\", \"%n did not always throw exception%C\");\n\n    if (commonJSModule) {\n        module.exports = assert;\n    } else {\n        sinon.assert = assert;\n    }\n}(typeof sinon == \"object\" && sinon || null, typeof window != \"undefined\" ? window : (typeof self != \"undefined\") ? self : global));\n\nreturn sinon;}.call(typeof window != 'undefined' && window || {}));\n"
  },
  {
    "path": "vendors/polyfills/es5.js",
    "content": "/* reduce implemintation by Mozila https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FReduce*/\nif ('function' !== typeof Array.prototype.reduce) {\n  Array.prototype.reduce = function(callback, opt_initialValue){\n    'use strict';\n    if (null === this || 'undefined' === typeof this) {\n      // At the moment all modern browsers, that support strict mode, have\n      // native implementation of Array.prototype.reduce. For instance, IE8\n      // does not support strict mode, so this check is actually useless.\n      throw new TypeError(\n          'Array.prototype.reduce called on null or undefined');\n    }\n    if ('function' !== typeof callback) {\n      throw new TypeError(callback + ' is not a function');\n    }\n    var index, value,\n        length = this.length >>> 0,\n        isValueSet = false;\n    if (1 < arguments.length) {\n      value = opt_initialValue;\n      isValueSet = true;\n    }\n    for (index = 0; length > index; ++index) {\n      if (this.hasOwnProperty(index)) {\n        if (isValueSet) {\n          value = callback(value, this[index], index, this);\n        }\n        else {\n          value = this[index];\n          isValueSet = true;\n        }\n      }\n    }\n    if (!isValueSet) {\n      throw new TypeError('Reduce of empty array with no initial value');\n    }\n    return value;\n  };\n}\n\n// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach\n// Production steps of ECMA-262, Edition 5, 15.4.4.18\n// Reference: http://es5.github.com/#x15.4.4.18\nif (!Array.prototype.forEach) {\n\n  Array.prototype.forEach = function forEach(callback, thisArg) {\n    'use strict';\n    var T, k;\n\n    if (this == null) {\n      throw new TypeError(\"this is null or not defined\");\n    }\n\n    var kValue,\n        // 1. Let O be the result of calling ToObject passing the |this| value as the argument.\n        O = Object(this),\n\n        // 2. Let lenValue be the result of calling the Get internal method of O with the argument \"length\".\n        // 3. Let len be ToUint32(lenValue).\n        len = O.length >>> 0; // Hack to convert O.length to a UInt32\n\n    // 4. If IsCallable(callback) is false, throw a TypeError exception.\n    // See: http://es5.github.com/#x9.11\n    if ({}.toString.call(callback) !== \"[object Function]\") {\n      throw new TypeError(callback + \" is not a function\");\n    }\n\n    // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.\n    if (arguments.length >= 2) {\n      T = thisArg;\n    }\n\n    // 6. Let k be 0\n    k = 0;\n\n    // 7. Repeat, while k < len\n    while (k < len) {\n\n      // a. Let Pk be ToString(k).\n      //   This is implicit for LHS operands of the in operator\n      // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.\n      //   This step can be combined with c\n      // c. If kPresent is true, then\n      if (k in O) {\n\n        // i. Let kValue be the result of calling the Get internal method of O with argument Pk.\n        kValue = O[k];\n\n        // ii. Call the Call internal method of callback with T as the this value and\n        // argument list containing kValue, k, and O.\n        callback.call(T, kValue, k, O);\n      }\n      // d. Increase k by 1.\n      k++;\n    }\n    // 8. return undefined\n  };\n}\n\n// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys\nif (!Object.keys) {\n  Object.keys = (function () {\n    'use strict';\n    var hasOwnProperty = Object.prototype.hasOwnProperty,\n        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),\n        dontEnums = [\n          'toString',\n          'toLocaleString',\n          'valueOf',\n          'hasOwnProperty',\n          'isPrototypeOf',\n          'propertyIsEnumerable',\n          'constructor'\n        ],\n        dontEnumsLength = dontEnums.length;\n\n    return function (obj) {\n      if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {\n        throw new TypeError('Object.keys called on non-object');\n      }\n\n      var result = [], prop, i;\n\n      for (prop in obj) {\n        if (hasOwnProperty.call(obj, prop)) {\n          result.push(prop);\n        }\n      }\n\n      if (hasDontEnumBug) {\n        for (i = 0; i < dontEnumsLength; i++) {\n          if (hasOwnProperty.call(obj, dontEnums[i])) {\n            result.push(dontEnums[i]);\n          }\n        }\n      }\n      return result;\n    };\n  }());\n}\n\n// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some\nif (!Array.prototype.some)\n{\n  Array.prototype.some = function(fun /*, thisArg */)\n  {\n    'use strict';\n\n    if (this === void 0 || this === null)\n      throw new TypeError();\n\n    var t = Object(this);\n    var len = t.length >>> 0;\n    if (typeof fun !== 'function')\n      throw new TypeError();\n\n    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n    for (var i = 0; i < len; i++)\n    {\n      if (i in t && fun.call(thisArg, t[i], i, t))\n        return true;\n    }\n\n    return false;\n  };\n}\n\n// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map\nif (!Array.prototype.map)\n{\n  Array.prototype.map = function(fun /*, thisArg */)\n  {\n    \"use strict\";\n\n    if (this === void 0 || this === null)\n      throw new TypeError();\n\n    var t = Object(this);\n    var len = t.length >>> 0;\n    if (typeof fun !== \"function\")\n      throw new TypeError();\n\n    var res = new Array(len);\n    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n    for (var i = 0; i < len; i++)\n    {\n      // NOTE: Absolute correctness would demand Object.defineProperty\n      //       be used.  But this method is fairly new, and failure is\n      //       possible only if Object.prototype or Array.prototype\n      //       has a property |i| (very unlikely), so use a less-correct\n      //       but more portable alternative.\n      if (i in t)\n        res[i] = fun.call(thisArg, t[i], i, t);\n    }\n\n    return res;\n  };\n}\n\n//From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter\nif (!Array.prototype.filter)\n{\n  Array.prototype.filter = function(fun /*, thisArg */)\n  {\n    \"use strict\";\n\n    if (this === void 0 || this === null)\n      throw new TypeError();\n\n    var t = Object(this);\n    var len = t.length >>> 0;\n    if (typeof fun != \"function\")\n      throw new TypeError();\n\n    var res = [];\n    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n    for (var i = 0; i < len; i++)\n    {\n      if (i in t)\n      {\n        var val = t[i];\n\n        // NOTE: Technically this should Object.defineProperty at\n        //       the next index, as push can be affected by\n        //       properties on Object.prototype and Array.prototype.\n        //       But that method's new, and collisions should be\n        //       rare, so use the more-compatible alternative.\n        if (fun.call(thisArg, val, i, t))\n          res.push(val);\n      }\n    }\n\n    return res;\n  };\n}\n\n//From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind\nif (!Function.prototype.bind) {\n  Function.prototype.bind = function (oThis) {\n    if (typeof this !== \"function\") {\n      // closest thing possible to the ECMAScript 5 internal IsCallable function\n      throw new TypeError(\"Function.prototype.bind - what is trying to be bound is not callable\");\n    }\n\n    var aArgs = Array.prototype.slice.call(arguments, 1),\n        fToBind = this,\n        fNOP = function () {},\n        fBound = function () {\n          return fToBind.apply(this instanceof fNOP && oThis\n                                 ? this\n                                 : oThis,\n                               aArgs.concat(Array.prototype.slice.call(arguments)));\n        };\n\n    fNOP.prototype = this.prototype;\n    fBound.prototype = new fNOP();\n\n    return fBound;\n  };\n}\n\n//From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf\nif (!Array.prototype.indexOf) {\n  Array.prototype.indexOf = function (searchElement, fromIndex) {\n    if ( this === undefined || this === null ) {\n      throw new TypeError( '\"this\" is null or not defined' );\n    }\n\n    var length = this.length >>> 0; // Hack to convert object.length to a UInt32\n\n    fromIndex = +fromIndex || 0;\n\n    if (Math.abs(fromIndex) === Infinity) {\n      fromIndex = 0;\n    }\n\n    if (fromIndex < 0) {\n      fromIndex += length;\n      if (fromIndex < 0) {\n        fromIndex = 0;\n      }\n    }\n\n    for (;fromIndex < length; fromIndex++) {\n      if (this[fromIndex] === searchElement) {\n        return fromIndex;\n      }\n    }\n\n    return -1;\n  };\n}\n"
  },
  {
    "path": "vendors/polyfills/promise.js",
    "content": "if (typeof Promise !== 'function') {\n  (function() {\n  var define, requireModule, require, requirejs;\n\n  (function() {\n    var registry = {}, seen = {};\n\n    define = function(name, deps, callback) {\n      registry[name] = { deps: deps, callback: callback };\n    };\n\n    requirejs = require = requireModule = function(name) {\n    requirejs._eak_seen = registry;\n\n      if (seen[name]) { return seen[name]; }\n      seen[name] = {};\n\n      if (!registry[name]) {\n        throw new Error(\"Could not find module \" + name);\n      }\n\n      var mod = registry[name],\n          deps = mod.deps,\n          callback = mod.callback,\n          reified = [],\n          exports;\n\n      for (var i=0, l=deps.length; i<l; i++) {\n        if (deps[i] === 'exports') {\n          reified.push(exports = {});\n        } else {\n          reified.push(requireModule(resolve(deps[i])));\n        }\n      }\n\n      var value = callback.apply(this, reified);\n      return seen[name] = exports || value;\n\n      function resolve(child) {\n        if (child.charAt(0) !== '.') { return child; }\n        var parts = child.split(\"/\");\n        var parentBase = name.split(\"/\").slice(0, -1);\n\n        for (var i=0, l=parts.length; i<l; i++) {\n          var part = parts[i];\n\n          if (part === '..') { parentBase.pop(); }\n          else if (part === '.') { continue; }\n          else { parentBase.push(part); }\n        }\n\n        return parentBase.join(\"/\");\n      }\n    };\n  })();\n\n  define(\"promise/all\",\n    [\"./utils\",\"exports\"],\n    function(__dependency1__, __exports__) {\n      \"use strict\";\n      /* global toString */\n\n      var isArray = __dependency1__.isArray;\n      var isFunction = __dependency1__.isFunction;\n\n      /**\n        Returns a promise that is fulfilled when all the given promises have been\n        fulfilled, or rejected if any of them become rejected. The return promise\n        is fulfilled with an array that gives all the values in the order they were\n        passed in the `promises` array argument.\n\n        Example:\n\n        ```javascript\n        var promise1 = RSVP.resolve(1);\n        var promise2 = RSVP.resolve(2);\n        var promise3 = RSVP.resolve(3);\n        var promises = [ promise1, promise2, promise3 ];\n\n        RSVP.all(promises).then(function(array){\n          // The array here would be [ 1, 2, 3 ];\n        });\n        ```\n\n        If any of the `promises` given to `RSVP.all` are rejected, the first promise\n        that is rejected will be given as an argument to the returned promises's\n        rejection handler. For example:\n\n        Example:\n\n        ```javascript\n        var promise1 = RSVP.resolve(1);\n        var promise2 = RSVP.reject(new Error(\"2\"));\n        var promise3 = RSVP.reject(new Error(\"3\"));\n        var promises = [ promise1, promise2, promise3 ];\n\n        RSVP.all(promises).then(function(array){\n          // Code here never runs because there are rejected promises!\n        }, function(error) {\n          // error.message === \"2\"\n        });\n        ```\n\n        @method all\n        @for RSVP\n        @param {Array} promises\n        @param {String} label\n        @return {Promise} promise that is fulfilled when all `promises` have been\n        fulfilled, or rejected if any of them become rejected.\n      */\n      function all(promises) {\n        /*jshint validthis:true */\n        var Promise = this;\n\n        if (!isArray(promises)) {\n          throw new TypeError('You must pass an array to all.');\n        }\n\n        return new Promise(function(resolve, reject) {\n          var results = [], remaining = promises.length,\n          promise;\n\n          if (remaining === 0) {\n            resolve([]);\n          }\n\n          function resolver(index) {\n            return function(value) {\n              resolveAll(index, value);\n            };\n          }\n\n          function resolveAll(index, value) {\n            results[index] = value;\n            if (--remaining === 0) {\n              resolve(results);\n            }\n          }\n\n          for (var i = 0; i < promises.length; i++) {\n            promise = promises[i];\n\n            if (promise && isFunction(promise.then)) {\n              promise.then(resolver(i), reject);\n            } else {\n              resolveAll(i, promise);\n            }\n          }\n        });\n      }\n\n      __exports__.all = all;\n    });\n  define(\"promise/asap\",\n    [\"exports\"],\n    function(__exports__) {\n      \"use strict\";\n      var browserGlobal = (typeof window !== 'undefined') ? window : {};\n      var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\n      var local = window;\n\n      // node\n      function useNextTick() {\n        return function() {\n          process.nextTick(flush);\n        };\n      }\n\n      function useMutationObserver() {\n        var iterations = 0;\n        var observer = new BrowserMutationObserver(flush);\n        var node = document.createTextNode('');\n        observer.observe(node, { characterData: true });\n\n        return function() {\n          node.data = (iterations = ++iterations % 2);\n        };\n      }\n\n      function useSetTimeout() {\n        return function() {\n          local.setTimeout(flush, 1);\n        };\n      }\n\n      var queue = [];\n      function flush() {\n        for (var i = 0; i < queue.length; i++) {\n          var tuple = queue[i];\n          var callback = tuple[0], arg = tuple[1];\n          callback(arg);\n        }\n        queue = [];\n      }\n\n      var scheduleFlush;\n\n      // Decide what async method to use to triggering processing of queued callbacks:\n      if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {\n        scheduleFlush = useNextTick();\n      } else if (BrowserMutationObserver) {\n        scheduleFlush = useMutationObserver();\n      } else {\n        scheduleFlush = useSetTimeout();\n      }\n\n      function asap(callback, arg) {\n        var length = queue.push([callback, arg]);\n        if (length === 1) {\n          // If length is 1, that means that we need to schedule an async flush.\n          // If additional callbacks are queued before the queue is flushed, they\n          // will be processed by this flush that we are scheduling.\n          scheduleFlush();\n        }\n      }\n\n      __exports__.asap = asap;\n    });\n  define(\"promise/config\",\n    [\"exports\"],\n    function(__exports__) {\n      \"use strict\";\n      var config = {\n        instrument: false\n      };\n\n      function configure(name, value) {\n        if (arguments.length === 2) {\n          config[name] = value;\n        } else {\n          return config[name];\n        }\n      }\n\n      __exports__.config = config;\n      __exports__.configure = configure;\n    });\n  define(\"promise/polyfill\",\n    [\"./promise\",\"./utils\",\"exports\"],\n    function(__dependency1__, __dependency2__, __exports__) {\n      \"use strict\";\n      /*global self*/\n      var RSVPPromise = __dependency1__.Promise;\n      var isFunction = __dependency2__.isFunction;\n\n      function polyfill() {\n        var local;\n\n        if (typeof window !== 'undefined' && window.document) {\n          local = window;\n        } else {\n          local = self;\n        }\n\n        var es6PromiseSupport =\n          \"Promise\" in local &&\n          // Some of these methods are missing from\n          // Firefox/Chrome experimental implementations\n          \"resolve\" in local.Promise &&\n          \"reject\" in local.Promise &&\n          \"all\" in local.Promise &&\n          \"race\" in local.Promise &&\n          // Older version of the spec had a resolver object\n          // as the arg rather than a function\n          (function() {\n            var resolve;\n            new local.Promise(function(r) { resolve = r; });\n            return isFunction(resolve);\n          }());\n\n        if (!es6PromiseSupport) {\n          local.Promise = RSVPPromise;\n        }\n      }\n\n      __exports__.polyfill = polyfill;\n    });\n  define(\"promise/promise\",\n    [\"./config\",\"./utils\",\"./all\",\"./race\",\"./resolve\",\"./reject\",\"./asap\",\"exports\"],\n    function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {\n      \"use strict\";\n      var config = __dependency1__.config;\n      var configure = __dependency1__.configure;\n      var objectOrFunction = __dependency2__.objectOrFunction;\n      var isFunction = __dependency2__.isFunction;\n      var now = __dependency2__.now;\n      var all = __dependency3__.all;\n      var race = __dependency4__.race;\n      var staticResolve = __dependency5__.resolve;\n      var staticReject = __dependency6__.reject;\n      var asap = __dependency7__.asap;\n\n      var counter = 0;\n\n      config.async = asap; // default async is asap;\n\n      function Promise(resolver) {\n        if (!isFunction(resolver)) {\n          throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n        }\n\n        if (!(this instanceof Promise)) {\n          throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n        }\n\n        this._subscribers = [];\n\n        invokeResolver(resolver, this);\n      }\n\n      function invokeResolver(resolver, promise) {\n        function resolvePromise(value) {\n          resolve(promise, value);\n        }\n\n        function rejectPromise(reason) {\n          reject(promise, reason);\n        }\n\n        try {\n          resolver(resolvePromise, rejectPromise);\n        } catch(e) {\n          rejectPromise(e);\n        }\n      }\n\n      function invokeCallback(settled, promise, callback, detail) {\n        var hasCallback = isFunction(callback),\n            value, error, succeeded, failed;\n\n        if (hasCallback) {\n          try {\n            value = callback(detail);\n            succeeded = true;\n          } catch(e) {\n            failed = true;\n            error = e;\n          }\n        } else {\n          value = detail;\n          succeeded = true;\n        }\n\n        if (handleThenable(promise, value)) {\n          return;\n        } else if (hasCallback && succeeded) {\n          resolve(promise, value);\n        } else if (failed) {\n          reject(promise, error);\n        } else if (settled === FULFILLED) {\n          resolve(promise, value);\n        } else if (settled === REJECTED) {\n          reject(promise, value);\n        }\n      }\n\n      var PENDING   = void 0;\n      var SEALED    = 0;\n      var FULFILLED = 1;\n      var REJECTED  = 2;\n\n      function subscribe(parent, child, onFulfillment, onRejection) {\n        var subscribers = parent._subscribers;\n        var length = subscribers.length;\n\n        subscribers[length] = child;\n        subscribers[length + FULFILLED] = onFulfillment;\n        subscribers[length + REJECTED]  = onRejection;\n      }\n\n      function publish(promise, settled) {\n        var child, callback, subscribers = promise._subscribers, detail = promise._detail;\n\n        for (var i = 0; i < subscribers.length; i += 3) {\n          child = subscribers[i];\n          callback = subscribers[i + settled];\n\n          invokeCallback(settled, child, callback, detail);\n        }\n\n        promise._subscribers = null;\n      }\n\n      Promise.prototype = {\n        constructor: Promise,\n\n        _state: undefined,\n        _detail: undefined,\n        _subscribers: undefined,\n\n        then: function(onFulfillment, onRejection) {\n          var promise = this;\n\n          var thenPromise = new this.constructor(function() {});\n\n          if (this._state) {\n            var callbacks = arguments;\n            config.async(function invokePromiseCallback() {\n              invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);\n            });\n          } else {\n            subscribe(this, thenPromise, onFulfillment, onRejection);\n          }\n\n          return thenPromise;\n        },\n\n        'catch': function(onRejection) {\n          return this.then(null, onRejection);\n        }\n      };\n\n      Promise.all = all;\n      Promise.race = race;\n      Promise.resolve = staticResolve;\n      Promise.reject = staticReject;\n\n      function handleThenable(promise, value) {\n        var then = null,\n        resolved;\n\n        try {\n          if (promise === value) {\n            throw new TypeError(\"A promises callback cannot return that same promise.\");\n          }\n\n          if (objectOrFunction(value)) {\n            then = value.then;\n\n            if (isFunction(then)) {\n              then.call(value, function(val) {\n                if (resolved) { return true; }\n                resolved = true;\n\n                if (value !== val) {\n                  resolve(promise, val);\n                } else {\n                  fulfill(promise, val);\n                }\n              }, function(val) {\n                if (resolved) { return true; }\n                resolved = true;\n\n                reject(promise, val);\n              });\n\n              return true;\n            }\n          }\n        } catch (error) {\n          if (resolved) { return true; }\n          reject(promise, error);\n          return true;\n        }\n\n        return false;\n      }\n\n      function resolve(promise, value) {\n        if (promise === value) {\n          fulfill(promise, value);\n        } else if (!handleThenable(promise, value)) {\n          fulfill(promise, value);\n        }\n      }\n\n      function fulfill(promise, value) {\n        if (promise._state !== PENDING) { return; }\n        promise._state = SEALED;\n        promise._detail = value;\n\n        config.async(publishFulfillment, promise);\n      }\n\n      function reject(promise, reason) {\n        if (promise._state !== PENDING) { return; }\n        promise._state = SEALED;\n        promise._detail = reason;\n\n        config.async(publishRejection, promise);\n      }\n\n      function publishFulfillment(promise) {\n        publish(promise, promise._state = FULFILLED);\n      }\n\n      function publishRejection(promise) {\n        publish(promise, promise._state = REJECTED);\n      }\n\n      __exports__.Promise = Promise;\n    });\n  define(\"promise/race\",\n    [\"./utils\",\"exports\"],\n    function(__dependency1__, __exports__) {\n      \"use strict\";\n      /* global toString */\n      var isArray = __dependency1__.isArray;\n\n      /**\n        `RSVP.race` allows you to watch a series of promises and act as soon as the\n        first promise given to the `promises` argument fulfills or rejects.\n\n        Example:\n\n        ```javascript\n        var promise1 = new RSVP.Promise(function(resolve, reject){\n          setTimeout(function(){\n            resolve(\"promise 1\");\n          }, 200);\n        });\n\n        var promise2 = new RSVP.Promise(function(resolve, reject){\n          setTimeout(function(){\n            resolve(\"promise 2\");\n          }, 100);\n        });\n\n        RSVP.race([promise1, promise2]).then(function(result){\n          // result === \"promise 2\" because it was resolved before promise1\n          // was resolved.\n        });\n        ```\n\n        `RSVP.race` is deterministic in that only the state of the first completed\n        promise matters. For example, even if other promises given to the `promises`\n        array argument are resolved, but the first completed promise has become\n        rejected before the other promises became fulfilled, the returned promise\n        will become rejected:\n\n        ```javascript\n        var promise1 = new RSVP.Promise(function(resolve, reject){\n          setTimeout(function(){\n            resolve(\"promise 1\");\n          }, 200);\n        });\n\n        var promise2 = new RSVP.Promise(function(resolve, reject){\n          setTimeout(function(){\n            reject(new Error(\"promise 2\"));\n          }, 100);\n        });\n\n        RSVP.race([promise1, promise2]).then(function(result){\n          // Code here never runs because there are rejected promises!\n        }, function(reason){\n          // reason.message === \"promise2\" because promise 2 became rejected before\n          // promise 1 became fulfilled\n        });\n        ```\n\n        @method race\n        @for RSVP\n        @param {Array} promises array of promises to observe\n        @param {String} label optional string for describing the promise returned.\n        Useful for tooling.\n        @return {Promise} a promise that becomes fulfilled with the value the first\n        completed promises is resolved with if the first completed promise was\n        fulfilled, or rejected with the reason that the first completed promise\n        was rejected with.\n      */\n      function race(promises) {\n        /*jshint validthis:true */\n        var Promise = this;\n\n        if (!isArray(promises)) {\n          throw new TypeError('You must pass an array to race.');\n        }\n        return new Promise(function(resolve, reject) {\n          var results = [], promise;\n\n          for (var i = 0; i < promises.length; i++) {\n            promise = promises[i];\n\n            if (promise && typeof promise.then === 'function') {\n              promise.then(resolve, reject);\n            } else {\n              resolve(promise);\n            }\n          }\n        });\n      }\n\n      __exports__.race = race;\n    });\n  define(\"promise/reject\",\n    [\"exports\"],\n    function(__exports__) {\n      \"use strict\";\n      /**\n        `RSVP.reject` returns a promise that will become rejected with the passed\n        `reason`. `RSVP.reject` is essentially shorthand for the following:\n\n        ```javascript\n        var promise = new RSVP.Promise(function(resolve, reject){\n          reject(new Error('WHOOPS'));\n        });\n\n        promise.then(function(value){\n          // Code here doesn't run because the promise is rejected!\n        }, function(reason){\n          // reason.message === 'WHOOPS'\n        });\n        ```\n\n        Instead of writing the above, your code now simply becomes the following:\n\n        ```javascript\n        var promise = RSVP.reject(new Error('WHOOPS'));\n\n        promise.then(function(value){\n          // Code here doesn't run because the promise is rejected!\n        }, function(reason){\n          // reason.message === 'WHOOPS'\n        });\n        ```\n\n        @method reject\n        @for RSVP\n        @param {Any} reason value that the returned promise will be rejected with.\n        @param {String} label optional string for identifying the returned promise.\n        Useful for tooling.\n        @return {Promise} a promise that will become rejected with the given\n        `reason`.\n      */\n      function reject(reason) {\n        /*jshint validthis:true */\n        var Promise = this;\n\n        return new Promise(function (resolve, reject) {\n          reject(reason);\n        });\n      }\n\n      __exports__.reject = reject;\n    });\n  define(\"promise/resolve\",\n    [\"exports\"],\n    function(__exports__) {\n      \"use strict\";\n      function resolve(value) {\n        /*jshint validthis:true */\n        if (value && typeof value === 'object' && value.constructor === this) {\n          return value;\n        }\n\n        var Promise = this;\n\n        return new Promise(function(resolve) {\n          resolve(value);\n        });\n      }\n\n      __exports__.resolve = resolve;\n    });\n  define(\"promise/utils\",\n    [\"exports\"],\n    function(__exports__) {\n      \"use strict\";\n      function objectOrFunction(x) {\n        return isFunction(x) || (typeof x === \"object\" && x !== null);\n      }\n\n      function isFunction(x) {\n        return typeof x === \"function\";\n      }\n\n      function isArray(x) {\n        return Object.prototype.toString.call(x) === \"[object Array]\";\n      }\n\n      // Date.now is not available in browsers < IE9\n      // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility\n      var now = Date.now || function() { return new Date().getTime(); };\n\n\n      __exports__.objectOrFunction = objectOrFunction;\n      __exports__.isFunction = isFunction;\n      __exports__.isArray = isArray;\n      __exports__.now = now;\n    });\n  requireModule('promise/polyfill').polyfill();\n  }());\n}\n"
  }
]