├── dist └── L.Control.LineStringSelect.d.ts ├── .npmrc ├── src ├── leaflet.lss.less ├── marker.js ├── endpoint.js ├── selection.js ├── geometry.js ├── select.js └── externs.js ├── index.html ├── examples ├── font │ ├── SourceCodePro-Bold.otf │ ├── SourceSansPro-Bold.otf │ ├── SourceSansPro-It.otf │ ├── SourceCodePro-Black.otf │ ├── SourceCodePro-Light.otf │ ├── SourceSansPro-Black.otf │ ├── SourceSansPro-BoldIt.otf │ ├── SourceSansPro-Light.otf │ ├── SourceCodePro-Regular.otf │ ├── SourceCodePro-Semibold.otf │ ├── SourceSansPro-BlackIt.otf │ ├── SourceSansPro-LightIt.otf │ ├── SourceSansPro-Regular.otf │ ├── SourceSansPro-Semibold.otf │ ├── SourceCodePro-ExtraLight.otf │ ├── SourceSansPro-ExtraLight.otf │ ├── SourceSansPro-SemiboldIt.otf │ ├── SourceSansPro-ExtraLightIt.otf │ └── LICENSE.txt ├── css │ └── style.css ├── js │ ├── L.TouchExtend.js │ ├── json-format.js │ ├── app.js │ └── bundle.js ├── index.html └── data.json ├── .editorconfig ├── index.js ├── .github └── workflows │ ├── publish.yml │ └── node.yml ├── bower.json ├── .gitignore ├── test └── geometry.test.js ├── LICENSE ├── .eslintrc ├── package.json └── README.md /dist/L.Control.LineStringSelect.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /src/leaflet.lss.less: -------------------------------------------------------------------------------- 1 | .leaflet-select { 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/font/SourceCodePro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-Bold.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-Bold.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-It.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-It.otf -------------------------------------------------------------------------------- /examples/font/SourceCodePro-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-Black.otf -------------------------------------------------------------------------------- /examples/font/SourceCodePro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-Light.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-Black.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-Black.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-BoldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-BoldIt.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-Light.otf -------------------------------------------------------------------------------- /examples/font/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /examples/font/SourceCodePro-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-Semibold.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-BlackIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-BlackIt.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-LightIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-LightIt.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-Regular.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-Semibold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-Semibold.otf -------------------------------------------------------------------------------- /examples/font/SourceCodePro-ExtraLight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceCodePro-ExtraLight.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-ExtraLight.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-ExtraLight.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-SemiboldIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-SemiboldIt.otf -------------------------------------------------------------------------------- /examples/font/SourceSansPro-ExtraLightIt.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w8r/L.Control.LineStringSelect/HEAD/examples/font/SourceSansPro-ExtraLightIt.otf -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | 10 | [*{.scss,.less}] 11 | indent_style = tab 12 | 13 | [Makefile] 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [*.json] 18 | indent_style = space 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Leaflet LineString selection control 3 | * @license MIT 4 | * @author Alexander Milevski 5 | * @preserve 6 | */ 7 | 8 | var L = require('leaflet'); 9 | 10 | L.Control.LineStringSelect = module.exports = require('./src/select'); 11 | L.control.lineStringSelect = function (options) { 12 | return new L.Control.LineStringSelect(options); 13 | }; 14 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | tags: 4 | - 'v*.*.*' 5 | 6 | jobs: 7 | publish: 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v1 13 | - uses: actions/setup-node@v1 14 | with: 15 | node-version: 12 16 | - run: npm ci 17 | - run: npm run build 18 | - run: npm test 19 | - uses: JS-DevTools/npm-publish@v1 20 | with: 21 | token: ${{ secrets.NPM_TOKEN }} 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "L.Control.LineStringSelect", 3 | "main": "dist/L.Control.LineStringSelect.js", 4 | "version": "1.0.0", 5 | "homepage": "https://github.com/w8r/L.Control.LineStringSelect", 6 | "authors": [ 7 | "w8r " 8 | ], 9 | "description": "LineString selection tool for Leaflet", 10 | "keywords": [ 11 | "leaflet", 12 | "geojson", 13 | "linestring", 14 | "select", 15 | "control", 16 | "range" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/marker.js: -------------------------------------------------------------------------------- 1 | var L = require('leaflet'); 2 | 3 | /** 4 | * Vector circle marker class with additional hide/show methods 5 | * 6 | * @class Marker 7 | * @extends {L.CircleMarker} 8 | */ 9 | module.exports = L.CircleMarker.extend( /** @lends Marker.prototype */ { 10 | 11 | /** 12 | * Show marker 13 | * @return {Marker} 14 | */ 15 | show: function () { 16 | this._container.style.visibility = ''; 17 | return this; 18 | }, 19 | 20 | /** 21 | * Hide marker 22 | * @return {Marker} 23 | */ 24 | hide: function () { 25 | this._container.style.visibility = 'hidden'; 26 | return this; 27 | } 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | dist/*.js 30 | dist/*.map 31 | dist/*.css 32 | -------------------------------------------------------------------------------- /.github/workflows/node.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x, 16.x] 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v3 23 | 24 | - name: Build ${{ matrix.node-version }} 25 | uses: actions/setup-node@v2 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - run: npm ci 29 | - run: npm test 30 | - run: npm run build --if-present 31 | -------------------------------------------------------------------------------- /test/geometry.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tape = require('tape'); 4 | var geometry = require('../src/geometry'); 5 | 6 | tape('geometry', function (t) { 7 | 8 | t.test('pointSegmentDistance', function (tt) { 9 | tt.equal(geometry.pointSegmentDistance([0, 0], [100, 100], [12, 12]), 288); 10 | tt.end(); 11 | }); 12 | 13 | t.test('closestPointOnSegment', function (tt) { 14 | tt.deepEqual(geometry.closestPointOnSegment([0, 0], [100, 100], [12, 12]), [12, 12]); 15 | tt.deepEqual(geometry.closestPointOnSegment([200, 200], [100, 100], [12, 12]), [100, 100]); 16 | tt.deepEqual(geometry.closestPointOnSegment([60, 50], [100, 100], [12, 12]), [55, 55]); 17 | tt.end(); 18 | }); 19 | 20 | t.test('euclidianDistance', function (tt) { 21 | tt.equal(geometry.distance([0, 0], [2, 2]), Math.sqrt(8)); 22 | tt.end(); 23 | }); 24 | 25 | t.test('pointOnSegment', function (tt) { 26 | tt.deepEqual( 27 | geometry.pointOnSegment([0, 0], [2, 2], 0.5, Math.sqrt(8)), [0.35355339059327373, 0.35355339059327373] 28 | ); 29 | tt.end(); 30 | }); 31 | 32 | t.end(); 33 | }); 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alexander Milevski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | background: #fff; 5 | } 6 | 7 | h2, h3 { 8 | font-weight: 300; 9 | } 10 | 11 | #map { 12 | width: 60%; 13 | height: 500px; 14 | display: block; 15 | float: left; 16 | } 17 | 18 | #controls { 19 | display: block; 20 | width: 40%; 21 | float: right; 22 | background: #fff; 23 | } 24 | 25 | #map, #controls { 26 | width: 100%; 27 | } 28 | 29 | #controls .wrapper { 30 | padding: 30px; 31 | } 32 | 33 | #controls .control { 34 | width: 20%; 35 | display: inline-block; 36 | text-align: center; 37 | } 38 | 39 | #controls .github-button { color: #fff; } 40 | 41 | #controls .control.range { 42 | width: 33%; 43 | } 44 | 45 | #controls .control input { 46 | display: inline-block; 47 | margin-right: 10px; 48 | text-align: right; 49 | } 50 | 51 | #geojson { 52 | display: block; 53 | width: 100%; 54 | height: 200px; 55 | } 56 | 57 | @media (min-width:900px) { 58 | #map { 59 | width: 60%; 60 | height: 100%; 61 | } 62 | 63 | #controls { 64 | width: 40%; 65 | } 66 | 67 | #controls .control.range { 68 | display: inline-block; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/endpoint.js: -------------------------------------------------------------------------------- 1 | var Marker = require('./marker'); 2 | 3 | /** 4 | * Selection endpoint 5 | * 6 | * @class EndPoint 7 | * @extends {Marker} 8 | */ 9 | var Endpoint = Marker.extend( /** @lends Endpoint.prototype */ { 10 | 11 | /** 12 | * @type {Object} 13 | */ 14 | options: { 15 | /** 16 | * Grow marker by this ratio on mouseover 17 | * @type {Number} 18 | */ 19 | radiusRatio: 1.2 20 | }, 21 | 22 | /** 23 | * @param {L.Map} map 24 | */ 25 | onAdd: function (map) { 26 | this.on('mouseover', this._onMouseOver, this) 27 | .on('mouseout', this._onMouseOut, this); 28 | Marker.prototype.onAdd.call(this, map); 29 | }, 30 | 31 | /** 32 | * @param {L.Map} map 33 | */ 34 | onRemove: function (map) { 35 | this.off('mouseover', this._onMouseOver, this) 36 | .off('mouseout', this._onMouseOut, this); 37 | Marker.prototype.onRemove.call(this, map); 38 | }, 39 | 40 | /** 41 | * Grow radius 42 | */ 43 | _onMouseOver: function () { 44 | this.setRadius(this.options.radius * this.options.radiusRatio); 45 | }, 46 | 47 | /** 48 | * Set radius back 49 | */ 50 | _onMouseOut: function () { 51 | this.setRadius(this.options.radius / this.options.radiusRatio); 52 | } 53 | 54 | }); 55 | 56 | module.exports = Endpoint; 57 | -------------------------------------------------------------------------------- /src/selection.js: -------------------------------------------------------------------------------- 1 | var L = require('leaflet'); 2 | 3 | /** 4 | * Selection polyline 5 | * @class Selection 6 | * @extends {L.Polyline} 7 | */ 8 | var Selection = L.Polyline.extend( /** @lends Selection.prototype */ { 9 | 10 | /** 11 | * @param {Array.} latlngs 12 | * @param {Object} options 13 | * @param {L.Polyline} source 14 | * @constructor 15 | */ 16 | initialize: function(latlngs, options, source) { 17 | 18 | /** 19 | * @type {L.Polyline} 20 | */ 21 | this._source = source; 22 | 23 | L.Polyline.prototype.initialize.call(this, latlngs, options); 24 | }, 25 | 26 | /** 27 | * Updates path from the source path string, avoid re-projections 28 | * 1. get the path chunk from the source, put it all together 29 | * 2. get the endpoints from latlng array 30 | * 3. update path 31 | * 32 | * @param {Number} start 33 | * @param {Number} end 34 | */ 35 | updatePathFromSource: function(start, end) { 36 | var sourcePoints = this._source._rings[0]; 37 | var originalPoints = sourcePoints.slice(start, end + 1); 38 | originalPoints.unshift( 39 | this._map.latLngToLayerPoint(this._latlngs[0]) 40 | ); 41 | originalPoints.push( 42 | this._map.latLngToLayerPoint(this._latlngs[this._latlngs.length - 1]) 43 | ); 44 | this._rings[0] = originalPoints; 45 | this._update(); 46 | } 47 | 48 | }); 49 | 50 | module.exports = Selection; 51 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true, 5 | "es6": true 6 | }, 7 | "globals": { 8 | "L": true 9 | }, 10 | "rules": { 11 | "yoda": 0, 12 | "block-scoped-var": 2, 13 | "camelcase": 1, 14 | "comma-style": 2, 15 | "curly": 0, 16 | "dot-notation": 0, 17 | "eqeqeq": [ 18 | 2, 19 | "allow-null" 20 | ], 21 | "guard-for-in": 2, 22 | "key-spacing": 0, 23 | "new-cap": 2, 24 | "no-bitwise": 2, 25 | "no-caller": 2, 26 | "no-cond-assign": [ 27 | 2, 28 | "except-parens" 29 | ], 30 | "no-debugger": 2, 31 | "no-empty": 2, 32 | "no-eval": 2, 33 | "no-extend-native": 2, 34 | "no-extra-parens": 0, 35 | "no-irregular-whitespace": 2, 36 | "no-iterator": 2, 37 | "no-loop-func": 2, 38 | "no-multi-spaces": 0, 39 | "no-multi-str": 0, 40 | "no-mixed-spaces-and-tabs": 0, 41 | "no-new": 2, 42 | "no-plusplus": 0, 43 | "no-proto": 2, 44 | "no-script-url": 2, 45 | "no-sequences": 2, 46 | "no-shadow": 2, 47 | "no-undef": 2, 48 | "no-underscore-dangle": 0, 49 | "no-unused-vars": [2, {"vars": "all", "args": "none"}], 50 | "no-use-before-define": [2, "nofunc"], 51 | "no-with": 2, 52 | "quotes": [2, "single"], 53 | "semi": [2, "always"], 54 | "no-extra-semi": 2, // disallow unnecessary semicolons 55 | "semi-spacing": [1, {"before": false, "after": true}], // enforce spacing before and after semicolons 56 | "strict": 0, 57 | "valid-typeof": 2, 58 | "wrap-iife": [2, "inside"] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/js/L.TouchExtend.js: -------------------------------------------------------------------------------- 1 | L.Map.mergeOptions({ 2 | touchExtend: true 3 | }); 4 | 5 | L.Map.TouchExtend = L.Handler.extend({ 6 | 7 | initialize: function(map) { 8 | this._map = map; 9 | this._container = map._container; 10 | this._pane = map._panes.overlayPane; 11 | }, 12 | 13 | addHooks: function() { 14 | L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this) 15 | .on(this._container, 'touchend', this._onTouchEnd, this) 16 | .on(this._container, 'touchmove', this._onTouchMove, this); 17 | }, 18 | 19 | removeHooks: function() { 20 | L.DomEvent.off(this._container, 'touchstart', this._onTouchStart) 21 | .off(this._container, 'touchend', this._onTouchEnd) 22 | .off(this._container, 'touchmove', this._onTouchMove); 23 | }, 24 | 25 | _onTouchEvent: function(e, type) { 26 | if (!this._map._loaded) { 27 | return; 28 | } 29 | 30 | var touch = e.touches[0]; 31 | var containerPoint = L.point(touch.clientX, touch.clientY); 32 | var layerPoint = this._map.containerPointToLayerPoint(containerPoint); 33 | var latlng = this._map.layerPointToLatLng(layerPoint); 34 | 35 | this._map.fire(type, { 36 | latlng: latlng, 37 | layerPoint: layerPoint, 38 | containerPoint: containerPoint, 39 | originalEvent: e 40 | }); 41 | }, 42 | 43 | _onTouchStart: function(e) { 44 | this._onTouchEvent(e, 'touchstart'); 45 | }, 46 | 47 | _onTouchEnd: function(e) { 48 | if (!this._map._loaded) { 49 | return; 50 | } 51 | this._map.fire('touchend', { 52 | originalEvent: e 53 | }); 54 | }, 55 | 56 | _onTouchMove: function(e) { 57 | this._onTouchEvent(e, 'touchmove'); 58 | } 59 | }); 60 | 61 | L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend); 62 | -------------------------------------------------------------------------------- /examples/js/json-format.js: -------------------------------------------------------------------------------- 1 | /* 2 | json-format v.1.1 3 | http://github.com/phoboslab/json-format 4 | 5 | Released under MIT license: 6 | http://www.opensource.org/licenses/mit-license.php 7 | */ 8 | 9 | var p = [], 10 | push = function(m) { 11 | return '\\' + p.push(m) + '\\'; 12 | }, 13 | pop = function(m, i) { 14 | return p[i - 1] 15 | }, 16 | tabs = function(count) { 17 | return new Array(count + 1).join('\t'); 18 | }; 19 | 20 | module.exports = function(json) { 21 | p = []; 22 | var out = "", 23 | indent = 0; 24 | 25 | // Extract backslashes and strings 26 | json = json 27 | .replace(/\\./g, push) 28 | .replace(/(".*?"|'.*?')/g, push) 29 | .replace(/\s+/, ''); 30 | 31 | // Indent and insert newlines 32 | for (var i = 0; i < json.length; i++) { 33 | var c = json.charAt(i); 34 | 35 | switch (c) { 36 | case '{': 37 | out += c + "\n" + tabs(++indent); 38 | break; 39 | case '[': 40 | out += c + "\n" + tabs(++indent); 41 | break; 42 | case ']': 43 | out += "\n" + tabs(--indent) + c; 44 | break; 45 | case '}': 46 | out += "\n" + tabs(--indent) + c; 47 | break; 48 | case ',': 49 | if (/\d/.test(json.charAt(i - 1))) { 50 | out += ", "; 51 | } else { 52 | out += ",\n" + tabs(indent); 53 | } 54 | break; 55 | case ':': 56 | out += ": "; 57 | break; 58 | default: 59 | out += c; 60 | break; 61 | } 62 | } 63 | 64 | // Strip whitespace from numeric arrays and put backslashes 65 | // and strings back in 66 | out = out 67 | .replace(/\[[\d,\s]+?\]/g, function(m) { 68 | return m.replace(/\s/g, ''); 69 | }) 70 | // number arrays 71 | .replace(/\[\s*(\d)/g, function(a, b) { 72 | return '[' + b; 73 | }) 74 | .replace(/(\d)\s*\]/g, function(a, b) { 75 | return b + ']'; 76 | }) 77 | .replace(/\{\s*\}/g, '{}') // empty objects 78 | .replace(/\\(\d+)\\/g, pop) // strings 79 | .replace(/\\(\d+)\\/g, pop); // backslashes in strings 80 | 81 | return out; 82 | }; 83 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Leaflet.Control.LineStringSelect 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |

LineString select

20 | Star 21 | Fork 22 |

23 | Here you can play with the rough coastline of HK New Territories. Try and select a part of it by putting control points on it, dragging them or using the external control. 24 |

25 |

26 | 27 | 28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 |
36 | 37 |

GeoJSON

38 | 39 |
40 |
41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "leaflet-linestring-select", 3 | "version": "1.1.1", 4 | "description": "LineString selection tool", 5 | "main": "dist/L.Control.LineStringSelect.no-rbush.js", 6 | "types": "dist/L.Control.LineStringSelect.d.ts", 7 | "files": [ 8 | "dist" 9 | ], 10 | "scripts": { 11 | "test": "tape test/*.test.js | tap-status", 12 | "start": "npm run watch-js & npm run watch-css & serve -p 3001", 13 | "lint": "eslint ./src/", 14 | "watch-css": "catw -c 'lessc -' 'src/*.less' -o dist/leaflet.lss.css -v", 15 | "watch-js": "watchify -v -d examples/js/app.js -o examples/js/bundle.js", 16 | "build-less": "lessc src/leaflet.lss.less > dist/leaflet.lss.css", 17 | "compress-less": "lessc -x src/leaflet.lss.less > dist/leaflet.lss.min.css", 18 | "build-css": "npm run build-less && npm run compress-less", 19 | "build-js": "browserify -t [ browserify-shim ] -s L.Control.LineStringSelect --external leaflet index.js -o dist/L.Control.LineStringSelect.js", 20 | "build-js-no-rbush": "browserify -t [ browserify-shim ] -s L.Control.LineStringSelect --external leaflet -u leaflet -u rbush index.js -o dist/L.Control.LineStringSelect.no-rbush.js", 21 | "compress": "npm run compress-js && npm run compress-js-no-rbush", 22 | "compress-js": "uglifyjs dist/L.Control.LineStringSelect.js --comments -m -c drop_console=true > dist/L.Control.LineStringSelect.min.js", 23 | "compress-js-no-rbush": "uglifyjs dist/L.Control.LineStringSelect.no-rbush.js --comments -m -c drop_console=true > dist/L.Control.LineStringSelect.no-rbush.min.js", 24 | "build": "npm run build-js && npm run build-js-no-rbush && npm run compress && npm run build-css" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/w8r/L.Control.LineStringSelect.git" 29 | }, 30 | "keywords": [ 31 | "leaflet", 32 | "geojson", 33 | "linestring", 34 | "select", 35 | "control", 36 | "range" 37 | ], 38 | "author": "Alexander Milevski ", 39 | "license": "MIT", 40 | "browserify-shim": { 41 | "leaflet": "global:L" 42 | }, 43 | "bugs": { 44 | "url": "https://github.com/w8r/L.Control.LineStringSelect/issues" 45 | }, 46 | "homepage": "https://github.com/w8r/L.Control.LineStringSelect", 47 | "devDependencies": { 48 | "browserify": "^13.1.0", 49 | "browserify-shim": "^3.8.12", 50 | "catw": "^1.0.1", 51 | "eslint": "^4.18.2", 52 | "less": "^2.1.2", 53 | "serve": "^10.1.2", 54 | "smokestack": "^3.3.1", 55 | "tap-closer": "^1.0.0", 56 | "tap-status": "^1.0.1", 57 | "tape": "^4.2.0", 58 | "uglify-js": "^3.6.0", 59 | "watchify": "^3.7.0" 60 | }, 61 | "dependencies": { 62 | "@types/geojson": "^7946.0.7", 63 | "leaflet": "^1.5.1", 64 | "rbush": "^3.0.1" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/geometry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Squared distance 3 | * @param {Array.} a 4 | * @param {Array.} b 5 | * @return {Number} 6 | */ 7 | function pointDistance(a, b) { 8 | var dx = a[0] - b[0], 9 | dy = a[1] - b[1]; 10 | return dx * dx + dy * dy; 11 | } 12 | 13 | /** 14 | * @param {Array.} a 15 | * @param {Array.} b 16 | * @return {Number} 17 | */ 18 | function euclidianDistance(a, b) { 19 | return Math.sqrt(pointDistance(a, b)); 20 | } 21 | 22 | /** 23 | * @param {Array.} c The point 24 | * @param {Array.} a Endpoint 1 25 | * @param {Array.} b Endpoint 2 26 | * @return {Number} 27 | */ 28 | function pointLineSegmentDistance(c, a, b) { 29 | var dx = b[0] - a[0], 30 | dy = b[1] - a[1], 31 | d2 = dx * dx + dy * dy, 32 | t = d2 && ((c[0] - a[0]) * dx + (c[1] - a[1]) * (b[1] - a[1])) / d2; 33 | return pointDistance(c, t <= 0 ? a : t >= 1 ? b : [a[0] + t * dx, a[1] + t * dy]); 34 | } 35 | 36 | /** 37 | * @param {Array.} p2 38 | * @param {Array.} p0 39 | * @param {Array.} p1 40 | * @return {Number} 41 | */ 42 | function pointLineSegmentParameter(p2, p0, p1) { 43 | var x10 = p1[0] - p0[0], 44 | y10 = p1[1] - p0[1], 45 | x20 = p2[0] - p0[0], 46 | y20 = p2[1] - p0[1], 47 | t = (x20 * x10 + y20 * y10) / (x10 * x10 + y10 * y10); 48 | return t < 0 ? 0 : t > 1 ? 1 : t; 49 | } 50 | 51 | /** 52 | * @param {Array.} p2 Point 53 | * @param {Array.} p0 Segment start 54 | * @param {Array.} p1 Segment end 55 | * @return {Array.} Closest point/projection 56 | */ 57 | function closestPointOnSegment(p2, p0, p1) { 58 | var t = pointLineSegmentParameter(p2, p0, p1), 59 | x10 = p1[0] - p0[0], 60 | y10 = p1[1] - p0[1], 61 | p3 = [p0[0] + t * x10, p0[1] + t * y10]; 62 | return p3; 63 | } 64 | 65 | /** 66 | * Performs linear interpolation between values a and b. Returns the value 67 | * between a and b proportional to x (when x is between 0 and 1. When x is 68 | * outside this range, the return value is a linear extrapolation). 69 | * 70 | * @param {Number} a A number. 71 | * @param {Number} b A number. 72 | * @param {Number} x The proportion between a and b. 73 | * 74 | * @return {Number} The interpolated value between a and b. 75 | */ 76 | function linearInterpolation(a, b, x) { 77 | return a + x * (b - a); 78 | } 79 | 80 | /** 81 | * @param {Array.} start 82 | * @param {Array.} end 83 | * @param {Number} m 84 | * @param {Number} length 85 | * @return {Array.} 86 | */ 87 | function pointOnSegment(start, end, m, length) { 88 | var t = m / length; 89 | return [ 90 | linearInterpolation(start[0], end[0], t), 91 | linearInterpolation(start[1], end[1], t) 92 | ]; 93 | } 94 | 95 | module.exports = { 96 | pointSegmentDistance: pointLineSegmentDistance, 97 | closestPointOnSegment: closestPointOnSegment, 98 | pointOnSegment: pointOnSegment, 99 | distance: euclidianDistance 100 | }; 101 | -------------------------------------------------------------------------------- /examples/js/app.js: -------------------------------------------------------------------------------- 1 | // var L = global.L || require('leaflet'); 2 | var data = require('../data.json'); 3 | var jsonFormat = global.jsonFormat = require('./json-format'); 4 | //var Select = require('../../index'); 5 | require('./L.TouchExtend'); 6 | 7 | // this piece here doubles the number of points in geojson 8 | // for (var i = 0, coords = data.geometry.coordinates, len = coords.length - 1; i < len; i += 2) { 9 | // var c1 = coords[i]; 10 | // var c2 = coords[i + 1]; 11 | // var mid = [(c1[0] + c2[0]) / 2, (c1[1] + c2[1]) / 2]; 12 | 13 | // coords.splice(i + 1, 0, mid); 14 | // len++; 15 | // } 16 | // console.log(JSON.stringify(coords)); 17 | 18 | L.Icon.Default.imagePath = 'http://cdn.leafletjs.com/leaflet-0.7/images'; 19 | 20 | //////////////////////////////////////////////////////////////////////////////// 21 | var map = global.map = new L.Map('map', {}).setView([22.42658, 114.1452], 11); 22 | 23 | L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { 24 | attribution: '© ' + 25 | 'OpenStreetMap contributors' 26 | }).addTo(map); 27 | 28 | var selectControl = global.control = new L.Control.LineStringSelect({}); 29 | map.addControl(selectControl); 30 | 31 | var layer = global.layer = L.geoJson(data).addTo(map); 32 | layer = layer.getLayers()[0]; 33 | 34 | control.enable({ 35 | feature: layer.feature, 36 | layer: layer 37 | }); 38 | 39 | //////////////////////////////////////////////////////////////////////////////// 40 | 41 | document.querySelector('#reset').addEventListener('click', function() { 42 | control.reset(); 43 | startRange.disabled = true; 44 | endRange.disabled = true; 45 | }); 46 | 47 | //////////////////////////////////////////////////////////////////////////////// 48 | var length = 0, 49 | distances = []; 50 | for (var i = 1, len = layer._latlngs.length; i < len; i++) { 51 | var dist = layer._latlngs[i].distanceTo(layer._latlngs[i - 1]); 52 | distances.push(dist); 53 | length += dist; 54 | } 55 | 56 | function getDistance(marker) { 57 | var d = 0; 58 | for (var i = 0, len = marker.start; i < len; i++) { 59 | d += distances[i]; 60 | } 61 | d += marker.getLatLng() 62 | .distanceTo(layer._latlngs[marker.start]); 63 | 64 | return d; 65 | } 66 | 67 | function getStartDistance() { 68 | return getDistance(control._startMarker); 69 | } 70 | 71 | function getEndDistance() { 72 | return getDistance(control._endMarker); 73 | } 74 | 75 | //////////////////////////////////////////////////////////////////////////////// 76 | 77 | var startRange = document.querySelector('#start-range'); 78 | var startM = document.querySelector('#start'); 79 | 80 | var endRange = document.querySelector('#end-range'); 81 | var endM = document.querySelector('#end'); 82 | 83 | function onStartRangeChange() { 84 | var meters = parseInt(startRange.value * length); 85 | if (endRange.value <= startRange.value) { 86 | endRange.value = startRange.value; 87 | endM.value = meters; 88 | } 89 | start.value = meters; 90 | 91 | control.selectMeters(meters, endM.value); 92 | } 93 | 94 | function onEndRangeChange() { 95 | var meters = parseInt(endRange.value * length); 96 | if (startRange.value >= endRange.value) { 97 | startRange.value = endRange.value; 98 | startM.value = meters; 99 | } 100 | end.value = meters; 101 | 102 | control.selectMeters(startM.value, meters); 103 | } 104 | 105 | startRange.onchange = startRange.oninput = onStartRangeChange; 106 | endRange.onchange = endRange.oninput = onEndRangeChange; 107 | 108 | var textarea = document.querySelector('#geojson'); 109 | control.on('select:start', function() { 110 | var dist = getStartDistance(); 111 | startRange.disabled = false; 112 | startRange.value = dist / length; 113 | startM.value = parseInt(dist); 114 | }); 115 | 116 | control.on('selection', function() { 117 | var dist1 = getStartDistance(); 118 | var dist2 = getEndDistance(); 119 | 120 | //console.log(dist1, startM.value, dist2, endM.value); 121 | 122 | startRange.value = dist1 / length; 123 | endRange.value = dist2 / length; 124 | 125 | startM.value = Math.round(dist1); 126 | endM.value = Math.round(dist2); 127 | 128 | endRange.disabled = false; 129 | textarea.value = jsonFormat(JSON.stringify(control.toGeoJSON())); 130 | }); 131 | 132 | control.on('reset', function() { 133 | startRange.value = endRange.value = 0; 134 | endM.value = startM.value = 0; 135 | textarea.value = ''; 136 | }); 137 | 138 | global.getStartDistance = getStartDistance; 139 | global.getEndDistance = getEndDistance; 140 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # L.Control.LineStringSelect [![npm version](https://badge.fury.io/js/leaflet-linestring-select.svg)](https://badge.fury.io/js/leaflet-linestring-select) [![CircleCI](https://circleci.com/gh/w8r/L.Control.LineStringSelect.svg?style=shield)](https://circleci.com/gh/w8r/L.Control.LineStringSelect) 2 | 3 | ![Screenshot](https://user-images.githubusercontent.com/26884/63355399-5912de00-c366-11e9-9fd9-445d68d4203c.png) 4 | 5 | LineString selection tool: you can select a part or a stretch of a polyline on the map. Performance-oriented, uses [rbush](https://github.com/mourner/rbush/) for segment lookup 6 | 7 | ## [Demo](https://w8r.github.io/L.Control.LineStringSelect) 8 | 9 | Look how this thing deals with a coastline polyline consisting of ~500 points 10 | 11 | [demo](https://w8r.github.io/L.Control.LineStringSelect) 12 | 13 | ## Options 14 | 15 | | Option | type | default value | 16 | | - | - | - | 17 | | `startMarkerClass` | `string` | 'select-marker select-start-marker' | 18 | | `endMarkerClass` | `string` | 'select-marker select-end-marker' | 19 | | `movingMarkerClass` | `string` | 'select-marker select-moving-marker' | 20 | | `name` | `string` | 'leaflet-linestring-select' | 21 | | `lineWeight` | `number` | 4 | 22 | | `lineTolerance` | `number` | `L.Browser.mobile ? 10 : 5` | 23 | | `movingMarkerStyle` | [`L.CircleMarcerOptions`](https://leafletjs.com/reference-1.6.0.html#circlemarker-option) | {
  fillColor: '#fff',
  fillOpacity: 1,
  weight: 2,
  opacity: 0.5,
  color: '#000'
}
| 24 | | `endpointStyle` | [`L.CircleMarcerOptions`](https://leafletjs.com/reference-1.6.0.html#circlemarker-option) | {
  radius: 5,
  color: '#111',
  fillColor: '#fff',
  fillOpacity: 1
}
| 25 | | `selectionStyle` | [`L.PolylineOptions`](https://leafletjs.com/reference-1.6.0.html#polyline-option) | {
  color: '#0ff',
  opacity: 1
} | 26 | | `useTouch` | `boolean` | `L.Browser.mobile` | 27 | | `position` | `'topright'|'topleft'|'bottomleft'|'bottomright'` | `'topright'` | 28 | 29 | ## API 30 | 31 | `.enable({layer: polyline, feature: feature})` 32 | Enables control, initializes it with provided polyline. You can pass GeoJSON object as well, otherwise it will be auto-generated 33 | 34 | `.disable()` 35 | Disable control, remove handlers and selection 36 | 37 | `.reset()` 38 | Reset selection 39 | 40 | `.selectMeters(startMeter, endMeter)` 41 | Select stretch by meter distances from linestring start. 42 | 43 | `.toGeoJSON()` 44 | Returns selection GeoJSON 45 | 46 | `.getSelection()` 47 | Returns array of selection `L.LatLng`s 48 | 49 | ### Events 50 | 51 | `selection` 52 | Selection changed or finished. 53 | 54 | `reset` 55 | Selection cleared 56 | 57 | `select:start : {pos: }` 58 | First point set 59 | 60 | `select:end : {pos: }` 61 | Second point set 62 | 63 | ## Usage 64 | 65 | ```javascript 66 | npm install --save leaflet-linestring-select 67 | ... 68 | var Select = require('leaflet-linestring-select'); 69 | ``` 70 | 71 | or 72 | 73 | ``` 74 | 75 | 76 | ``` 77 | 78 | See `/examples/app.js` for initialization and other things 79 | 80 | ## Requirements 81 | 82 | - `leaflet@>=1.x` 83 | - `rbush@>=3.x` 84 | 85 | 86 | ## License 87 | 88 | The MIT License (MIT) 89 | 90 | Copyright (c) 2019 Alexander Milevski 91 | 92 | Permission is hereby granted, free of charge, to any person obtaining a copy of 93 | this software and associated documentation files (the "Software"), to deal in 94 | the Software without restriction, including without limitation the rights to 95 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 96 | the Software, and to permit persons to whom the Software is furnished to do so, 97 | subject to the following conditions: 98 | 99 | The above copyright notice and this permission notice shall be included in all 100 | copies or substantial portions of the Software. 101 | 102 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 103 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 104 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 105 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 106 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 107 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 108 | -------------------------------------------------------------------------------- /examples/font/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | 5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /src/select.js: -------------------------------------------------------------------------------- 1 | var L = require('leaflet'); 2 | var geometry = require('./geometry'); 3 | var ControlMarker = require('./marker'); 4 | var Endpoint = require('./endpoint'); 5 | var Selection = require('./selection'); 6 | var Rbush = global.Rbush || require('rbush'); 7 | 8 | var START = L.Browser.touch ? 'touchstart mousedown' : 'mousedown'; 9 | 10 | /** 11 | * LineString select control 12 | * 13 | * @class L.Control.LineStringSelect 14 | * @extends {L.Control} 15 | */ 16 | var Select = L.Control.extend( /** @lends Select.prototype */ { 17 | 18 | statics: { 19 | Selection: Selection, 20 | Endpoint: Endpoint, 21 | ControlMarker: ControlMarker 22 | }, 23 | 24 | /** 25 | * @type {Object} 26 | */ 27 | options: { 28 | startMarkerClass: 'select-marker select-start-marker', 29 | endMarkerClass: 'select-marker select-end-marker', 30 | movingMarkerClass: 'select-marker select-moving-marker', 31 | name: 'leaflet-linestring-select', 32 | lineWeight: 4, 33 | lineTolerance: L.Browser.mobile ? 10 : 5, 34 | 35 | // moving(sliding) marker 36 | movingMarkerStyle: { 37 | fillColor: '#fff', 38 | fillOpacity: 1, 39 | weight: 2, 40 | opacity: 0.5, 41 | color: '#000' 42 | }, 43 | 44 | // endpoint 45 | endpointStyle: { 46 | radius: 5, 47 | color: '#111', 48 | fillColor: '#fff', 49 | fillOpacity: 1 50 | }, 51 | 52 | selectionStyle: { 53 | color: '#0ff', 54 | opacity: 1 55 | }, 56 | 57 | useTouch: L.Browser.mobile, 58 | 59 | position: 'topright' // chose your own if you want 60 | }, 61 | 62 | /** 63 | * @param {Object} options 64 | * @constructor 65 | */ 66 | initialize: function(options) { 67 | 68 | options = options || {}; 69 | 70 | /** 71 | * @type {Endpoint} 72 | */ 73 | this._startMarker = null; 74 | 75 | /** 76 | * @type {Endpoint} 77 | */ 78 | this._endMarker = null; 79 | 80 | /** 81 | * @type {Marker} 82 | */ 83 | this._movingMarker = null; 84 | 85 | /** 86 | * @type {Object} 87 | */ 88 | this._feature = null; 89 | 90 | /** 91 | * @type {L.Polyline} 92 | */ 93 | this._layer = null; 94 | 95 | /** 96 | * @type {Selection} 97 | */ 98 | this._selection = null; 99 | 100 | /** 101 | * Mouse pointer tolerance 102 | * @type {L.LatLng} 103 | */ 104 | this._tolerance = null; 105 | 106 | L.Util.setOptions(this, options); 107 | L.Control.prototype.initialize.call(this, this.options); 108 | }, 109 | 110 | /** 111 | * @param {L.Map} map 112 | */ 113 | onAdd: function(map) { 114 | var container = this._container = L.DomUtil.create('div', 115 | this.options.containerClass 116 | ); 117 | L.DomEvent 118 | .disableClickPropagation(container) 119 | .disableScrollPropagation(container); 120 | 121 | return container; 122 | }, 123 | 124 | /** 125 | * @param {L.Map} map 126 | */ 127 | onRemove: function(map) { 128 | this.disable(); 129 | }, 130 | 131 | /** 132 | * Enable selection mode for line string 133 | * @param {Object} options 134 | * @param {L.Polyline} options.layer 135 | * @param {Object} options.feature 136 | * @return {Select} 137 | */ 138 | enable: function(options) { 139 | this._layer = options['layer']; 140 | this._feature = options['feature'] || options['layer'].toGeoJSON(); 141 | 142 | this._createHandles(); 143 | 144 | this._buildTree(); 145 | 146 | this._layer.on('click', this._onLayerClick, this); 147 | 148 | this._map.on('moveend zoomend resize', this._calculatePointerTolerance, this) 149 | .on('mousemove touchmove', this._onMousemove, this) 150 | .on(START, this._onMouseDown, this) 151 | .on('click contextmenu', this._onMapClick, this); 152 | 153 | this._calculatePointerTolerance(); 154 | 155 | return this; 156 | }, 157 | 158 | /** 159 | * Disable selection 160 | * @return {Select} 161 | */ 162 | disable: function() { 163 | this.reset(); 164 | 165 | this._map.removeLayer(this._movingMarker); 166 | this._movingMarker = null; 167 | 168 | this._layer.off('click', this._onLayerClick, this); 169 | 170 | this._map.off('moveend zoomend resize', this._calculatePointerTolerance, this) 171 | .off('mousemove touchmove', this._onMousemove, this) 172 | .off(START, this._onMouseDown, this) 173 | .off('click contextmenu', this._onMapClick, this); 174 | 175 | this._feature = null; 176 | this._layer = null; 177 | 178 | return this; 179 | }, 180 | 181 | /** 182 | * Reset selection 183 | * @return {Select} 184 | */ 185 | reset: function() { 186 | if (this._startMarker) { 187 | this._map.removeLayer(this._startMarker); 188 | this._startMarker = null; 189 | } 190 | 191 | if (this._endMarker) { 192 | this._map.removeLayer(this._endMarker); 193 | this._endMarker = null; 194 | } 195 | 196 | if (this._selection) { 197 | this._map.removeLayer(this._selection); 198 | this._selection = null; 199 | } 200 | 201 | if (this._movingMarker) { 202 | this._movingMarker.setLatLng(this._layer.getLatLngs()[0]); 203 | } 204 | 205 | if (!this.options.useTouch) { 206 | //this._movingMarker.show(); 207 | this._map.addLayer(this._movingMarker); 208 | } 209 | 210 | this.fire('reset'); 211 | 212 | return this; 213 | }, 214 | 215 | /** 216 | * Selection latlngs 217 | * @return {Array.} 218 | */ 219 | getSelection: function() { 220 | if (this._selection) { 221 | return this._selection.getLatLngs(); 222 | } 223 | return null; 224 | }, 225 | 226 | /** 227 | * Selection geoJSON 228 | * @return {Object|Null} 229 | */ 230 | toGeoJSON: function() { 231 | if (this._selection) { 232 | return this._selection.toGeoJSON(); 233 | } 234 | return null; 235 | }, 236 | 237 | /** 238 | * Select from one meter point to another 239 | * @param {Number} startM 240 | * @param {Number} endM 241 | * @return {Select} 242 | */ 243 | selectMeters: function(startM, endM) { 244 | this.reset(); 245 | 246 | if (startM < 0 || endM < 0) { 247 | throw new Error('Can\'t use negative meter values for distance selection'); 248 | } 249 | 250 | var start = this._pointAtM(startM); 251 | var end = this._pointAtM(endM); 252 | 253 | start = this._getNearestPoint(start); 254 | end = this._getNearestPoint(end); 255 | 256 | this._setPoint(start, start.start, start.end); 257 | this._setPoint(end, end.start, end.end); 258 | return this; 259 | }, 260 | 261 | /** 262 | * Replace this method if you want to subclass moving marker 263 | * @param {L.LatLng} pos 264 | * @param {Object} style 265 | * @return {L.Control.LineStringSelect.ControlMarker} 266 | */ 267 | movingMarkerFactory: function(pos, style) { 268 | return new ControlMarker(pos, style); 269 | }, 270 | 271 | /** 272 | * Replace this method if you want to subclass endpoint marker 273 | * @param {L.LatLng} pos 274 | * @param {Object} style 275 | * @param {Boolean} isEnd 276 | * @return {L.Control.LineStringSelect.Endpoint} 277 | */ 278 | endpointFactory: function(pos, style, isEnd) { 279 | return new Endpoint(pos, style); 280 | }, 281 | 282 | /** 283 | * Craetes a selection polyline. Replace or extend if you want 284 | * to subclass selection polyline 285 | * @param {Array.} coords 286 | * @param {Object} style 287 | * @param {L.Polyline} layer 288 | * @return {L.Control.LineStringSelect.Selection} 289 | */ 290 | selectionFactory: function(coords, style, layer) { 291 | return new Selection(coords, style, layer); 292 | }, 293 | 294 | /** 295 | * Calculate distance in meters from one point to another 296 | * 297 | * @param {Array.} A 298 | * @param {Array.} B 299 | * @return {Number} 300 | */ 301 | _distance: function(A, B) { 302 | if (this.options.distance) { 303 | return this.options.distance(A, B); 304 | } else { 305 | return new L.LatLng(A[1], A[0]).distanceTo(new L.LatLng(B[1], B[0])); 306 | } 307 | }, 308 | 309 | /** 310 | * Projected point from GeoJSON 311 | * 312 | * @param {Array.} coord 313 | * @return {Array.} 314 | */ 315 | _getProjectedPoint: function(coord) { 316 | if (this.options.getProjectedPoint) { 317 | return this.options.getProjectedPoint.call(this, coord); 318 | } 319 | coord = this._map.options.crs.latLngToPoint(new L.LatLng(coord[1], coord[0]), this._map.getMaxZoom()); 320 | return [coord.x, coord.y]; 321 | }, 322 | 323 | /** 324 | * Point on segment, `m` meters from the start 325 | * @param {Array.} start 326 | * @param {Array.} end 327 | * @param {Number} m 328 | * @return {Array.} 329 | */ 330 | _pointAtSegmentM: function(start, end, m) { 331 | var length = this._distance(start, end); 332 | 333 | start = this._getProjectedPoint(start); 334 | end = this._getProjectedPoint(end); 335 | 336 | var coords = geometry.pointOnSegment(start, end, m, length); 337 | return L.point(coords); 338 | }, 339 | 340 | /** 341 | * Point at `m` mark on the linestring 342 | * @param {Number} m 343 | * @return {L.LatLng} 344 | */ 345 | _pointAtM: function(m) { 346 | var coords = this._feature.geometry.coordinates; 347 | var dist = 0; 348 | var point, i, len; 349 | 350 | for (i = 1, len = coords.length; i < len; i++) { 351 | var segmentLength = this._distance(coords[i - 1], coords[i]); 352 | if (dist + segmentLength <= m) { 353 | dist += segmentLength; 354 | } else { 355 | break; 356 | } 357 | } 358 | 359 | if (dist === m || i === coords.length) { 360 | point = coords[i - 1]; 361 | return new L.LatLng(point[1], point[0]); 362 | } 363 | 364 | point = this._pointAtSegmentM(coords[i - 1], coords[i], m - dist); 365 | return this._map.options.crs.pointToLatLng(point, this._map.getMaxZoom()); 366 | }, 367 | 368 | /** 369 | * Calculates buffer zone around pointer. 370 | * If map state changes it has to be recalculated in order 371 | * to maintain precision 372 | */ 373 | _calculatePointerTolerance: function() { 374 | var center = this._map.getCenter(); 375 | var shift = this.options.lineWeight * 0.5 + this.options.lineTolerance; 376 | var shifted = this._map.layerPointToLatLng( 377 | this._map.latLngToLayerPoint(center) 378 | .add(new L.Point(shift, shift))); 379 | 380 | this._tolerance = new L.LatLng( 381 | Math.abs(center.lat - shifted.lat), 382 | Math.abs(center.lng - shifted.lng) 383 | ); 384 | }, 385 | 386 | /** 387 | * Control handles 388 | */ 389 | _createHandles: function() { 390 | var pos = L.latLng(this._layer.getLatLngs()[0]); 391 | var style = this.options.movingMarkerStyle; 392 | 393 | style.radius = this.options.lineTolerance; 394 | style.className = this.options.movingMarkerClass; 395 | 396 | this._movingMarker = this.movingMarkerFactory(pos, style).addTo(this._map); 397 | this._movingMarker.on('click', this._onMovingMarkerClick, this); 398 | 399 | if (this.options.useTouch) { 400 | //this._movingMarker.hide(); 401 | this._map.removeLayer(this._movingMarker); 402 | } 403 | }, 404 | 405 | /** 406 | * @param {Object} evt 407 | */ 408 | _onMovingMarkerClick: function(evt) { 409 | L.DomEvent.stopPropagation(evt); 410 | this._setPoint(this._movingMarker.getLatLng(), 411 | this._movingMarker.start, 412 | this._movingMarker.end); 413 | }, 414 | 415 | /** 416 | * No moving marker on touch device 417 | * @param {L.MouseEvent} evt 418 | */ 419 | _onLayerClick: function(evt) { 420 | var coords = this._getNearestPoint(evt.latlng); 421 | if (coords) { 422 | this._setPoint(L.latLng(coords), coords.start, coords.end); 423 | } else { 424 | this._setPoint(evt.latlng); 425 | } 426 | }, 427 | 428 | /** 429 | * Map clicked, if near the moving point - set endpoint 430 | * @param {L.MouseEvent} evt 431 | */ 432 | _onMapClick: function(evt) { 433 | if (!this._endMarker) { 434 | var pos = this._map.latLngToLayerPoint(evt.latlng); 435 | var coords = this._movingMarker.getLatLng(); 436 | 437 | if (this.options.useTouch) { // no mousemove, try and move marker here 438 | var nearest = this._getNearestPoint(evt.latlng); 439 | if (nearest) { 440 | coords = L.latLng(nearest); 441 | this._movingMarker.setLatLng(coords); 442 | } 443 | } 444 | 445 | var mPos = this._map.latLngToLayerPoint(coords); 446 | var distance = geometry.distance([pos.x, pos.y], [mPos.x, mPos.y]); 447 | 448 | if (distance <= this.options.lineTolerance * 2) { 449 | coords = this._getNearestPoint(coords); 450 | this._setPoint(coords, coords.start, coords.end); 451 | } 452 | } 453 | }, 454 | 455 | /** 456 | * @param {Object} evt 457 | */ 458 | _setPoint: function(pos, start, end) { 459 | var style = this.options.endpointStyle; 460 | if (!this._startMarker) { 461 | style.className = this.options.startMarkerClass; 462 | 463 | this._startMarker = this.endpointFactory(pos, style, false).addTo(this._map); 464 | // this._startMarker.on('mouseover', this._movingMarker.hide, this._movingMarker) 465 | // .on('mouseout', this._movingMarker.show, this._movingMarker); 466 | this._startMarker.start = start; 467 | this._startMarker.end = end; 468 | 469 | this.fire('select:start', { 470 | latlng: pos 471 | }); 472 | } else if (!this._endMarker) { 473 | style.className = this.options.endMarkerClass; 474 | this._endMarker = this.endpointFactory(pos, style, true).addTo(this._map); 475 | // this._endMarker.on('mouseover', this._movingMarker.hide, this._movingMarker) 476 | // .on('mouseout', this._movingMarker.show, this._movingMarker); 477 | 478 | this._endMarker.start = start; 479 | this._endMarker.end = end; 480 | 481 | //this._map.off('mousemove', this._onMousemove, this); 482 | //this._movingMarker.hide(); 483 | this._map.removeLayer(this._movingMarker); 484 | this.fire('select:end', { 485 | latlng: pos 486 | }); 487 | if (this._startMarker && this._endMarker) { 488 | this._onSelect(); 489 | } 490 | } 491 | }, 492 | 493 | /** 494 | * Mouse pointer bounds 495 | * @param {L.LatLng} latlng 496 | * @return {Array.>} 497 | */ 498 | _getPointerBounds: function(latlng) { 499 | var tx = this._tolerance.lng, 500 | ty = this._tolerance.lat; 501 | 502 | return { 503 | minY: latlng.lat - ty, minX: latlng.lng - tx, 504 | maxY: latlng.lat + ty, maxX: latlng.lng + tx 505 | }; 506 | }, 507 | 508 | /** 509 | * Check if user tries to drag a handle 510 | * @param {Object} evt 511 | */ 512 | _onMouseDown: function(evt) { 513 | var target = (evt['originalEvent'].target || evt['originalEvent'].srcElement); 514 | 515 | if (this.options.useTouch) { 516 | var point; 517 | if (this._startMarker) { 518 | point = this._map.latLngToContainerPoint(this._startMarker.getLatLng()); 519 | if (geometry.distance( 520 | [evt.containerPoint.x, evt.containerPoint.y], [point.x, point.y] 521 | ) <= this.options.lineTolerance * 2) { 522 | //this._startMarker._onMouseOver(); 523 | target = this._startMarker._path; 524 | } 525 | } 526 | if (this._endMarker) { 527 | point = this._map.latLngToContainerPoint(this._endMarker.getLatLng()); 528 | if (geometry.distance( 529 | [evt.containerPoint.x, evt.containerPoint.y], [point.x, point.y] 530 | ) <= this.options.lineTolerance * 2) { 531 | //this._endMarker._onMouseOver(); 532 | target = this._endMarker._path; 533 | } 534 | } 535 | } 536 | 537 | if (this._startMarker && this._startMarker._path === target) { 538 | this._dragging = this._startMarker; 539 | this._static = this._endMarker; 540 | } else if (this._endMarker && this._endMarker._path === target) { 541 | this._dragging = this._endMarker; 542 | this._static = this._startMarker; 543 | } 544 | 545 | if (this._dragging) { 546 | L.DomEvent.stop(evt); 547 | this._dragging._dragging = true; 548 | 549 | L.Draggable._disabled = true; 550 | this._map.dragging.disable(); 551 | 552 | this._map.once('mouseup', this._stopHandlerDrag, this); 553 | } 554 | }, 555 | 556 | /** 557 | * Clears drag handlers 558 | * @param {L.MouseEvent} evt 559 | */ 560 | _stopHandlerDrag: function(evt) { 561 | if (this._dragging) { 562 | global.clearTimeout(this._dragTimer); 563 | 564 | L.Draggable._disabled = false; 565 | this._map.dragging.enable(); 566 | 567 | this._dragging._dragging = null; 568 | this._dragging = null; 569 | this._onDragStopped(this._dragging, evt.latlng); 570 | } 571 | }, 572 | 573 | /** 574 | * @param {Endpoint} handle 575 | * @param {L.LatLng} coords 576 | */ 577 | _onDragStopped: function(handle, coords) { 578 | if (this._startMarker && this._endMarker) { 579 | this._onSelect(); 580 | } 581 | }, 582 | 583 | /** 584 | * Ensures that the startpoint would be before endpoint 585 | */ 586 | _checkEndPoints: function() { 587 | if (this._startMarker.start > this._endMarker.start) { 588 | var swap = this._startMarker; 589 | this._startMarker = this._endMarker; 590 | this._endMarker = swap; 591 | } 592 | }, 593 | 594 | /** 595 | * Selection event, show selected polyline 596 | */ 597 | _onSelect: function() { 598 | this._checkEndPoints(); 599 | 600 | var start = this._startMarker.end; 601 | var end = this._endMarker.start; 602 | var coords = this._layer._latlngs.slice(start, end + 1); 603 | 604 | coords.unshift(this._startMarker.getLatLng()); 605 | coords.push(this._endMarker.getLatLng()); 606 | 607 | if (!this._selection) { 608 | this._selection = this.selectionFactory( 609 | coords, 610 | this.options.selectionStyle, 611 | this._layer 612 | ).addTo(this._map); 613 | 614 | // markers should be above the selection 615 | this._startMarker.bringToFront(); 616 | this._endMarker.bringToFront(); 617 | } else { 618 | this._selection._latlngs = coords; 619 | this._selection.updatePathFromSource( 620 | this._startMarker.end, 621 | this._endMarker.start 622 | ); 623 | } 624 | this.fire('selection'); 625 | }, 626 | 627 | /** 628 | * Mouse move: follow the path with the moving marker or drag 629 | * 630 | * @param {L.MouseEvent} evt 631 | */ 632 | _onMousemove: function(evt) { 633 | var coords = this._getNearestPoint(evt.latlng); 634 | if (this._dragging) { 635 | if (coords) { 636 | this._dragging.start = coords.start; 637 | this._dragging.end = coords.end; 638 | this._dragging.setLatLng(coords); 639 | } 640 | if (this._startMarker && this._endMarker) { 641 | this._onSelect(); 642 | } 643 | global.clearTimeout(this._dragTimer); 644 | this._dragTimer = global.setTimeout(this._stopHandlerDrag.bind(this, evt), 750); 645 | } else { 646 | if (coords) { 647 | this._movingMarker.setLatLng(coords); 648 | this._movingMarker.start = coords.start; 649 | this._movingMarker.end = coords.end; 650 | } 651 | } 652 | }, 653 | 654 | /** 655 | * Fin nearest point on the line string. 656 | * 1. search RTree of segments 657 | * 2. calculate nearest segment 658 | * 3. , then the point on it 659 | * 660 | * @param {L.LatLng} latlng 661 | * @param {L.LatLng} tolerance 662 | * @return {Array.} 663 | */ 664 | _getNearestPoint: function(latlng, tolerance) { 665 | var coords = this._getPointerBounds(latlng, tolerance); 666 | 667 | ////// visual debug 668 | // if (!this._m) { 669 | // this._m = new L.Rectangle(coords, { 670 | // weight: 2, 671 | // fillOpacity: 0 672 | // }).addTo(this._map); 673 | // this._m.bringToBack(); 674 | // } else { 675 | // this._m.setBounds(coords); 676 | // } 677 | ////// visual debug 678 | 679 | var boxes = this._tree.search(coords); 680 | 681 | if (boxes.length !== 0) { 682 | var fcoords = this._feature.geometry.coordinates; 683 | var d = Number.MAX_VALUE; 684 | var pos = [latlng.lng, latlng.lat]; 685 | var startIndex = boxes[0].start; 686 | var endIndex = boxes[0].end; 687 | var start = fcoords[startIndex]; 688 | var end = fcoords[endIndex]; 689 | 690 | if (boxes.length > 1) { // avoid distance calculation 691 | for (var i = 0, len = boxes.length; i < len; i++) { 692 | var box = boxes[i]; 693 | var A = fcoords[box.start]; 694 | var B = fcoords[box.end]; 695 | var dist = geometry.pointSegmentDistance(pos, A, B); 696 | 697 | if (dist < d) { 698 | d = dist; 699 | start = A; 700 | end = B; 701 | startIndex = box.start; 702 | endIndex = box.end; 703 | } 704 | } 705 | } 706 | 707 | pos = geometry.closestPointOnSegment(pos, start, end); 708 | pos = [pos[1], pos[0]]; 709 | pos.start = startIndex; 710 | pos.end = endIndex; 711 | 712 | return pos; 713 | } else { 714 | return null; 715 | } 716 | }, 717 | 718 | /** 719 | * Builds R-Tree for the feature 720 | */ 721 | _buildTree: function() { 722 | var coords = this._feature.geometry.coordinates, 723 | data = []; 724 | 725 | if (this._tree) { 726 | this._tree.clear(); 727 | } else { 728 | this._tree = new Rbush(16); 729 | } 730 | 731 | for (var i = 1, len = coords.length; i < len; i++) { 732 | var obj = this._toTreeNode(coords[i - 1], coords[i]); 733 | obj.start = i - 1; 734 | obj.end = i; 735 | data.push(obj); 736 | } 737 | this._tree.load(data); 738 | }, 739 | 740 | /** 741 | * Two points to BBOX node for RBush 742 | * 743 | * @param {Array.} a 744 | * @param {Array.} b 745 | * @return {Array.} 746 | */ 747 | _toTreeNode: function(a, b) { 748 | var xmin = a[0], 749 | xmax = b[0], 750 | ymin = a[1], 751 | ymax = b[1]; 752 | 753 | if (xmin > xmax) { 754 | xmax = a[0]; 755 | xmin = b[0]; 756 | } 757 | 758 | if (ymin > ymax) { 759 | ymax = a[1]; 760 | ymin = b[1]; 761 | } 762 | 763 | return { minX: xmin, minY: ymin, maxX: xmax, maxY: ymax }; 764 | } 765 | 766 | }); 767 | 768 | L.Util.extend(Select.prototype, L.Evented.prototype); 769 | 770 | module.exports = Select; 771 | -------------------------------------------------------------------------------- /examples/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Feature", 3 | "properties": {}, 4 | "geometry": { 5 | "type": "LineString", 6 | "coordinates": [ 7 | [114.29053795700017, 22.28794993700008], 8 | [114.28976484500015, 22.287563381000112], 9 | [114.28899173300013, 22.287176825000145], 10 | [114.2893579440001, 22.28443024300013], 11 | [114.28972415500007, 22.281683661000116], 12 | [114.28964277450007, 22.277797756000126], 13 | [114.28956139400006, 22.273911851000136], 14 | [114.29481041750006, 22.27547842000007], 15 | [114.30005944100006, 22.277044989], 16 | [114.3016056650001, 22.273118394000022], 17 | [114.30315188900013, 22.26919179900004], 18 | [114.30315188900013, 22.26567210500005], 19 | [114.30315188900013, 22.26215241100006], 20 | [114.29993737050009, 22.260219631000055], 21 | [114.29672285200004, 22.25828685100005], 22 | [114.29285729250009, 22.26144033400007], 23 | [114.28899173300013, 22.26459381700009], 24 | [114.2836613290001, 22.267523504500105], 25 | [114.27833092500006, 22.27045319200012], 26 | [114.27906334700015, 22.274908758500132], 27 | [114.27979576900023, 22.279364325000145], 28 | [114.27658125100018, 22.287563381000112], 29 | [114.27336673300013, 22.29576243700008], 30 | [114.26909427200016, 22.29885488500011], 31 | [114.26482181100019, 22.301947333000143], 32 | [114.26522871200021, 22.305873928000125], 33 | [114.26563561300023, 22.309800523000106], 34 | [114.26600182400014, 22.312892971000096], 35 | [114.26636803500006, 22.315985419000086], 36 | [114.26095625100007, 22.31915924700006], 37 | [114.25554446700008, 22.32233307500003], 38 | [114.2535099620001, 22.313747463000016], 39 | [114.25147545700011, 22.305161851], 40 | [114.25224856900007, 22.30046214400004], 41 | [114.25302168100004, 22.29576243700008], 42 | [114.24598229300011, 22.288723049000097], 43 | [114.23894290500019, 22.281683661000116], 44 | [114.2335311210002, 22.286769924000097], 45 | [114.22811933700021, 22.29185618700008], 46 | [114.2199406260001, 22.30121491100006], 47 | [114.21176191499998, 22.31057363500004], 48 | [114.21330813900002, 22.30587392800004], 49 | [114.21485436300006, 22.30117422100004], 50 | [114.21367435000013, 22.30117422100004], 51 | [114.21249433700021, 22.30117422100004], 52 | [114.20399010500014, 22.309719143000052], 53 | [114.19548587300008, 22.318264065000065], 54 | [114.19100996150016, 22.31350332250007], 55 | [114.18653405000023, 22.30874258000007], 56 | [114.18897545650017, 22.305344956500107], 57 | [114.19141686300011, 22.301947333000143], 58 | [114.19141686300011, 22.300421454000144], 59 | [114.19141686300011, 22.298895575000145], 60 | [114.1875513030001, 22.300421454000144], 61 | [114.1836857430001, 22.301947333000143], 62 | [114.18266849050013, 22.29818349850015], 63 | [114.18165123800017, 22.29441966400016], 64 | [114.17908776150011, 22.292751369500152], 65 | [114.17652428500006, 22.291083075000145], 66 | [114.17420494900009, 22.28990306200008], 67 | [114.17188561300011, 22.288723049000012], 68 | [114.16956627700014, 22.29144928600003], 69 | [114.16724694100017, 22.29417552300005], 70 | [114.16773522250017, 22.29983144750004], 71 | [114.16822350400017, 22.30548737200003], 72 | [114.16696211050012, 22.308030503500035], 73 | [114.16570071700008, 22.31057363500004], 74 | [114.16529381600012, 22.312892971000096], 75 | [114.16488691500015, 22.315212307000152], 76 | [114.16220136800013, 22.315212307000152], 77 | [114.1595158210001, 22.315212307000152], 78 | [114.1595158210001, 22.3187320010001], 79 | [114.1595158210001, 22.32225169500005], 80 | [114.15585371150013, 22.325384833000072], 81 | [114.15219160200016, 22.328517971000096], 82 | [114.14519290450014, 22.33226146050012], 83 | [114.13819420700011, 22.336004950000145], 84 | [114.13127688900008, 22.33911774300013], 85 | [114.12435957100004, 22.342230536000116], 86 | [114.12395267000008, 22.339687404500058], 87 | [114.12354576900012, 22.337144273], 88 | [114.11845950600008, 22.344916083], 89 | [114.11337324300004, 22.352687893], 90 | [114.11219323000012, 22.359320380000064], 91 | [114.11101321700019, 22.365952867000132], 92 | [114.10792076900012, 22.367905992000132], 93 | [114.10482832100004, 22.369859117000132], 94 | [114.10116621150004, 22.36644114800012], 95 | [114.09750410200004, 22.36302317900011], 96 | [114.08830813850005, 22.36448802300012], 97 | [114.07911217500006, 22.365952867000132], 98 | [114.07870527400007, 22.364406643000137], 99 | [114.07829837300008, 22.362860419000143], 100 | [114.07435143300015, 22.362860419000143], 101 | [114.07040449300021, 22.362860419000143], 102 | [114.06881757900018, 22.36092763900014], 103 | [114.06723066500015, 22.358994859000134], 104 | [114.06259199300007, 22.36015452700012], 105 | [114.05795332099999, 22.361314195000105], 106 | [114.05408776099998, 22.36015452700012], 107 | [114.05022220099997, 22.358994859000134], 108 | [114.04505455800006, 22.357001044000143], 109 | [114.03988691500015, 22.35500722900015], 110 | [114.0302026700002, 22.352687893000095], 111 | [114.02051842500023, 22.35036855700004], 112 | [114.01775149800014, 22.351914781000076], 113 | [114.01498457100004, 22.353461005000113], 114 | [114.01498457100004, 22.356227932000124], 115 | [114.01498457100004, 22.358994859000134], 116 | [114.00680586000013, 22.358994859000134], 117 | [113.99862714900021, 22.358994859000134], 118 | [113.99524987050015, 22.36153799050014], 119 | [113.99187259200008, 22.364081122000144], 120 | [113.98727461050004, 22.3654238955001], 121 | [113.982676629, 22.366766669000057], 122 | [113.97970625100004, 22.3729922550001], 123 | [113.97673587300008, 22.37921784100014], 124 | [113.97482343850012, 22.379604397000108], 125 | [113.97291100400017, 22.379990953000075], 126 | [113.97177168100012, 22.383530992000104], 127 | [113.97063235800007, 22.387071031000133], 128 | [113.96749922000015, 22.383876857500127], 129 | [113.96436608200023, 22.38068268400012], 130 | [113.96949303500014, 22.376369533000116], 131 | [113.97461998800006, 22.37205638200011], 132 | [113.96477298250005, 22.37095774950012], 133 | [113.95492597700004, 22.369859117000132], 134 | [113.94988040450005, 22.365973212000128], 135 | [113.94483483200005, 22.362087307000124], 136 | [113.93775475350014, 22.365586656000062], 137 | [113.93067467500023, 22.369086005], 138 | [113.92831464900013, 22.369086005], 139 | [113.92595462300002, 22.369086005], 140 | [113.92017662850003, 22.372605699000033], 141 | [113.91439863400004, 22.376125393000066], 142 | [113.91635175900004, 22.381984768000066], 143 | [113.91830488400004, 22.387844143000066], 144 | [113.91443932400006, 22.39325592650006], 145 | [113.91057376400008, 22.398667710000055], 146 | [113.90377851650015, 22.403713283000044], 147 | [113.89698326900023, 22.408758856000034], 148 | [113.90320885500014, 22.413682358500083], 149 | [113.90943444100006, 22.41860586100013], 150 | [113.92005455800015, 22.419216213000098], 151 | [113.93067467500023, 22.419826565000065], 152 | [113.93584231850014, 22.423305568500055], 153 | [113.94100996200004, 22.426784572000045], 154 | [113.94756106850008, 22.43813711150007], 155 | [113.95411217500012, 22.449489651000093], 156 | [113.96583092500012, 22.45416901250006], 157 | [113.97754967500012, 22.458848374000027], 158 | [113.98808841200017, 22.47370026250009], 159 | [113.99862714900021, 22.48855215100015], 160 | [114.0017602870002, 22.48855215100015], 161 | [114.00489342500018, 22.48855215100015], 162 | [114.0087996750002, 22.48733144750014], 163 | [114.01270592500023, 22.48611074400013], 164 | [114.01221764400015, 22.48307933150008], 165 | [114.01172936300006, 22.48004791900003], 166 | [114.01144453200004, 22.476467189500013], 167 | [114.01115970100003, 22.47288646], 168 | [114.01307213600003, 22.47404612800007], 169 | [114.01498457100004, 22.47520579600014], 170 | [114.02088463600003, 22.47673167500014], 171 | [114.02678470100003, 22.478257554000137], 172 | [114.02833092500006, 22.478257554000137], 173 | [114.0298771490001, 22.478257554000137], 174 | [114.03065026100012, 22.48025136900013], 175 | [114.03142337300014, 22.48224518400012], 176 | [114.03101647200009, 22.484951076000144], 177 | [114.03060957100004, 22.487656968000167], 178 | [114.03060957100004, 22.491583563000148], 179 | [114.03060957100004, 22.49551015800013], 180 | [114.03642825600002, 22.498256740000144], 181 | [114.042246941, 22.50100332200016], 182 | [114.050100131, 22.502936102000078], 183 | [114.05795332099999, 22.504868882], 184 | [114.05986575600005, 22.50682200700004], 185 | [114.06177819100012, 22.508775132000082], 186 | [114.06377200600011, 22.51231517100011], 187 | [114.0657658210001, 22.51585521000014], 188 | [114.06963138100014, 22.517014878000126], 189 | [114.07349694100017, 22.51817454600011], 190 | [114.07589765700013, 22.51894765800013], 191 | [114.07829837300008, 22.51972077000015], 192 | [114.08179772200012, 22.521328029500125], 193 | [114.08529707100016, 22.522935289000102], 194 | [114.08383222750015, 22.52614980700011], 195 | [114.08236738400015, 22.529364325000117], 196 | [114.08691593100016, 22.531876122000057], 197 | [114.09146447800018, 22.534387919], 198 | [114.0999394125001, 22.534387919], 199 | [114.10841434700004, 22.534387919], 200 | [114.11120487450003, 22.531597391500043], 201 | [114.11399540200003, 22.52880686400009], 202 | [114.1155456950001, 22.528186747000063], 203 | [114.11709598800016, 22.527566630000038], 204 | [114.12298710100012, 22.53283762650007], 205 | [114.12887821400008, 22.5381086230001], 206 | [114.13352909300013, 22.538728740000124], 207 | [114.13817997200019, 22.53934885700015], 208 | [114.14345096850013, 22.538728740000124], 209 | [114.14872196500008, 22.5381086230001], 210 | [114.15130578700015, 22.54498158850012], 211 | [114.15388960900023, 22.551854554000144], 212 | [114.1579203705002, 22.556195374000126], 213 | [114.16195113200015, 22.560536194000107], 214 | [114.16758426650017, 22.562241113000084], 215 | [114.17321740100019, 22.56394603200006], 216 | [114.17812625850019, 22.560070703000093], 217 | [114.18303511600018, 22.556195374000126], 218 | [114.19145837450017, 22.556195374000126], 219 | [114.19988163300016, 22.556195374000126], 220 | [114.21029768550014, 22.555658267500093], 221 | [114.22071373800011, 22.55512116100006], 222 | [114.22527102950008, 22.555467027000077], 223 | [114.22982832100004, 22.555812893000095], 224 | [114.23226972750001, 22.555995998500094], 225 | [114.23471113399998, 22.556179104000094], 226 | [114.23096764450005, 22.551621812000064], 227 | [114.22722415500013, 22.547064520000035], 228 | [114.22470136850009, 22.544256903000075], 229 | [114.22217858200005, 22.541449286000116], 230 | [114.21851647250006, 22.537970282000074], 231 | [114.21485436300006, 22.534491278000033], 232 | [114.21241295650009, 22.534491278000033], 233 | [114.20997155000012, 22.534491278000033], 234 | [114.20964602950014, 22.529099839500077], 235 | [114.20932050900015, 22.52370840100012], 236 | [114.21363366000011, 22.524868068500098], 237 | [114.21794681100008, 22.526027736000074], 238 | [114.21831302200007, 22.527940171000083], 239 | [114.21867923300007, 22.52985260600009], 240 | [114.22453860800013, 22.531398830000043], 241 | [114.23039798300019, 22.532945054], 242 | [114.23235110800022, 22.534938869000072], 243 | [114.23430423300024, 22.53693268400015], 244 | [114.23816979250017, 22.543565171000125], 245 | [114.2420353520001, 22.5501976580001], 246 | [114.2439884770001, 22.55058421400005], 247 | [114.2459416020001, 22.55097077], 248 | [114.24748782600014, 22.54940420100007], 249 | [114.24903405000018, 22.54783763200014], 250 | [114.25180097750018, 22.54940420100007], 251 | [114.25456790500019, 22.55097077], 252 | [114.25611412850017, 22.54940420100007], 253 | [114.25766035200016, 22.54783763200014], 254 | [114.25546308650007, 22.543646551500103], 255 | [114.25326582099999, 22.539455471000068], 256 | [114.2562361985, 22.540126857500113], 257 | [114.25920657600003, 22.540798244000158], 258 | [114.26242109450013, 22.538031317000147], 259 | [114.26563561300023, 22.535264390000137], 260 | [114.26539147250023, 22.531866766500087], 261 | [114.26514733200023, 22.528469143000038], 262 | [114.26758873800017, 22.527024644000065], 263 | [114.27003014400012, 22.52558014500009], 264 | [114.2740177745001, 22.52771637550009], 265 | [114.27800540500007, 22.52985260600009], 266 | [114.27890058700015, 22.527940171000083], 267 | [114.27979576900023, 22.526027736000074], 268 | [114.27979576900023, 22.52287425300011], 269 | [114.27979576900023, 22.51972077000015], 270 | [114.27873782650019, 22.51569245000009], 271 | [114.27767988400015, 22.511664130000028], 272 | [114.28142337350013, 22.511419989000075], 273 | [114.28516686300011, 22.51117584800012], 274 | [114.2872013680001, 22.508185125500106], 275 | [114.28923587300008, 22.50519440300009], 276 | [114.29387454500014, 22.503098862500124], 277 | [114.29851321700019, 22.50100332200016], 278 | [114.31255130300016, 22.50488922700012], 279 | [114.32658938900013, 22.508775132000082], 280 | [114.32968183700015, 22.51036204600011], 281 | [114.33277428500017, 22.51194896000014], 282 | [114.3339542980001, 22.509182033000087], 283 | [114.33513431100002, 22.506415106000034], 284 | [114.32573489700005, 22.49939606300005], 285 | [114.31633548300007, 22.492377020000063], 286 | [114.31088300900004, 22.48769765800006], 287 | [114.305430535, 22.483018296000054], 288 | [114.29953047000004, 22.480637925000096], 289 | [114.29363040500007, 22.478257554000137], 290 | [114.28703860800013, 22.475572007000068], 291 | [114.28044681100019, 22.47288646], 292 | [114.27458743600019, 22.468959865000002], 293 | [114.26872806100019, 22.46503327], 294 | [114.26640872500019, 22.461554266000046], 295 | [114.26408938900019, 22.458075262000094], 296 | [114.25892174550017, 22.45492177900013], 297 | [114.25375410200016, 22.451768296000168], 298 | [114.24984785200013, 22.451768296000168], 299 | [114.2459416020001, 22.451768296000168], 300 | [114.23857669350014, 22.46078115400013], 301 | [114.23121178500017, 22.469794012000094], 302 | [114.22417239700016, 22.46857330900012], 303 | [114.21713300900015, 22.467352606000148], 304 | [114.21444746200007, 22.468959865000087], 305 | [114.21176191499998, 22.470567124000027], 306 | [114.21054121200007, 22.46818675300007], 307 | [114.20932050900015, 22.46580638200011], 308 | [114.2101343110001, 22.4615542665001], 309 | [114.21094811300006, 22.457302151000093], 310 | [114.21326744900003, 22.456142483000107], 311 | [114.215586785, 22.454982815000122], 312 | [114.21635989700007, 22.45146312100009], 313 | [114.21713300900015, 22.447943427000055], 314 | [114.21355227950014, 22.448716539000074], 315 | [114.20997155000012, 22.449489651000093], 316 | [114.20964602950014, 22.451788641500116], 317 | [114.20932050900015, 22.45408763200014], 318 | [114.20578047000012, 22.456081447000116], 319 | [114.20224043100009, 22.458075262000094], 320 | [114.19642174600014, 22.457302150500126], 321 | [114.19060306100019, 22.45652903900016], 322 | [114.18864993600019, 22.454148667500164], 323 | [114.18669681100019, 22.451768296000168], 324 | [114.17709394650021, 22.4499168965001], 325 | [114.16749108200023, 22.44806549700003], 326 | [114.17200768350014, 22.445644435500085], 327 | [114.17652428500006, 22.44322337400014], 328 | [114.18201744900009, 22.43968333500011], 329 | [114.18751061300011, 22.436143296000083], 330 | [114.19385826900015, 22.4321556660001], 331 | [114.20020592500018, 22.428168036000116], 332 | [114.20598392000008, 22.424383856500057], 333 | [114.21176191499998, 22.420599677], 334 | [114.21086673250005, 22.41667308150005], 335 | [114.20997155000012, 22.412746486000103], 336 | [114.21241295650009, 22.41081370650005], 337 | [114.21485436300006, 22.408880927], 338 | [114.2120874360001, 22.403774318500027], 339 | [114.20932050900015, 22.398667710000055], 340 | [114.21245364700007, 22.39950185750007], 341 | [114.215586785, 22.400336005000085], 342 | [114.21949303500006, 22.407680568500083], 343 | [114.22339928500011, 22.415025132000082], 344 | [114.22881106850005, 22.4198875995001], 345 | [114.23422285199999, 22.42475006700012], 346 | [114.23621666750012, 22.430060125500134], 347 | [114.23821048300024, 22.43537018400015], 348 | [114.24101810000016, 22.43545156450014], 349 | [114.24382571700008, 22.435532945000134], 350 | [114.2476505870001, 22.433132228500085], 351 | [114.25147545700011, 22.430731512000037], 352 | [114.2593286470001, 22.430731512000037], 353 | [114.2671818370001, 22.430731512000037], 354 | [114.26828046950013, 22.428127345500044], 355 | [114.26937910200016, 22.425523179000052], 356 | [114.26828046950013, 22.420742092000054], 357 | [114.2671818370001, 22.415961005000057], 358 | [114.26986738400015, 22.41280752200008], 359 | [114.2725529310002, 22.409654039000102], 360 | [114.2745060560002, 22.414740302000084], 361 | [114.2764591810002, 22.419826565000065], 362 | [114.28272545700017, 22.42291901250009], 363 | [114.28899173300013, 22.42601146000011], 364 | [114.28272545700017, 22.435003973000093], 365 | [114.2764591810002, 22.443996486000074], 366 | [114.28272545700017, 22.448655503000037], 367 | [114.28899173300013, 22.45331452], 368 | [114.29529869900006, 22.45492177950008], 369 | [114.30160566499998, 22.45652903900016], 370 | [114.30119876400005, 22.46078115450008], 371 | [114.30079186300011, 22.46503327], 372 | [114.31226647250008, 22.472540594500014], 373 | [114.32374108200005, 22.48004791900003], 374 | [114.32439212350008, 22.477626857500084], 375 | [114.3250431650001, 22.47520579600014], 376 | [114.32789147250008, 22.47465648000012], 377 | [114.33073978000007, 22.474107164000102], 378 | [114.32789147250008, 22.469183661000088], 379 | [114.3250431650001, 22.464260158000073], 380 | [114.33037356850005, 22.46299876500011], 381 | [114.335703972, 22.461737372000144], 382 | [114.33688398500004, 22.454046942000133], 383 | [114.33806399800008, 22.446356512000122], 384 | [114.33541914150013, 22.443182684000107], 385 | [114.33277428500017, 22.44000885600009], 386 | [114.33509362100014, 22.435797430500116], 387 | [114.33741295700011, 22.431586005000142], 388 | [114.34009850350014, 22.43463776250013], 389 | [114.34278405000018, 22.43768952000012], 390 | [114.34518476650021, 22.43030426600008], 391 | [114.34758548300024, 22.422919012000037], 392 | [114.34994550900021, 22.423305568000103], 393 | [114.35230553500017, 22.42369212400017], 394 | [114.3519393240002, 22.432338771500156], 395 | [114.35157311300023, 22.440985419000143], 396 | [114.35572350350017, 22.45107656450007], 397 | [114.35987389400012, 22.46116771], 398 | [114.3638615245001, 22.45807526250006], 399 | [114.36784915500007, 22.454982815000122], 400 | [114.36760501400008, 22.45062897350013], 401 | [114.36736087300008, 22.44627513200014], 402 | [114.36878502700014, 22.443141994000115], 403 | [114.3702091810002, 22.44000885600009], 404 | [114.37798099050016, 22.439622300000124], 405 | [114.38575280000012, 22.439235744000158], 406 | [114.39275149800005, 22.43768952000012], 407 | [114.39975019599999, 22.436143296000083], 408 | [114.39857018300006, 22.432277736500083], 409 | [114.39739017000014, 22.428412177000084], 410 | [114.39934329500014, 22.420579331500093], 411 | [114.40129642000014, 22.412746486000103], 412 | [114.39531497500016, 22.41533030800005], 413 | [114.38933353000019, 22.41791413], 414 | [114.38554935000022, 22.418483791500066], 415 | [114.38176517000025, 22.41905345300013], 416 | [114.37598717550023, 22.408514716000127], 417 | [114.3702091810002, 22.397975979000122], 418 | [114.37260989700016, 22.399257717000083], 419 | [114.37501061300011, 22.400539455000043], 420 | [114.37997480550015, 22.39394765800006], 421 | [114.3849389980002, 22.387355861000074], 422 | [114.3873397145002, 22.376654364000103], 423 | [114.3897404310002, 22.365952867000132], 424 | [114.38815351650013, 22.36558665600016], 425 | [114.38656660200004, 22.36522044500019], 426 | [114.38615970100008, 22.367702541000128], 427 | [114.38575280000012, 22.370184637000065], 428 | [114.38107343800007, 22.37040843300005], 429 | [114.37639407600003, 22.370632229000037], 430 | [114.37794030000006, 22.36635976800008], 431 | [114.3794865240001, 22.362087307000124], 432 | [114.3775333990001, 22.35777415600012], 433 | [114.3755802740001, 22.353461005000113], 434 | [114.37289472750015, 22.351141669000057], 435 | [114.3702091810002, 22.348822333], 436 | [114.36552981900016, 22.347296454000045], 437 | [114.36085045700011, 22.34577057500009], 438 | [114.35922285250007, 22.339097398000092], 439 | [114.35759524800002, 22.332424221000096], 440 | [114.3549503915001, 22.33594391500013], 441 | [114.35230553500017, 22.339463609000163], 442 | [114.35230553500017, 22.34568919500012], 443 | [114.35230553500017, 22.351914781000076], 444 | [114.34713789150013, 22.348842678000082], 445 | [114.34197024800008, 22.34577057500009], 446 | [114.34050540450005, 22.349229234000042], 447 | [114.33904056100002, 22.352687893], 448 | [114.3359074230001, 22.35622793200003], 449 | [114.33277428500017, 22.359767971000068], 450 | [114.3335473970001, 22.367539781000104], 451 | [114.33432050900004, 22.37531159100014], 452 | [114.32736250100004, 22.37803782800007], 453 | [114.32040449300004, 22.380764065], 454 | [114.3195093110001, 22.385077216000052], 455 | [114.31861412900017, 22.389390367000104], 456 | [114.3143416680002, 22.386582749500064], 457 | [114.31006920700023, 22.383775132000025], 458 | [114.30506432400014, 22.382676499500064], 459 | [114.30005944100006, 22.381577867000104], 460 | [114.29302005300005, 22.38627757400012], 461 | [114.28598066500004, 22.390977281000133], 462 | [114.28199303500006, 22.390977281000133], 463 | [114.27800540500007, 22.390977281000133], 464 | [114.27336673300013, 22.384711005000085], 465 | [114.26872806100019, 22.378444729000037], 466 | [114.27104739700016, 22.3710391300001], 467 | [114.27336673300013, 22.36363353100016], 468 | [114.27658125100018, 22.359320380000156], 469 | [114.27979576900023, 22.35500722900015], 470 | [114.27812747500022, 22.35152822500011], 471 | [114.2764591810002, 22.348049221000068], 472 | [114.27182050900015, 22.351914781000076], 473 | [114.2671818370001, 22.355780341000084], 474 | [114.26677493600008, 22.36086660400011], 475 | [114.26636803500006, 22.365952867000132], 476 | [114.26238040450008, 22.364020087000128], 477 | [114.2583927740001, 22.362087307000124], 478 | [114.25696862050009, 22.35899485900009], 479 | [114.25554446700008, 22.35590241100006], 480 | [114.26067142000014, 22.351121323500067], 481 | [114.2657983730002, 22.346340236000074], 482 | [114.2691756520002, 22.333522853500043], 483 | [114.2725529310002, 22.32070547100001], 484 | [114.27487226650018, 22.319952704000073], 485 | [114.27719160200016, 22.319199937000135], 486 | [114.28423099050013, 22.317877508500146], 487 | [114.29127037900011, 22.316555080000157], 488 | [114.29167728000016, 22.31085846550008], 489 | [114.2920841810002, 22.305161851], 490 | [114.2940373060002, 22.305161851], 491 | [114.2959904310002, 22.305161851], 492 | [114.29993737100014, 22.305934963000016], 493 | [114.30388431100008, 22.30670807500003], 494 | [114.30774987100008, 22.302008368000074], 495 | [114.31161543100009, 22.297308661000116], 496 | [114.30864505300016, 22.294033107500127], 497 | [114.30567467500023, 22.290757554000137], 498 | [114.30168704500014, 22.288194077500123], 499 | [114.29769941500004, 22.285630601000108] 500 | ] 501 | } 502 | } 503 | -------------------------------------------------------------------------------- /src/externs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Externs file for google closure compiler 3 | */ 4 | 5 | // this makes GCC play with browserify 6 | 7 | /** 8 | * @param {*=}o 9 | * @param {*=}u 10 | */ 11 | window.require = function(o, u) {}; 12 | 13 | /** 14 | * @type {Object} 15 | */ 16 | window.module = { 17 | exports: {} 18 | }; 19 | 20 | var L = { 21 | 'version': {}, 22 | 'noConflict': function() {}, 23 | 'Util': { 24 | 'extend': function() {}, 25 | 'bind': function() {}, 26 | 'stamp': function() {}, 27 | 'invokeEach': function() {}, 28 | 'limitExecByInterval': function() {}, 29 | 'falseFn': function() {}, 30 | 'formatNum': function() {}, 31 | 'trim': function() {}, 32 | 'splitWords': function() {}, 33 | 'setOptions': function() {}, 34 | 'getParamString': function() {}, 35 | 'template': function() {}, 36 | 'isArray': function() {}, 37 | 'emptyImageUrl': {}, 38 | 'requestAnimFrame': function() {}, 39 | 'cancelAnimFrame': function() {} 40 | }, 41 | 'extend': function() {}, 42 | 'bind': function() {}, 43 | 'stamp': function() {}, 44 | 'setOptions': function() {}, 45 | 'Class': function() {}, 46 | 'Mixin': { 47 | 'Events': { 48 | 'addEventListener': function() {}, 49 | 'hasEventListeners': function() {}, 50 | 'removeEventListener': function() {}, 51 | 'clearAllEventListeners': function() {}, 52 | 'fireEvent': function() {}, 53 | 'addOneTimeEventListener': function() {}, 54 | 'on': function() {}, 55 | 'off': function() {}, 56 | 'once': function() {}, 57 | 'fire': function() {} 58 | } 59 | }, 60 | 'Browser': { 61 | 'ie': {}, 62 | 'ielt9': {}, 63 | 'webkit': {}, 64 | 'gecko': {}, 65 | 'android': {}, 66 | 'android23': {}, 67 | 'chrome': {}, 68 | 'ie3d': {}, 69 | 'webkit3d': {}, 70 | 'gecko3d': {}, 71 | 'opera3d': {}, 72 | 'any3d': {}, 73 | 'mobile': {}, 74 | 'mobileWebkit': {}, 75 | 'mobileWebkit3d': {}, 76 | 'mobileOpera': {}, 77 | 'touch': {}, 78 | 'msPointer': {}, 79 | 'pointer': {}, 80 | 'retina': {}, 81 | 'svg': {}, 82 | 'vml': {}, 83 | 'canvas': {} 84 | }, 85 | 'Point': function() {}, 86 | 'point': function() {}, 87 | 'Bounds': function() {}, 88 | 'bounds': function() {}, 89 | 'Transformation': function() {}, 90 | 'DomUtil': { 91 | 'get': function() {}, 92 | 'getStyle': function() {}, 93 | 'getViewportOffset': function() {}, 94 | 'documentIsLtr': function() {}, 95 | 'create': function() {}, 96 | 'hasClass': function() {}, 97 | 'addClass': function() {}, 98 | 'removeClass': function() {}, 99 | '_setClass': function() {}, 100 | '_getClass': function() {}, 101 | 'setOpacity': function() {}, 102 | 'testProp': function() {}, 103 | 'getTranslateString': function() {}, 104 | 'getScaleString': function() {}, 105 | 'setPosition': function() {}, 106 | 'getPosition': function() {}, 107 | 'TRANSFORM': {}, 108 | 'TRANSITION': {}, 109 | 'TRANSITION_END': {}, 110 | 'disableTextSelection': function() {}, 111 | 'enableTextSelection': function() {}, 112 | 'disableImageDrag': function() {}, 113 | 'enableImageDrag': function() {} 114 | }, 115 | 'LatLng': function() {}, 116 | 'latLng': function() {}, 117 | 'LatLngBounds': function() {}, 118 | 'latLngBounds': function() {}, 119 | 'Projection': { 120 | 'SphericalMercator': { 121 | 'MAX_LATITUDE': {}, 122 | 'project': function() {}, 123 | 'unproject': function() {} 124 | }, 125 | 'LonLat': { 126 | 'project': function() {}, 127 | 'unproject': function() {} 128 | }, 129 | 'Mercator': { 130 | 'MAX_LATITUDE': {}, 131 | 'R_MINOR': {}, 132 | 'R_MAJOR': {}, 133 | 'project': function() {}, 134 | 'unproject': function() {} 135 | } 136 | }, 137 | 'CRS': { 138 | 'latLngToPoint': function() {}, 139 | 'pointToLatLng': function() {}, 140 | 'project': function() {}, 141 | 'scale': function() {}, 142 | 'getSize': function() {}, 143 | 'Simple': { 144 | 'latLngToPoint': function() {}, 145 | 'pointToLatLng': function() {}, 146 | 'project': function() {}, 147 | 'scale': function() {}, 148 | 'getSize': function() {}, 149 | 'projection': { 150 | 'project': function() {}, 151 | 'unproject': function() {} 152 | }, 153 | 'transformation': { 154 | '_a': {}, 155 | '_b': {}, 156 | '_c': {}, 157 | '_d': {}, 158 | 'transform': function() {}, 159 | '_transform': function() {}, 160 | 'untransform': function() {} 161 | } 162 | }, 163 | 'EPSG3857': { 164 | 'latLngToPoint': function() {}, 165 | 'pointToLatLng': function() {}, 166 | 'project': function() {}, 167 | 'scale': function() {}, 168 | 'getSize': function() {}, 169 | 'Simple': { 170 | 'latLngToPoint': function() {}, 171 | 'pointToLatLng': function() {}, 172 | 'project': function() {}, 173 | 'scale': function() {}, 174 | 'getSize': function() {}, 175 | 'projection': { 176 | 'project': function() {}, 177 | 'unproject': function() {} 178 | }, 179 | 'transformation': { 180 | '_a': {}, 181 | '_b': {}, 182 | '_c': {}, 183 | '_d': {}, 184 | 'transform': function() {}, 185 | '_transform': function() {}, 186 | 'untransform': function() {} 187 | } 188 | }, 189 | 'code': {}, 190 | 'projection': { 191 | 'MAX_LATITUDE': {}, 192 | 'project': function() {}, 193 | 'unproject': function() {} 194 | }, 195 | 'transformation': { 196 | '_a': {}, 197 | '_b': {}, 198 | '_c': {}, 199 | '_d': {}, 200 | 'transform': function() {}, 201 | '_transform': function() {}, 202 | 'untransform': function() {} 203 | } 204 | }, 205 | 'EPSG900913': { 206 | 'latLngToPoint': function() {}, 207 | 'pointToLatLng': function() {}, 208 | 'project': function() {}, 209 | 'scale': function() {}, 210 | 'getSize': function() {}, 211 | 'Simple': { 212 | 'latLngToPoint': function() {}, 213 | 'pointToLatLng': function() {}, 214 | 'project': function() {}, 215 | 'scale': function() {}, 216 | 'getSize': function() {}, 217 | 'projection': { 218 | 'project': function() {}, 219 | 'unproject': function() {} 220 | }, 221 | 'transformation': { 222 | '_a': {}, 223 | '_b': {}, 224 | '_c': {}, 225 | '_d': {}, 226 | 'transform': function() {}, 227 | '_transform': function() {}, 228 | 'untransform': function() {} 229 | } 230 | }, 231 | 'code': {}, 232 | 'projection': { 233 | 'MAX_LATITUDE': {}, 234 | 'project': function() {}, 235 | 'unproject': function() {} 236 | }, 237 | 'transformation': { 238 | '_a': {}, 239 | '_b': {}, 240 | '_c': {}, 241 | '_d': {}, 242 | 'transform': function() {}, 243 | '_transform': function() {}, 244 | 'untransform': function() {} 245 | } 246 | }, 247 | 'EPSG4326': { 248 | 'latLngToPoint': function() {}, 249 | 'pointToLatLng': function() {}, 250 | 'project': function() {}, 251 | 'scale': function() {}, 252 | 'getSize': function() {}, 253 | 'Simple': { 254 | 'latLngToPoint': function() {}, 255 | 'pointToLatLng': function() {}, 256 | 'project': function() {}, 257 | 'scale': function() {}, 258 | 'getSize': function() {}, 259 | 'projection': { 260 | 'project': function() {}, 261 | 'unproject': function() {} 262 | }, 263 | 'transformation': { 264 | '_a': {}, 265 | '_b': {}, 266 | '_c': {}, 267 | '_d': {}, 268 | 'transform': function() {}, 269 | '_transform': function() {}, 270 | 'untransform': function() {} 271 | } 272 | }, 273 | 'EPSG3857': { 274 | 'latLngToPoint': function() {}, 275 | 'pointToLatLng': function() {}, 276 | 'project': function() {}, 277 | 'scale': function() {}, 278 | 'getSize': function() {}, 279 | 'Simple': { 280 | 'latLngToPoint': function() {}, 281 | 'pointToLatLng': function() {}, 282 | 'project': function() {}, 283 | 'scale': function() {}, 284 | 'getSize': function() {}, 285 | 'projection': { 286 | 'project': function() {}, 287 | 'unproject': function() {} 288 | }, 289 | 'transformation': { 290 | '_a': {}, 291 | '_b': {}, 292 | '_c': {}, 293 | '_d': {}, 294 | 'transform': function() {}, 295 | '_transform': function() {}, 296 | 'untransform': function() {} 297 | } 298 | }, 299 | 'code': {}, 300 | 'projection': { 301 | 'MAX_LATITUDE': {}, 302 | 'project': function() {}, 303 | 'unproject': function() {} 304 | }, 305 | 'transformation': { 306 | '_a': {}, 307 | '_b': {}, 308 | '_c': {}, 309 | '_d': {}, 310 | 'transform': function() {}, 311 | '_transform': function() {}, 312 | 'untransform': function() {} 313 | } 314 | }, 315 | 'EPSG900913': { 316 | 'latLngToPoint': function() {}, 317 | 'pointToLatLng': function() {}, 318 | 'project': function() {}, 319 | 'scale': function() {}, 320 | 'getSize': function() {}, 321 | 'Simple': { 322 | 'latLngToPoint': function() {}, 323 | 'pointToLatLng': function() {}, 324 | 'project': function() {}, 325 | 'scale': function() {}, 326 | 'getSize': function() {}, 327 | 'projection': { 328 | 'project': function() {}, 329 | 'unproject': function() {} 330 | }, 331 | 'transformation': { 332 | '_a': {}, 333 | '_b': {}, 334 | '_c': {}, 335 | '_d': {}, 336 | 'transform': function() {}, 337 | '_transform': function() {}, 338 | 'untransform': function() {} 339 | } 340 | }, 341 | 'code': {}, 342 | 'projection': { 343 | 'MAX_LATITUDE': {}, 344 | 'project': function() {}, 345 | 'unproject': function() {} 346 | }, 347 | 'transformation': { 348 | '_a': {}, 349 | '_b': {}, 350 | '_c': {}, 351 | '_d': {}, 352 | 'transform': function() {}, 353 | '_transform': function() {}, 354 | 'untransform': function() {} 355 | } 356 | }, 357 | 'code': {}, 358 | 'projection': { 359 | 'project': function() {}, 360 | 'unproject': function() {} 361 | }, 362 | 'transformation': { 363 | '_a': {}, 364 | '_b': {}, 365 | '_c': {}, 366 | '_d': {}, 367 | 'transform': function() {}, 368 | '_transform': function() {}, 369 | 'untransform': function() {} 370 | } 371 | }, 372 | 'EPSG3395': { 373 | 'latLngToPoint': function() {}, 374 | 'pointToLatLng': function() {}, 375 | 'project': function() {}, 376 | 'scale': function() {}, 377 | 'getSize': function() {}, 378 | 'Simple': { 379 | 'latLngToPoint': function() {}, 380 | 'pointToLatLng': function() {}, 381 | 'project': function() {}, 382 | 'scale': function() {}, 383 | 'getSize': function() {}, 384 | 'projection': { 385 | 'project': function() {}, 386 | 'unproject': function() {} 387 | }, 388 | 'transformation': { 389 | '_a': {}, 390 | '_b': {}, 391 | '_c': {}, 392 | '_d': {}, 393 | 'transform': function() {}, 394 | '_transform': function() {}, 395 | 'untransform': function() {} 396 | } 397 | }, 398 | 'EPSG3857': { 399 | 'latLngToPoint': function() {}, 400 | 'pointToLatLng': function() {}, 401 | 'project': function() {}, 402 | 'scale': function() {}, 403 | 'getSize': function() {}, 404 | 'Simple': { 405 | 'latLngToPoint': function() {}, 406 | 'pointToLatLng': function() {}, 407 | 'project': function() {}, 408 | 'scale': function() {}, 409 | 'getSize': function() {}, 410 | 'projection': { 411 | 'project': function() {}, 412 | 'unproject': function() {} 413 | }, 414 | 'transformation': { 415 | '_a': {}, 416 | '_b': {}, 417 | '_c': {}, 418 | '_d': {}, 419 | 'transform': function() {}, 420 | '_transform': function() {}, 421 | 'untransform': function() {} 422 | } 423 | }, 424 | 'code': {}, 425 | 'projection': { 426 | 'MAX_LATITUDE': {}, 427 | 'project': function() {}, 428 | 'unproject': function() {} 429 | }, 430 | 'transformation': { 431 | '_a': {}, 432 | '_b': {}, 433 | '_c': {}, 434 | '_d': {}, 435 | 'transform': function() {}, 436 | '_transform': function() {}, 437 | 'untransform': function() {} 438 | } 439 | }, 440 | 'EPSG900913': { 441 | 'latLngToPoint': function() {}, 442 | 'pointToLatLng': function() {}, 443 | 'project': function() {}, 444 | 'scale': function() {}, 445 | 'getSize': function() {}, 446 | 'Simple': { 447 | 'latLngToPoint': function() {}, 448 | 'pointToLatLng': function() {}, 449 | 'project': function() {}, 450 | 'scale': function() {}, 451 | 'getSize': function() {}, 452 | 'projection': { 453 | 'project': function() {}, 454 | 'unproject': function() {} 455 | }, 456 | 'transformation': { 457 | '_a': {}, 458 | '_b': {}, 459 | '_c': {}, 460 | '_d': {}, 461 | 'transform': function() {}, 462 | '_transform': function() {}, 463 | 'untransform': function() {} 464 | } 465 | }, 466 | 'code': {}, 467 | 'projection': { 468 | 'MAX_LATITUDE': {}, 469 | 'project': function() {}, 470 | 'unproject': function() {} 471 | }, 472 | 'transformation': { 473 | '_a': {}, 474 | '_b': {}, 475 | '_c': {}, 476 | '_d': {}, 477 | 'transform': function() {}, 478 | '_transform': function() {}, 479 | 'untransform': function() {} 480 | } 481 | }, 482 | 'EPSG4326': { 483 | 'latLngToPoint': function() {}, 484 | 'pointToLatLng': function() {}, 485 | 'project': function() {}, 486 | 'scale': function() {}, 487 | 'getSize': function() {}, 488 | 'Simple': { 489 | 'latLngToPoint': function() {}, 490 | 'pointToLatLng': function() {}, 491 | 'project': function() {}, 492 | 'scale': function() {}, 493 | 'getSize': function() {}, 494 | 'projection': { 495 | 'project': function() {}, 496 | 'unproject': function() {} 497 | }, 498 | 'transformation': { 499 | '_a': {}, 500 | '_b': {}, 501 | '_c': {}, 502 | '_d': {}, 503 | 'transform': function() {}, 504 | '_transform': function() {}, 505 | 'untransform': function() {} 506 | } 507 | }, 508 | 'EPSG3857': { 509 | 'latLngToPoint': function() {}, 510 | 'pointToLatLng': function() {}, 511 | 'project': function() {}, 512 | 'scale': function() {}, 513 | 'getSize': function() {}, 514 | 'Simple': { 515 | 'latLngToPoint': function() {}, 516 | 'pointToLatLng': function() {}, 517 | 'project': function() {}, 518 | 'scale': function() {}, 519 | 'getSize': function() {}, 520 | 'projection': { 521 | 'project': function() {}, 522 | 'unproject': function() {} 523 | }, 524 | 'transformation': { 525 | '_a': {}, 526 | '_b': {}, 527 | '_c': {}, 528 | '_d': {}, 529 | 'transform': function() {}, 530 | '_transform': function() {}, 531 | 'untransform': function() {} 532 | } 533 | }, 534 | 'code': {}, 535 | 'projection': { 536 | 'MAX_LATITUDE': {}, 537 | 'project': function() {}, 538 | 'unproject': function() {} 539 | }, 540 | 'transformation': { 541 | '_a': {}, 542 | '_b': {}, 543 | '_c': {}, 544 | '_d': {}, 545 | 'transform': function() {}, 546 | '_transform': function() {}, 547 | 'untransform': function() {} 548 | } 549 | }, 550 | 'EPSG900913': { 551 | 'latLngToPoint': function() {}, 552 | 'pointToLatLng': function() {}, 553 | 'project': function() {}, 554 | 'scale': function() {}, 555 | 'getSize': function() {}, 556 | 'Simple': { 557 | 'latLngToPoint': function() {}, 558 | 'pointToLatLng': function() {}, 559 | 'project': function() {}, 560 | 'scale': function() {}, 561 | 'getSize': function() {}, 562 | 'projection': { 563 | 'project': function() {}, 564 | 'unproject': function() {} 565 | }, 566 | 'transformation': { 567 | '_a': {}, 568 | '_b': {}, 569 | '_c': {}, 570 | '_d': {}, 571 | 'transform': function() {}, 572 | '_transform': function() {}, 573 | 'untransform': function() {} 574 | } 575 | }, 576 | 'code': {}, 577 | 'projection': { 578 | 'MAX_LATITUDE': {}, 579 | 'project': function() {}, 580 | 'unproject': function() {} 581 | }, 582 | 'transformation': { 583 | '_a': {}, 584 | '_b': {}, 585 | '_c': {}, 586 | '_d': {}, 587 | 'transform': function() {}, 588 | '_transform': function() {}, 589 | 'untransform': function() {} 590 | } 591 | }, 592 | 'code': {}, 593 | 'projection': { 594 | 'project': function() {}, 595 | 'unproject': function() {} 596 | }, 597 | 'transformation': { 598 | '_a': {}, 599 | '_b': {}, 600 | '_c': {}, 601 | '_d': {}, 602 | 'transform': function() {}, 603 | '_transform': function() {}, 604 | 'untransform': function() {} 605 | } 606 | }, 607 | 'code': {}, 608 | 'projection': { 609 | 'MAX_LATITUDE': {}, 610 | 'R_MINOR': {}, 611 | 'R_MAJOR': {}, 612 | 'project': function() {}, 613 | 'unproject': function() {} 614 | }, 615 | 'transformation': { 616 | '_a': {}, 617 | '_b': {}, 618 | '_c': {}, 619 | '_d': {}, 620 | 'transform': function() {}, 621 | '_transform': function() {}, 622 | 'untransform': function() {} 623 | } 624 | } 625 | }, 626 | 'Map': function() {}, 627 | 'map': function() {}, 628 | 'TileLayer': function() {}, 629 | 'tileLayer': function() {}, 630 | 'ImageOverlay': function() {}, 631 | 'imageOverlay': function() {}, 632 | 'Icon': function() {}, 633 | 'icon': function() {}, 634 | 'Marker': function() {}, 635 | 'marker': function() {}, 636 | 'DivIcon': function() {}, 637 | 'divIcon': function() {}, 638 | 'Popup': function() {}, 639 | 'popup': function() {}, 640 | 'LayerGroup': function() {}, 641 | 'layerGroup': function() {}, 642 | 'FeatureGroup': function() {}, 643 | 'featureGroup': function() {}, 644 | 'Path': function() {}, 645 | 'LineUtil': { 646 | 'simplify': function() {}, 647 | 'pointToSegmentDistance': function() {}, 648 | 'closestPointOnSegment': function() {}, 649 | '_simplifyDP': function() {}, 650 | '_simplifyDPStep': function() {}, 651 | '_reducePoints': function() {}, 652 | 'clipSegment': function() {}, 653 | '_getEdgeIntersection': function() {}, 654 | '_getBitCode': function() {}, 655 | '_sqDist': function() {}, 656 | '_sqClosestPointOnSegment': function() {} 657 | }, 658 | 'Polyline': function() {}, 659 | 'polyline': function() {}, 660 | 'PolyUtil': { 661 | 'clipPolygon': function() {} 662 | }, 663 | 'Polygon': function() {}, 664 | 'polygon': function() {}, 665 | 'MultiPolyline': function() {}, 666 | 'MultiPolygon': function() {}, 667 | 'multiPolyline': function() {}, 668 | 'multiPolygon': function() {}, 669 | 'Rectangle': function() {}, 670 | 'rectangle': function() {}, 671 | 'Circle': function() {}, 672 | 'circle': function() {}, 673 | 'CircleMarker': function() {}, 674 | 'circleMarker': function() {}, 675 | 'GeoJSON': function() {}, 676 | 'geoJson': function() {}, 677 | 'DomEvent': { 678 | 'addListener': function() {}, 679 | 'removeListener': function() {}, 680 | 'stopPropagation': function() {}, 681 | 'disableScrollPropagation': function() {}, 682 | 'disableClickPropagation': function() {}, 683 | 'preventDefault': function() {}, 684 | 'stop': function() {}, 685 | 'getMousePosition': function() {}, 686 | 'getWheelDelta': function() {}, 687 | '_skipEvents': function() {}, 688 | '_fakeStop': function() {}, 689 | '_skipped': function() {}, 690 | '_checkMouse': function() {}, 691 | '_getEvent': function() {}, 692 | '_filterClick': function() {}, 693 | 'on': function() {}, 694 | 'off': function() {}, 695 | '_touchstart': {}, 696 | '_touchend': {}, 697 | 'addDoubleTapListener': function() {}, 698 | 'removeDoubleTapListener': function() {}, 699 | 'POINTER_DOWN': {}, 700 | 'POINTER_MOVE': {}, 701 | 'POINTER_UP': {}, 702 | 'POINTER_CANCEL': {}, 703 | '_pointers': function() {}, 704 | '_pointerDocumentListener': {}, 705 | 'addPointerListener': function() {}, 706 | 'addPointerListenerStart': function() {}, 707 | 'addPointerListenerMove': function() {}, 708 | 'addPointerListenerEnd': function() {}, 709 | 'removePointerListener': function() {} 710 | }, 711 | 'Draggable': function() {}, 712 | 'Handler': function() {}, 713 | 'Control': function() {}, 714 | 'control': function() {}, 715 | 'PosAnimation': function() {} 716 | }; 717 | 718 | L.MouseEvent = { 719 | latlng: undefined, 720 | layerPoint: undefined, 721 | containerPoint: undefined, 722 | originalEvent: undefined 723 | }; 724 | 725 | L.Draggable = function() {}; 726 | 727 | L.Draggable.START = null; 728 | L.Draggable.END = null; 729 | L.Draggable.MOVE = null; 730 | 731 | L.Draggable._disabled = false; 732 | 733 | L.LatLng.prototype.distanceTo = function() {}; 734 | 735 | L.LatLng.prototype.lat; 736 | 737 | L.LatLng.prototype.lng; 738 | 739 | L.Map.prototype.addLayer = function() {}; 740 | 741 | L.Map.prototype.removeLayer = function() {}; 742 | 743 | L.Map.prototype.getMaxZoom = function() {}; 744 | 745 | L.Map.prototype.getCenter = function() {}; 746 | 747 | L.Map.prototype.latLngToContainerPoint = function() {}; 748 | 749 | L.Map.prototype.latLngToLayerPoint = function() {}; 750 | 751 | L.Map.prototype.layerPointToLatLng = function() {}; 752 | 753 | L.Map.prototype.dragging = { 754 | enable: function() {}, 755 | disable: function() {} 756 | }; 757 | 758 | L.Map.prototype.options = { 759 | crs: { 760 | latLngToPoint: function() {}, 761 | pointToLatLng: function() {} 762 | } 763 | }; 764 | 765 | L.Control.prototype.extend = function() {}; 766 | 767 | /** 768 | * @type {L.Map} 769 | */ 770 | L.Control.prototype._map = null; 771 | 772 | L.CircleMarker.prototype.extend = function() {}; 773 | 774 | L.CircleMarker.prototype.setRadius = function() {}; 775 | 776 | L.CircleMarker.prototype.bringToFront = function() {}; 777 | 778 | L.CircleMarker.prototype._container = null; 779 | 780 | L.CircleMarker.prototype.setLatLng = function() {}; 781 | 782 | L.CircleMarker.prototype.getLatLng = function() {}; 783 | 784 | L.CircleMarker.prototype.addTo = function(map) {}; 785 | 786 | L.CircleMarker.prototype._path; 787 | 788 | L.Polyline.prototype.getLatLngs = function() {}; 789 | 790 | L.Polyline.prototype.setLatLngs = function(latlngs) {}; 791 | 792 | L.Polyline.prototype.toGeoJSON = function() {}; 793 | 794 | L.Polyline.prototype._map = null; 795 | 796 | L.Polyline.prototype._latlngs = []; 797 | 798 | L.Polyline.prototype._originalPoints = []; 799 | 800 | L.Polyline.prototype._updatePath = function() {}; 801 | 802 | /** 803 | * @constructor 804 | * @extends {L.Control} 805 | */ 806 | L.Control.LineStringSelect = function(options) {}; 807 | 808 | L.Control.LineStringSelect.prototype.initialize = function(options) {}; 809 | 810 | L.Control.LineStringSelect.prototype.includes; 811 | 812 | L.Control.LineStringSelect.prototype.statics; 813 | 814 | /** 815 | * @constructor 816 | */ 817 | L.Control.LineStringSelect.Selection = function() {}; 818 | 819 | /** 820 | * @type {L.Polyline} 821 | */ 822 | L.Control.LineStringSelect.Selection.prototype._source = null; 823 | 824 | L.Control.LineStringSelect.Endpoint = function() {}; 825 | 826 | /** 827 | * @param {L.Map} map 828 | */ 829 | L.Control.LineStringSelect.Endpoint.prototype.onAdd = function(map) {}; 830 | 831 | /** 832 | * @type {Object} 833 | */ 834 | L.Control.LineStringSelect.Endpoint.prototype.options = { 835 | /** 836 | * Grow marker by this ratio on mouseover 837 | * @type {Number} 838 | */ 839 | radiusRatio: 1.2 840 | }; 841 | 842 | /** 843 | * @param {L.Map} map 844 | */ 845 | L.Control.LineStringSelect.Endpoint.prototype.onRemove = function(map) {}; 846 | 847 | L.Control.LineStringSelect.ControlMarker = function() {}; 848 | 849 | L.Control.LineStringSelect.ControlMarker.prototype.show = function() {}; 850 | 851 | L.Control.LineStringSelect.ControlMarker.prototype.hide = function() {}; 852 | 853 | /** 854 | * @type {Object} 855 | */ 856 | L.Control.LineStringSelect.prototype.options = { 857 | 858 | getProjectedPoint: function() {}, 859 | 860 | distance: function() {}, 861 | 862 | /** 863 | * @type {String} 864 | */ 865 | startMarkerClass: '', 866 | 867 | /** 868 | * @type {String} 869 | */ 870 | endMarkerClass: '', 871 | 872 | /** 873 | * @type {String} 874 | */ 875 | movingMarkerClass: '', 876 | 877 | /** 878 | * @type {String} 879 | */ 880 | name: '', 881 | 882 | /** 883 | * @type {Number} 884 | */ 885 | lineWeight: 4, 886 | 887 | /** 888 | * @type {Number} 889 | */ 890 | lineTolerance: L.Browser.touch ? 10 : 5, 891 | 892 | /** 893 | * @type {Object} 894 | */ 895 | movingMarkerStyle: { 896 | fillColor: '', 897 | fillOpacity: 1, 898 | weight: 2, 899 | opacity: 0.5, 900 | color: '' 901 | }, 902 | 903 | /** 904 | * @type {Object} 905 | */ 906 | endpointStyle: { 907 | radius: 5, 908 | color: '', 909 | fillColor: '', 910 | fillOpacity: 1 911 | }, 912 | 913 | /** 914 | * @type {Object} 915 | */ 916 | selectionStyle: { 917 | color: '', 918 | opacity: 1 919 | }, 920 | 921 | /** 922 | * @type {Boolean} 923 | */ 924 | useTouch: true, 925 | 926 | /** 927 | * @type {String} 928 | */ 929 | position: '' 930 | }; 931 | 932 | L.Control.LineStringSelect.prototype._feature = { 933 | geometry: { 934 | coordinates: [] 935 | } 936 | }; 937 | 938 | L.Control.LineStringSelect.prototype._startMarker; 939 | 940 | L.Control.LineStringSelect.prototype._endMarker; 941 | 942 | L.Control.LineStringSelect.prototype._movingMarker; 943 | 944 | L.Control.LineStringSelect.prototype.fire = function() {}; 945 | 946 | /** 947 | * @param {L.Map} map 948 | */ 949 | L.Control.LineStringSelect.prototype.onAdd = function(map) {}; 950 | 951 | /** 952 | * @param {L.Map} map 953 | */ 954 | L.Control.LineStringSelect.prototype.onRemove = function(map) {}; 955 | 956 | /** 957 | * Enable selection mode for line string 958 | * @param {Object} options 959 | * @return {Select} 960 | */ 961 | L.Control.LineStringSelect.prototype.enable = function(options) {}; 962 | 963 | /** 964 | * Disable selection 965 | * @return {Select} 966 | */ 967 | L.Control.LineStringSelect.prototype.disable = function() {}; 968 | 969 | /** 970 | * Reset selection 971 | * @return {Select} 972 | */ 973 | L.Control.LineStringSelect.prototype.reset = function() {}; 974 | 975 | /** 976 | * Selection latlngs 977 | * @return {Array.} 978 | */ 979 | L.Control.LineStringSelect.prototype.getSelection = function() {}; 980 | 981 | /** 982 | * Selection geoJSON 983 | * @return {Object|Null} 984 | */ 985 | L.Control.LineStringSelect.prototype.toGeoJSON = function() {}; 986 | 987 | /** 988 | * Select from one meter point to another 989 | * @param {Number} startM 990 | * @param {Number} endM 991 | * @return {Select} 992 | */ 993 | L.Control.LineStringSelect.prototype.selectMeters = function(startM, endM) {}; 994 | 995 | /** 996 | * Replace this method if you want to subclass moving marker 997 | * @param {L.LatLng} pos 998 | * @param {Object} style 999 | * @return {L.Control.LineStringSelect.ControlMarker} 1000 | */ 1001 | L.Control.LineStringSelect.prototype.movingMarkerFactory = function(pos, style) {}; 1002 | 1003 | /** 1004 | * Replace this method if you want to subclass endpoint marker 1005 | * @param {L.LatLng} pos 1006 | * @param {Object} style 1007 | * @param {Boolean} isEnd 1008 | * @return {L.Control.LineStringSelect.Endpoint} 1009 | */ 1010 | L.Control.LineStringSelect.prototype.endpointFactory = function(pos, style, isEnd) {}; 1011 | 1012 | /** 1013 | * Craetes a selection polyline. Replace or extend if you want 1014 | * to subclass selection polyline 1015 | * @param {Array.} coords 1016 | * @param {Object} style 1017 | * @param {L.Polyline} layer 1018 | * @return {L.Control.LineStringSelect.Selection} 1019 | */ 1020 | L.Control.LineStringSelect.prototype.selectionFactory = function(coords, style, layer) {}; 1021 | -------------------------------------------------------------------------------- /examples/js/bundle.js: -------------------------------------------------------------------------------- 1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;iOpenStreetMap contributors' 595 | }).addTo(map); 596 | 597 | var selectControl = global.control = new L.Control.LineStringSelect({}); 598 | map.addControl(selectControl); 599 | 600 | var layer = global.layer = L.geoJson(data).addTo(map); 601 | layer = layer.getLayers()[0]; 602 | 603 | control.enable({ 604 | feature: layer.feature, 605 | layer: layer 606 | }); 607 | 608 | //////////////////////////////////////////////////////////////////////////////// 609 | 610 | document.querySelector('#reset').addEventListener('click', function() { 611 | control.reset(); 612 | startRange.disabled = true; 613 | endRange.disabled = true; 614 | }); 615 | 616 | //////////////////////////////////////////////////////////////////////////////// 617 | var length = 0, 618 | distances = []; 619 | for (var i = 1, len = layer._latlngs.length; i < len; i++) { 620 | var dist = layer._latlngs[i].distanceTo(layer._latlngs[i - 1]); 621 | distances.push(dist); 622 | length += dist; 623 | } 624 | 625 | function getDistance(marker) { 626 | var d = 0; 627 | for (var i = 0, len = marker.start; i < len; i++) { 628 | d += distances[i]; 629 | } 630 | d += marker.getLatLng() 631 | .distanceTo(layer._latlngs[marker.start]); 632 | 633 | return d; 634 | } 635 | 636 | function getStartDistance() { 637 | return getDistance(control._startMarker); 638 | } 639 | 640 | function getEndDistance() { 641 | return getDistance(control._endMarker); 642 | } 643 | 644 | //////////////////////////////////////////////////////////////////////////////// 645 | 646 | var startRange = document.querySelector('#start-range'); 647 | var startM = document.querySelector('#start'); 648 | 649 | var endRange = document.querySelector('#end-range'); 650 | var endM = document.querySelector('#end'); 651 | 652 | function onStartRangeChange() { 653 | var meters = parseInt(startRange.value * length); 654 | if (endRange.value <= startRange.value) { 655 | endRange.value = startRange.value; 656 | endM.value = meters; 657 | } 658 | start.value = meters; 659 | 660 | control.selectMeters(meters, endM.value); 661 | } 662 | 663 | function onEndRangeChange() { 664 | var meters = parseInt(endRange.value * length); 665 | if (startRange.value >= endRange.value) { 666 | startRange.value = endRange.value; 667 | startM.value = meters; 668 | } 669 | end.value = meters; 670 | 671 | control.selectMeters(startM.value, meters); 672 | } 673 | 674 | startRange.onchange = startRange.oninput = onStartRangeChange; 675 | endRange.onchange = endRange.oninput = onEndRangeChange; 676 | 677 | var textarea = document.querySelector('#geojson'); 678 | control.on('select:start', function() { 679 | var dist = getStartDistance(); 680 | startRange.disabled = false; 681 | startRange.value = dist / length; 682 | startM.value = parseInt(dist); 683 | }); 684 | 685 | control.on('selection', function() { 686 | var dist1 = getStartDistance(); 687 | var dist2 = getEndDistance(); 688 | 689 | //console.log(dist1, startM.value, dist2, endM.value); 690 | 691 | startRange.value = dist1 / length; 692 | endRange.value = dist2 / length; 693 | 694 | startM.value = Math.round(dist1); 695 | endM.value = Math.round(dist2); 696 | 697 | endRange.disabled = false; 698 | textarea.value = jsonFormat(JSON.stringify(control.toGeoJSON())); 699 | }); 700 | 701 | control.on('reset', function() { 702 | startRange.value = endRange.value = 0; 703 | endM.value = startM.value = 0; 704 | textarea.value = ''; 705 | }); 706 | 707 | global.getStartDistance = getStartDistance; 708 | global.getEndDistance = getEndDistance; 709 | 710 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 711 | 712 | },{"../data.json":1,"./L.TouchExtend":2,"./json-format":4}],4:[function(require,module,exports){ 713 | /* 714 | json-format v.1.1 715 | http://github.com/phoboslab/json-format 716 | 717 | Released under MIT license: 718 | http://www.opensource.org/licenses/mit-license.php 719 | */ 720 | 721 | var p = [], 722 | push = function(m) { 723 | return '\\' + p.push(m) + '\\'; 724 | }, 725 | pop = function(m, i) { 726 | return p[i - 1] 727 | }, 728 | tabs = function(count) { 729 | return new Array(count + 1).join('\t'); 730 | }; 731 | 732 | module.exports = function(json) { 733 | p = []; 734 | var out = "", 735 | indent = 0; 736 | 737 | // Extract backslashes and strings 738 | json = json 739 | .replace(/\\./g, push) 740 | .replace(/(".*?"|'.*?')/g, push) 741 | .replace(/\s+/, ''); 742 | 743 | // Indent and insert newlines 744 | for (var i = 0; i < json.length; i++) { 745 | var c = json.charAt(i); 746 | 747 | switch (c) { 748 | case '{': 749 | out += c + "\n" + tabs(++indent); 750 | break; 751 | case '[': 752 | out += c + "\n" + tabs(++indent); 753 | break; 754 | case ']': 755 | out += "\n" + tabs(--indent) + c; 756 | break; 757 | case '}': 758 | out += "\n" + tabs(--indent) + c; 759 | break; 760 | case ',': 761 | if (/\d/.test(json.charAt(i - 1))) { 762 | out += ", "; 763 | } else { 764 | out += ",\n" + tabs(indent); 765 | } 766 | break; 767 | case ':': 768 | out += ": "; 769 | break; 770 | default: 771 | out += c; 772 | break; 773 | } 774 | } 775 | 776 | // Strip whitespace from numeric arrays and put backslashes 777 | // and strings back in 778 | out = out 779 | .replace(/\[[\d,\s]+?\]/g, function(m) { 780 | return m.replace(/\s/g, ''); 781 | }) 782 | // number arrays 783 | .replace(/\[\s*(\d)/g, function(a, b) { 784 | return '[' + b; 785 | }) 786 | .replace(/(\d)\s*\]/g, function(a, b) { 787 | return b + ']'; 788 | }) 789 | .replace(/\{\s*\}/g, '{}') // empty objects 790 | .replace(/\\(\d+)\\/g, pop) // strings 791 | .replace(/\\(\d+)\\/g, pop); // backslashes in strings 792 | 793 | return out; 794 | }; 795 | 796 | },{}]},{},[3]) 797 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJleGFtcGxlcy9kYXRhLmpzb24iLCJleGFtcGxlcy9qcy9MLlRvdWNoRXh0ZW5kLmpzIiwiZXhhbXBsZXMvanMvYXBwLmpzIiwiZXhhbXBsZXMvanMvanNvbi1mb3JtYXQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQzNJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24oKXtmdW5jdGlvbiByKGUsbix0KXtmdW5jdGlvbiBvKGksZil7aWYoIW5baV0pe2lmKCFlW2ldKXt2YXIgYz1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlO2lmKCFmJiZjKXJldHVybiBjKGksITApO2lmKHUpcmV0dXJuIHUoaSwhMCk7dmFyIGE9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitpK1wiJ1wiKTt0aHJvdyBhLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsYX12YXIgcD1uW2ldPXtleHBvcnRzOnt9fTtlW2ldWzBdLmNhbGwocC5leHBvcnRzLGZ1bmN0aW9uKHIpe3ZhciBuPWVbaV1bMV1bcl07cmV0dXJuIG8obnx8cil9LHAscC5leHBvcnRzLHIsZSxuLHQpfXJldHVybiBuW2ldLmV4cG9ydHN9Zm9yKHZhciB1PVwiZnVuY3Rpb25cIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmUsaT0wO2k8dC5sZW5ndGg7aSsrKW8odFtpXSk7cmV0dXJuIG99cmV0dXJuIHJ9KSgpIiwibW9kdWxlLmV4cG9ydHM9e1xuICBcInR5cGVcIjogXCJGZWF0dXJlXCIsXG4gIFwicHJvcGVydGllc1wiOiB7fSxcbiAgXCJnZW9tZXRyeVwiOiB7XG4gICAgXCJ0eXBlXCI6IFwiTGluZVN0cmluZ1wiLFxuICAgIFwiY29vcmRpbmF0ZXNcIjogW1xuICAgICAgWzExNC4yOTA1Mzc5NTcwMDAxNywgMjIuMjg3OTQ5OTM3MDAwMDhdLFxuICAgICAgWzExNC4yODk3NjQ4NDUwMDAxNSwgMjIuMjg3NTYzMzgxMDAwMTEyXSxcbiAgICAgIFsxMTQuMjg4OTkxNzMzMDAwMTMsIDIyLjI4NzE3NjgyNTAwMDE0NV0sXG4gICAgICBbMTE0LjI4OTM1Nzk0NDAwMDEsIDIyLjI4NDQzMDI0MzAwMDEzXSxcbiAgICAgIFsxMTQuMjg5NzI0MTU1MDAwMDcsIDIyLjI4MTY4MzY2MTAwMDExNl0sXG4gICAgICBbMTE0LjI4OTY0Mjc3NDUwMDA3LCAyMi4yNzc3OTc3NTYwMDAxMjZdLFxuICAgICAgWzExNC4yODk1NjEzOTQwMDAwNiwgMjIuMjczOTExODUxMDAwMTM2XSxcbiAgICAgIFsxMTQuMjk0ODEwNDE3NTAwMDYsIDIyLjI3NTQ3ODQyMDAwMDA3XSxcbiAgICAgIFsxMTQuMzAwMDU5NDQxMDAwMDYsIDIyLjI3NzA0NDk4OV0sXG4gICAgICBbMTE0LjMwMTYwNTY2NTAwMDEsIDIyLjI3MzExODM5NDAwMDAyMl0sXG4gICAgICBbMTE0LjMwMzE1MTg4OTAwMDEzLCAyMi4yNjkxOTE3OTkwMDAwNF0sXG4gICAgICBbMTE0LjMwMzE1MTg4OTAwMDEzLCAyMi4yNjU2NzIxMDUwMDAwNV0sXG4gICAgICBbMTE0LjMwMzE1MTg4OTAwMDEzLCAyMi4yNjIxNTI0MTEwMDAwNl0sXG4gICAgICBbMTE0LjI5OTkzNzM3MDUwMDA5LCAyMi4yNjAyMTk2MzEwMDAwNTVdLFxuICAgICAgWzExNC4yOTY3MjI4NTIwMDAwNCwgMjIuMjU4Mjg2ODUxMDAwMDVdLFxuICAgICAgWzExNC4yOTI4NTcyOTI1MDAwOSwgMjIuMjYxNDQwMzM0MDAwMDddLFxuICAgICAgWzExNC4yODg5OTE3MzMwMDAxMywgMjIuMjY0NTkzODE3MDAwMDldLFxuICAgICAgWzExNC4yODM2NjEzMjkwMDAxLCAyMi4yNjc1MjM1MDQ1MDAxMDVdLFxuICAgICAgWzExNC4yNzgzMzA5MjUwMDAwNiwgMjIuMjcwNDUzMTkyMDAwMTJdLFxuICAgICAgWzExNC4yNzkwNjMzNDcwMDAxNSwgMjIuMjc0OTA4NzU4NTAwMTMyXSxcbiAgICAgIFsxMTQuMjc5Nzk1NzY5MDAwMjMsIDIyLjI3OTM2NDMyNTAwMDE0NV0sXG4gICAgICBbMTE0LjI3NjU4MTI1MTAwMDE4LCAyMi4yODc1NjMzODEwMDAxMTJdLFxuICAgICAgWzExNC4yNzMzNjY3MzMwMDAxMywgMjIuMjk1NzYyNDM3MDAwMDhdLFxuICAgICAgWzExNC4yNjkwOTQyNzIwMDAxNiwgMjIuMjk4ODU0ODg1MDAwMTFdLFxuICAgICAgWzExNC4yNjQ4MjE4MTEwMDAxOSwgMjIuMzAxOTQ3MzMzMDAwMTQzXSxcbiAgICAgIFsxMTQuMjY1MjI4NzEyMDAwMjEsIDIyLjMwNTg3MzkyODAwMDEyNV0sXG4gICAgICBbMTE0LjI2NTYzNTYxMzAwMDIzLCAyMi4zMDk4MDA1MjMwMDAxMDZdLFxuICAgICAgWzExNC4yNjYwMDE4MjQwMDAxNCwgMjIuMzEyODkyOTcxMDAwMDk2XSxcbiAgICAgIFsxMTQuMjY2MzY4MDM1MDAwMDYsIDIyLjMxNTk4NTQxOTAwMDA4Nl0sXG4gICAgICBbMTE0LjI2MDk1NjI1MTAwMDA3LCAyMi4zMTkxNTkyNDcwMDAwNl0sXG4gICAgICBbMTE0LjI1NTU0NDQ2NzAwMDA4LCAyMi4zMjIzMzMwNzUwMDAwM10sXG4gICAgICBbMTE0LjI1MzUwOTk2MjAwMDEsIDIyLjMxMzc0NzQ2MzAwMDAxNl0sXG4gICAgICBbMTE0LjI1MTQ3NTQ1NzAwMDExLCAyMi4zMDUxNjE4NTFdLFxuICAgICAgWzExNC4yNTIyNDg1NjkwMDAwNywgMjIuMzAwNDYyMTQ0MDAwMDRdLFxuICAgICAgWzExNC4yNTMwMjE2ODEwMDAwNCwgMjIuMjk1NzYyNDM3MDAwMDhdLFxuICAgICAgWzExNC4yNDU5ODIyOTMwMDAxMSwgMjIuMjg4NzIzMDQ5MDAwMDk3XSxcbiAgICAgIFsxMTQuMjM4OTQyOTA1MDAwMTksIDIyLjI4MTY4MzY2MTAwMDExNl0sXG4gICAgICBbMTE0LjIzMzUzMTEyMTAwMDIsIDIyLjI4Njc2OTkyNDAwMDA5N10sXG4gICAgICBbMTE0LjIyODExOTMzNzAwMDIxLCAyMi4yOTE4NTYxODcwMDAwOF0sXG4gICAgICBbMTE0LjIxOTk0MDYyNjAwMDEsIDIyLjMwMTIxNDkxMTAwMDA2XSxcbiAgICAgIFsxMTQuMjExNzYxOTE0OTk5OTgsIDIyLjMxMDU3MzYzNTAwMDA0XSxcbiAgICAgIFsxMTQuMjEzMzA4MTM5MDAwMDIsIDIyLjMwNTg3MzkyODAwMDA0XSxcbiAgICAgIFsxMTQuMjE0ODU0MzYzMDAwMDYsIDIyLjMwMTE3NDIyMTAwMDA0XSxcbiAgICAgIFsxMTQuMjEzNjc0MzUwMDAwMTMsIDIyLjMwMTE3NDIyMTAwMDA0XSxcbiAgICAgIFsxMTQuMjEyNDk0MzM3MDAwMjEsIDIyLjMwMTE3NDIyMTAwMDA0XSxcbiAgICAgIFsxMTQuMjAzOTkwMTA1MDAwMTQsIDIyLjMwOTcxOTE0MzAwMDA1Ml0sXG4gICAgICBbMTE0LjE5NTQ4NTg3MzAwMDA4LCAyMi4zMTgyNjQwNjUwMDAwNjVdLFxuICAgICAgWzExNC4xOTEwMDk5NjE1MDAxNiwgMjIuMzEzNTAzMzIyNTAwMDddLFxuICAgICAgWzExNC4xODY1MzQwNTAwMDAyMywgMjIuMzA4NzQyNTgwMDAwMDddLFxuICAgICAgWzExNC4xODg5NzU0NTY1MDAxNywgMjIuMzA1MzQ0OTU2NTAwMTA3XSxcbiAgICAgIFsxMTQuMTkxNDE2ODYzMDAwMTEsIDIyLjMwMTk0NzMzMzAwMDE0M10sXG4gICAgICBbMTE0LjE5MTQxNjg2MzAwMDExLCAyMi4zMDA0MjE0NTQwMDAxNDRdLFxuICAgICAgWzExNC4xOTE0MTY4NjMwMDAxMSwgMjIuMjk4ODk1NTc1MDAwMTQ1XSxcbiAgICAgIFsxMTQuMTg3NTUxMzAzMDAwMSwgMjIuMzAwNDIxNDU0MDAwMTQ0XSxcbiAgICAgIFsxMTQuMTgzNjg1NzQzMDAwMSwgMjIuMzAxOTQ3MzMzMDAwMTQzXSxcbiAgICAgIFsxMTQuMTgyNjY4NDkwNTAwMTMsIDIyLjI5ODE4MzQ5ODUwMDE1XSxcbiAgICAgIFsxMTQuMTgxNjUxMjM4MDAwMTcsIDIyLjI5NDQxOTY2NDAwMDE2XSxcbiAgICAgIFsxMTQuMTc5MDg3NzYxNTAwMTEsIDIyLjI5Mjc1MTM2OTUwMDE1Ml0sXG4gICAgICBbMTE0LjE3NjUyNDI4NTAwMDA2LCAyMi4yOTEwODMwNzUwMDAxNDVdLFxuICAgICAgWzExNC4xNzQyMDQ5NDkwMDAwOSwgMjIuMjg5OTAzMDYyMDAwMDhdLFxuICAgICAgWzExNC4xNzE4ODU2MTMwMDAxMSwgMjIuMjg4NzIzMDQ5MDAwMDEyXSxcbiAgICAgIFsxMTQuMTY5NTY2Mjc3MDAwMTQsIDIyLjI5MTQ0OTI4NjAwMDAzXSxcbiAgICAgIFsxMTQuMTY3MjQ2OTQxMDAwMTcsIDIyLjI5NDE3NTUyMzAwMDA1XSxcbiAgICAgIFsxMTQuMTY3NzM1MjIyNTAwMTcsIDIyLjI5OTgzMTQ0NzUwMDA0XSxcbiAgICAgIFsxMTQuMTY4MjIzNTA0MDAwMTcsIDIyLjMwNTQ4NzM3MjAwMDAzXSxcbiAgICAgIFsxMTQuMTY2OTYyMTEwNTAwMTIsIDIyLjMwODAzMDUwMzUwMDAzNV0sXG4gICAgICBbMTE0LjE2NTcwMDcxNzAwMDA4LCAyMi4zMTA1NzM2MzUwMDAwNF0sXG4gICAgICBbMTE0LjE2NTI5MzgxNjAwMDEyLCAyMi4zMTI4OTI5NzEwMDAwOTZdLFxuICAgICAgWzExNC4xNjQ4ODY5MTUwMDAxNSwgMjIuMzE1MjEyMzA3MDAwMTUyXSxcbiAgICAgIFsxMTQuMTYyMjAxMzY4MDAwMTMsIDIyLjMxNTIxMjMwNzAwMDE1Ml0sXG4gICAgICBbMTE0LjE1OTUxNTgyMTAwMDEsIDIyLjMxNTIxMjMwNzAwMDE1Ml0sXG4gICAgICBbMTE0LjE1OTUxNTgyMTAwMDEsIDIyLjMxODczMjAwMTAwMDFdLFxuICAgICAgWzExNC4xNTk1MTU4MjEwMDAxLCAyMi4zMjIyNTE2OTUwMDAwNV0sXG4gICAgICBbMTE0LjE1NTg1MzcxMTUwMDEzLCAyMi4zMjUzODQ4MzMwMDAwNzJdLFxuICAgICAgWzExNC4xNTIxOTE2MDIwMDAxNiwgMjIuMzI4NTE3OTcxMDAwMDk2XSxcbiAgICAgIFsxMTQuMTQ1MTkyOTA0NTAwMTQsIDIyLjMzMjI2MTQ2MDUwMDEyXSxcbiAgICAgIFsxMTQuMTM4MTk0MjA3MDAwMTEsIDIyLjMzNjAwNDk1MDAwMDE0NV0sXG4gICAgICBbMTE0LjEzMTI3Njg4OTAwMDA4LCAyMi4zMzkxMTc3NDMwMDAxM10sXG4gICAgICBbMTE0LjEyNDM1OTU3MTAwMDA0LCAyMi4zNDIyMzA1MzYwMDAxMTZdLFxuICAgICAgWzExNC4xMjM5NTI2NzAwMDAwOCwgMjIuMzM5Njg3NDA0NTAwMDU4XSxcbiAgICAgIFsxMTQuMTIzNTQ1NzY5MDAwMTIsIDIyLjMzNzE0NDI3M10sXG4gICAgICBbMTE0LjExODQ1OTUwNjAwMDA4LCAyMi4zNDQ5MTYwODNdLFxuICAgICAgWzExNC4xMTMzNzMyNDMwMDAwNCwgMjIuMzUyNjg3ODkzXSxcbiAgICAgIFsxMTQuMTEyMTkzMjMwMDAwMTIsIDIyLjM1OTMyMDM4MDAwMDA2NF0sXG4gICAgICBbMTE0LjExMTAxMzIxNzAwMDE5LCAyMi4zNjU5NTI4NjcwMDAxMzJdLFxuICAgICAgWzExNC4xMDc5MjA3NjkwMDAxMiwgMjIuMzY3OTA1OTkyMDAwMTMyXSxcbiAgICAgIFsxMTQuMTA0ODI4MzIxMDAwMDQsIDIyLjM2OTg1OTExNzAwMDEzMl0sXG4gICAgICBbMTE0LjEwMTE2NjIxMTUwMDA0LCAyMi4zNjY0NDExNDgwMDAxMl0sXG4gICAgICBbMTE0LjA5NzUwNDEwMjAwMDA0LCAyMi4zNjMwMjMxNzkwMDAxMV0sXG4gICAgICBbMTE0LjA4ODMwODEzODUwMDA1LCAyMi4zNjQ0ODgwMjMwMDAxMl0sXG4gICAgICBbMTE0LjA3OTExMjE3NTAwMDA2LCAyMi4zNjU5NTI4NjcwMDAxMzJdLFxuICAgICAgWzExNC4wNzg3MDUyNzQwMDAwNywgMjIuMzY0NDA2NjQzMDAwMTM3XSxcbiAgICAgIFsxMTQuMDc4Mjk4MzczMDAwMDgsIDIyLjM2Mjg2MDQxOTAwMDE0M10sXG4gICAgICBbMTE0LjA3NDM1MTQzMzAwMDE1LCAyMi4zNjI4NjA0MTkwMDAxNDNdLFxuICAgICAgWzExNC4wNzA0MDQ0OTMwMDAyMSwgMjIuMzYyODYwNDE5MDAwMTQzXSxcbiAgICAgIFsxMTQuMDY4ODE3NTc5MDAwMTgsIDIyLjM2MDkyNzYzOTAwMDE0XSxcbiAgICAgIFsxMTQuMDY3MjMwNjY1MDAwMTUsIDIyLjM1ODk5NDg1OTAwMDEzNF0sXG4gICAgICBbMTE0LjA2MjU5MTk5MzAwMDA3LCAyMi4zNjAxNTQ1MjcwMDAxMl0sXG4gICAgICBbMTE0LjA1Nzk1MzMyMDk5OTk5LCAyMi4zNjEzMTQxOTUwMDAxMDVdLFxuICAgICAgWzExNC4wNTQwODc3NjA5OTk5OCwgMjIuMzYwMTU0NTI3MDAwMTJdLFxuICAgICAgWzExNC4wNTAyMjIyMDA5OTk5NywgMjIuMzU4OTk0ODU5MDAwMTM0XSxcbiAgICAgIFsxMTQuMDQ1MDU0NTU4MDAwMDYsIDIyLjM1NzAwMTA0NDAwMDE0M10sXG4gICAgICBbMTE0LjAzOTg4NjkxNTAwMDE1LCAyMi4zNTUwMDcyMjkwMDAxNV0sXG4gICAgICBbMTE0LjAzMDIwMjY3MDAwMDIsIDIyLjM1MjY4Nzg5MzAwMDA5NV0sXG4gICAgICBbMTE0LjAyMDUxODQyNTAwMDIzLCAyMi4zNTAzNjg1NTcwMDAwNF0sXG4gICAgICBbMTE0LjAxNzc1MTQ5ODAwMDE0LCAyMi4zNTE5MTQ3ODEwMDAwNzZdLFxuICAgICAgWzExNC4wMTQ5ODQ1NzEwMDAwNCwgMjIuMzUzNDYxMDA1MDAwMTEzXSxcbiAgICAgIFsxMTQuMDE0OTg0NTcxMDAwMDQsIDIyLjM1NjIyNzkzMjAwMDEyNF0sXG4gICAgICBbMTE0LjAxNDk4NDU3MTAwMDA0LCAyMi4zNTg5OTQ4NTkwMDAxMzRdLFxuICAgICAgWzExNC4wMDY4MDU4NjAwMDAxMywgMjIuMzU4OTk0ODU5MDAwMTM0XSxcbiAgICAgIFsxMTMuOTk4NjI3MTQ5MDAwMjEsIDIyLjM1ODk5NDg1OTAwMDEzNF0sXG4gICAgICBbMTEzLjk5NTI0OTg3MDUwMDE1LCAyMi4zNjE1Mzc5OTA1MDAxNF0sXG4gICAgICBbMTEzLjk5MTg3MjU5MjAwMDA4LCAyMi4zNjQwODExMjIwMDAxNDRdLFxuICAgICAgWzExMy45ODcyNzQ2MTA1MDAwNCwgMjIuMzY1NDIzODk1NTAwMV0sXG4gICAgICBbMTEzLjk4MjY3NjYyOSwgMjIuMzY2NzY2NjY5MDAwMDU3XSxcbiAgICAgIFsxMTMuOTc5NzA2MjUxMDAwMDQsIDIyLjM3Mjk5MjI1NTAwMDFdLFxuICAgICAgWzExMy45NzY3MzU4NzMwMDAwOCwgMjIuMzc5MjE3ODQxMDAwMTRdLFxuICAgICAgWzExMy45NzQ4MjM0Mzg1MDAxMiwgMjIuMzc5NjA0Mzk3MDAwMTA4XSxcbiAgICAgIFsxMTMuOTcyOTExMDA0MDAwMTcsIDIyLjM3OTk5MDk1MzAwMDA3NV0sXG4gICAgICBbMTEzLjk3MTc3MTY4MTAwMDEyLCAyMi4zODM1MzA5OTIwMDAxMDRdLFxuICAgICAgWzExMy45NzA2MzIzNTgwMDAwNywgMjIuMzg3MDcxMDMxMDAwMTMzXSxcbiAgICAgIFsxMTMuOTY3NDk5MjIwMDAwMTUsIDIyLjM4Mzg3Njg1NzUwMDEyN10sXG4gICAgICBbMTEzLjk2NDM2NjA4MjAwMDIzLCAyMi4zODA2ODI2ODQwMDAxMl0sXG4gICAgICBbMTEzLjk2OTQ5MzAzNTAwMDE0LCAyMi4zNzYzNjk1MzMwMDAxMTZdLFxuICAgICAgWzExMy45NzQ2MTk5ODgwMDAwNiwgMjIuMzcyMDU2MzgyMDAwMTFdLFxuICAgICAgWzExMy45NjQ3NzI5ODI1MDAwNSwgMjIuMzcwOTU3NzQ5NTAwMTJdLFxuICAgICAgWzExMy45NTQ5MjU5NzcwMDAwNCwgMjIuMzY5ODU5MTE3MDAwMTMyXSxcbiAgICAgIFsxMTMuOTQ5ODgwNDA0NTAwMDUsIDIyLjM2NTk3MzIxMjAwMDEyOF0sXG4gICAgICBbMTEzLjk0NDgzNDgzMjAwMDA1LCAyMi4zNjIwODczMDcwMDAxMjRdLFxuICAgICAgWzExMy45Mzc3NTQ3NTM1MDAxNCwgMjIuMzY1NTg2NjU2MDAwMDYyXSxcbiAgICAgIFsxMTMuOTMwNjc0Njc1MDAwMjMsIDIyLjM2OTA4NjAwNV0sXG4gICAgICBbMTEzLjkyODMxNDY0OTAwMDEzLCAyMi4zNjkwODYwMDVdLFxuICAgICAgWzExMy45MjU5NTQ2MjMwMDAwMiwgMjIuMzY5MDg2MDA1XSxcbiAgICAgIFsxMTMuOTIwMTc2NjI4NTAwMDMsIDIyLjM3MjYwNTY5OTAwMDAzM10sXG4gICAgICBbMTEzLjkxNDM5ODYzNDAwMDA0LCAyMi4zNzYxMjUzOTMwMDAwNjZdLFxuICAgICAgWzExMy45MTYzNTE3NTkwMDAwNCwgMjIuMzgxOTg0NzY4MDAwMDY2XSxcbiAgICAgIFsxMTMuOTE4MzA0ODg0MDAwMDQsIDIyLjM4Nzg0NDE0MzAwMDA2Nl0sXG4gICAgICBbMTEzLjkxNDQzOTMyNDAwMDA2LCAyMi4zOTMyNTU5MjY1MDAwNl0sXG4gICAgICBbMTEzLjkxMDU3Mzc2NDAwMDA4LCAyMi4zOTg2Njc3MTAwMDAwNTVdLFxuICAgICAgWzExMy45MDM3Nzg1MTY1MDAxNSwgMjIuNDAzNzEzMjgzMDAwMDQ0XSxcbiAgICAgIFsxMTMuODk2OTgzMjY5MDAwMjMsIDIyLjQwODc1ODg1NjAwMDAzNF0sXG4gICAgICBbMTEzLjkwMzIwODg1NTAwMDE0LCAyMi40MTM2ODIzNTg1MDAwODNdLFxuICAgICAgWzExMy45MDk0MzQ0NDEwMDAwNiwgMjIuNDE4NjA1ODYxMDAwMTNdLFxuICAgICAgWzExMy45MjAwNTQ1NTgwMDAxNSwgMjIuNDE5MjE2MjEzMDAwMDk4XSxcbiAgICAgIFsxMTMuOTMwNjc0Njc1MDAwMjMsIDIyLjQxOTgyNjU2NTAwMDA2NV0sXG4gICAgICBbMTEzLjkzNTg0MjMxODUwMDE0LCAyMi40MjMzMDU1Njg1MDAwNTVdLFxuICAgICAgWzExMy45NDEwMDk5NjIwMDAwNCwgMjIuNDI2Nzg0NTcyMDAwMDQ1XSxcbiAgICAgIFsxMTMuOTQ3NTYxMDY4NTAwMDgsIDIyLjQzODEzNzExMTUwMDA3XSxcbiAgICAgIFsxMTMuOTU0MTEyMTc1MDAwMTIsIDIyLjQ0OTQ4OTY1MTAwMDA5M10sXG4gICAgICBbMTEzLjk2NTgzMDkyNTAwMDEyLCAyMi40NTQxNjkwMTI1MDAwNl0sXG4gICAgICBbMTEzLjk3NzU0OTY3NTAwMDEyLCAyMi40NTg4NDgzNzQwMDAwMjddLFxuICAgICAgWzExMy45ODgwODg0MTIwMDAxNywgMjIuNDczNzAwMjYyNTAwMDldLFxuICAgICAgWzExMy45OTg2MjcxNDkwMDAyMSwgMjIuNDg4NTUyMTUxMDAwMTVdLFxuICAgICAgWzExNC4wMDE3NjAyODcwMDAyLCAyMi40ODg1NTIxNTEwMDAxNV0sXG4gICAgICBbMTE0LjAwNDg5MzQyNTAwMDE4LCAyMi40ODg1NTIxNTEwMDAxNV0sXG4gICAgICBbMTE0LjAwODc5OTY3NTAwMDIsIDIyLjQ4NzMzMTQ0NzUwMDE0XSxcbiAgICAgIFsxMTQuMDEyNzA1OTI1MDAwMjMsIDIyLjQ4NjExMDc0NDAwMDEzXSxcbiAgICAgIFsxMTQuMDEyMjE3NjQ0MDAwMTUsIDIyLjQ4MzA3OTMzMTUwMDA4XSxcbiAgICAgIFsxMTQuMDExNzI5MzYzMDAwMDYsIDIyLjQ4MDA0NzkxOTAwMDAzXSxcbiAgICAgIFsxMTQuMDExNDQ0NTMyMDAwMDQsIDIyLjQ3NjQ2NzE4OTUwMDAxM10sXG4gICAgICBbMTE0LjAxMTE1OTcwMTAwMDAzLCAyMi40NzI4ODY0Nl0sXG4gICAgICBbMTE0LjAxMzA3MjEzNjAwMDAzLCAyMi40NzQwNDYxMjgwMDAwN10sXG4gICAgICBbMTE0LjAxNDk4NDU3MTAwMDA0LCAyMi40NzUyMDU3OTYwMDAxNF0sXG4gICAgICBbMTE0LjAyMDg4NDYzNjAwMDAzLCAyMi40NzY3MzE2NzUwMDAxNF0sXG4gICAgICBbMTE0LjAyNjc4NDcwMTAwMDAzLCAyMi40NzgyNTc1NTQwMDAxMzddLFxuICAgICAgWzExNC4wMjgzMzA5MjUwMDAwNiwgMjIuNDc4MjU3NTU0MDAwMTM3XSxcbiAgICAgIFsxMTQuMDI5ODc3MTQ5MDAwMSwgMjIuNDc4MjU3NTU0MDAwMTM3XSxcbiAgICAgIFsxMTQuMDMwNjUwMjYxMDAwMTIsIDIyLjQ4MDI1MTM2OTAwMDEzXSxcbiAgICAgIFsxMTQuMDMxNDIzMzczMDAwMTQsIDIyLjQ4MjI0NTE4NDAwMDEyXSxcbiAgICAgIFsxMTQuMDMxMDE2NDcyMDAwMDksIDIyLjQ4NDk1MTA3NjAwMDE0NF0sXG4gICAgICBbMTE0LjAzMDYwOTU3MTAwMDA0LCAyMi40ODc2NTY5NjgwMDAxNjddLFxuICAgICAgWzExNC4wMzA2MDk1NzEwMDAwNCwgMjIuNDkxNTgzNTYzMDAwMTQ4XSxcbiAgICAgIFsxMTQuMDMwNjA5NTcxMDAwMDQsIDIyLjQ5NTUxMDE1ODAwMDEzXSxcbiAgICAgIFsxMTQuMDM2NDI4MjU2MDAwMDIsIDIyLjQ5ODI1Njc0MDAwMDE0NF0sXG4gICAgICBbMTE0LjA0MjI0Njk0MSwgMjIuNTAxMDAzMzIyMDAwMTZdLFxuICAgICAgWzExNC4wNTAxMDAxMzEsIDIyLjUwMjkzNjEwMjAwMDA3OF0sXG4gICAgICBbMTE0LjA1Nzk1MzMyMDk5OTk5LCAyMi41MDQ4Njg4ODJdLFxuICAgICAgWzExNC4wNTk4NjU3NTYwMDAwNSwgMjIuNTA2ODIyMDA3MDAwMDRdLFxuICAgICAgWzExNC4wNjE3NzgxOTEwMDAxMiwgMjIuNTA4Nzc1MTMyMDAwMDgyXSxcbiAgICAgIFsxMTQuMDYzNzcyMDA2MDAwMTEsIDIyLjUxMjMxNTE3MTAwMDExXSxcbiAgICAgIFsxMTQuMDY1NzY1ODIxMDAwMSwgMjIuNTE1ODU1MjEwMDAwMTRdLFxuICAgICAgWzExNC4wNjk2MzEzODEwMDAxNCwgMjIuNTE3MDE0ODc4MDAwMTI2XSxcbiAgICAgIFsxMTQuMDczNDk2OTQxMDAwMTcsIDIyLjUxODE3NDU0NjAwMDExXSxcbiAgICAgIFsxMTQuMDc1ODk3NjU3MDAwMTMsIDIyLjUxODk0NzY1ODAwMDEzXSxcbiAgICAgIFsxMTQuMDc4Mjk4MzczMDAwMDgsIDIyLjUxOTcyMDc3MDAwMDE1XSxcbiAgICAgIFsxMTQuMDgxNzk3NzIyMDAwMTIsIDIyLjUyMTMyODAyOTUwMDEyNV0sXG4gICAgICBbMTE0LjA4NTI5NzA3MTAwMDE2LCAyMi41MjI5MzUyODkwMDAxMDJdLFxuICAgICAgWzExNC4wODM4MzIyMjc1MDAxNSwgMjIuNTI2MTQ5ODA3MDAwMTFdLFxuICAgICAgWzExNC4wODIzNjczODQwMDAxNSwgMjIuNTI5MzY0MzI1MDAwMTE3XSxcbiAgICAgIFsxMTQuMDg2OTE1OTMxMDAwMTYsIDIyLjUzMTg3NjEyMjAwMDA1N10sXG4gICAgICBbMTE0LjA5MTQ2NDQ3ODAwMDE4LCAyMi41MzQzODc5MTldLFxuICAgICAgWzExNC4wOTk5Mzk0MTI1MDAxLCAyMi41MzQzODc5MTldLFxuICAgICAgWzExNC4xMDg0MTQzNDcwMDAwNCwgMjIuNTM0Mzg3OTE5XSxcbiAgICAgIFsxMTQuMTExMjA0ODc0NTAwMDMsIDIyLjUzMTU5NzM5MTUwMDA0M10sXG4gICAgICBbMTE0LjExMzk5NTQwMjAwMDAzLCAyMi41Mjg4MDY4NjQwMDAwOV0sXG4gICAgICBbMTE0LjExNTU0NTY5NTAwMDEsIDIyLjUyODE4Njc0NzAwMDA2M10sXG4gICAgICBbMTE0LjExNzA5NTk4ODAwMDE2LCAyMi41Mjc1NjY2MzAwMDAwMzhdLFxuICAgICAgWzExNC4xMjI5ODcxMDEwMDAxMiwgMjIuNTMyODM3NjI2NTAwMDddLFxuICAgICAgWzExNC4xMjg4NzgyMTQwMDAwOCwgMjIuNTM4MTA4NjIzMDAwMV0sXG4gICAgICBbMTE0LjEzMzUyOTA5MzAwMDEzLCAyMi41Mzg3Mjg3NDAwMDAxMjRdLFxuICAgICAgWzExNC4xMzgxNzk5NzIwMDAxOSwgMjIuNTM5MzQ4ODU3MDAwMTVdLFxuICAgICAgWzExNC4xNDM0NTA5Njg1MDAxMywgMjIuNTM4NzI4NzQwMDAwMTI0XSxcbiAgICAgIFsxMTQuMTQ4NzIxOTY1MDAwMDgsIDIyLjUzODEwODYyMzAwMDFdLFxuICAgICAgWzExNC4xNTEzMDU3ODcwMDAxNSwgMjIuNTQ0OTgxNTg4NTAwMTJdLFxuICAgICAgWzExNC4xNTM4ODk2MDkwMDAyMywgMjIuNTUxODU0NTU0MDAwMTQ0XSxcbiAgICAgIFsxMTQuMTU3OTIwMzcwNTAwMiwgMjIuNTU2MTk1Mzc0MDAwMTI2XSxcbiAgICAgIFsxMTQuMTYxOTUxMTMyMDAwMTUsIDIyLjU2MDUzNjE5NDAwMDEwN10sXG4gICAgICBbMTE0LjE2NzU4NDI2NjUwMDE3LCAyMi41NjIyNDExMTMwMDAwODRdLFxuICAgICAgWzExNC4xNzMyMTc0MDEwMDAxOSwgMjIuNTYzOTQ2MDMyMDAwMDZdLFxuICAgICAgWzExNC4xNzgxMjYyNTg1MDAxOSwgMjIuNTYwMDcwNzAzMDAwMDkzXSxcbiAgICAgIFsxMTQuMTgzMDM1MTE2MDAwMTgsIDIyLjU1NjE5NTM3NDAwMDEyNl0sXG4gICAgICBbMTE0LjE5MTQ1ODM3NDUwMDE3LCAyMi41NTYxOTUzNzQwMDAxMjZdLFxuICAgICAgWzExNC4xOTk4ODE2MzMwMDAxNiwgMjIuNTU2MTk1Mzc0MDAwMTI2XSxcbiAgICAgIFsxMTQuMjEwMjk3Njg1NTAwMTQsIDIyLjU1NTY1ODI2NzUwMDA5M10sXG4gICAgICBbMTE0LjIyMDcxMzczODAwMDExLCAyMi41NTUxMjExNjEwMDAwNl0sXG4gICAgICBbMTE0LjIyNTI3MTAyOTUwMDA4LCAyMi41NTU0NjcwMjcwMDAwNzddLFxuICAgICAgWzExNC4yMjk4MjgzMjEwMDAwNCwgMjIuNTU1ODEyODkzMDAwMDk1XSxcbiAgICAgIFsxMTQuMjMyMjY5NzI3NTAwMDEsIDIyLjU1NTk5NTk5ODUwMDA5NF0sXG4gICAgICBbMTE0LjIzNDcxMTEzMzk5OTk4LCAyMi41NTYxNzkxMDQwMDAwOTRdLFxuICAgICAgWzExNC4yMzA5Njc2NDQ1MDAwNSwgMjIuNTUxNjIxODEyMDAwMDY0XSxcbiAgICAgIFsxMTQuMjI3MjI0MTU1MDAwMTMsIDIyLjU0NzA2NDUyMDAwMDAzNV0sXG4gICAgICBbMTE0LjIyNDcwMTM2ODUwMDA5LCAyMi41NDQyNTY5MDMwMDAwNzVdLFxuICAgICAgWzExNC4yMjIxNzg1ODIwMDAwNSwgMjIuNTQxNDQ5Mjg2MDAwMTE2XSxcbiAgICAgIFsxMTQuMjE4NTE2NDcyNTAwMDYsIDIyLjUzNzk3MDI4MjAwMDA3NF0sXG4gICAgICBbMTE0LjIxNDg1NDM2MzAwMDA2LCAyMi41MzQ0OTEyNzgwMDAwMzNdLFxuICAgICAgWzExNC4yMTI0MTI5NTY1MDAwOSwgMjIuNTM0NDkxMjc4MDAwMDMzXSxcbiAgICAgIFsxMTQuMjA5OTcxNTUwMDAwMTIsIDIyLjUzNDQ5MTI3ODAwMDAzM10sXG4gICAgICBbMTE0LjIwOTY0NjAyOTUwMDE0LCAyMi41MjkwOTk4Mzk1MDAwNzddLFxuICAgICAgWzExNC4yMDkzMjA1MDkwMDAxNSwgMjIuNTIzNzA4NDAxMDAwMTJdLFxuICAgICAgWzExNC4yMTM2MzM2NjAwMDAxMSwgMjIuNTI0ODY4MDY4NTAwMDk4XSxcbiAgICAgIFsxMTQuMjE3OTQ2ODExMDAwMDgsIDIyLjUyNjAyNzczNjAwMDA3NF0sXG4gICAgICBbMTE0LjIxODMxMzAyMjAwMDA3LCAyMi41Mjc5NDAxNzEwMDAwODNdLFxuICAgICAgWzExNC4yMTg2NzkyMzMwMDAwNywgMjIuNTI5ODUyNjA2MDAwMDldLFxuICAgICAgWzExNC4yMjQ1Mzg2MDgwMDAxMywgMjIuNTMxMzk4ODMwMDAwMDQzXSxcbiAgICAgIFsxMTQuMjMwMzk3OTgzMDAwMTksIDIyLjUzMjk0NTA1NF0sXG4gICAgICBbMTE0LjIzMjM1MTEwODAwMDIyLCAyMi41MzQ5Mzg4NjkwMDAwNzJdLFxuICAgICAgWzExNC4yMzQzMDQyMzMwMDAyNCwgMjIuNTM2OTMyNjg0MDAwMTVdLFxuICAgICAgWzExNC4yMzgxNjk3OTI1MDAxNywgMjIuNTQzNTY1MTcxMDAwMTI1XSxcbiAgICAgIFsxMTQuMjQyMDM1MzUyMDAwMSwgMjIuNTUwMTk3NjU4MDAwMV0sXG4gICAgICBbMTE0LjI0Mzk4ODQ3NzAwMDEsIDIyLjU1MDU4NDIxNDAwMDA1XSxcbiAgICAgIFsxMTQuMjQ1OTQxNjAyMDAwMSwgMjIuNTUwOTcwNzddLFxuICAgICAgWzExNC4yNDc0ODc4MjYwMDAxNCwgMjIuNTQ5NDA0MjAxMDAwMDddLFxuICAgICAgWzExNC4yNDkwMzQwNTAwMDAxOCwgMjIuNTQ3ODM3NjMyMDAwMTRdLFxuICAgICAgWzExNC4yNTE4MDA5Nzc1MDAxOCwgMjIuNTQ5NDA0MjAxMDAwMDddLFxuICAgICAgWzExNC4yNTQ1Njc5MDUwMDAxOSwgMjIuNTUwOTcwNzddLFxuICAgICAgWzExNC4yNTYxMTQxMjg1MDAxNywgMjIuNTQ5NDA0MjAxMDAwMDddLFxuICAgICAgWzExNC4yNTc2NjAzNTIwMDAxNiwgMjIuNTQ3ODM3NjMyMDAwMTRdLFxuICAgICAgWzExNC4yNTU0NjMwODY1MDAwNywgMjIuNTQzNjQ2NTUxNTAwMTAzXSxcbiAgICAgIFsxMTQuMjUzMjY1ODIwOTk5OTksIDIyLjUzOTQ1NTQ3MTAwMDA2OF0sXG4gICAgICBbMTE0LjI1NjIzNjE5ODUsIDIyLjU0MDEyNjg1NzUwMDExM10sXG4gICAgICBbMTE0LjI1OTIwNjU3NjAwMDAzLCAyMi41NDA3OTgyNDQwMDAxNThdLFxuICAgICAgWzExNC4yNjI0MjEwOTQ1MDAxMywgMjIuNTM4MDMxMzE3MDAwMTQ3XSxcbiAgICAgIFsxMTQuMjY1NjM1NjEzMDAwMjMsIDIyLjUzNTI2NDM5MDAwMDEzN10sXG4gICAgICBbMTE0LjI2NTM5MTQ3MjUwMDIzLCAyMi41MzE4NjY3NjY1MDAwODddLFxuICAgICAgWzExNC4yNjUxNDczMzIwMDAyMywgMjIuNTI4NDY5MTQzMDAwMDM4XSxcbiAgICAgIFsxMTQuMjY3NTg4NzM4MDAwMTcsIDIyLjUyNzAyNDY0NDAwMDA2NV0sXG4gICAgICBbMTE0LjI3MDAzMDE0NDAwMDEyLCAyMi41MjU1ODAxNDUwMDAwOV0sXG4gICAgICBbMTE0LjI3NDAxNzc3NDUwMDEsIDIyLjUyNzcxNjM3NTUwMDA5XSxcbiAgICAgIFsxMTQuMjc4MDA1NDA1MDAwMDcsIDIyLjUyOTg1MjYwNjAwMDA5XSxcbiAgICAgIFsxMTQuMjc4OTAwNTg3MDAwMTUsIDIyLjUyNzk0MDE3MTAwMDA4M10sXG4gICAgICBbMTE0LjI3OTc5NTc2OTAwMDIzLCAyMi41MjYwMjc3MzYwMDAwNzRdLFxuICAgICAgWzExNC4yNzk3OTU3NjkwMDAyMywgMjIuNTIyODc0MjUzMDAwMTFdLFxuICAgICAgWzExNC4yNzk3OTU3NjkwMDAyMywgMjIuNTE5NzIwNzcwMDAwMTVdLFxuICAgICAgWzExNC4yNzg3Mzc4MjY1MDAxOSwgMjIuNTE1NjkyNDUwMDAwMDldLFxuICAgICAgWzExNC4yNzc2Nzk4ODQwMDAxNSwgMjIuNTExNjY0MTMwMDAwMDI4XSxcbiAgICAgIFsxMTQuMjgxNDIzMzczNTAwMTMsIDIyLjUxMTQxOTk4OTAwMDA3NV0sXG4gICAgICBbMTE0LjI4NTE2Njg2MzAwMDExLCAyMi41MTExNzU4NDgwMDAxMl0sXG4gICAgICBbMTE0LjI4NzIwMTM2ODAwMDEsIDIyLjUwODE4NTEyNTUwMDEwNl0sXG4gICAgICBbMTE0LjI4OTIzNTg3MzAwMDA4LCAyMi41MDUxOTQ0MDMwMDAwOV0sXG4gICAgICBbMTE0LjI5Mzg3NDU0NTAwMDE0LCAyMi41MDMwOTg4NjI1MDAxMjRdLFxuICAgICAgWzExNC4yOTg1MTMyMTcwMDAxOSwgMjIuNTAxMDAzMzIyMDAwMTZdLFxuICAgICAgWzExNC4zMTI1NTEzMDMwMDAxNiwgMjIuNTA0ODg5MjI3MDAwMTJdLFxuICAgICAgWzExNC4zMjY1ODkzODkwMDAxMywgMjIuNTA4Nzc1MTMyMDAwMDgyXSxcbiAgICAgIFsxMTQuMzI5NjgxODM3MDAwMTUsIDIyLjUxMDM2MjA0NjAwMDExXSxcbiAgICAgIFsxMTQuMzMyNzc0Mjg1MDAwMTcsIDIyLjUxMTk0ODk2MDAwMDE0XSxcbiAgICAgIFsxMTQuMzMzOTU0Mjk4MDAwMSwgMjIuNTA5MTgyMDMzMDAwMDg3XSxcbiAgICAgIFsxMTQuMzM1MTM0MzExMDAwMDIsIDIyLjUwNjQxNTEwNjAwMDAzNF0sXG4gICAgICBbMTE0LjMyNTczNDg5NzAwMDA1LCAyMi40OTkzOTYwNjMwMDAwNV0sXG4gICAgICBbMTE0LjMxNjMzNTQ4MzAwMDA3LCAyMi40OTIzNzcwMjAwMDAwNjNdLFxuICAgICAgWzExNC4zMTA4ODMwMDkwMDAwNCwgMjIuNDg3Njk3NjU4MDAwMDZdLFxuICAgICAgWzExNC4zMDU0MzA1MzUsIDIyLjQ4MzAxODI5NjAwMDA1NF0sXG4gICAgICBbMTE0LjI5OTUzMDQ3MDAwMDA0LCAyMi40ODA2Mzc5MjUwMDAwOTZdLFxuICAgICAgWzExNC4yOTM2MzA0MDUwMDAwNywgMjIuNDc4MjU3NTU0MDAwMTM3XSxcbiAgICAgIFsxMTQuMjg3MDM4NjA4MDAwMTMsIDIyLjQ3NTU3MjAwNzAwMDA2OF0sXG4gICAgICBbMTE0LjI4MDQ0NjgxMTAwMDE5LCAyMi40NzI4ODY0Nl0sXG4gICAgICBbMTE0LjI3NDU4NzQzNjAwMDE5LCAyMi40Njg5NTk4NjUwMDAwMDJdLFxuICAgICAgWzExNC4yNjg3MjgwNjEwMDAxOSwgMjIuNDY1MDMzMjddLFxuICAgICAgWzExNC4yNjY0MDg3MjUwMDAxOSwgMjIuNDYxNTU0MjY2MDAwMDQ2XSxcbiAgICAgIFsxMTQuMjY0MDg5Mzg5MDAwMTksIDIyLjQ1ODA3NTI2MjAwMDA5NF0sXG4gICAgICBbMTE0LjI1ODkyMTc0NTUwMDE3LCAyMi40NTQ5MjE3NzkwMDAxM10sXG4gICAgICBbMTE0LjI1Mzc1NDEwMjAwMDE2LCAyMi40NTE3NjgyOTYwMDAxNjhdLFxuICAgICAgWzExNC4yNDk4NDc4NTIwMDAxMywgMjIuNDUxNzY4Mjk2MDAwMTY4XSxcbiAgICAgIFsxMTQuMjQ1OTQxNjAyMDAwMSwgMjIuNDUxNzY4Mjk2MDAwMTY4XSxcbiAgICAgIFsxMTQuMjM4NTc2NjkzNTAwMTQsIDIyLjQ2MDc4MTE1NDAwMDEzXSxcbiAgICAgIFsxMTQuMjMxMjExNzg1MDAwMTcsIDIyLjQ2OTc5NDAxMjAwMDA5NF0sXG4gICAgICBbMTE0LjIyNDE3MjM5NzAwMDE2LCAyMi40Njg1NzMzMDkwMDAxMl0sXG4gICAgICBbMTE0LjIxNzEzMzAwOTAwMDE1LCAyMi40NjczNTI2MDYwMDAxNDhdLFxuICAgICAgWzExNC4yMTQ0NDc0NjIwMDAwNywgMjIuNDY4OTU5ODY1MDAwMDg3XSxcbiAgICAgIFsxMTQuMjExNzYxOTE0OTk5OTgsIDIyLjQ3MDU2NzEyNDAwMDAyN10sXG4gICAgICBbMTE0LjIxMDU0MTIxMjAwMDA3LCAyMi40NjgxODY3NTMwMDAwN10sXG4gICAgICBbMTE0LjIwOTMyMDUwOTAwMDE1LCAyMi40NjU4MDYzODIwMDAxMV0sXG4gICAgICBbMTE0LjIxMDEzNDMxMTAwMDEsIDIyLjQ2MTU1NDI2NjUwMDFdLFxuICAgICAgWzExNC4yMTA5NDgxMTMwMDAwNiwgMjIuNDU3MzAyMTUxMDAwMDkzXSxcbiAgICAgIFsxMTQuMjEzMjY3NDQ5MDAwMDMsIDIyLjQ1NjE0MjQ4MzAwMDEwN10sXG4gICAgICBbMTE0LjIxNTU4Njc4NSwgMjIuNDU0OTgyODE1MDAwMTIyXSxcbiAgICAgIFsxMTQuMjE2MzU5ODk3MDAwMDcsIDIyLjQ1MTQ2MzEyMTAwMDA5XSxcbiAgICAgIFsxMTQuMjE3MTMzMDA5MDAwMTUsIDIyLjQ0Nzk0MzQyNzAwMDA1NV0sXG4gICAgICBbMTE0LjIxMzU1MjI3OTUwMDE0LCAyMi40NDg3MTY1MzkwMDAwNzRdLFxuICAgICAgWzExNC4yMDk5NzE1NTAwMDAxMiwgMjIuNDQ5NDg5NjUxMDAwMDkzXSxcbiAgICAgIFsxMTQuMjA5NjQ2MDI5NTAwMTQsIDIyLjQ1MTc4ODY0MTUwMDExNl0sXG4gICAgICBbMTE0LjIwOTMyMDUwOTAwMDE1LCAyMi40NTQwODc2MzIwMDAxNF0sXG4gICAgICBbMTE0LjIwNTc4MDQ3MDAwMDEyLCAyMi40NTYwODE0NDcwMDAxMTZdLFxuICAgICAgWzExNC4yMDIyNDA0MzEwMDAwOSwgMjIuNDU4MDc1MjYyMDAwMDk0XSxcbiAgICAgIFsxMTQuMTk2NDIxNzQ2MDAwMTQsIDIyLjQ1NzMwMjE1MDUwMDEyNl0sXG4gICAgICBbMTE0LjE5MDYwMzA2MTAwMDE5LCAyMi40NTY1MjkwMzkwMDAxNl0sXG4gICAgICBbMTE0LjE4ODY0OTkzNjAwMDE5LCAyMi40NTQxNDg2Njc1MDAxNjRdLFxuICAgICAgWzExNC4xODY2OTY4MTEwMDAxOSwgMjIuNDUxNzY4Mjk2MDAwMTY4XSxcbiAgICAgIFsxMTQuMTc3MDkzOTQ2NTAwMjEsIDIyLjQ0OTkxNjg5NjUwMDFdLFxuICAgICAgWzExNC4xNjc0OTEwODIwMDAyMywgMjIuNDQ4MDY1NDk3MDAwMDNdLFxuICAgICAgWzExNC4xNzIwMDc2ODM1MDAxNCwgMjIuNDQ1NjQ0NDM1NTAwMDg1XSxcbiAgICAgIFsxMTQuMTc2NTI0Mjg1MDAwMDYsIDIyLjQ0MzIyMzM3NDAwMDE0XSxcbiAgICAgIFsxMTQuMTgyMDE3NDQ5MDAwMDksIDIyLjQzOTY4MzMzNTAwMDExXSxcbiAgICAgIFsxMTQuMTg3NTEwNjEzMDAwMTEsIDIyLjQzNjE0MzI5NjAwMDA4M10sXG4gICAgICBbMTE0LjE5Mzg1ODI2OTAwMDE1LCAyMi40MzIxNTU2NjYwMDAxXSxcbiAgICAgIFsxMTQuMjAwMjA1OTI1MDAwMTgsIDIyLjQyODE2ODAzNjAwMDExNl0sXG4gICAgICBbMTE0LjIwNTk4MzkyMDAwMDA4LCAyMi40MjQzODM4NTY1MDAwNTddLFxuICAgICAgWzExNC4yMTE3NjE5MTQ5OTk5OCwgMjIuNDIwNTk5Njc3XSxcbiAgICAgIFsxMTQuMjEwODY2NzMyNTAwMDUsIDIyLjQxNjY3MzA4MTUwMDA1XSxcbiAgICAgIFsxMTQuMjA5OTcxNTUwMDAwMTIsIDIyLjQxMjc0NjQ4NjAwMDEwM10sXG4gICAgICBbMTE0LjIxMjQxMjk1NjUwMDA5LCAyMi40MTA4MTM3MDY1MDAwNV0sXG4gICAgICBbMTE0LjIxNDg1NDM2MzAwMDA2LCAyMi40MDg4ODA5MjddLFxuICAgICAgWzExNC4yMTIwODc0MzYwMDAxLCAyMi40MDM3NzQzMTg1MDAwMjddLFxuICAgICAgWzExNC4yMDkzMjA1MDkwMDAxNSwgMjIuMzk4NjY3NzEwMDAwMDU1XSxcbiAgICAgIFsxMTQuMjEyNDUzNjQ3MDAwMDcsIDIyLjM5OTUwMTg1NzUwMDA3XSxcbiAgICAgIFsxMTQuMjE1NTg2Nzg1LCAyMi40MDAzMzYwMDUwMDAwODVdLFxuICAgICAgWzExNC4yMTk0OTMwMzUwMDAwNiwgMjIuNDA3NjgwNTY4NTAwMDgzXSxcbiAgICAgIFsxMTQuMjIzMzk5Mjg1MDAwMTEsIDIyLjQxNTAyNTEzMjAwMDA4Ml0sXG4gICAgICBbMTE0LjIyODgxMTA2ODUwMDA1LCAyMi40MTk4ODc1OTk1MDAxXSxcbiAgICAgIFsxMTQuMjM0MjIyODUxOTk5OTksIDIyLjQyNDc1MDA2NzAwMDEyXSxcbiAgICAgIFsxMTQuMjM2MjE2NjY3NTAwMTIsIDIyLjQzMDA2MDEyNTUwMDEzNF0sXG4gICAgICBbMTE0LjIzODIxMDQ4MzAwMDI0LCAyMi40MzUzNzAxODQwMDAxNV0sXG4gICAgICBbMTE0LjI0MTAxODEwMDAwMDE2LCAyMi40MzU0NTE1NjQ1MDAxNF0sXG4gICAgICBbMTE0LjI0MzgyNTcxNzAwMDA4LCAyMi40MzU1MzI5NDUwMDAxMzRdLFxuICAgICAgWzExNC4yNDc2NTA1ODcwMDAxLCAyMi40MzMxMzIyMjg1MDAwODVdLFxuICAgICAgWzExNC4yNTE0NzU0NTcwMDAxMSwgMjIuNDMwNzMxNTEyMDAwMDM3XSxcbiAgICAgIFsxMTQuMjU5MzI4NjQ3MDAwMSwgMjIuNDMwNzMxNTEyMDAwMDM3XSxcbiAgICAgIFsxMTQuMjY3MTgxODM3MDAwMSwgMjIuNDMwNzMxNTEyMDAwMDM3XSxcbiAgICAgIFsxMTQuMjY4MjgwNDY5NTAwMTMsIDIyLjQyODEyNzM0NTUwMDA0NF0sXG4gICAgICBbMTE0LjI2OTM3OTEwMjAwMDE2LCAyMi40MjU1MjMxNzkwMDAwNTJdLFxuICAgICAgWzExNC4yNjgyODA0Njk1MDAxMywgMjIuNDIwNzQyMDkyMDAwMDU0XSxcbiAgICAgIFsxMTQuMjY3MTgxODM3MDAwMSwgMjIuNDE1OTYxMDA1MDAwMDU3XSxcbiAgICAgIFsxMTQuMjY5ODY3Mzg0MDAwMTUsIDIyLjQxMjgwNzUyMjAwMDA4XSxcbiAgICAgIFsxMTQuMjcyNTUyOTMxMDAwMiwgMjIuNDA5NjU0MDM5MDAwMTAyXSxcbiAgICAgIFsxMTQuMjc0NTA2MDU2MDAwMiwgMjIuNDE0NzQwMzAyMDAwMDg0XSxcbiAgICAgIFsxMTQuMjc2NDU5MTgxMDAwMiwgMjIuNDE5ODI2NTY1MDAwMDY1XSxcbiAgICAgIFsxMTQuMjgyNzI1NDU3MDAwMTcsIDIyLjQyMjkxOTAxMjUwMDA5XSxcbiAgICAgIFsxMTQuMjg4OTkxNzMzMDAwMTMsIDIyLjQyNjAxMTQ2MDAwMDExXSxcbiAgICAgIFsxMTQuMjgyNzI1NDU3MDAwMTcsIDIyLjQzNTAwMzk3MzAwMDA5M10sXG4gICAgICBbMTE0LjI3NjQ1OTE4MTAwMDIsIDIyLjQ0Mzk5NjQ4NjAwMDA3NF0sXG4gICAgICBbMTE0LjI4MjcyNTQ1NzAwMDE3LCAyMi40NDg2NTU1MDMwMDAwMzddLFxuICAgICAgWzExNC4yODg5OTE3MzMwMDAxMywgMjIuNDUzMzE0NTJdLFxuICAgICAgWzExNC4yOTUyOTg2OTkwMDAwNiwgMjIuNDU0OTIxNzc5NTAwMDhdLFxuICAgICAgWzExNC4zMDE2MDU2NjQ5OTk5OCwgMjIuNDU2NTI5MDM5MDAwMTZdLFxuICAgICAgWzExNC4zMDExOTg3NjQwMDAwNSwgMjIuNDYwNzgxMTU0NTAwMDhdLFxuICAgICAgWzExNC4zMDA3OTE4NjMwMDAxMSwgMjIuNDY1MDMzMjddLFxuICAgICAgWzExNC4zMTIyNjY0NzI1MDAwOCwgMjIuNDcyNTQwNTk0NTAwMDE0XSxcbiAgICAgIFsxMTQuMzIzNzQxMDgyMDAwMDUsIDIyLjQ4MDA0NzkxOTAwMDAzXSxcbiAgICAgIFsxMTQuMzI0MzkyMTIzNTAwMDgsIDIyLjQ3NzYyNjg1NzUwMDA4NF0sXG4gICAgICBbMTE0LjMyNTA0MzE2NTAwMDEsIDIyLjQ3NTIwNTc5NjAwMDE0XSxcbiAgICAgIFsxMTQuMzI3ODkxNDcyNTAwMDgsIDIyLjQ3NDY1NjQ4MDAwMDEyXSxcbiAgICAgIFsxMTQuMzMwNzM5NzgwMDAwMDcsIDIyLjQ3NDEwNzE2NDAwMDEwMl0sXG4gICAgICBbMTE0LjMyNzg5MTQ3MjUwMDA4LCAyMi40NjkxODM2NjEwMDAwODhdLFxuICAgICAgWzExNC4zMjUwNDMxNjUwMDAxLCAyMi40NjQyNjAxNTgwMDAwNzNdLFxuICAgICAgWzExNC4zMzAzNzM1Njg1MDAwNSwgMjIuNDYyOTk4NzY1MDAwMTFdLFxuICAgICAgWzExNC4zMzU3MDM5NzIsIDIyLjQ2MTczNzM3MjAwMDE0NF0sXG4gICAgICBbMTE0LjMzNjg4Mzk4NTAwMDA0LCAyMi40NTQwNDY5NDIwMDAxMzNdLFxuICAgICAgWzExNC4zMzgwNjM5OTgwMDAwOCwgMjIuNDQ2MzU2NTEyMDAwMTIyXSxcbiAgICAgIFsxMTQuMzM1NDE5MTQxNTAwMTMsIDIyLjQ0MzE4MjY4NDAwMDEwN10sXG4gICAgICBbMTE0LjMzMjc3NDI4NTAwMDE3LCAyMi40NDAwMDg4NTYwMDAwOV0sXG4gICAgICBbMTE0LjMzNTA5MzYyMTAwMDE0LCAyMi40MzU3OTc0MzA1MDAxMTZdLFxuICAgICAgWzExNC4zMzc0MTI5NTcwMDAxMSwgMjIuNDMxNTg2MDA1MDAwMTQyXSxcbiAgICAgIFsxMTQuMzQwMDk4NTAzNTAwMTQsIDIyLjQzNDYzNzc2MjUwMDEzXSxcbiAgICAgIFsxMTQuMzQyNzg0MDUwMDAwMTgsIDIyLjQzNzY4OTUyMDAwMDEyXSxcbiAgICAgIFsxMTQuMzQ1MTg0NzY2NTAwMjEsIDIyLjQzMDMwNDI2NjAwMDA4XSxcbiAgICAgIFsxMTQuMzQ3NTg1NDgzMDAwMjQsIDIyLjQyMjkxOTAxMjAwMDAzN10sXG4gICAgICBbMTE0LjM0OTk0NTUwOTAwMDIxLCAyMi40MjMzMDU1NjgwMDAxMDNdLFxuICAgICAgWzExNC4zNTIzMDU1MzUwMDAxNywgMjIuNDIzNjkyMTI0MDAwMTddLFxuICAgICAgWzExNC4zNTE5MzkzMjQwMDAyLCAyMi40MzIzMzg3NzE1MDAxNTZdLFxuICAgICAgWzExNC4zNTE1NzMxMTMwMDAyMywgMjIuNDQwOTg1NDE5MDAwMTQzXSxcbiAgICAgIFsxMTQuMzU1NzIzNTAzNTAwMTcsIDIyLjQ1MTA3NjU2NDUwMDA3XSxcbiAgICAgIFsxMTQuMzU5ODczODk0MDAwMTIsIDIyLjQ2MTE2NzcxXSxcbiAgICAgIFsxMTQuMzYzODYxNTI0NTAwMSwgMjIuNDU4MDc1MjYyNTAwMDZdLFxuICAgICAgWzExNC4zNjc4NDkxNTUwMDAwNywgMjIuNDU0OTgyODE1MDAwMTIyXSxcbiAgICAgIFsxMTQuMzY3NjA1MDE0MDAwMDgsIDIyLjQ1MDYyODk3MzUwMDEzXSxcbiAgICAgIFsxMTQuMzY3MzYwODczMDAwMDgsIDIyLjQ0NjI3NTEzMjAwMDE0XSxcbiAgICAgIFsxMTQuMzY4Nzg1MDI3MDAwMTQsIDIyLjQ0MzE0MTk5NDAwMDExNV0sXG4gICAgICBbMTE0LjM3MDIwOTE4MTAwMDIsIDIyLjQ0MDAwODg1NjAwMDA5XSxcbiAgICAgIFsxMTQuMzc3OTgwOTkwNTAwMTYsIDIyLjQzOTYyMjMwMDAwMDEyNF0sXG4gICAgICBbMTE0LjM4NTc1MjgwMDAwMDEyLCAyMi40MzkyMzU3NDQwMDAxNThdLFxuICAgICAgWzExNC4zOTI3NTE0OTgwMDAwNSwgMjIuNDM3Njg5NTIwMDAwMTJdLFxuICAgICAgWzExNC4zOTk3NTAxOTU5OTk5OSwgMjIuNDM2MTQzMjk2MDAwMDgzXSxcbiAgICAgIFsxMTQuMzk4NTcwMTgzMDAwMDYsIDIyLjQzMjI3NzczNjUwMDA4M10sXG4gICAgICBbMTE0LjM5NzM5MDE3MDAwMDE0LCAyMi40Mjg0MTIxNzcwMDAwODRdLFxuICAgICAgWzExNC4zOTkzNDMyOTUwMDAxNCwgMjIuNDIwNTc5MzMxNTAwMDkzXSxcbiAgICAgIFsxMTQuNDAxMjk2NDIwMDAwMTQsIDIyLjQxMjc0NjQ4NjAwMDEwM10sXG4gICAgICBbMTE0LjM5NTMxNDk3NTAwMDE2LCAyMi40MTUzMzAzMDgwMDAwNV0sXG4gICAgICBbMTE0LjM4OTMzMzUzMDAwMDE5LCAyMi40MTc5MTQxM10sXG4gICAgICBbMTE0LjM4NTU0OTM1MDAwMDIyLCAyMi40MTg0ODM3OTE1MDAwNjZdLFxuICAgICAgWzExNC4zODE3NjUxNzAwMDAyNSwgMjIuNDE5MDUzNDUzMDAwMTNdLFxuICAgICAgWzExNC4zNzU5ODcxNzU1MDAyMywgMjIuNDA4NTE0NzE2MDAwMTI3XSxcbiAgICAgIFsxMTQuMzcwMjA5MTgxMDAwMiwgMjIuMzk3OTc1OTc5MDAwMTIyXSxcbiAgICAgIFsxMTQuMzcyNjA5ODk3MDAwMTYsIDIyLjM5OTI1NzcxNzAwMDA4M10sXG4gICAgICBbMTE0LjM3NTAxMDYxMzAwMDExLCAyMi40MDA1Mzk0NTUwMDAwNDNdLFxuICAgICAgWzExNC4zNzk5NzQ4MDU1MDAxNSwgMjIuMzkzOTQ3NjU4MDAwMDZdLFxuICAgICAgWzExNC4zODQ5Mzg5OTgwMDAyLCAyMi4zODczNTU4NjEwMDAwNzRdLFxuICAgICAgWzExNC4zODczMzk3MTQ1MDAyLCAyMi4zNzY2NTQzNjQwMDAxMDNdLFxuICAgICAgWzExNC4zODk3NDA0MzEwMDAyLCAyMi4zNjU5NTI4NjcwMDAxMzJdLFxuICAgICAgWzExNC4zODgxNTM1MTY1MDAxMywgMjIuMzY1NTg2NjU2MDAwMTZdLFxuICAgICAgWzExNC4zODY1NjY2MDIwMDAwNCwgMjIuMzY1MjIwNDQ1MDAwMTldLFxuICAgICAgWzExNC4zODYxNTk3MDEwMDAwOCwgMjIuMzY3NzAyNTQxMDAwMTI4XSxcbiAgICAgIFsxMTQuMzg1NzUyODAwMDAwMTIsIDIyLjM3MDE4NDYzNzAwMDA2NV0sXG4gICAgICBbMTE0LjM4MTA3MzQzODAwMDA3LCAyMi4zNzA0MDg0MzMwMDAwNV0sXG4gICAgICBbMTE0LjM3NjM5NDA3NjAwMDAzLCAyMi4zNzA2MzIyMjkwMDAwMzddLFxuICAgICAgWzExNC4zNzc5NDAzMDAwMDAwNiwgMjIuMzY2MzU5NzY4MDAwMDhdLFxuICAgICAgWzExNC4zNzk0ODY1MjQwMDAxLCAyMi4zNjIwODczMDcwMDAxMjRdLFxuICAgICAgWzExNC4zNzc1MzMzOTkwMDAxLCAyMi4zNTc3NzQxNTYwMDAxMl0sXG4gICAgICBbMTE0LjM3NTU4MDI3NDAwMDEsIDIyLjM1MzQ2MTAwNTAwMDExM10sXG4gICAgICBbMTE0LjM3Mjg5NDcyNzUwMDE1LCAyMi4zNTExNDE2NjkwMDAwNTddLFxuICAgICAgWzExNC4zNzAyMDkxODEwMDAyLCAyMi4zNDg4MjIzMzNdLFxuICAgICAgWzExNC4zNjU1Mjk4MTkwMDAxNiwgMjIuMzQ3Mjk2NDU0MDAwMDQ1XSxcbiAgICAgIFsxMTQuMzYwODUwNDU3MDAwMTEsIDIyLjM0NTc3MDU3NTAwMDA5XSxcbiAgICAgIFsxMTQuMzU5MjIyODUyNTAwMDcsIDIyLjMzOTA5NzM5ODAwMDA5Ml0sXG4gICAgICBbMTE0LjM1NzU5NTI0ODAwMDAyLCAyMi4zMzI0MjQyMjEwMDAwOTZdLFxuICAgICAgWzExNC4zNTQ5NTAzOTE1MDAxLCAyMi4zMzU5NDM5MTUwMDAxM10sXG4gICAgICBbMTE0LjM1MjMwNTUzNTAwMDE3LCAyMi4zMzk0NjM2MDkwMDAxNjNdLFxuICAgICAgWzExNC4zNTIzMDU1MzUwMDAxNywgMjIuMzQ1Njg5MTk1MDAwMTJdLFxuICAgICAgWzExNC4zNTIzMDU1MzUwMDAxNywgMjIuMzUxOTE0NzgxMDAwMDc2XSxcbiAgICAgIFsxMTQuMzQ3MTM3ODkxNTAwMTMsIDIyLjM0ODg0MjY3ODAwMDA4Ml0sXG4gICAgICBbMTE0LjM0MTk3MDI0ODAwMDA4LCAyMi4zNDU3NzA1NzUwMDAwOV0sXG4gICAgICBbMTE0LjM0MDUwNTQwNDUwMDA1LCAyMi4zNDkyMjkyMzQwMDAwNDJdLFxuICAgICAgWzExNC4zMzkwNDA1NjEwMDAwMiwgMjIuMzUyNjg3ODkzXSxcbiAgICAgIFsxMTQuMzM1OTA3NDIzMDAwMSwgMjIuMzU2MjI3OTMyMDAwMDNdLFxuICAgICAgWzExNC4zMzI3NzQyODUwMDAxNywgMjIuMzU5NzY3OTcxMDAwMDY4XSxcbiAgICAgIFsxMTQuMzMzNTQ3Mzk3MDAwMSwgMjIuMzY3NTM5NzgxMDAwMTA0XSxcbiAgICAgIFsxMTQuMzM0MzIwNTA5MDAwMDQsIDIyLjM3NTMxMTU5MTAwMDE0XSxcbiAgICAgIFsxMTQuMzI3MzYyNTAxMDAwMDQsIDIyLjM3ODAzNzgyODAwMDA3XSxcbiAgICAgIFsxMTQuMzIwNDA0NDkzMDAwMDQsIDIyLjM4MDc2NDA2NV0sXG4gICAgICBbMTE0LjMxOTUwOTMxMTAwMDEsIDIyLjM4NTA3NzIxNjAwMDA1Ml0sXG4gICAgICBbMTE0LjMxODYxNDEyOTAwMDE3LCAyMi4zODkzOTAzNjcwMDAxMDRdLFxuICAgICAgWzExNC4zMTQzNDE2NjgwMDAyLCAyMi4zODY1ODI3NDk1MDAwNjRdLFxuICAgICAgWzExNC4zMTAwNjkyMDcwMDAyMywgMjIuMzgzNzc1MTMyMDAwMDI1XSxcbiAgICAgIFsxMTQuMzA1MDY0MzI0MDAwMTQsIDIyLjM4MjY3NjQ5OTUwMDA2NF0sXG4gICAgICBbMTE0LjMwMDA1OTQ0MTAwMDA2LCAyMi4zODE1Nzc4NjcwMDAxMDRdLFxuICAgICAgWzExNC4yOTMwMjAwNTMwMDAwNSwgMjIuMzg2Mjc3NTc0MDAwMTJdLFxuICAgICAgWzExNC4yODU5ODA2NjUwMDAwNCwgMjIuMzkwOTc3MjgxMDAwMTMzXSxcbiAgICAgIFsxMTQuMjgxOTkzMDM1MDAwMDYsIDIyLjM5MDk3NzI4MTAwMDEzM10sXG4gICAgICBbMTE0LjI3ODAwNTQwNTAwMDA3LCAyMi4zOTA5NzcyODEwMDAxMzNdLFxuICAgICAgWzExNC4yNzMzNjY3MzMwMDAxMywgMjIuMzg0NzExMDA1MDAwMDg1XSxcbiAgICAgIFsxMTQuMjY4NzI4MDYxMDAwMTksIDIyLjM3ODQ0NDcyOTAwMDAzN10sXG4gICAgICBbMTE0LjI3MTA0NzM5NzAwMDE2LCAyMi4zNzEwMzkxMzAwMDAxXSxcbiAgICAgIFsxMTQuMjczMzY2NzMzMDAwMTMsIDIyLjM2MzYzMzUzMTAwMDE2XSxcbiAgICAgIFsxMTQuMjc2NTgxMjUxMDAwMTgsIDIyLjM1OTMyMDM4MDAwMDE1Nl0sXG4gICAgICBbMTE0LjI3OTc5NTc2OTAwMDIzLCAyMi4zNTUwMDcyMjkwMDAxNV0sXG4gICAgICBbMTE0LjI3ODEyNzQ3NTAwMDIyLCAyMi4zNTE1MjgyMjUwMDAxMV0sXG4gICAgICBbMTE0LjI3NjQ1OTE4MTAwMDIsIDIyLjM0ODA0OTIyMTAwMDA2OF0sXG4gICAgICBbMTE0LjI3MTgyMDUwOTAwMDE1LCAyMi4zNTE5MTQ3ODEwMDAwNzZdLFxuICAgICAgWzExNC4yNjcxODE4MzcwMDAxLCAyMi4zNTU3ODAzNDEwMDAwODRdLFxuICAgICAgWzExNC4yNjY3NzQ5MzYwMDAwOCwgMjIuMzYwODY2NjA0MDAwMTFdLFxuICAgICAgWzExNC4yNjYzNjgwMzUwMDAwNiwgMjIuMzY1OTUyODY3MDAwMTMyXSxcbiAgICAgIFsxMTQuMjYyMzgwNDA0NTAwMDgsIDIyLjM2NDAyMDA4NzAwMDEyOF0sXG4gICAgICBbMTE0LjI1ODM5Mjc3NDAwMDEsIDIyLjM2MjA4NzMwNzAwMDEyNF0sXG4gICAgICBbMTE0LjI1Njk2ODYyMDUwMDA5LCAyMi4zNTg5OTQ4NTkwMDAwOV0sXG4gICAgICBbMTE0LjI1NTU0NDQ2NzAwMDA4LCAyMi4zNTU5MDI0MTEwMDAwNl0sXG4gICAgICBbMTE0LjI2MDY3MTQyMDAwMDE0LCAyMi4zNTExMjEzMjM1MDAwNjddLFxuICAgICAgWzExNC4yNjU3OTgzNzMwMDAyLCAyMi4zNDYzNDAyMzYwMDAwNzRdLFxuICAgICAgWzExNC4yNjkxNzU2NTIwMDAyLCAyMi4zMzM1MjI4NTM1MDAwNDNdLFxuICAgICAgWzExNC4yNzI1NTI5MzEwMDAyLCAyMi4zMjA3MDU0NzEwMDAwMV0sXG4gICAgICBbMTE0LjI3NDg3MjI2NjUwMDE4LCAyMi4zMTk5NTI3MDQwMDAwNzNdLFxuICAgICAgWzExNC4yNzcxOTE2MDIwMDAxNiwgMjIuMzE5MTk5OTM3MDAwMTM1XSxcbiAgICAgIFsxMTQuMjg0MjMwOTkwNTAwMTMsIDIyLjMxNzg3NzUwODUwMDE0Nl0sXG4gICAgICBbMTE0LjI5MTI3MDM3OTAwMDExLCAyMi4zMTY1NTUwODAwMDAxNTddLFxuICAgICAgWzExNC4yOTE2NzcyODAwMDAxNiwgMjIuMzEwODU4NDY1NTAwMDhdLFxuICAgICAgWzExNC4yOTIwODQxODEwMDAyLCAyMi4zMDUxNjE4NTFdLFxuICAgICAgWzExNC4yOTQwMzczMDYwMDAyLCAyMi4zMDUxNjE4NTFdLFxuICAgICAgWzExNC4yOTU5OTA0MzEwMDAyLCAyMi4zMDUxNjE4NTFdLFxuICAgICAgWzExNC4yOTk5MzczNzEwMDAxNCwgMjIuMzA1OTM0OTYzMDAwMDE2XSxcbiAgICAgIFsxMTQuMzAzODg0MzExMDAwMDgsIDIyLjMwNjcwODA3NTAwMDAzXSxcbiAgICAgIFsxMTQuMzA3NzQ5ODcxMDAwMDgsIDIyLjMwMjAwODM2ODAwMDA3NF0sXG4gICAgICBbMTE0LjMxMTYxNTQzMTAwMDA5LCAyMi4yOTczMDg2NjEwMDAxMTZdLFxuICAgICAgWzExNC4zMDg2NDUwNTMwMDAxNiwgMjIuMjk0MDMzMTA3NTAwMTI3XSxcbiAgICAgIFsxMTQuMzA1Njc0Njc1MDAwMjMsIDIyLjI5MDc1NzU1NDAwMDEzN10sXG4gICAgICBbMTE0LjMwMTY4NzA0NTAwMDE0LCAyMi4yODgxOTQwNzc1MDAxMjNdLFxuICAgICAgWzExNC4yOTc2OTk0MTUwMDAwNCwgMjIuMjg1NjMwNjAxMDAwMTA4XVxuICAgIF1cbiAgfVxufVxuIiwiTC5NYXAubWVyZ2VPcHRpb25zKHtcbiAgdG91Y2hFeHRlbmQ6IHRydWVcbn0pO1xuXG5MLk1hcC5Ub3VjaEV4dGVuZCA9IEwuSGFuZGxlci5leHRlbmQoe1xuXG4gIGluaXRpYWxpemU6IGZ1bmN0aW9uKG1hcCkge1xuICAgIHRoaXMuX21hcCA9IG1hcDtcbiAgICB0aGlzLl9jb250YWluZXIgPSBtYXAuX2NvbnRhaW5lcjtcbiAgICB0aGlzLl9wYW5lID0gbWFwLl9wYW5lcy5vdmVybGF5UGFuZTtcbiAgfSxcblxuICBhZGRIb29rczogZnVuY3Rpb24oKSB7XG4gICAgTC5Eb21FdmVudC5vbih0aGlzLl9jb250YWluZXIsICd0b3VjaHN0YXJ0JywgdGhpcy5fb25Ub3VjaFN0YXJ0LCB0aGlzKVxuICAgICAgLm9uKHRoaXMuX2NvbnRhaW5lciwgJ3RvdWNoZW5kJywgdGhpcy5fb25Ub3VjaEVuZCwgdGhpcylcbiAgICAgIC5vbih0aGlzLl9jb250YWluZXIsICd0b3VjaG1vdmUnLCB0aGlzLl9vblRvdWNoTW92ZSwgdGhpcyk7XG4gIH0sXG5cbiAgcmVtb3ZlSG9va3M6IGZ1bmN0aW9uKCkge1xuICAgIEwuRG9tRXZlbnQub2ZmKHRoaXMuX2NvbnRhaW5lciwgJ3RvdWNoc3RhcnQnLCB0aGlzLl9vblRvdWNoU3RhcnQpXG4gICAgICAub2ZmKHRoaXMuX2NvbnRhaW5lciwgJ3RvdWNoZW5kJywgdGhpcy5fb25Ub3VjaEVuZClcbiAgICAgIC5vZmYodGhpcy5fY29udGFpbmVyLCAndG91Y2htb3ZlJywgdGhpcy5fb25Ub3VjaE1vdmUpO1xuICB9LFxuXG4gIF9vblRvdWNoRXZlbnQ6IGZ1bmN0aW9uKGUsIHR5cGUpIHtcbiAgICBpZiAoIXRoaXMuX21hcC5fbG9hZGVkKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHRvdWNoID0gZS50b3VjaGVzWzBdO1xuICAgIHZhciBjb250YWluZXJQb2ludCA9IEwucG9pbnQodG91Y2guY2xpZW50WCwgdG91Y2guY2xpZW50WSk7XG4gICAgdmFyIGxheWVyUG9pbnQgPSB0aGlzLl9tYXAuY29udGFpbmVyUG9pbnRUb0xheWVyUG9pbnQoY29udGFpbmVyUG9pbnQpO1xuICAgIHZhciBsYXRsbmcgPSB0aGlzLl9tYXAubGF5ZXJQb2ludFRvTGF0TG5nKGxheWVyUG9pbnQpO1xuXG4gICAgdGhpcy5fbWFwLmZpcmUodHlwZSwge1xuICAgICAgbGF0bG5nOiBsYXRsbmcsXG4gICAgICBsYXllclBvaW50OiBsYXllclBvaW50LFxuICAgICAgY29udGFpbmVyUG9pbnQ6IGNvbnRhaW5lclBvaW50LFxuICAgICAgb3JpZ2luYWxFdmVudDogZVxuICAgIH0pO1xuICB9LFxuXG4gIF9vblRvdWNoU3RhcnQ6IGZ1bmN0aW9uKGUpIHtcbiAgICB0aGlzLl9vblRvdWNoRXZlbnQoZSwgJ3RvdWNoc3RhcnQnKTtcbiAgfSxcblxuICBfb25Ub3VjaEVuZDogZnVuY3Rpb24oZSkge1xuICAgIGlmICghdGhpcy5fbWFwLl9sb2FkZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5fbWFwLmZpcmUoJ3RvdWNoZW5kJywge1xuICAgICAgb3JpZ2luYWxFdmVudDogZVxuICAgIH0pO1xuICB9LFxuXG4gIF9vblRvdWNoTW92ZTogZnVuY3Rpb24oZSkge1xuICAgIHRoaXMuX29uVG91Y2hFdmVudChlLCAndG91Y2htb3ZlJyk7XG4gIH1cbn0pO1xuXG5MLk1hcC5hZGRJbml0SG9vaygnYWRkSGFuZGxlcicsICd0b3VjaEV4dGVuZCcsIEwuTWFwLlRvdWNoRXh0ZW5kKTtcbiIsIi8vIHZhciBMID0gZ2xvYmFsLkwgfHwgcmVxdWlyZSgnbGVhZmxldCcpO1xudmFyIGRhdGEgPSByZXF1aXJlKCcuLi9kYXRhLmpzb24nKTtcbnZhciBqc29uRm9ybWF0ID0gZ2xvYmFsLmpzb25Gb3JtYXQgPSByZXF1aXJlKCcuL2pzb24tZm9ybWF0Jyk7XG4vL3ZhciBTZWxlY3QgPSByZXF1aXJlKCcuLi8uLi9pbmRleCcpO1xucmVxdWlyZSgnLi9MLlRvdWNoRXh0ZW5kJyk7XG5cbi8vIHRoaXMgcGllY2UgaGVyZSBkb3VibGVzIHRoZSBudW1iZXIgb2YgcG9pbnRzIGluIGdlb2pzb25cbi8vIGZvciAodmFyIGkgPSAwLCBjb29yZHMgPSBkYXRhLmdlb21ldHJ5LmNvb3JkaW5hdGVzLCBsZW4gPSBjb29yZHMubGVuZ3RoIC0gMTsgaSA8IGxlbjsgaSArPSAyKSB7XG4vLyAgIHZhciBjMSA9IGNvb3Jkc1tpXTtcbi8vICAgdmFyIGMyID0gY29vcmRzW2kgKyAxXTtcbi8vICAgdmFyIG1pZCA9IFsoYzFbMF0gKyBjMlswXSkgLyAyLCAoYzFbMV0gKyBjMlsxXSkgLyAyXTtcblxuLy8gICBjb29yZHMuc3BsaWNlKGkgKyAxLCAwLCBtaWQpO1xuLy8gICBsZW4rKztcbi8vIH1cbi8vIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGNvb3JkcykpO1xuXG5MLkljb24uRGVmYXVsdC5pbWFnZVBhdGggPSAnaHR0cDovL2Nkbi5sZWFmbGV0anMuY29tL2xlYWZsZXQtMC43L2ltYWdlcyc7XG5cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG52YXIgbWFwID0gZ2xvYmFsLm1hcCA9IG5ldyBMLk1hcCgnbWFwJywge30pLnNldFZpZXcoWzIyLjQyNjU4LCAxMTQuMTQ1Ml0sIDExKTtcblxuTC50aWxlTGF5ZXIoJ2h0dHA6Ly97c30udGlsZS5vc20ub3JnL3t6fS97eH0ve3l9LnBuZycsIHtcbiAgYXR0cmlidXRpb246ICcmY29weTsgJyArXG4gICAgJzxhIGhyZWY9XCJodHRwOi8vb3NtLm9yZy9jb3B5cmlnaHRcIj5PcGVuU3RyZWV0TWFwPC9hPiBjb250cmlidXRvcnMnXG59KS5hZGRUbyhtYXApO1xuXG52YXIgc2VsZWN0Q29udHJvbCA9IGdsb2JhbC5jb250cm9sID0gbmV3IEwuQ29udHJvbC5MaW5lU3RyaW5nU2VsZWN0KHt9KTtcbm1hcC5hZGRDb250cm9sKHNlbGVjdENvbnRyb2wpO1xuXG52YXIgbGF5ZXIgPSBnbG9iYWwubGF5ZXIgPSBMLmdlb0pzb24oZGF0YSkuYWRkVG8obWFwKTtcbmxheWVyID0gbGF5ZXIuZ2V0TGF5ZXJzKClbMF07XG5cbmNvbnRyb2wuZW5hYmxlKHtcbiAgZmVhdHVyZTogbGF5ZXIuZmVhdHVyZSxcbiAgbGF5ZXI6IGxheWVyXG59KTtcblxuLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3Jlc2V0JykuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBmdW5jdGlvbigpIHtcbiAgY29udHJvbC5yZXNldCgpO1xuICBzdGFydFJhbmdlLmRpc2FibGVkID0gdHJ1ZTtcbiAgZW5kUmFuZ2UuZGlzYWJsZWQgPSB0cnVlO1xufSk7XG5cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG52YXIgbGVuZ3RoID0gMCxcbiAgZGlzdGFuY2VzID0gW107XG5mb3IgKHZhciBpID0gMSwgbGVuID0gbGF5ZXIuX2xhdGxuZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgdmFyIGRpc3QgPSBsYXllci5fbGF0bG5nc1tpXS5kaXN0YW5jZVRvKGxheWVyLl9sYXRsbmdzW2kgLSAxXSk7XG4gIGRpc3RhbmNlcy5wdXNoKGRpc3QpO1xuICBsZW5ndGggKz0gZGlzdDtcbn1cblxuZnVuY3Rpb24gZ2V0RGlzdGFuY2UobWFya2VyKSB7XG4gIHZhciBkID0gMDtcbiAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IG1hcmtlci5zdGFydDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgZCArPSBkaXN0YW5jZXNbaV07XG4gIH1cbiAgZCArPSBtYXJrZXIuZ2V0TGF0TG5nKClcbiAgICAuZGlzdGFuY2VUbyhsYXllci5fbGF0bG5nc1ttYXJrZXIuc3RhcnRdKTtcblxuICByZXR1cm4gZDtcbn1cblxuZnVuY3Rpb24gZ2V0U3RhcnREaXN0YW5jZSgpIHtcbiAgcmV0dXJuIGdldERpc3RhbmNlKGNvbnRyb2wuX3N0YXJ0TWFya2VyKTtcbn1cblxuZnVuY3Rpb24gZ2V0RW5kRGlzdGFuY2UoKSB7XG4gIHJldHVybiBnZXREaXN0YW5jZShjb250cm9sLl9lbmRNYXJrZXIpO1xufVxuXG4vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG52YXIgc3RhcnRSYW5nZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNzdGFydC1yYW5nZScpO1xudmFyIHN0YXJ0TSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNzdGFydCcpO1xuXG52YXIgZW5kUmFuZ2UgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjZW5kLXJhbmdlJyk7XG52YXIgZW5kTSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyNlbmQnKTtcblxuZnVuY3Rpb24gb25TdGFydFJhbmdlQ2hhbmdlKCkge1xuICB2YXIgbWV0ZXJzID0gcGFyc2VJbnQoc3RhcnRSYW5nZS52YWx1ZSAqIGxlbmd0aCk7XG4gIGlmIChlbmRSYW5nZS52YWx1ZSA8PSBzdGFydFJhbmdlLnZhbHVlKSB7XG4gICAgZW5kUmFuZ2UudmFsdWUgPSBzdGFydFJhbmdlLnZhbHVlO1xuICAgIGVuZE0udmFsdWUgPSBtZXRlcnM7XG4gIH1cbiAgc3RhcnQudmFsdWUgPSBtZXRlcnM7XG5cbiAgY29udHJvbC5zZWxlY3RNZXRlcnMobWV0ZXJzLCBlbmRNLnZhbHVlKTtcbn1cblxuZnVuY3Rpb24gb25FbmRSYW5nZUNoYW5nZSgpIHtcbiAgdmFyIG1ldGVycyA9IHBhcnNlSW50KGVuZFJhbmdlLnZhbHVlICogbGVuZ3RoKTtcbiAgaWYgKHN0YXJ0UmFuZ2UudmFsdWUgPj0gZW5kUmFuZ2UudmFsdWUpIHtcbiAgICBzdGFydFJhbmdlLnZhbHVlID0gZW5kUmFuZ2UudmFsdWU7XG4gICAgc3RhcnRNLnZhbHVlID0gbWV0ZXJzO1xuICB9XG4gIGVuZC52YWx1ZSA9IG1ldGVycztcblxuICBjb250cm9sLnNlbGVjdE1ldGVycyhzdGFydE0udmFsdWUsIG1ldGVycyk7XG59XG5cbnN0YXJ0UmFuZ2Uub25jaGFuZ2UgPSBzdGFydFJhbmdlLm9uaW5wdXQgPSBvblN0YXJ0UmFuZ2VDaGFuZ2U7XG5lbmRSYW5nZS5vbmNoYW5nZSA9IGVuZFJhbmdlLm9uaW5wdXQgPSBvbkVuZFJhbmdlQ2hhbmdlO1xuXG52YXIgdGV4dGFyZWEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcjZ2VvanNvbicpO1xuY29udHJvbC5vbignc2VsZWN0OnN0YXJ0JywgZnVuY3Rpb24oKSB7XG4gIHZhciBkaXN0ID0gZ2V0U3RhcnREaXN0YW5jZSgpO1xuICBzdGFydFJhbmdlLmRpc2FibGVkID0gZmFsc2U7XG4gIHN0YXJ0UmFuZ2UudmFsdWUgPSBkaXN0IC8gbGVuZ3RoO1xuICBzdGFydE0udmFsdWUgPSBwYXJzZUludChkaXN0KTtcbn0pO1xuXG5jb250cm9sLm9uKCdzZWxlY3Rpb24nLCBmdW5jdGlvbigpIHtcbiAgdmFyIGRpc3QxID0gZ2V0U3RhcnREaXN0YW5jZSgpO1xuICB2YXIgZGlzdDIgPSBnZXRFbmREaXN0YW5jZSgpO1xuXG4gIC8vY29uc29sZS5sb2coZGlzdDEsIHN0YXJ0TS52YWx1ZSwgZGlzdDIsIGVuZE0udmFsdWUpO1xuXG4gIHN0YXJ0UmFuZ2UudmFsdWUgPSBkaXN0MSAvIGxlbmd0aDtcbiAgZW5kUmFuZ2UudmFsdWUgPSBkaXN0MiAvIGxlbmd0aDtcblxuICBzdGFydE0udmFsdWUgPSBNYXRoLnJvdW5kKGRpc3QxKTtcbiAgZW5kTS52YWx1ZSA9IE1hdGgucm91bmQoZGlzdDIpO1xuXG4gIGVuZFJhbmdlLmRpc2FibGVkID0gZmFsc2U7XG4gIHRleHRhcmVhLnZhbHVlID0ganNvbkZvcm1hdChKU09OLnN0cmluZ2lmeShjb250cm9sLnRvR2VvSlNPTigpKSk7XG59KTtcblxuY29udHJvbC5vbigncmVzZXQnLCBmdW5jdGlvbigpIHtcbiAgc3RhcnRSYW5nZS52YWx1ZSA9IGVuZFJhbmdlLnZhbHVlID0gMDtcbiAgZW5kTS52YWx1ZSA9IHN0YXJ0TS52YWx1ZSA9IDA7XG4gIHRleHRhcmVhLnZhbHVlID0gJyc7XG59KTtcblxuZ2xvYmFsLmdldFN0YXJ0RGlzdGFuY2UgPSBnZXRTdGFydERpc3RhbmNlO1xuZ2xvYmFsLmdldEVuZERpc3RhbmNlID0gZ2V0RW5kRGlzdGFuY2U7XG4iLCIvKlxuICAgIGpzb24tZm9ybWF0IHYuMS4xXG4gICAgaHR0cDovL2dpdGh1Yi5jb20vcGhvYm9zbGFiL2pzb24tZm9ybWF0XG5cbiAgICBSZWxlYXNlZCB1bmRlciBNSVQgbGljZW5zZTpcbiAgICBodHRwOi8vd3d3Lm9wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNlbnNlLnBocFxuKi9cblxudmFyIHAgPSBbXSxcbiAgcHVzaCA9IGZ1bmN0aW9uKG0pIHtcbiAgICByZXR1cm4gJ1xcXFwnICsgcC5wdXNoKG0pICsgJ1xcXFwnO1xuICB9LFxuICBwb3AgPSBmdW5jdGlvbihtLCBpKSB7XG4gICAgcmV0dXJuIHBbaSAtIDFdXG4gIH0sXG4gIHRhYnMgPSBmdW5jdGlvbihjb3VudCkge1xuICAgIHJldHVybiBuZXcgQXJyYXkoY291bnQgKyAxKS5qb2luKCdcXHQnKTtcbiAgfTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihqc29uKSB7XG4gIHAgPSBbXTtcbiAgdmFyIG91dCA9IFwiXCIsXG4gICAgaW5kZW50ID0gMDtcblxuICAvLyBFeHRyYWN0IGJhY2tzbGFzaGVzIGFuZCBzdHJpbmdzXG4gIGpzb24gPSBqc29uXG4gICAgLnJlcGxhY2UoL1xcXFwuL2csIHB1c2gpXG4gICAgLnJlcGxhY2UoLyhcIi4qP1wifCcuKj8nKS9nLCBwdXNoKVxuICAgIC5yZXBsYWNlKC9cXHMrLywgJycpO1xuXG4gIC8vIEluZGVudCBhbmQgaW5zZXJ0IG5ld2xpbmVzXG4gIGZvciAodmFyIGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkrKykge1xuICAgIHZhciBjID0ganNvbi5jaGFyQXQoaSk7XG5cbiAgICBzd2l0Y2ggKGMpIHtcbiAgICAgIGNhc2UgJ3snOlxuICAgICAgICBvdXQgKz0gYyArIFwiXFxuXCIgKyB0YWJzKCsraW5kZW50KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdbJzpcbiAgICAgICAgb3V0ICs9IGMgKyBcIlxcblwiICsgdGFicygrK2luZGVudCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnXSc6XG4gICAgICAgIG91dCArPSBcIlxcblwiICsgdGFicygtLWluZGVudCkgKyBjO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ30nOlxuICAgICAgICBvdXQgKz0gXCJcXG5cIiArIHRhYnMoLS1pbmRlbnQpICsgYztcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICcsJzpcbiAgICAgICAgaWYgKC9cXGQvLnRlc3QoanNvbi5jaGFyQXQoaSAtIDEpKSkge1xuICAgICAgICAgIG91dCArPSBcIiwgXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgb3V0ICs9IFwiLFxcblwiICsgdGFicyhpbmRlbnQpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnOic6XG4gICAgICAgIG91dCArPSBcIjogXCI7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgb3V0ICs9IGM7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8vIFN0cmlwIHdoaXRlc3BhY2UgZnJvbSBudW1lcmljIGFycmF5cyBhbmQgcHV0IGJhY2tzbGFzaGVzXG4gIC8vIGFuZCBzdHJpbmdzIGJhY2sgaW5cbiAgb3V0ID0gb3V0XG4gICAgLnJlcGxhY2UoL1xcW1tcXGQsXFxzXSs/XFxdL2csIGZ1bmN0aW9uKG0pIHtcbiAgICAgIHJldHVybiBtLnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgfSlcbiAgICAvLyBudW1iZXIgYXJyYXlzXG4gICAgLnJlcGxhY2UoL1xcW1xccyooXFxkKS9nLCBmdW5jdGlvbihhLCBiKSB7XG4gICAgICByZXR1cm4gJ1snICsgYjtcbiAgICB9KVxuICAgIC5yZXBsYWNlKC8oXFxkKVxccypcXF0vZywgZnVuY3Rpb24oYSwgYikge1xuICAgICAgcmV0dXJuIGIgKyAnXSc7XG4gICAgfSlcbiAgICAucmVwbGFjZSgvXFx7XFxzKlxcfS9nLCAne30nKSAvLyBlbXB0eSBvYmplY3RzXG4gICAgLnJlcGxhY2UoL1xcXFwoXFxkKylcXFxcL2csIHBvcCkgLy8gc3RyaW5nc1xuICAgIC5yZXBsYWNlKC9cXFxcKFxcZCspXFxcXC9nLCBwb3ApOyAvLyBiYWNrc2xhc2hlcyBpbiBzdHJpbmdzXG5cbiAgcmV0dXJuIG91dDtcbn07XG4iXX0= 798 | --------------------------------------------------------------------------------