diff --git a/.docker/init.sh b/.docker/init.sh index 73a9d92..9aa3952 100644 --- a/.docker/init.sh +++ b/.docker/init.sh @@ -10,6 +10,11 @@ chown nginx:nginx /run/nginx sed -i "s/^nobody:.*$/nobody:x:1000:50::nobody:\/:\/sbin\/nologin/" /etc/passwd sed -i "s/^nobody:.*$/nobody:x:50:/" /etc/group +# Prepare ulogger filesystem +grep '^[$ /var/www/html/config.php +chown nobody:nobody /var/www/html/uploads +chmod 775 /var/www/html/uploads + if [ "$ULOGGER_DB_DRIVER" = "sqlite" ]; then sed -i "s/^\$dbuser = .*$//" /var/www/html/config.php sed -i "s/^\$dbpass = .*$//" /var/www/html/config.php @@ -49,12 +54,12 @@ else mysqld_safe --datadir=/data & mysqladmin --silent --wait=30 ping mysqladmin -u root password "${DB_ROOT_PASS}" - mysql -u root -p${DB_ROOT_PASS} < /var/www/html/scripts/ulogger.sql - mysql -u root -p${DB_ROOT_PASS} -e "CREATE USER 'ulogger'@'localhost' IDENTIFIED BY '${DB_USER_PASS}'" - mysql -u root -p${DB_ROOT_PASS} -e "GRANT ALL PRIVILEGES ON ulogger.* TO 'ulogger'@'localhost'" - mysql -u root -p${DB_ROOT_PASS} -e "CREATE USER 'ulogger'@'%' IDENTIFIED BY '${DB_USER_PASS}'" - mysql -u root -p${DB_ROOT_PASS} -e "GRANT ALL PRIVILEGES ON ulogger.* TO 'ulogger'@'%'" - mysql -u root -p${DB_ROOT_PASS} -e "INSERT INTO users (login, password) VALUES ('admin', '\$2y\$10\$7OvZrKgonVZM9lkzrTbiou.CVhO3HjPk5y0W9L68fVwPs/osBRIMq')" ulogger - mysqladmin -u root -p${DB_ROOT_PASS} shutdown + mysql -u root -p"${DB_ROOT_PASS}" < /var/www/html/scripts/ulogger.sql + mysql -u root -p"${DB_ROOT_PASS}" -e "CREATE USER 'ulogger'@'localhost' IDENTIFIED BY '${DB_USER_PASS}'" + mysql -u root -p"${DB_ROOT_PASS}" -e "GRANT ALL PRIVILEGES ON ulogger.* TO 'ulogger'@'localhost'" + mysql -u root -p"${DB_ROOT_PASS}" -e "CREATE USER 'ulogger'@'%' IDENTIFIED BY '${DB_USER_PASS}'" + mysql -u root -p"${DB_ROOT_PASS}" -e "GRANT ALL PRIVILEGES ON ulogger.* TO 'ulogger'@'%'" + mysql -u root -p"${DB_ROOT_PASS}" -e "INSERT INTO users (login, password) VALUES ('admin', '\$2y\$10\$7OvZrKgonVZM9lkzrTbiou.CVhO3HjPk5y0W9L68fVwPs/osBRIMq')" ulogger + mysqladmin -u root -p"${DB_ROOT_PASS}" shutdown sed -i "s/^\$dbdsn = .*$/\$dbdsn = \"mysql:host=localhost;port=3306;dbname=ulogger;charset=utf8\";/" /var/www/html/config.php fi diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..61b0213 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,343 @@ +module.exports = { + "env": { + "browser": true, + "es6": true, + "jasmine": true + }, + "extends": [ + "eslint:recommended", + "plugin:jasmine/recommended", + "plugin:import/errors", + "plugin:import/warnings" + ], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly", + "google": true + }, + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "plugins": [ + "jasmine", + "import" + ], + "rules": { + "accessor-pairs": "error", + "array-bracket-newline": "error", + "array-bracket-spacing": [ + "error", + "always" + ], + "array-callback-return": "error", + "array-element-newline": "off", + "arrow-body-style": "error", + "arrow-parens": "error", + "arrow-spacing": "error", + "block-scoped-var": "off", + "block-spacing": "off", + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + "callback-return": "error", + "camelcase": "off", + "capitalized-comments": "off", + "class-methods-use-this": "error", + "comma-dangle": "error", + "comma-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "comma-style": [ + "error", + "last" + ], + "complexity": "error", + "computed-property-spacing": [ + "error", + "never" + ], + "consistent-return": "error", + "consistent-this": "off", + "curly": "error", + "default-case": "error", + "dot-location": [ + "error", + "property" + ], + "dot-notation": "off", + "eol-last": "error", + "eqeqeq": "off", + "func-call-spacing": "error", + "func-name-matching": "error", + "func-names": "off", + "func-style": [ + "error", + "declaration", + { + "allowArrowFunctions": true + } + ], + "function-paren-newline": "off", + "generator-star-spacing": "error", + "global-require": "error", + "guard-for-in": "off", + "handle-callback-err": "error", + "id-blacklist": "error", + "id-length": "off", + "id-match": "error", + "implicit-arrow-linebreak": "error", + "indent": "off", + "indent-legacy": "off", + "init-declarations": "off", + "jsx-quotes": "error", + "key-spacing": "error", + "keyword-spacing": [ + "error", + { + "after": true, + "before": true + } + ], + "line-comment-position": "off", + "linebreak-style": [ + "error", + "unix" + ], + "lines-around-comment": "off", + "lines-around-directive": "error", + "lines-between-class-members": "error", + "max-classes-per-file": "error", + "max-depth": "off", + "max-len": "off", + "max-lines": "off", + "max-lines-per-function": "off", + "max-nested-callbacks": "error", + "max-params": "error", + "max-statements": "off", + "max-statements-per-line": "off", + "multiline-comment-style": "off", + "multiline-ternary": [ + "error", + "never" + ], + "new-cap": [ + "error", { "newIsCapExceptionPattern": "^u[A-Z]" } + ], + "new-parens": "error", + "newline-after-var": "off", + "newline-before-return": "off", + "newline-per-chained-call": "off", + "no-alert": "off", + "no-array-constructor": "error", + "no-async-promise-executor": "error", + "no-await-in-loop": "error", + "no-bitwise": "error", + "no-buffer-constructor": "error", + "no-caller": "error", + "no-catch-shadow": "error", + "no-cond-assign": [ + "error", + "except-parens" + ], + "no-confusing-arrow": "error", + "no-continue": "error", + "no-div-regex": "error", + "no-duplicate-imports": "error", + "no-else-return": "error", + "no-empty-function": "error", + "no-eq-null": "off", + "no-eval": "error", + "no-extend-native": "off", + "no-extra-bind": "error", + "no-extra-label": "error", + "no-extra-parens": "off", + "no-floating-decimal": "error", + "no-implicit-globals": "off", + "no-implied-eval": "error", + "no-inline-comments": "off", + "no-inner-declarations": [ + "error", + "functions" + ], + "no-invalid-this": "off", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-lonely-if": "error", + "no-loop-func": "error", + "no-magic-numbers": "off", + "no-misleading-character-class": "error", + "no-mixed-operators": "off", + "no-mixed-requires": "error", + "no-multi-assign": "error", + "no-multi-spaces": "error", + "no-multi-str": "error", + "no-multiple-empty-lines": "error", + "no-native-reassign": "error", + "no-negated-condition": "off", + "no-negated-in-lhs": "error", + "no-nested-ternary": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-wrappers": "error", + "no-octal-escape": "error", + "no-param-reassign": "off", + "no-path-concat": "error", + "no-plusplus": "off", + "no-process-env": "error", + "no-process-exit": "error", + "no-proto": "error", + "no-prototype-builtins": "off", + "no-restricted-globals": "error", + "no-restricted-imports": "error", + "no-restricted-modules": "error", + "no-restricted-properties": "error", + "no-restricted-syntax": "error", + "no-return-assign": [ + "error", + "except-parens" + ], + "no-return-await": "error", + "no-script-url": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow": "error", + "no-shadow-restricted-names": "error", + "no-spaced-func": "error", + "no-sync": "error", + "no-tabs": "error", + "no-template-curly-in-string": "error", + "no-ternary": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-undefined": "error", + "no-underscore-dangle": [ + "error", + { + "allowAfterThis": true + } + ], + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": "error", + "no-unused-expressions": "error", + "no-use-before-define": "off", + "no-useless-call": "error", + "no-useless-catch": "error", + "no-useless-computed-key": "error", + "no-useless-concat": "off", + "no-useless-constructor": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-var": "error", + "no-void": "error", + "no-warning-comments": "warn", + "no-whitespace-before-property": "error", + "no-with": "error", + "nonblock-statement-body-position": "error", + "object-curly-newline": "error", + "object-curly-spacing": [ + "error", + "always" + ], + "object-shorthand": [ + "error", + "consistent-as-needed" + ], + "one-var": "off", + "one-var-declaration-per-line": [ + "error", + "initializations" + ], + "operator-assignment": [ + "error", + "always" + ], + "operator-linebreak": "error", + "padded-blocks": "off", + "padding-line-between-statements": "error", + "prefer-arrow-callback": "error", + "prefer-const": "error", + "prefer-destructuring": "off", + "prefer-named-capture-group": "off", + "prefer-numeric-literals": "error", + "prefer-object-spread": "error", + "prefer-promise-reject-errors": "error", + "prefer-reflect": "off", + "prefer-rest-params": "off", + "prefer-spread": "error", + "prefer-template": "off", + "quote-props": "off", + "quotes": [ + "error", + "single", + "avoid-escape" + ], + "radix": [ + "error", + "as-needed" + ], + "require-atomic-updates": "error", + "require-await": "error", + "require-jsdoc": "off", + "require-unicode-regexp": "off", + "rest-spread-spacing": "error", + "semi": "off", + "semi-spacing": [ + "error", + { + "after": true, + "before": false + } + ], + "semi-style": [ + "error", + "last" + ], + "sort-imports": "error", + "sort-keys": "off", + "sort-vars": "off", + "space-before-blocks": "error", + "space-before-function-paren": "off", + "space-in-parens": [ + "error", + "never" + ], + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": [ + "error", + "always" + ], + "strict": "off", + "switch-colon-spacing": "error", + "symbol-description": "error", + "template-curly-spacing": "error", + "template-tag-spacing": "error", + "unicode-bom": [ + "error", + "never" + ], + "valid-jsdoc": "off", + "vars-on-top": "off", + "wrap-regex": "error", + "yield-star-spacing": "error", + "yoda": [ + "error", + "never" + ] + } +}; diff --git a/.tests/lib/BaseDatabaseTestCase.php b/.tests/lib/BaseDatabaseTestCase.php index 35dc482..2e71e53 100644 --- a/.tests/lib/BaseDatabaseTestCase.php +++ b/.tests/lib/BaseDatabaseTestCase.php @@ -36,7 +36,7 @@ abstract class BaseDatabaseTestCase extends PHPUnit_Extensions_Database_TestCase protected $testAccuracy = 10; protected $testProvider = "gps"; protected $testComment = "test comment"; - protected $testImageId = 1; + protected $testImage = "1234_1502974402_5d1a1960335cf.jpg"; // Fixes PostgreSQL: "cannot truncate a table referenced in a foreign key constraint" protected function getSetUpOperation() { @@ -180,7 +180,11 @@ abstract class BaseDatabaseTestCase extends PHPUnit_Extensions_Database_TestCase protected function addTestUser($user = NULL, $pass = NULL) { if (is_null($user)) { $user = $this->testUser; } if (is_null($pass)) { $pass = $this->testPass; } - return $this->pdoInsert('users', [ 'login' => $user, 'password' => $pass ]); + $id = $this->pdoInsert('users', [ 'login' => $user, 'password' => $pass ]); + if ($id !== false) { + return (int) $id; + } + return false; } /** @@ -196,7 +200,11 @@ abstract class BaseDatabaseTestCase extends PHPUnit_Extensions_Database_TestCase if (is_null($userId)) { $userId = $this->testUserId; } if (is_null($trackName)) { $trackName = $this->testTrackName; } if (is_null($comment)) { $comment = $this->testTrackComment; } - return $this->pdoInsert('tracks', [ 'user_id' => $userId, 'name' => $trackName, 'comment' => $comment ]); + $id = $this->pdoInsert('tracks', [ 'user_id' => $userId, 'name' => $trackName, 'comment' => $comment ]); + if ($id !== false) { + return (int) $id; + } + return false; } /** diff --git a/.tests/tests/ClientAPITest.php b/.tests/tests/ClientAPITest.php index 1b99e8d..390682f 100644 --- a/.tests/tests/ClientAPITest.php +++ b/.tests/tests/ClientAPITest.php @@ -224,8 +224,7 @@ class ClientAPITest extends UloggerAPITestCase { 'bearing' => $this->testBearing, 'accuracy' => $this->testAccuracy, 'provider' => $this->testProvider, - 'comment' => $this->testComment, - 'imageid' => $this->testImageId + 'comment' => $this->testComment ], ]; $response = $this->http->post('/client/index.php', $options); @@ -246,15 +245,115 @@ class ClientAPITest extends UloggerAPITestCase { "accuracy" => $this->testAccuracy, "provider" => $this->testProvider, "comment" => $this->testComment, - "image_id" => $this->testImageId + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", - "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); } + public function testAddPositionWithImage() { + $this->assertTrue($this->authenticate(), "Authentication failed"); + + $trackId = $this->addTestTrack($this->testUserId); + $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count"); + $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count"); + + $options = [ + 'http_errors' => false, + 'multipart' => [ + [ + 'name' => 'action', + 'contents' => 'addpos', + ], + [ + 'name' => 'trackid', + 'contents' => $trackId, + ], + [ + 'name' => 'time', + 'contents' => $this->testTimestamp, + ], + [ + 'name' => 'lat', + 'contents' => $this->testLat, + ], + [ + 'name' => 'lon', + 'contents' => $this->testLon, + ], + [ + 'name' => 'altitude', + 'contents' => $this->testAltitude, + ], + [ + 'name' => 'speed', + 'contents' => $this->testSpeed, + ], + [ + 'name' => 'bearing', + 'contents' => $this->testBearing, + ], + [ + 'name' => 'accuracy', + 'contents' => $this->testAccuracy, + ], + [ + 'name' => 'provider', + 'contents' => $this->testProvider, + ], + [ + 'name' => 'comment', + 'contents' => $this->testComment, + ], + [ + 'name' => 'image', + 'contents' => 'DEADBEEF', + 'filename' => 'upload', + 'headers' => [ 'Content-Type' => 'image/jpeg', 'Content-Transfer-Encoding' => 'binary' ] + ] + ] + ]; + $response = $this->http->post('/client/index.php', $options); + $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); + $json = json_decode((string) $response->getBody()); + $this->assertFalse($json->{'error'}, "Unexpected error"); + $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count"); + $expected = [ + "id" => 1, + "user_id" => $this->testUserId, + "track_id" => $trackId, + "time" => $this->testTimestamp, + "latitude" => $this->testLat, + "longitude" => $this->testLon, + "altitude" => $this->testAltitude, + "speed" => $this->testSpeed, + "bearing" => $this->testBearing, + "accuracy" => $this->testAccuracy, + "provider" => $this->testProvider, + "comment" => $this->testComment + ]; + $actual = $this->getConnection()->createQueryTable( + "positions", + "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions" + ); + $this->assertEquals($expected['id'], $actual->getValue(0, 'id')); + $this->assertEquals($expected['user_id'], $actual->getValue(0, 'user_id')); + $this->assertEquals($expected['track_id'], $actual->getValue(0, 'track_id')); + $this->assertEquals($expected['time'], $actual->getValue(0, 'time')); + $this->assertEquals($expected['latitude'], $actual->getValue(0, 'latitude')); + $this->assertEquals($expected['longitude'], $actual->getValue(0, 'longitude')); + $this->assertEquals($expected['altitude'], $actual->getValue(0, 'altitude')); + $this->assertEquals($expected['speed'], $actual->getValue(0, 'speed')); + $this->assertEquals($expected['bearing'], $actual->getValue(0, 'bearing')); + $this->assertEquals($expected['accuracy'], $actual->getValue(0, 'accuracy')); + $this->assertEquals($expected['provider'], $actual->getValue(0, 'provider')); + $this->assertEquals($expected['comment'], $actual->getValue(0, 'comment')); + $this->assertContains('.jpg', $actual->getValue(0, 'image')); + } + public function testAddPositionNoexistantTrack() { $this->assertTrue($this->authenticate(), "Authentication failed"); @@ -275,7 +374,7 @@ class ClientAPITest extends UloggerAPITestCase { 'accuracy' => $this->testAccuracy, 'provider' => $this->testProvider, 'comment' => $this->testComment, - 'imageid' => $this->testImageId + 'imageid' => $this->testImage ], ]; $response = $this->http->post('/client/index.php', $options); @@ -306,7 +405,7 @@ class ClientAPITest extends UloggerAPITestCase { 'accuracy' => $this->testAccuracy, 'provider' => $this->testProvider, 'comment' => $this->testComment, - 'imageid' => $this->testImageId + 'imageid' => $this->testImage ], ]; @@ -343,7 +442,7 @@ class ClientAPITest extends UloggerAPITestCase { 'accuracy' => $this->testAccuracy, 'provider' => $this->testProvider, 'comment' => $this->testComment, - 'imageid' => $this->testImageId + 'imageid' => $this->testImage ], ]; diff --git a/.tests/tests/ImportTest.php b/.tests/tests/ImportTest.php index a59a9f1..1b3dba8 100644 --- a/.tests/tests/ImportTest.php +++ b/.tests/tests/ImportTest.php @@ -1,4 +1,4 @@ -http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of tracks"); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); - $this->assertEquals(1, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(1, (int) $xml->trackcnt, "Wrong error message"); + $track = $json[0]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(2, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -88,12 +89,12 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); @@ -110,7 +111,7 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -170,12 +171,14 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); - $this->assertEquals(1, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(1, (int) $xml->trackcnt, "Wrong error message"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of tracks"); + + $track = $json[0]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(1, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -204,12 +207,12 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -241,7 +244,7 @@ class ImportTest extends UloggerAPITestCase { ' . $this->testAltitude . ' 1 - + testComment . ']]> ' . $this->testSpeed . ' ' . $this->testBearing . ' @@ -270,12 +273,14 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); - $this->assertEquals(1, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(1, (int) $xml->trackcnt, "Wrong error message"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of tracks"); + + $track = $json[0]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(1, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -303,13 +308,13 @@ class ImportTest extends UloggerAPITestCase { "bearing" => $this->testBearing, "accuracy" => $this->testAccuracy, "provider" => $this->testProvider, - "comment" => null, - "image_id" => null + "comment" => $this->testComment, + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -351,12 +356,14 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); - $this->assertEquals(1, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(1, (int) $xml->trackcnt, "Wrong error message"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of tracks"); + + $track = $json[0]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(1, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -385,12 +392,12 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -438,12 +445,14 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status: $xml->message"); - $this->assertEquals(1, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(1, (int) $xml->trackcnt, "Wrong error message"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of tracks"); + + $track = $json[0]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(2, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -472,12 +481,12 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); $expected = [ @@ -493,7 +502,7 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -543,12 +552,18 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status: $xml->message"); - $this->assertEquals(2, (int) $xml->trackid, "Wrong error message"); - $this->assertEquals(2, (int) $xml->trackcnt, "Wrong error message"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of tracks"); + + $track = $json[0]; + $this->assertEquals(2, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); + + $track = $json[1]; + $this->assertEquals(1, (int) $track->id, "Wrong track id"); + $this->assertEquals($this->testTrackName, $track->name, "Wrong track name"); $this->assertEquals(2, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(2, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -584,12 +599,12 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $actual = $this->getConnection()->createQueryTable( "positions", "SELECT id, " . $this->unix_timestamp('time') . " AS time, user_id, track_id, latitude, longitude, - altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); $expected = [ @@ -605,7 +620,7 @@ class ImportTest extends UloggerAPITestCase { "accuracy" => null, "provider" => "gps", "comment" => null, - "image_id" => null + "image" => null ]; $this->assertTableContains($expected, $actual, "Wrong actual table data"); } @@ -647,11 +662,11 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals($lang["iparsefailure"], (string) $xml->message, "Wrong error status"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals($lang["iparsefailure"], (string) $json->message, "Wrong error status"); $this->assertEquals(0, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(0, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -694,11 +709,11 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals($lang["iparsefailure"], (string) $xml->message, "Wrong error status"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals($lang["iparsefailure"], (string) $json->message, "Wrong error status"); $this->assertEquals(0, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(0, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -735,11 +750,11 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals($lang["iparsefailure"], (string) $xml->message, "Wrong error status"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals($lang["iparsefailure"], (string) $json->message, "Wrong error status"); $this->assertEquals(0, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(0, $this->getConnection()->getRowCount("positions"), "Wrong row count"); @@ -780,29 +795,16 @@ class ImportTest extends UloggerAPITestCase { $response = $this->http->post("/utils/import.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals(0, strpos((string) $xml->message, $lang["iparsefailure"]), "Wrong error status"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals(0, strpos((string) $json->message, $lang["iparsefailure"]), "Wrong error status"); $this->assertEquals(0, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals(0, $this->getConnection()->getRowCount("positions"), "Wrong row count"); } - /** - * @param ResponseInterface $response - * @return bool|SimpleXMLElement - */ - private function getXMLfromResponse($response) { - $xml = false; - libxml_use_internal_errors(true); - try { - $xml = new SimpleXMLElement((string) $response->getBody()); - } catch (Exception $e) { /* ignore */ } - return $xml; - } - private function getStream($string) { $stream = tmpfile(); fwrite($stream, $string); diff --git a/.tests/tests/InternalAPITest.php b/.tests/tests/InternalAPITest.php index ea8f652..8a68d80 100644 --- a/.tests/tests/InternalAPITest.php +++ b/.tests/tests/InternalAPITest.php @@ -28,20 +28,20 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 2, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of positions"); - $position = $xml->position[0]; - $this->assertEquals((int) $position["id"], 1, "Wrong position id"); + $position = $json[0]; + $this->assertEquals((int) $position->id, 1, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp, "Wrong timestamp"); $this->assertEquals((string) $position->username, $this->testAdminUser, "Wrong username"); $this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname"); - $position = $xml->position[1]; - $this->assertEquals((int) $position["id"], 2, "Wrong position id"); + $position = $json[1]; + $this->assertEquals((int) $position->id, 2, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 1, "Wrong timestamp"); @@ -67,20 +67,20 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 2, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of positions"); - $position = $xml->position[0]; - $this->assertEquals((int) $position["id"], 1, "Wrong position id"); + $position = $json[0]; + $this->assertEquals((int) $position->id, 1, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp, "Wrong timestamp"); $this->assertEquals((string) $position->username, $this->testUser, "Wrong username"); $this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname"); - $position = $xml->position[1]; - $this->assertEquals((int) $position["id"], 2, "Wrong position id"); + $position = $json[1]; + $this->assertEquals((int) $position->id, 2, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 1, "Wrong timestamp"); @@ -107,9 +107,9 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 0, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 0, "Wrong count of positions"); } public function testGetPositionsOtherUserByAdmin() { @@ -131,20 +131,20 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 2, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of positions"); - $position = $xml->position[0]; - $this->assertEquals((int) $position["id"], 1, "Wrong position id"); + $position = $json[0]; + $this->assertEquals((int) $position->id, 1, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp, "Wrong timestamp"); $this->assertEquals((string) $position->username, $this->testUser, "Wrong username"); $this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname"); - $position = $xml->position[1]; - $this->assertEquals((int) $position["id"], 2, "Wrong position id"); + $position = $json[1]; + $this->assertEquals((int) $position->id, 2, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 1, "Wrong timestamp"); @@ -175,12 +175,12 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 1, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 1, "Wrong count of positions"); - $position = $xml->position[0]; - $this->assertEquals((int) $position["id"], 2, "Wrong position id"); + $position = $json[0]; + $this->assertEquals((int) $position->id, 2, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 3, "Wrong timestamp"); @@ -212,20 +212,20 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->position->count(), 2, "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of positions"); - $position = $xml->position[0]; - $this->assertEquals((int) $position["id"], 2, "Wrong position id"); + $position = $json[0]; + $this->assertEquals((int) $position->id, 2, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 3, "Wrong timestamp"); $this->assertEquals((string) $position->username, $this->testAdminUser, "Wrong username"); $this->assertEquals((string) $position->trackname, $this->testTrackName, "Wrong trackname"); - $position = $xml->position[1]; - $this->assertEquals((int) $position["id"], 3, "Wrong position id"); + $position = $json[1]; + $this->assertEquals((int) $position->id, 3, "Wrong position id"); $this->assertEquals((float) $position->latitude, $this->testLat, "Wrong latitude"); $this->assertEquals((float) $position->longitude, $this->testLon, "Wrong longitude"); $this->assertEquals((int) $position->timestamp, $this->testTimestamp + 2, "Wrong timestamp"); @@ -250,9 +250,9 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, $xml->position->count(), "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertCount(0, $json, "Wrong count of positions"); } public function testGetPositionsNoUserId() { @@ -272,10 +272,9 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, $xml->position->count(), "Wrong count of positions"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertCount(0, $json, "Wrong count of positions"); } public function testGetPositionsNoAuth() { @@ -291,10 +290,10 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/getpositions.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); + $json = json_decode($response->getBody()); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals($xml->position->count(), 0, "Wrong count of positions"); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 0, "Wrong count of positions"); } @@ -317,17 +316,17 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/gettracks.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->track->count(), 2, "Wrong count of tracks"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of tracks"); - $track = $xml->track[0]; - $this->assertEquals((int) $track->trackid, $this->testTrackId2, "Wrong track id"); - $this->assertEquals((string) $track->trackname, $this->testTrackName . "2", "Wrong track name"); + $track = $json[0]; + $this->assertEquals((int) $track->id, $this->testTrackId2, "Wrong track id"); + $this->assertEquals((string) $track->name, $this->testTrackName . "2", "Wrong track name"); - $track = $xml->track[1]; - $this->assertEquals((int) $track->trackid, $this->testTrackId, "Wrong track id"); - $this->assertEquals((string) $track->trackname, $this->testTrackName, "Wrong track name"); + $track = $json[1]; + $this->assertEquals((int) $track->id, $this->testTrackId, "Wrong track id"); + $this->assertEquals((string) $track->name, $this->testTrackName, "Wrong track name"); } public function testGetTracksUser() { @@ -347,18 +346,18 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/gettracks.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->track->count(), 2, "Wrong count of tracks"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 2, "Wrong count of tracks"); - $track = $xml->track[0]; - $this->assertEquals((int) $track->trackid, $this->testTrackId2, "Wrong track id"); - $this->assertEquals((string) $track->trackname, $this->testTrackName . "2", "Wrong track name"); + $track = $json[0]; + $this->assertEquals((int) $track->id, $this->testTrackId2, "Wrong track id"); + $this->assertEquals((string) $track->name, $this->testTrackName . "2", "Wrong track name"); - $track = $xml->track[1]; - $this->assertEquals((int) $track->trackid, $this->testTrackId, "Wrong track id"); - $this->assertEquals((string) $track->trackname, $this->testTrackName, "Wrong track name"); - } + $track = $json[1]; + $this->assertEquals((int) $track->id, $this->testTrackId, "Wrong track id"); + $this->assertEquals((string) $track->name, $this->testTrackName, "Wrong track name"); + } public function testGetTracksOtherUser() { $this->addTestUser($this->testUser, password_hash($this->testPass, PASSWORD_DEFAULT)); @@ -377,9 +376,9 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/gettracks.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals($xml->track->count(), 0, "Wrong count of tracks"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 0, "Wrong count of tracks"); } public function testGetTracksNoUserId() { @@ -397,9 +396,9 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->get("/utils/gettracks.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals($xml->track->count(), 0, "Wrong count of tracks"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 0, "Wrong count of tracks"); } public function testGetTracksNoAuth() { @@ -416,9 +415,9 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->get("/utils/gettracks.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals($xml->track->count(), 0, "Wrong count of tracks"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(count($json), 0, "Wrong count of tracks"); } @@ -428,15 +427,19 @@ class InternalAPITest extends UloggerAPITestCase { $options = [ "http_errors" => false, - "form_params" => [ "userid" => $this->testUserId ], + "form_params" => [ + "login" => $this->testUser, + "pass" => $this->testPass, + "oldpass" => $this->testPass + ], ]; $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(401, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "Unauthorized", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Unauthorized", "Wrong error message"); } public function testChangePassEmpty() { @@ -449,13 +452,13 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "Empty password", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Empty password", "Wrong error message"); } - public function testChangePassNoUser() { + public function testChangePassUserUnknown() { $this->assertTrue($this->authenticate(), "Authentication failed"); $options = [ @@ -468,10 +471,28 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "User unknown", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "User unknown", "Wrong error message"); + } + + public function testChangePassEmptyLogin() { + $this->assertTrue($this->authenticate(), "Authentication failed"); + + $options = [ + "http_errors" => false, + "form_params" => [ + "pass" => $this->testPass, + ], + ]; + $response = $this->http->post("/utils/changepass.php", $options); + $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); + + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Empty login", "Wrong error message"); } public function testChangePassWrongOldpass() { @@ -480,6 +501,7 @@ class InternalAPITest extends UloggerAPITestCase { $options = [ "http_errors" => false, "form_params" => [ + "login" => $this->testAdminUser, "oldpass" => "badpass", "pass" => "newpass", ], @@ -487,10 +509,10 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "Wrong old password", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Wrong old password", "Wrong error message"); } public function testChangePassNoOldpass() { @@ -499,16 +521,17 @@ class InternalAPITest extends UloggerAPITestCase { $options = [ "http_errors" => false, "form_params" => [ + "login" => $this->testAdminUser, "pass" => "newpass", ], ]; $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "Wrong old password", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Wrong old password", "Wrong error message"); } public function testChangePassSelfAdmin() { @@ -519,6 +542,7 @@ class InternalAPITest extends UloggerAPITestCase { $options = [ "http_errors" => false, "form_params" => [ + "login" => $this->testAdminUser, "oldpass" => $this->testAdminPass, "pass" => $newPass, ], @@ -526,9 +550,8 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertTrue(password_verify($newPass, $this->pdoGetColumn("SELECT password FROM users")), "Wrong actual password hash"); } @@ -541,6 +564,7 @@ class InternalAPITest extends UloggerAPITestCase { $options = [ "http_errors" => false, "form_params" => [ + "login" => $this->testUser, "oldpass" => $this->testPass, "pass" => $newPass, ], @@ -548,9 +572,8 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertTrue(password_verify($newPass, $this->pdoGetColumn("SELECT password FROM users WHERE id = $userId")), "Wrong actual password hash"); } @@ -570,9 +593,8 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertTrue(password_verify($newPass, $this->pdoGetColumn("SELECT password FROM users WHERE id = $userId")), "Wrong actual password hash"); } @@ -593,10 +615,10 @@ class InternalAPITest extends UloggerAPITestCase { $response = $this->http->post("/utils/changepass.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is not false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, "Unauthorized", "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, "Unauthorized", "Wrong error message"); } /* handletrack.php */ @@ -617,9 +639,8 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals($trackId2, $this->pdoGetColumn("SELECT id FROM tracks WHERE id = $trackId2"), "Wrong actual track id"); } @@ -640,9 +661,8 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(1, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $this->assertEquals($trackId2, $this->pdoGetColumn("SELECT id FROM tracks WHERE id = $trackId2"), "Wrong actual track id"); } @@ -663,10 +683,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); } public function testHandleTrackUpdate() { @@ -686,9 +706,8 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 0, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(2, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); $row1 = [ "id" => $trackId2, @@ -727,10 +746,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(2, $this->getConnection()->getRowCount("tracks"), "Wrong row count"); } @@ -752,10 +771,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); } public function testHandleTrackMissingAction() { @@ -767,10 +786,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handletrack.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); } @@ -785,10 +804,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); } public function testHandleUserNonAdmin() { @@ -803,10 +822,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); } @@ -822,10 +841,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(1, $this->getConnection()->getRowCount("users"), "Wrong row count"); } @@ -840,10 +859,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(1, $this->getConnection()->getRowCount("users"), "Wrong row count"); } @@ -859,10 +878,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals((int) $xml->error, 1, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals((int) $json->error, 1, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); } @@ -876,9 +895,8 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); $expected = [ "login" => $this->testUser, @@ -903,10 +921,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["userexists"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["userexists"], "Wrong error message"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); } @@ -922,9 +940,8 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); $this->assertTrue(password_verify($newPass, $this->pdoGetColumn("SELECT password FROM users WHERE login = '$this->testUser'")), "Wrong actual password hash"); } @@ -941,10 +958,10 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(1, (int) $xml->error, "Wrong error status"); - $this->assertEquals((string) $xml->message, $lang["servererror"], "Wrong error message"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); + $this->assertEquals(1, (int) $json->error, "Wrong error status"); + $this->assertEquals((string) $json->message, $lang["servererror"], "Wrong error message"); $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); $this->assertTrue(password_verify($this->testPass, $this->pdoGetColumn("SELECT password FROM users WHERE login = '$this->testUser'")), "Wrong actual password hash"); } @@ -960,25 +977,11 @@ class InternalAPITest extends UloggerAPITestCase { ]; $response = $this->http->post("/utils/handleuser.php", $options); $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); - $xml = $this->getXMLfromResponse($response); - $this->assertTrue($xml !== false, "XML object is false"); - $this->assertEquals(0, (int) $xml->error, "Wrong error status"); + $json = json_decode($response->getBody()); + $this->assertNotNull($json, "JSON object is null"); $this->assertEquals(1, $this->getConnection()->getRowCount("users"), "Wrong row count"); } - /** - * @param ResponseInterface $response - * @return bool|SimpleXMLElement - */ - private function getXMLfromResponse($response) { - $xml = false; - libxml_use_internal_errors(true); - try { - $xml = new SimpleXMLElement((string) $response->getBody()); - } catch (Exception $e) { /* ignore */ } - return $xml; - } - } ?> \ No newline at end of file diff --git a/.tests/tests/PositionTest.php b/.tests/tests/PositionTest.php index 98a6f0b..3d04d4d 100644 --- a/.tests/tests/PositionTest.php +++ b/.tests/tests/PositionTest.php @@ -11,15 +11,15 @@ class PositionTest extends UloggerDatabaseTestCase { $trackId = $this->addTestTrack($userId); $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count"); - $posId = uPosition::add($userId, $trackId + 1, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = uPosition::add($userId, $trackId + 1, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $this->assertFalse($posId, "Adding position with nonexistant track should fail"); - $posId = uPosition::add($userId + 1, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = uPosition::add($userId + 1, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $this->assertFalse($posId, "Adding position with wrong user should fail"); - $posId = uPosition::add($userId, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = uPosition::add($userId, $trackId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $expected = [ "id" => $posId, @@ -34,11 +34,11 @@ class PositionTest extends UloggerDatabaseTestCase { "accuracy" => $this->testAccuracy, "provider" => $this->testProvider, "comment" => $this->testComment, - "image_id" => $this->testImageId + "image" => $this->testImage ]; $actual = $this->getConnection()->createQueryTable( "positions", - "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); diff --git a/.tests/tests/TrackTest.php b/.tests/tests/TrackTest.php index 2d4f089..30e8bb6 100644 --- a/.tests/tests/TrackTest.php +++ b/.tests/tests/TrackTest.php @@ -41,16 +41,16 @@ class TrackTest extends UloggerDatabaseTestCase { $this->assertEquals(1, $this->getConnection()->getRowCount('tracks'), "Wrong row count"); $track = new uTrack($trackId + 1); - $posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $this->assertFalse($posId, "Adding position with nonexistant track should fail"); $track = new uTrack($trackId); - $posId = $track->addPosition($userId2, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = $track->addPosition($userId2, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(0, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $this->assertFalse($posId, "Adding position with wrong user should fail"); - $posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImageId); + $posId = $track->addPosition($userId, $this->testTimestamp, $this->testLat, $this->testLon, $this->testAltitude, $this->testSpeed, $this->testBearing, $this->testAccuracy, $this->testProvider, $this->testComment, $this->testImage); $this->assertEquals(1, $this->getConnection()->getRowCount('positions'), "Wrong row count"); $expected = [ "id" => $posId, @@ -65,11 +65,11 @@ class TrackTest extends UloggerDatabaseTestCase { "accuracy" => $this->testAccuracy, "provider" => $this->testProvider, "comment" => $this->testComment, - "image_id" => $this->testImageId + "image" => $this->testImage ]; $actual = $this->getConnection()->createQueryTable( "positions", - "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id FROM positions" + "SELECT id, user_id, track_id, " . $this->unix_timestamp('time') . " AS time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image FROM positions" ); $this->assertTableContains($expected, $actual, "Wrong actual table data"); diff --git a/.travis.yml b/.travis.yml index b237bf1..969cc62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,7 @@ before_install: ;; esac - composer install + - npm install - until netstat -atn 2>/dev/null | grep '8080.*LISTEN'; do sleep 1; done after_success: @@ -56,9 +57,14 @@ after_success: tx push -s --no-interactive fi +after_failure: + - docker logs ulogger script: - ./vendor/bin/phpunit -c .tests/phpunit.xml + - npm test + - npm run lint:js + - npm run lint:css addons: coverity_scan: diff --git a/Dockerfile b/Dockerfile index d33ae33..47ee91f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,6 @@ RUN chown nginx.nginx /etc/nginx/conf.d/default.conf RUN rm -rf /var/www/html RUN mkdir -p /var/www/html COPY . /var/www/html -RUN grep '^[$ /var/www/html/config.php RUN /init.sh "${DB_ROOT_PASS}" "${DB_USER_PASS}" diff --git a/README.md b/README.md index 233d47f..88ac199 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ Together with a dedicated [μlogger mobile client](https://github.com/bfabiszews - user authentication - Google Maps - OpenLayers (OpenStreet and other layers) -- ajax - user preferences stored in cookies - simple admin menu - export tracks to gpx and kml @@ -30,6 +29,8 @@ Together with a dedicated [μlogger mobile client](https://github.com/bfabiszews ## Install - Download zipped archive or clone the repository on your computer - Move it to your web server directory (unzip if needed) +- Fix folder permissions: `uploads` folder (for uploaded images) should be writeable by PHP scripts +- In case of development version it is necessary to build javascript bundle from source files. You will need to install `npm` and run `npm install` and `npm run build` in root folder - Create database and database user (at least SELECT, INSERT, UPDATE, DELETE privileges, CREATE, DROP for setup script, SEQUENCES for postgreSQL) - Create a copy of `config.default.php` and rename it to `config.php`. Customize it and add database credentials - Edit `scripts/setup.php` script, enable it by setting [$enabled](https://github.com/bfabiszewski/ulogger-server/blob/master/scripts/setup.php#L21) value to `true` @@ -51,6 +52,7 @@ Together with a dedicated [μlogger mobile client](https://github.com/bfabiszews ## Tests - Install tests dependecies. - `composer install` + - `npm install` - Integration tests may be run against docker image. We need exposed http and optionally database ports (eg. mapped to localhost 8080 and 8081). Below example for MySQL setup. - `docker build -t ulogger .` - `docker run -d --name ulogger -p 8080:80 -p 8081:3306 --expose 3306 -e ULOGGER_ENABLE_SETUP=1 ulogger` @@ -59,13 +61,13 @@ Together with a dedicated [μlogger mobile client](https://github.com/bfabiszews - `DB_USER=ulogger` - `DB_PASS=secret2` - `ULOGGER_URL="http://127.0.0.1:8080"` -- Run tests +- PHP tests - `./vendor/bin/phpunit -c .tests/phpunit.xml` - -## Todo -- improve track editing -- track display filters (accurracy, provider) -- improve interface on mobile devices +- JS tests + - `npm test` +- Other tests + - `npm run lint:js` + - `npm run lint:css` ## Translations - translations may be contributed via [Transifex](https://www.transifex.com/bfabiszewski/ulogger/). diff --git a/client/index.php b/client/index.php index 43addbd..3de795d 100644 --- a/client/index.php +++ b/client/index.php @@ -55,7 +55,7 @@ exitWithError("Unauthorized"); } - switch ($action) { +switch ($action) { // action: authorize case "auth": $login = uUtils::postString('user'); @@ -111,16 +111,21 @@ $accuracy = uUtils::postInt('accuracy'); $provider = uUtils::postString('provider'); $comment = uUtils::postString('comment'); - $imageId = uUtils::postInt('imageid'); + $imageMeta = uUtils::requestFile('image'); $trackId = uUtils::postInt('trackid'); if (!is_float($lat) || !is_float($lon) || !is_int($timestamp) || !is_int($trackId)) { exitWithError("Missing required parameter"); } + $image = null; + if (!empty($imageMeta)) { + $image = uUpload::add($imageMeta, $trackId); + } + require_once(ROOT_DIR . "/helpers/position.php"); $positionId = uPosition::add($auth->user->id, $trackId, - $timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $imageId); + $timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $image); if ($positionId === false) { exitWithError("Server error"); diff --git a/composer.lock b/composer.lock index d352563..3258483 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "e0409bcb302c1bef7caa031dafc841a9", + "content-hash": "ffb1c6d77d755002ea20d1c1c6338b43", "packages": [ { "name": "ulrichsg/getopt-php", @@ -1656,16 +1656,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -1677,7 +1677,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -1693,13 +1693,13 @@ "MIT" ], "authors": [ - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - }, { "name": "Gert de Pagter", "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony polyfill for ctype functions", @@ -1710,20 +1710,20 @@ "polyfill", "portable" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.22", + "version": "v3.4.36", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "ba11776e9e6c15ad5759a07bffb15899bac75c2d" + "reference": "dab657db15207879217fc81df4f875947bf68804" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/ba11776e9e6c15ad5759a07bffb15899bac75c2d", - "reference": "ba11776e9e6c15ad5759a07bffb15899bac75c2d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/dab657db15207879217fc81df4f875947bf68804", + "reference": "dab657db15207879217fc81df4f875947bf68804", "shasum": "" }, "require": { @@ -1769,7 +1769,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2019-01-16T10:59:17+00:00" + "time": "2019-10-24T15:33:53+00:00" }, { "name": "vlucas/phpdotenv", @@ -1880,6 +1880,12 @@ "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, - "platform": [], + "platform": { + "ext-json": "*", + "ext-pdo": "*", + "ext-xmlwriter": "*", + "ext-simplexml": "*", + "ext-libxml": "*" + }, "platform-dev": [] } diff --git a/css/chartist.min.css b/css/chartist.min.css new file mode 100644 index 0000000..6a23d47 --- /dev/null +++ b/css/chartist.min.css @@ -0,0 +1 @@ +.ct-double-octave:after,.ct-major-eleventh:after,.ct-major-second:after,.ct-major-seventh:after,.ct-major-sixth:after,.ct-major-tenth:after,.ct-major-third:after,.ct-major-twelfth:after,.ct-minor-second:after,.ct-minor-seventh:after,.ct-minor-sixth:after,.ct-minor-third:after,.ct-octave:after,.ct-perfect-fifth:after,.ct-perfect-fourth:after,.ct-square:after{content:"";clear:both}.ct-label{fill:rgba(0,0,0,.4);color:rgba(0,0,0,.4);font-size:.75rem;line-height:1}.ct-grid-background,.ct-line{fill:none}.ct-chart-bar .ct-label,.ct-chart-line .ct-label{display:block;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}.ct-chart-donut .ct-label,.ct-chart-pie .ct-label{dominant-baseline:central}.ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-label.ct-vertical.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-label.ct-vertical.ct-end{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;text-align:center;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-start{-webkit-box-align:flex-end;-webkit-align-items:flex-end;-ms-flex-align:flex-end;align-items:flex-end;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-horizontal.ct-end{-webkit-box-align:flex-start;-webkit-align-items:flex-start;-ms-flex-align:flex-start;align-items:flex-start;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:start}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-start{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-end;-webkit-justify-content:flex-end;-ms-flex-pack:flex-end;justify-content:flex-end;text-align:right;text-anchor:end}.ct-chart-bar.ct-horizontal-bars .ct-label.ct-vertical.ct-end{-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:flex-start;-webkit-justify-content:flex-start;-ms-flex-pack:flex-start;justify-content:flex-start;text-align:left;text-anchor:end}.ct-grid{stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:2px}.ct-point{stroke-width:10px;stroke-linecap:round}.ct-line{stroke-width:4px}.ct-area{stroke:none;fill-opacity:.1}.ct-bar{fill:none;stroke-width:10px}.ct-slice-donut{fill:none;stroke-width:60px}.ct-series-a .ct-bar,.ct-series-a .ct-line,.ct-series-a .ct-point,.ct-series-a .ct-slice-donut{stroke:#d70206}.ct-series-a .ct-area,.ct-series-a .ct-slice-donut-solid,.ct-series-a .ct-slice-pie{fill:#d70206}.ct-series-b .ct-bar,.ct-series-b .ct-line,.ct-series-b .ct-point,.ct-series-b .ct-slice-donut{stroke:#f05b4f}.ct-series-b .ct-area,.ct-series-b .ct-slice-donut-solid,.ct-series-b .ct-slice-pie{fill:#f05b4f}.ct-series-c .ct-bar,.ct-series-c .ct-line,.ct-series-c .ct-point,.ct-series-c .ct-slice-donut{stroke:#f4c63d}.ct-series-c .ct-area,.ct-series-c .ct-slice-donut-solid,.ct-series-c .ct-slice-pie{fill:#f4c63d}.ct-series-d .ct-bar,.ct-series-d .ct-line,.ct-series-d .ct-point,.ct-series-d .ct-slice-donut{stroke:#d17905}.ct-series-d .ct-area,.ct-series-d .ct-slice-donut-solid,.ct-series-d .ct-slice-pie{fill:#d17905}.ct-series-e .ct-bar,.ct-series-e .ct-line,.ct-series-e .ct-point,.ct-series-e .ct-slice-donut{stroke:#453d3f}.ct-series-e .ct-area,.ct-series-e .ct-slice-donut-solid,.ct-series-e .ct-slice-pie{fill:#453d3f}.ct-series-f .ct-bar,.ct-series-f .ct-line,.ct-series-f .ct-point,.ct-series-f .ct-slice-donut{stroke:#59922b}.ct-series-f .ct-area,.ct-series-f .ct-slice-donut-solid,.ct-series-f .ct-slice-pie{fill:#59922b}.ct-series-g .ct-bar,.ct-series-g .ct-line,.ct-series-g .ct-point,.ct-series-g .ct-slice-donut{stroke:#0544d3}.ct-series-g .ct-area,.ct-series-g .ct-slice-donut-solid,.ct-series-g .ct-slice-pie{fill:#0544d3}.ct-series-h .ct-bar,.ct-series-h .ct-line,.ct-series-h .ct-point,.ct-series-h .ct-slice-donut{stroke:#6b0392}.ct-series-h .ct-area,.ct-series-h .ct-slice-donut-solid,.ct-series-h .ct-slice-pie{fill:#6b0392}.ct-series-i .ct-bar,.ct-series-i .ct-line,.ct-series-i .ct-point,.ct-series-i .ct-slice-donut{stroke:#f05b4f}.ct-series-i .ct-area,.ct-series-i .ct-slice-donut-solid,.ct-series-i .ct-slice-pie{fill:#f05b4f}.ct-series-j .ct-bar,.ct-series-j .ct-line,.ct-series-j .ct-point,.ct-series-j .ct-slice-donut{stroke:#dda458}.ct-series-j .ct-area,.ct-series-j .ct-slice-donut-solid,.ct-series-j .ct-slice-pie{fill:#dda458}.ct-series-k .ct-bar,.ct-series-k .ct-line,.ct-series-k .ct-point,.ct-series-k .ct-slice-donut{stroke:#eacf7d}.ct-series-k .ct-area,.ct-series-k .ct-slice-donut-solid,.ct-series-k .ct-slice-pie{fill:#eacf7d}.ct-series-l .ct-bar,.ct-series-l .ct-line,.ct-series-l .ct-point,.ct-series-l .ct-slice-donut{stroke:#86797d}.ct-series-l .ct-area,.ct-series-l .ct-slice-donut-solid,.ct-series-l .ct-slice-pie{fill:#86797d}.ct-series-m .ct-bar,.ct-series-m .ct-line,.ct-series-m .ct-point,.ct-series-m .ct-slice-donut{stroke:#b2c326}.ct-series-m .ct-area,.ct-series-m .ct-slice-donut-solid,.ct-series-m .ct-slice-pie{fill:#b2c326}.ct-series-n .ct-bar,.ct-series-n .ct-line,.ct-series-n .ct-point,.ct-series-n .ct-slice-donut{stroke:#6188e2}.ct-series-n .ct-area,.ct-series-n .ct-slice-donut-solid,.ct-series-n .ct-slice-pie{fill:#6188e2}.ct-series-o .ct-bar,.ct-series-o .ct-line,.ct-series-o .ct-point,.ct-series-o .ct-slice-donut{stroke:#a748ca}.ct-series-o .ct-area,.ct-series-o .ct-slice-donut-solid,.ct-series-o .ct-slice-pie{fill:#a748ca}.ct-square{display:block;position:relative;width:100%}.ct-square:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:100%}.ct-square:after{display:table}.ct-square>svg{display:block;position:absolute;top:0;left:0}.ct-minor-second{display:block;position:relative;width:100%}.ct-minor-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:93.75%}.ct-minor-second:after{display:table}.ct-minor-second>svg{display:block;position:absolute;top:0;left:0}.ct-major-second{display:block;position:relative;width:100%}.ct-major-second:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:88.8888888889%}.ct-major-second:after{display:table}.ct-major-second>svg{display:block;position:absolute;top:0;left:0}.ct-minor-third{display:block;position:relative;width:100%}.ct-minor-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:83.3333333333%}.ct-minor-third:after{display:table}.ct-minor-third>svg{display:block;position:absolute;top:0;left:0}.ct-major-third{display:block;position:relative;width:100%}.ct-major-third:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:80%}.ct-major-third:after{display:table}.ct-major-third>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fourth{display:block;position:relative;width:100%}.ct-perfect-fourth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:75%}.ct-perfect-fourth:after{display:table}.ct-perfect-fourth>svg{display:block;position:absolute;top:0;left:0}.ct-perfect-fifth{display:block;position:relative;width:100%}.ct-perfect-fifth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:66.6666666667%}.ct-perfect-fifth:after{display:table}.ct-perfect-fifth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-sixth{display:block;position:relative;width:100%}.ct-minor-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:62.5%}.ct-minor-sixth:after{display:table}.ct-minor-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-golden-section{display:block;position:relative;width:100%}.ct-golden-section:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:61.804697157%}.ct-golden-section:after{content:"";display:table;clear:both}.ct-golden-section>svg{display:block;position:absolute;top:0;left:0}.ct-major-sixth{display:block;position:relative;width:100%}.ct-major-sixth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:60%}.ct-major-sixth:after{display:table}.ct-major-sixth>svg{display:block;position:absolute;top:0;left:0}.ct-minor-seventh{display:block;position:relative;width:100%}.ct-minor-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:56.25%}.ct-minor-seventh:after{display:table}.ct-minor-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-seventh{display:block;position:relative;width:100%}.ct-major-seventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:53.3333333333%}.ct-major-seventh:after{display:table}.ct-major-seventh>svg{display:block;position:absolute;top:0;left:0}.ct-octave{display:block;position:relative;width:100%}.ct-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:50%}.ct-octave:after{display:table}.ct-octave>svg{display:block;position:absolute;top:0;left:0}.ct-major-tenth{display:block;position:relative;width:100%}.ct-major-tenth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:40%}.ct-major-tenth:after{display:table}.ct-major-tenth>svg{display:block;position:absolute;top:0;left:0}.ct-major-eleventh{display:block;position:relative;width:100%}.ct-major-eleventh:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:37.5%}.ct-major-eleventh:after{display:table}.ct-major-eleventh>svg{display:block;position:absolute;top:0;left:0}.ct-major-twelfth{display:block;position:relative;width:100%}.ct-major-twelfth:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:33.3333333333%}.ct-major-twelfth:after{display:table}.ct-major-twelfth>svg{display:block;position:absolute;top:0;left:0}.ct-double-octave{display:block;position:relative;width:100%}.ct-double-octave:before{display:block;float:left;content:"";width:0;height:0;padding-bottom:25%}.ct-double-octave:after{display:table}.ct-double-octave>svg{display:block;position:absolute;top:0;left:0} \ No newline at end of file diff --git a/css/fonts.css b/css/fonts.css new file mode 100644 index 0000000..e58f85c --- /dev/null +++ b/css/fonts.css @@ -0,0 +1,224 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0Udc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0ddc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0Vdc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0adc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0Wdc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0Xdc1GAK6bt6o.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 400; + src: local('Open Sans Italic'), local('OpenSans-Italic'), url(../fonts/mem6YaGs126MiZpBA-UFUK0Zdc1GAK6b.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhmIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhvIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhnIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhoIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhkIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhlIqOxjaPXZSk.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: italic; + font-weight: 700; + src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(../fonts/memnYaGs126MiZpBA-UFUKWiUNhrIqOxjaPX.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFWJ0bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFUZ0bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFWZ0bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFVp0bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans Regular'), local('OpenSans-Regular'), url(../fonts/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOX-hpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOVuhpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOXuhpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOUehpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+0370-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOXehpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOXOhpKKSTj5PW.woff2) format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url(../fonts/mem5YaGs126MiZpBA-UN7rgOUuhpKKSTjw.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/css/main.css b/css/main.css index 4e5563c..61d38f9 100644 --- a/css/main.css +++ b/css/main.css @@ -19,238 +19,360 @@ html { height: 100%; } + body { height: 100%; margin: 0; padding: 0; background-color: #666; } + a { - color: #bce; + cursor: pointer; text-decoration: none; + color: #bce; } + :link, :visited { color: #bce; } + select { - width: 150px; font-weight: normal; + width: 150px; padding-top: 0.2em; } + +#container { + display: flex; + height: 100%; +} + +#main { + flex-grow: 1; + order: 1; + height: 100%; +} + +#map-canvas { + height: 100%; +} + +#menu { + font-family: "Open Sans", Verdana, sans-serif; + font-size: 0.7em; + font-weight: bold; + float: right; + overflow-x: hidden; + overflow-y: auto; + order: 2; + width: 165px; + height: 100%; + color: white; + background-color: #666; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; +} + +#menu-content { + padding: 10px 0 3em 10px; +} + +#footer { + line-height: 3em; + position: fixed; + bottom: 0; + width: 165px; + padding-left: 10px; + color: lightgray; + background-color: rgba(102, 102, 102, 0.9); +} + +#menu-button { + font-size: 28px; + font-weight: normal; + line-height: 28px; + position: absolute; + z-index: 1900; + top: 5px; + right: 0; + width: 30px; + height: 35px; + cursor: pointer; + text-align: center; + border-width: 1px 0 1px 1px; + border-style: solid; + border-color: #bce; + border-radius: 11px 0 0 11px; + background-color: #666; +} + +#menu-button a { + color: white; +} + +#menu-button a::after { + content: "»"; +} + +#menu.menu-hidden { + width: 0; +} + +#menu.menu-hidden #menu-button { + font-weight: normal; + border-color: white; + background-color: rgba(0, 60, 136, 0.3); +} + +#menu.menu-hidden #menu-button a::after { + content: "«"; +} + #menu input, #login input { width: 150px; text-align: center; border: 1px solid black; } -#menu input[type = "submit"], -#login input[type = "submit"] { - background-color: black; + +#menu input[type="submit"], +#login input[type="submit"] { color: white; border: 1px solid white; -} -#menu input[type = "checkbox"] { - width: auto; -} -.menulink { - display: block; - margin-top: .2em; -} -#main { - height: 100%; - margin-right: 165px; -} -#map-canvas { - height: 100%; -} -#menu { - font-family: 'Open Sans', Verdana, sans-serif; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-size: 0.7em; - font-weight: bold; - color: white; - float: right; - width: 165px; - height: 100%; - background-color: #666; - overflow-x: hidden; - overflow-y: auto; -} -#menu-content { - padding: 10px 0 3em 10px; -} -#footer { - position: fixed; - bottom:0; - width: 165px; - line-height: 3em; - padding-left: 10px; - background-color:rgba(102, 102, 102, 0.9); - color: lightgray; -} -#menu-close { - background-color: #666; - opacity: 0.9; - position: absolute; - top: 55px; - right: 165px; - z-index: 1900; - width: 18px; - height: 20px; - line-height: 18px; - text-align: right; - font-size: 18px; - font-weight: bolder; - border-radius: 11px 0 0 11px; - cursor: pointer; + background-color: black; } -#user, #track, #summary, #export, #import, #other, #units { +#menu input[type="checkbox"] { + width: auto; +} + +.menu-link { + display: block; + margin-top: 0.2em; +} + +label[for=user] { + display: block; + padding-top: 1em; +} + +.section { + display: block; padding-bottom: 10px; } -#summary div { - padding-top: .3em; + +.section:first-child { + padding-top: 1em; } + +#input-file { + display: none; +} + +#summary div { + padding-top: 0.3em; +} + #summary div img { margin-bottom: -2px; } + #login { - font-family: 'Open Sans', Verdana, sans-serif; + font-family: "Open Sans", Verdana, sans-serif; + font-size: 0.8em; position: relative; top: 10%; - background-color: #444; width: 30%; min-width: 200px; margin: auto; padding: 30px; - font-size: 0.8em; text-align: center; color: white; + background-color: #444; } + #title { font-size: 1.3em; - padding-bottom: 0.5em; padding-top: 0.6em; + padding-bottom: 0.5em; } + #subtitle { padding-bottom: 2em; } + #error { padding-top: 1.2em; color: yellow; } + #popup { - font-family: 'Open Sans', Verdana, sans-serif; + font-family: "Open Sans", Verdana, sans-serif; + max-width: 25em; + background-color: #666; } + #pheader { + font-size: 0.9rem; float: left; - font-size: .9rem; - color: #297b9a; - padding-bottom: .5rem; + padding-bottom: 0.5rem; + color: #bce; } + #pheader div { float: left; padding-right: 2em; } -#pbody { - clear: both; - padding-top: .2rem; - border-top: 1px solid #6cdae7;; - font-size: .8rem; - white-space: nowrap; + +#pheader div img { + background-image: radial-gradient(circle closest-side, #bfbfbc, #666); } + +#pbody { + font-size: 0.8rem; + line-height: 1.3rem; + clear: both; + padding-top: 0.2rem; + white-space: nowrap; + color: #e6e2e2; + border-top: 1px solid #bce; +} + #pcomments { clear: both; - color: #903; + padding: 1em; + text-align: center; + white-space: normal; + color: #e6e6e6; + border-radius: 10px; + background-color: #777676; } + +#pimage { + text-align: center; +} + +#pimage img { + max-width: 100%; + max-height: 25em; + cursor: pointer; + border-radius: 10px; +} + +#pimage img:hover { + opacity: 0.7; +} + #pleft, #pright { display: inline-block; padding-top: 5px; padding-right: 20px; } -#pbody .smaller { - color: gray; - font-size: .9em; -} -#pfooter { - font-size: .6rem; - padding-top: 20px; -} -#bottom { - display: none; - position: absolute; - z-index: 10000; -} -#chart { - position: fixed; - bottom: 0; left:0; right: 0; - height: 200px; - margin-right: 165px; - background-color: white; - opacity: 0.8; -} -#close { - position: fixed; - bottom: 175px; - right: 175px; - z-index: 10001; - font-size: 0.8em; + +#pleft img { + background-image: radial-gradient(circle closest-side, #bfbfbc, #666); } -#close a, #close:link, #close:visited { +#pbody .smaller { + font-size: 0.9em; + color: #cacaca; +} + +#pfooter { + font-size: 0.6rem; + padding-top: 20px; + color: #f0f8ff; +} + +#pfooter div:first-child { + width: 40%; + float: left; +} + +#pfooter div:last-child { + width: 40%; + float: right; + text-align: right; +} + +#bottom { + position: relative; + z-index: 10000; + display: none; +} + +#chart { + font-family: "Open Sans", Verdana, sans-serif; + position: absolute; + right: 0; + bottom: -15px; + left: 0; + height: 200px; + padding: 0 10px; + opacity: 0.8; + background-color: white; +} + +#chart-close { + font-size: 0.8em; + position: absolute; + z-index: 10001; + right: 15px; + bottom: 160px; + cursor: pointer; color: #5070af; } .mi { - color:white; - padding-right:0.1em; - font-style:italic; + font-style: italic; + padding-right: 0.1em; + color: white; } #modal { - font-family: 'Open Sans', Verdana, sans-serif; - display: block; + font-family: "Open Sans", Verdana, sans-serif; position: fixed; z-index: 10010; - left: 0; top: 0; + left: 0; + display: block; + overflow: auto; width: 100%; height: 100%; - overflow: auto; - background-color: black; /* fallback */ - background-color: rgba(0,0,0,0.4); padding-top: 10%; + background-color: black; /* fallback */ + background-color: rgba(0, 0, 0, 0.4); } #modal-header { - top: 20px; position: relative; - text-align: right; - margin: 0 auto; + top: 20px; width: 40%; min-width: 300px; + margin: 0 auto; + text-align: right; } #modal-header button { - background-color: rgba(0, 0, 0, 0); border: none; + background-color: rgba(0, 0, 0, 0); } #modal-body { font-size: 0.9em; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - color: white; - background-color: rgba(102, 102, 102, 0.9); - margin: 0 auto 15% auto; - border: 1px solid #888; width: 40%; min-width: 300px; + margin: 0 auto 15% auto; padding: 1em; - border-radius: 10px; + color: white; + border: 1px solid #888; -moz-border-radius: 10px; -webkit-border-radius: 10px; + border-radius: 10px; + background-color: rgba(102, 102, 102, 0.9); + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; } #modal-body .buttons { @@ -258,27 +380,53 @@ select { } #modal input[type=text], #modal input[type=password] { - width: 100%; - padding: 0.4em; - margin: 0.8em 0; display: inline-block; - border: 1px solid #ccc; box-sizing: border-box; - border-radius: 5px; + width: 100%; + margin: 0.8em 0; + padding: 0.4em; + border: 1px solid #ccc; -moz-border-radius: 5px; -webkit-border-radius: 5px; + border-radius: 5px; +} + +#modal.image { + overflow: hidden; + padding-top: 0; + background-color: rgba(45, 45, 45, 0.95); +} + +#modal.image #modal-body img { + max-width: 100%; + height: auto; + max-height: 87vh; +} + +#modal.image #modal-body { + width: 90%; + text-align: center; + background-color: rgb(45, 45, 45); +} + +#modal.image #modal-header { + width: 90%; } button { - color: white; - background-color: #434343; - cursor: pointer; - border: 1px solid white; - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; font-weight: bold; margin-right: 5px; + cursor: pointer; + color: white; + border: 1px solid white; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + background-color: #434343; +} + +button > * { + pointer-events: none; } #cancel { @@ -286,131 +434,205 @@ button { } .red-button { - color: white; float: right; - background-color: red; - padding: .1em .4em; - border-radius: 10px; + padding: 0.1em 0.4em; + color: white; -moz-border-radius: 10px; -webkit-border-radius: 10px; + border-radius: 10px; + background-color: red; } -.dropdown { - display: none; +#user-menu { position: absolute; - background-color: gray; - padding: 1em; - width: 130px; - border: 1px solid #888; -} - -.dropdown a { display: block; - padding-bottom: .5em; - padding-top: .5em; + width: 130px; + padding: 1em; + border: 1px solid #888; + background-color: gray; } -.show { display: block; } +#user-menu.menu-hidden, a.menu-hidden { + display: none; +} -.icon { height: 1.4em; } +#user-menu a { + display: block; + padding-top: 0.5em; + padding-bottom: 0.5em; +} -.u { text-decoration: underline; } +.icon { + height: 1.4em; + margin-right: 4px; + vertical-align: text-top; +} + +.menu-title { + text-decoration: underline; +} .loader { animation: blink 1s linear infinite; } @keyframes blink { - 50% { opacity: 0; } + 50% { + opacity: 0; + } +} + +/* chart */ +.ct-point { + transition: 0.3s; + stroke-width: 5px !important; +} + +.ct-point:hover { + cursor: pointer; + stroke-width: 10px !important; +} + +.ct-point-hilight { + stroke-width: 10px !important; +} + +.ct-point-selected { + stroke-width: 10px !important; + stroke: #f4c63d !important; +} + +.ct-line { + stroke-width: 2px !important; +} + +.ct-axis-title { + font-size: 0.8em; } /* openlayers 3 popup */ .ol-popup { position: absolute; - background-color: white; - -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); - filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); - padding: 15px; - border-radius: 10px; - border: 1px solid #cccccc; bottom: 12px; left: -50px; min-width: 280px; + padding: 15px; + border: 1px solid #ccc; + border-radius: 10px; + background-color: #666; + -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); + filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2)); } -.ol-popup:after, .ol-popup:before { - top: 100%; - border: solid transparent; - content: " "; - height: 0; - width: 0; + +.ol-popup::after, .ol-popup::before { position: absolute; + top: 100%; + width: 0; + height: 0; + content: " "; pointer-events: none; + border: solid transparent; } -.ol-popup:after { - border-top-color: white; - border-width: 10px; + +.ol-popup::after { left: 48px; margin-left: -10px; + border-width: 10px; + border-top-color: #666; } -.ol-popup:before { - border-top-color: #cccccc; - border-width: 11px; + +.ol-popup::before { left: 48px; margin-left: -11px; + border-width: 11px; + border-top-color: #ccc; } + .ol-popup-closer { - text-decoration: none; position: absolute; - top: 2px; - right: 8px; + top: -5px; + right: -10px; + width: 30px; + height: 30px; + background-image: url(../images/close.svg) !important; + background-repeat: no-repeat !important; } -.ol-popup-closer:after { - content: "✖"; + +.ol-overlay-container { + background-color: #666; +} + +/* Google Maps InfoWindow */ +.gm-style .gm-style-iw-c { + background-color: #666 !important; + overflow: visible !important; +} + +.gm-style .gm-style-iw-t::after { + background: linear-gradient(45deg, rgb(102, 102, 102) 50%, rgba(255, 255, 255, 0) 51%, rgba(255, 255, 255, 0) 100%) !important; +} + +.gm-style-iw button { + background-image: url(../images/close.svg) !important; + background-repeat: no-repeat !important; +} + +.gm-style-iw button img { + visibility: hidden; } #switcher { - display: none; position: absolute; bottom: 12px; left: 10px; + display: none; min-width: 200px; } + .ol-layerswitcher { + font-family: sans-serif; + font-size: 0.9em; + font-weight: bold; margin: 1px; + padding: 0.5em; color: #fff; - background-color: rgba(0, 60, 136, .5); border: none; border-radius: 2px; - font-family: sans-serif; - font-weight: bold; - font-size: .9em; - padding: 0.5em; + background-color: rgba(0, 60, 136, 0.5); } + .ol-layerswitcher:hover { - background-color: rgba(0, 60, 136, .7) + background-color: rgba(0, 60, 136, 0.7); } + .ol-layerswitcher label { display: block; clear: both; - margin: .5em 0; + margin: 0.5em 0; cursor: pointer; } + .ol-layerswitcher label:hover { color: #c8dcf2; } + .ol-layerswitcher input { margin-right: 1em; } + label.ol-datalayer { margin-top: 1.5em; } + .ol-datalayer ~ .ol-datalayer { - margin-top: .5em; + margin-top: 0.5em; } + .ol-switcher-button { top: 6.6em; - left: .5em; + left: 0.5em; } + .ol-touch .ol-switcher-button { top: 10em; -} \ No newline at end of file +} diff --git a/fonts/OpenSans.LICENSE b/fonts/OpenSans.LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/fonts/OpenSans.LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/fonts/OpenSans.README b/fonts/OpenSans.README new file mode 100644 index 0000000..e156adc --- /dev/null +++ b/fonts/OpenSans.README @@ -0,0 +1,5 @@ +Open Sans is a humanist sans serif typeface designed by Steve Matteson, +Type Director of Ascender Corp. This version contains the complete 897 character set, +which includes the standard ISO Latin 1, Latin CE, Greek and Cyrillic character sets. +Open Sans was designed with an upright stress, open forms and a neutral, yet friendly appearance. +It was optimized for print, web, and mobile interfaces, and has excellent legibility characteristics in its letterforms. \ No newline at end of file diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOUehpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOUehpKKSTj5PW.woff2 new file mode 100644 index 0000000..b6ceebf Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOUehpKKSTj5PW.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOUuhpKKSTjw.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOUuhpKKSTjw.woff2 new file mode 100644 index 0000000..90f3939 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOUuhpKKSTjw.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOVuhpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOVuhpKKSTj5PW.woff2 new file mode 100644 index 0000000..3f39502 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOVuhpKKSTj5PW.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOX-hpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOX-hpKKSTj5PW.woff2 new file mode 100644 index 0000000..a339675 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOX-hpKKSTj5PW.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOXOhpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOXOhpKKSTj5PW.woff2 new file mode 100644 index 0000000..a21f919 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOXOhpKKSTj5PW.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOXehpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOXehpKKSTj5PW.woff2 new file mode 100644 index 0000000..20d5832 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOXehpKKSTj5PW.woff2 differ diff --git a/fonts/mem5YaGs126MiZpBA-UN7rgOXuhpKKSTj5PW.woff2 b/fonts/mem5YaGs126MiZpBA-UN7rgOXuhpKKSTj5PW.woff2 new file mode 100644 index 0000000..efc5c40 Binary files /dev/null and b/fonts/mem5YaGs126MiZpBA-UN7rgOXuhpKKSTj5PW.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0Udc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0Udc1GAK6bt6o.woff2 new file mode 100644 index 0000000..736c1e7 Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0Udc1GAK6bt6o.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0Vdc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0Vdc1GAK6bt6o.woff2 new file mode 100644 index 0000000..deabb6d Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0Vdc1GAK6bt6o.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0Wdc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0Wdc1GAK6bt6o.woff2 new file mode 100644 index 0000000..45a75c3 Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0Wdc1GAK6bt6o.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0Xdc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0Xdc1GAK6bt6o.woff2 new file mode 100644 index 0000000..5754164 Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0Xdc1GAK6bt6o.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0Zdc1GAK6b.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0Zdc1GAK6b.woff2 new file mode 100644 index 0000000..3907070 Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0Zdc1GAK6b.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0adc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0adc1GAK6bt6o.woff2 new file mode 100644 index 0000000..94738e9 Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0adc1GAK6bt6o.woff2 differ diff --git a/fonts/mem6YaGs126MiZpBA-UFUK0ddc1GAK6bt6o.woff2 b/fonts/mem6YaGs126MiZpBA-UFUK0ddc1GAK6bt6o.woff2 new file mode 100644 index 0000000..41fc44c Binary files /dev/null and b/fonts/mem6YaGs126MiZpBA-UFUK0ddc1GAK6bt6o.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFUZ0bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFUZ0bf8pkAp6a.woff2 new file mode 100644 index 0000000..cf58322 Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFUZ0bf8pkAp6a.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2 b/fonts/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2 new file mode 100644 index 0000000..97338d6 Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFVp0bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFVp0bf8pkAp6a.woff2 new file mode 100644 index 0000000..a0c17c7 Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFVp0bf8pkAp6a.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2 new file mode 100644 index 0000000..c9470c7 Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFWJ0bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFWJ0bf8pkAp6a.woff2 new file mode 100644 index 0000000..458c98d Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFWJ0bf8pkAp6a.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFWZ0bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFWZ0bf8pkAp6a.woff2 new file mode 100644 index 0000000..9f0e782 Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFWZ0bf8pkAp6a.woff2 differ diff --git a/fonts/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2 b/fonts/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2 new file mode 100644 index 0000000..c01e28d Binary files /dev/null and b/fonts/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhkIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhkIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..99a75fd Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhkIqOxjaPXZSk.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhlIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhlIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..fe8323c Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhlIqOxjaPXZSk.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhmIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhmIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..73c6afa Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhmIqOxjaPXZSk.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhnIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhnIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..4703c88 Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhnIqOxjaPXZSk.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhoIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhoIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..5683616 Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhoIqOxjaPXZSk.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhrIqOxjaPX.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhrIqOxjaPX.woff2 new file mode 100644 index 0000000..1c153db Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhrIqOxjaPX.woff2 differ diff --git a/fonts/memnYaGs126MiZpBA-UFUKWiUNhvIqOxjaPXZSk.woff2 b/fonts/memnYaGs126MiZpBA-UFUKWiUNhvIqOxjaPXZSk.woff2 new file mode 100644 index 0000000..d2e3337 Binary files /dev/null and b/fonts/memnYaGs126MiZpBA-UFUKWiUNhvIqOxjaPXZSk.woff2 differ diff --git a/helpers/auth.php b/helpers/auth.php index 6206bd2..afe9f78 100644 --- a/helpers/auth.php +++ b/helpers/auth.php @@ -27,6 +27,7 @@ */ class uAuth { + /** @var bool Is user authenticated */ private $isAuthenticated = false; /** @var null|uUser */ public $user = null; @@ -40,6 +41,15 @@ } } + /** + * Update user instance stored in session + */ + public function updateSession() { + if ($this->isAuthenticated()) { + $this->user->storeInSession(); + } + } + /** * Is user authenticated * diff --git a/helpers/config.php b/helpers/config.php index 35169c4..58733d2 100644 --- a/helpers/config.php +++ b/helpers/config.php @@ -27,59 +27,108 @@ * Handles config values */ class uConfig { - // version number - static $version = "0.6"; + /** + * @var string Version number + */ + static $version = "1.0-beta"; - // default map drawing framework + /** + * @var string Default map drawing framework + */ static $mapapi = "openlayers"; - // gmaps key + /** + * @var string|null Google maps key + */ static $gkey = null; - // openlayers additional map layers + /** + * @var array Openlayers additional map layers + */ static $ol_layers = []; - // default coordinates for initial map + /** + * @var float Default latitude for initial map + */ static $init_latitude = 52.23; + /** + * @var float Default longitude for initial map + */ static $init_longitude = 21.01; - // MySQL config - static $dbdsn = ""; // database dsn - static $dbuser = ""; // database user - static $dbpass = ""; // database pass - static $dbprefix = ""; // optional table names prefix, eg. "ulogger_" + /** + * @var string Database dsn + */ + static $dbdsn = ""; + /** + * @var string Database user + */ + static $dbuser = ""; + /** + * @var string Database pass + */ + static $dbpass = ""; + /** + * @var string Optional table names prefix, eg. "ulogger_" + */ + static $dbprefix = ""; - // require login/password authentication + /** + * @var bool Require login/password authentication + */ static $require_authentication = true; - // all users tracks are visible to authenticated user + /** + * @var bool All users tracks are visible to authenticated user + */ static $public_tracks = false; - // admin user who has access to all users locations - // none if empty + /** + * @var string Admin user who has access to all users locations + * none if empty + */ static $admin_user = ""; - // miniumum required length of user password + /** + * @var int Miniumum required length of user password + */ static $pass_lenmin = 12; - // required strength of user password - // 0 = no requirements, - // 1 = require mixed case letters (lower and upper), - // 2 = require mixed case and numbers - // 3 = require mixed case, numbers and non-alphanumeric characters + /** + * @var int Required strength of user password + * 0 = no requirements, + * 1 = require mixed case letters (lower and upper), + * 2 = require mixed case and numbers + * 3 = require mixed case, numbers and non-alphanumeric characters + */ static $pass_strength = 2; - // Default interval in seconds for live auto reload + /** + * @var int Default interval in seconds for live auto reload + */ static $interval = 10; - // Default language + /** + * @var string Default language code + */ static $lang = "en"; - // units + /** + * @var string Default units + */ static $units = "metric"; + /** + * @var int Stroke weight + */ static $strokeWeight = 2; + /** + * @var string Stroke color + */ static $strokeColor = '#ff0000'; + /** + * @var int Stroke opacity + */ static $strokeOpacity = 1; private static $fileLoaded = false; @@ -109,7 +158,7 @@ include_once($configFile); if (isset($mapapi)) { self::$mapapi = $mapapi; } - if (isset($gkey)) { self::$gkey = $gkey; } + if (isset($gkey) && !empty($gkey)) { self::$gkey = $gkey; } if (isset($ol_layers)) { self::$ol_layers = $ol_layers; } if (isset($init_latitude)) { self::$init_latitude = $init_latitude; } if (isset($init_longitude)) { self::$init_longitude = $init_longitude; } diff --git a/helpers/position.php b/helpers/position.php index 10e6cca..185cf56 100644 --- a/helpers/position.php +++ b/helpers/position.php @@ -17,8 +17,9 @@ * along with this program; if not, see . */ - require_once(ROOT_DIR . "/helpers/db.php"); - require_once(ROOT_DIR . "/helpers/track.php"); +require_once(ROOT_DIR . "/helpers/db.php"); +require_once(ROOT_DIR . "/helpers/track.php"); +require_once(ROOT_DIR . "/helpers/upload.php"); /** * Positions handling @@ -51,9 +52,9 @@ /** @param String Provider */ public $provider; /** @param String Comment */ - public $comment; // not used yet - /** @param int Image id */ - public $imageId; // not used yet + public $comment; + /** @param String Image path */ + public $image; public $isValid = false; @@ -66,11 +67,11 @@ if (!empty($positionId)) { $query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id, p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider, - p.comment, p.image_id, u.login, t.name + p.comment, p.image, u.login, t.name FROM " . self::db()->table('positions') . " p LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id) LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id) - WHERE id = ? LIMIT 1"; + WHERE p.id = ? LIMIT 1"; $params = [ $positionId ]; try { $this->loadWithQuery($query, $params); @@ -90,6 +91,15 @@ return uDb::getInstance(); } + /** + * Has image + * + * @return bool True if has image + */ + public function hasImage() { + return !empty($this->image); + } + /** * Add position * @@ -104,27 +114,27 @@ * @param int $accuracy Optional * @param string $provider Optional * @param string $comment Optional - * @param int $imageId Optional + * @param int $image Optional * @return int|bool New position id in database, false on error */ public static function add($userId, $trackId, $timestamp, $lat, $lon, $altitude = NULL, $speed = NULL, $bearing = NULL, $accuracy = NULL, - $provider = NULL, $comment = NULL, $imageId = NULL) { + $provider = NULL, $comment = NULL, $image = NULL) { $positionId = false; if (is_numeric($lat) && is_numeric($lon) && is_numeric($timestamp) && is_numeric($userId) && is_numeric($trackId)) { $track = new uTrack($trackId); - if ($track->isValid && $track->userId == $userId) { + if ($track->isValid && $track->userId === $userId) { try { $table = self::db()->table('positions'); $query = "INSERT INTO $table (user_id, track_id, - time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image_id) + time, latitude, longitude, altitude, speed, bearing, accuracy, provider, comment, image) VALUES (?, ?, " . self::db()->from_unixtime('?') . ", ?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = self::db()->prepare($query); $params = [ $userId, $trackId, - $timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $imageId ]; + $timestamp, $lat, $lon, $altitude, $speed, $bearing, $accuracy, $provider, $comment, $image ]; $stmt->execute($params); - $positionId = self::db()->lastInsertId("${table}_id_seq"); + $positionId = (int) self::db()->lastInsertId("${table}_id_seq"); } catch (PDOException $e) { // TODO: handle error syslog(LOG_ERR, $e->getMessage()); @@ -134,6 +144,70 @@ return $positionId; } + /** + * Save position to database + * + * @return bool True if success, false otherwise + */ + public function update() { + $ret = false; + if ($this->isValid) { + try { + $query = "UPDATE " . self::db()->table('positions') . " SET + time = " . self::db()->from_unixtime('?') . ", user_id = ?, track_id = ?, latitude = ?, longitude = ?, altitude = ?, + speed = ?, bearing = ?, accuracy = ?, provider = ?, comment = ?, image = ? WHERE id = ?"; + $stmt = self::db()->prepare($query); + $params = [ + $this->timestamp, + $this->userId, + $this->trackId, + $this->latitude, + $this->longitude, + $this->altitude, + $this->speed, + $this->bearing, + $this->accuracy, + $this->provider, + $this->comment, + $this->image, + $this->id + ]; + $stmt->execute($params); + $ret = true; + } catch (PDOException $e) { + // TODO: handle exception + syslog(LOG_ERR, $e->getMessage()); + } + } + return $ret; + } + + /** + * Delete positions + * + * @return bool True if success, false otherwise + */ + public function delete() { + $ret = false; + if ($this->isValid) { + try { + $query = "DELETE FROM " . self::db()->table('positions') . " WHERE id = ?"; + $stmt = self::db()->prepare($query); + $stmt->execute([ $this->id ]); + if ($this->hasImage()) { + uUpload::delete($this->image); + } + $ret = true; + $this->id = NULL; + $this->isValid = false; + } catch (PDOException $e) { + // TODO: handle exception + syslog(LOG_ERR, $e->getMessage()); + } + } + return $ret; + } + /** * Delete all user's positions, optionally limit to given track * @@ -151,6 +225,7 @@ $where .= " AND track_id = ?"; $args[] = $trackId; } + self::removeImages($userId, $trackId); try { $query = "DELETE FROM " . self::db()->table('positions') . " $where"; $stmt = self::db()->prepare($query); @@ -181,7 +256,7 @@ } $query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id, p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider, - p.comment, p.image_id, u.login, t.name + p.comment, p.image, u.login, t.name FROM " . self::db()->table('positions') . " p LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id) LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id) @@ -205,7 +280,7 @@ public static function getLastAllUsers() { $query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id, p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider, - p.comment, p.image_id, u.login, t.name + p.comment, p.image, u.login, t.name FROM " . self::db()->table('positions') . " p LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id) LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id) @@ -224,25 +299,30 @@ } catch (PDOException $e) { // TODO: handle exception syslog(LOG_ERR, $e->getMessage()); + $positionsArr = false; } return $positionsArr; } - /** - * Get array of all positions - * - * @param int $userId Optional limit to given user id - * @param int $trackId Optional limit to given track id - * @return uPosition[]|bool Array of uPosition positions, false on error - */ - public static function getAll($userId = NULL, $trackId = NULL) { - $rules = []; + /** + * Get array of all positions + * + * @param int $userId Optional limit to given user id + * @param int $trackId Optional limit to given track id + * @param int $afterId Optional limit to positions with id greater then given id + * @param array $rules Optional rules + * @return uPosition[]|bool Array of uPosition positions, false on error + */ + public static function getAll($userId = NULL, $trackId = NULL, $afterId = NULL, $rules = []) { if (!empty($userId)) { $rules[] = "p.user_id = " . self::db()->quote($userId); } if (!empty($trackId)) { $rules[] = "p.track_id = " . self::db()->quote($trackId); } + if (!empty($afterId)) { + $rules[] = "p.id > " . self::db()->quote($afterId); + } if (!empty($rules)) { $where = "WHERE " . implode(" AND ", $rules); } else { @@ -250,7 +330,7 @@ } $query = "SELECT p.id, " . self::db()->unix_timestamp('p.time') . " AS tstamp, p.user_id, p.track_id, p.latitude, p.longitude, p.altitude, p.speed, p.bearing, p.accuracy, p.provider, - p.comment, p.image_id, u.login, t.name + p.comment, p.image, u.login, t.name FROM " . self::db()->table('positions') . " p LEFT JOIN " . self::db()->table('users') . " u ON (p.user_id = u.id) LEFT JOIN " . self::db()->table('tracks') . " t ON (p.track_id = t.id) @@ -265,10 +345,53 @@ } catch (PDOException $e) { // TODO: handle exception syslog(LOG_ERR, $e->getMessage()); + $positionsArr = false; } return $positionsArr; } + /** + * Get array of all positions with image + * + * @param int $userId Optional limit to given user id + * @param int $trackId Optional limit to given track id + * @param int $afterId Optional limit to positions with id greater then given id + * @param array $rules Optional rules + * @return uPosition[]|bool Array of uPosition positions, false on error + */ + public static function getAllWithImage($userId = NULL, $trackId = NULL, $afterId = NULL, $rules = []) { + $rules[] = "p.image IS NOT NULL"; + return self::getAll($userId, $trackId, $afterId, $rules); + } + + /** + * Delete all user's uploads, optionally limit to given track + * + * @param int $userId User id + * @param int $trackId Optional track id + * @return bool True if success, false otherwise + */ + public static function removeImages($userId, $trackId = NULL) { + if (($positions = self::getAllWithImage($userId, $trackId)) !== false) { + /** @var uUpload $position */ + foreach ($positions as $position) { + try { + $query = "UPDATE " . self::db()->table('positions') . " + SET image = NULL WHERE id = ?"; + $stmt = self::db()->prepare($query); + $stmt->execute([ $position->id ]); + // ignore unlink errors + uUpload::delete($position->image); + } catch (PDOException $e) { + // TODO: handle exception + syslog(LOG_ERR, $e->getMessage()); + return false; + } + } + } + return true; + } + /** * Calculate distance to target point using haversine formula * @@ -282,7 +405,7 @@ $lon2 = deg2rad($target->longitude); $latD = $lat2 - $lat1; $lonD = $lon2 - $lon1; - $bearing = 2 * asin(sqrt(pow(sin($latD / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($lonD / 2), 2))); + $bearing = 2 * asin(sqrt((sin($latD / 2) ** 2) + cos($lat1) * cos($lat2) * (sin($lonD / 2) ** 2))); return $bearing * 6371000; } @@ -318,7 +441,7 @@ $position->accuracy = $row['accuracy']; $position->provider = $row['provider']; $position->comment = $row['comment']; - $position->imageId = $row['image_id']; + $position->image = $row['image']; $position->isValid = true; return $position; } @@ -346,7 +469,7 @@ $stmt->bindColumn('accuracy', $this->accuracy, PDO::PARAM_INT); $stmt->bindColumn('provider', $this->provider); $stmt->bindColumn('comment', $this->comment); - $stmt->bindColumn('image_id', $this->imageId, PDO::PARAM_INT); + $stmt->bindColumn('image', $this->image); $stmt->bindColumn('login', $this->userLogin); $stmt->bindColumn('name', $this->trackName); if ($stmt->fetch(PDO::FETCH_BOUND)) { diff --git a/helpers/track.php b/helpers/track.php index e2aecf2..aa19ef1 100644 --- a/helpers/track.php +++ b/helpers/track.php @@ -84,7 +84,7 @@ $stmt = self::db()->prepare($query); $params = [ $userId, $name, $comment ]; $stmt->execute($params); - $trackId = self::db()->lastInsertId("${table}_id_seq"); + $trackId = (int) self::db()->lastInsertId("${table}_id_seq"); } catch (PDOException $e) { // TODO: handle exception syslog(LOG_ERR, $e->getMessage()); @@ -158,7 +158,7 @@ $ret = false; if (empty($name)) { $name = $this->name; } if (is_null($comment)) { $comment = $this->comment; } - if ($comment == "") { $comment = NULL; } + if ($comment === "") { $comment = NULL; } if ($this->isValid) { try { $query = "UPDATE " . self::db()->table('tracks') . " SET name = ?, comment = ? WHERE id = ?"; @@ -184,21 +184,17 @@ */ public static function deleteAll($userId) { $ret = false; - if (!empty($userId)) { - // remove all positions - if (uPosition::deleteAll($userId) === true) { - // remove all tracks - try { - $query = "DELETE FROM " . self::db()->table('tracks') . " WHERE user_id = ?"; - $stmt = self::db()->prepare($query); - $stmt->execute([ $userId ]); - $ret = true; - } catch (PDOException $e) { - // TODO: handle exception - syslog(LOG_ERR, $e->getMessage()); - } + if (!empty($userId) && uPosition::deleteAll($userId) === true) { + // remove all tracks + try { + $query = "DELETE FROM " . self::db()->table('tracks') . " WHERE user_id = ?"; + $stmt = self::db()->prepare($query); + $stmt->execute([ $userId ]); + $ret = true; + } catch (PDOException $e) { + // TODO: handle exception + syslog(LOG_ERR, $e->getMessage()); } - } return $ret; } diff --git a/helpers/upload.php b/helpers/upload.php new file mode 100644 index 0000000..15a4380 --- /dev/null +++ b/helpers/upload.php @@ -0,0 +1,166 @@ +. + */ + +require_once(ROOT_DIR . "/helpers/db.php"); +require_once(ROOT_DIR . "/helpers/utils.php"); + +/** + * Uploaded files + */ +class uUpload { + + const META_TYPE = "type"; + const META_NAME = "name"; + const META_TMP_NAME = "tmp_name"; + const META_ERROR = "error"; + const META_SIZE = "size"; + public static $uploadDir = ROOT_DIR . "/uploads/"; + private static $filePattern = "[a-z0-9_.]{20,}"; + private static $mimeMap = []; + + /** + * @return string[] Mime to extension mapping + */ + private static function getMimeMap() { + if (empty(self::$mimeMap)) { + self::$mimeMap["image/jpeg"] = "jpg"; + self::$mimeMap["image/x-ms-bmp"] = "bmp"; + self::$mimeMap["image/gif"] = "gif"; + self::$mimeMap["image/png"] = "png"; + } + return self::$mimeMap; + } + + /** + * Is mime accepted type + * @param string $mime Mime type + * @return bool True if known + */ + private static function isKnownMime($mime) { + return array_key_exists($mime, self::getMimeMap()); + } + + /** + * Get file extension for given mime + * @param $mime + * @return string|null Extension or NULL if not found + */ + private static function getExtension($mime) { + if (self::isKnownMime($mime)) { + return self::getMimeMap()[$mime]; + } + return NULL; + } + + /** + * Save file to uploads, basic sanitizing + * @param array $uploaded File meta array from $_FILES[] + * @param int $trackId + * @return string|NULL Unique file name, null on error + */ + public static function add($uploaded, $trackId) { + try { + $fileMeta = self::sanitizeUpload($uploaded); + } catch (Exception $e) { + syslog(LOG_ERR, $e->getMessage()); + // save exception to txt file as image replacement? + return NULL; + } + + $extension = self::getExtension($fileMeta[self::META_TYPE]); + + do { + $fileName = uniqid("{$trackId}_") . ".$extension"; + } while (file_exists(self::$uploadDir . $fileName)); + if (move_uploaded_file($fileMeta[self::META_TMP_NAME], self::$uploadDir . $fileName)) { + return $fileName; + } + return NULL; + } + + /** + * Delete upload from database and filesystem + * @param String $path File relative path + * @return bool False if file exists but can't be unlinked + */ + public static function delete($path) { + $ret = true; + if (preg_match(self::$filePattern, $path)) { + $path = self::$uploadDir . $path; + if (file_exists($path)) { + $ret = unlink($path); + } + } + return $ret; + } + + /** + * @param array $fileMeta File meta array from $_FILES[] + * @param boolean $checkMime Check with known mime types + * @return array File metadata array + * @throws ErrorException Internal server exception + * @throws Exception File upload exception + */ + public static function sanitizeUpload($fileMeta, $checkMime = true) { + if (!isset($fileMeta) || + !isset($fileMeta[self::META_NAME]) || !isset($fileMeta[self::META_TYPE]) || + !isset($fileMeta[self::META_SIZE]) || !isset($fileMeta[self::META_TMP_NAME])) { + $message = "no uploaded file"; + $lastErr = error_get_last(); + if (!empty($lastErr)) { + $message = $lastErr["message"]; + } + throw new ErrorException($message); + } + + $uploadErrors = []; + $uploadErrors[UPLOAD_ERR_INI_SIZE] = "Uploaded file exceeds the upload_max_filesize directive in php.ini"; + $uploadErrors[UPLOAD_ERR_FORM_SIZE] = "Uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"; + $uploadErrors[UPLOAD_ERR_PARTIAL] = "File was only partially uploaded"; + $uploadErrors[UPLOAD_ERR_NO_FILE] = "No file was uploaded"; + $uploadErrors[UPLOAD_ERR_NO_TMP_DIR] = "Missing a temporary folder"; + $uploadErrors[UPLOAD_ERR_CANT_WRITE] = "Failed to write file to disk"; + $uploadErrors[UPLOAD_ERR_EXTENSION] = "A PHP extension stopped file upload"; + + $file = NULL; + $fileError = isset($fileMeta[self::META_ERROR]) ? $fileMeta[self::META_ERROR] : UPLOAD_ERR_OK; + if ($fileMeta[self::META_SIZE] > uUtils::getUploadMaxSize() && $fileError == UPLOAD_ERR_OK) { + $fileError = UPLOAD_ERR_FORM_SIZE; + } + if ($fileError == UPLOAD_ERR_OK) { + $file = $fileMeta[self::META_TMP_NAME]; + } else { + $message = "Unknown error"; + if (isset($uploadErrors[$fileError])) { + $message = $uploadErrors[$fileError]; + } + $message .= " ($fileError)"; + throw new Exception($message); + } + + if (!$file || !file_exists($file)) { + throw new ErrorException("File not found"); + } + if ($checkMime && !self::isKnownMime($fileMeta[self::META_TYPE])) { + throw new Exception("Unsupported mime type"); + } + return $fileMeta; + } +} \ No newline at end of file diff --git a/helpers/user.php b/helpers/user.php index 1decc2a..7d44d71 100644 --- a/helpers/user.php +++ b/helpers/user.php @@ -84,7 +84,7 @@ $query = "INSERT INTO $table (login, password) VALUES (?, ?)"; $stmt = self::db()->prepare($query); $stmt->execute([ $login, $hash ]); - $userid = self::db()->lastInsertId("${table}_id_seq"); + $userid = (int) self::db()->lastInsertId("${table}_id_seq"); } catch (PDOException $e) { // TODO: handle exception syslog(LOG_ERR, $e->getMessage()); @@ -140,6 +140,7 @@ $stmt = self::db()->prepare($query); $stmt->execute([ $hash, $this->login ]); $ret = true; + $this->hash = $hash; } catch (PDOException $e) { // TODO: handle exception syslog(LOG_ERR, $e->getMessage()); @@ -194,7 +195,7 @@ /** * Get all users * - * @return array|bool Array of uUser users, false on error + * @return uUser[]|bool Array of uUser users, false on error */ public static function getAll() { try { diff --git a/helpers/utils.php b/helpers/utils.php index fc20279..2524e4c 100644 --- a/helpers/utils.php +++ b/helpers/utils.php @@ -32,7 +32,7 @@ $upload_max_filesize = self::iniGetBytes('upload_max_filesize'); $post_max_size = self::iniGetBytes('post_max_size'); // post_max_size = 0 means unlimited size - if ($post_max_size == 0) { $post_max_size = $upload_max_filesize; } + if ($post_max_size === 0) { $post_max_size = $upload_max_filesize; } $memory_limit = self::iniGetBytes('memory_limit'); // memory_limit = -1 means no limit if ($memory_limit < 0) { $memory_limit = $post_max_size; } @@ -45,10 +45,11 @@ * * @param string $iniParam Ini parameter name * @return int Bytes + * @noinspection PhpMissingBreakStatementInspection */ private static function iniGetBytes($iniParam) { $iniStr = ini_get($iniParam); - $val = floatval($iniStr); + $val = (float) $iniStr; $suffix = substr(trim($iniStr), -1); if (ctype_alpha($suffix)) { switch (strtolower($suffix)) { @@ -89,22 +90,17 @@ * @param array|null $extra Optional array of extra parameters */ private static function exitWithStatus($isError, $extra = NULL) { - header("Content-type: text/xml"); - $xml = new XMLWriter(); - $xml->openURI("php://output"); - $xml->startDocument("1.0"); - $xml->setIndent(true); - $xml->startElement("root"); - $xml->writeElement("error", (int) $isError); + $output = []; + if ($isError) { + $output["error"] = true; + } if (!empty($extra)) { foreach ($extra as $key => $value) { - $xml->writeElement($key, $value); + $output[$key] = $value; } } - - $xml->endElement(); - $xml->endDocument(); - $xml->flush(); + header("Content-type: application/json"); + echo json_encode($output); exit; } @@ -115,9 +111,9 @@ * @return string URL */ public static function getBaseUrl() { - $proto = (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] == "" || $_SERVER["HTTPS"] == "off") ? "http://" : "https://"; + $proto = (!isset($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] === "" || $_SERVER["HTTPS"] === "off") ? "http://" : "https://"; // Check if we are behind an https proxy - if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] == "https") { + if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"]) && $_SERVER["HTTP_X_FORWARDED_PROTO"] === "https") { $proto = "https://"; } $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : ""; @@ -165,29 +161,47 @@ return self::requestInt($name, $default, INPUT_GET); } + public static function requestFile($name, $default = NULL) { + if (isset($_FILES[$name])) { + $files = $_FILES[$name]; + if (isset($files["name"], $files["type"], $files["size"], $files["tmp_name"])) { + return $_FILES[$name]; + } + } + return $default; + } + + /** + * @param string $name Input name + * @param boolean $checkMime Optionally check mime with known types + * @return array File metadata array + * @throws Exception Upload exception + * @throws ErrorException Internal server exception + */ + public static function requireFile($name, $checkMime = false) { + return uUpload::sanitizeUpload($_FILES[$name], $checkMime); + } + private static function requestString($name, $default, $type) { if (is_string(($val = self::requestValue($name, $default, $type)))) { return trim($val); - } else { - return $val; } + return $val; } private static function requestInt($name, $default, $type) { if (is_float(($val = self::requestValue($name, $default, $type, FILTER_VALIDATE_FLOAT)))) { return (int) round($val); - } else { - return self::requestValue($name, $default, $type, FILTER_VALIDATE_INT); } + return self::requestValue($name, $default, $type, FILTER_VALIDATE_INT); } private static function requestValue($name, $default, $type, $filters = FILTER_DEFAULT, $flags = NULL) { $input = filter_input($type, $name, $filters, $flags); - if ($input !== false && !is_null($input)) { + if ($input !== false && $input !== null) { return $input; - } else { - return $default; } + return $default; } } diff --git a/images/bearing.svg b/images/bearing.svg new file mode 100644 index 0000000..f69d466 --- /dev/null +++ b/images/bearing.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/distance_blue.svg b/images/distance_blue.svg index 1a18d95..6fe2624 100644 --- a/images/distance_blue.svg +++ b/images/distance_blue.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/images/marker-gold.png b/images/marker-gold.png deleted file mode 100644 index 82dd7c4..0000000 Binary files a/images/marker-gold.png and /dev/null differ diff --git a/images/marker-green.png b/images/marker-green.png deleted file mode 100644 index 653fbf4..0000000 Binary files a/images/marker-green.png and /dev/null differ diff --git a/images/marker-red.png b/images/marker-red.png deleted file mode 100644 index a20eff5..0000000 Binary files a/images/marker-red.png and /dev/null differ diff --git a/images/marker-white.png b/images/marker-white.png deleted file mode 100644 index 6e70481..0000000 Binary files a/images/marker-white.png and /dev/null differ diff --git a/images/position.svg b/images/position.svg new file mode 100644 index 0000000..249434f --- /dev/null +++ b/images/position.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/speed_blue.svg b/images/speed_blue.svg index 2440465..4f442ef 100644 --- a/images/speed_blue.svg +++ b/images/speed_blue.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/images/stats_blue.svg b/images/stats_blue.svg index 69075ad..26b79cd 100644 --- a/images/stats_blue.svg +++ b/images/stats_blue.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/images/time_blue.svg b/images/time_blue.svg index 374ae07..576faa0 100644 --- a/images/time_blue.svg +++ b/images/time_blue.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/index.php b/index.php index 92f00fb..e4fd8d5 100644 --- a/index.php +++ b/index.php @@ -17,12 +17,12 @@ * along with this program; if not, see . */ - require_once(__DIR__ . "/helpers/auth.php"); - require_once(ROOT_DIR . "/helpers/config.php"); - require_once(ROOT_DIR . "/helpers/position.php"); - require_once(ROOT_DIR . "/helpers/track.php"); - require_once(ROOT_DIR . "/helpers/utils.php"); - require_once(ROOT_DIR . "/helpers/lang.php"); + require_once(__DIR__ . '/helpers/auth.php'); + require_once(ROOT_DIR . '/helpers/config.php'); + require_once(ROOT_DIR . '/helpers/position.php'); + require_once(ROOT_DIR . '/helpers/track.php'); + require_once(ROOT_DIR . '/helpers/utils.php'); + require_once(ROOT_DIR . '/helpers/lang.php'); $login = uUtils::postString('user'); $pass = uUtils::postPass('pass'); @@ -32,202 +32,127 @@ $langsArr = uLang::getLanguages(); $auth = new uAuth(); - if ($action == "auth") { + if ($action === 'auth') { $auth->checkLogin($login, $pass); } - if (!$auth->isAuthenticated() && $action == "auth") { - $auth->exitWithRedirect("login.php?auth_error=1"); + if ($action === 'auth' && !$auth->isAuthenticated()) { + $auth->exitWithRedirect('login.php?auth_error=1'); } - if (!$auth->isAuthenticated() && uConfig::$require_authentication) { - $auth->exitWithRedirect("login.php"); - } - - - $displayUserId = NULL; - $usersArr = []; - if ($auth->isAdmin() || uConfig::$public_tracks) { - // public access or admin user - // get last position user - $lastPosition = uPosition::getLast(); - if ($lastPosition->isValid) { - // display track of last position user - $displayUserId = $lastPosition->userId; - } - // populate users array (for - - - - - - + + <?= $lang['login'] ?> - -
- -
- +
+ +
+ + +
+ ( s)
+
+
+ +
+ +
+ +
+ +
+ + -
- ( s)
- -
-
+ -
- -
- -
- -
- -
- -
-
- -
- -
- $langName): ?> - + -
-
+ -
- -
- + + + -
-
- -
- - kml - gpx -
- - isAuthenticated()): ?> -
- -
- - -
- gpx
-
- - isAdmin()): ?> - - - - +
+ + kml + gpx
- + isAuthenticated()): ?> +
+ +
+ + +
+ gpx +
+ +
+ + isAdmin()): ?> + + + + +
+ + +
+ + - - - -
-
-
-
-
+
+
+
+
+ +
-
+
diff --git a/js/admin.js b/js/admin.js deleted file mode 100644 index 13c979a..0000000 --- a/js/admin.js +++ /dev/null @@ -1,119 +0,0 @@ -/* μlogger - * - * Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net) - * - * This is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -function addUser() { - var form = '
'; - form += ''; - form += ''; - form += ''; - form += '
'; - form += '
'; - showModal(form); -} - -function editUser() { - var userForm = document.getElementsByName('user')[0]; - var userLogin = (userForm !== undefined) ? userForm.options[userForm.selectedIndex].text : auth; - if (userLogin == auth) { - alert(lang['selfeditwarn']); - return; - } - var message = '
' + sprintf(lang['editinguser'], '' + htmlEncode(userLogin) + '') + '
'; - message += ''; - message += '
'; - - var form = '
'; - form += ''; - form += ''; - form += ''; - form += '
'; - form += '
'; - showModal(message + form); -} - -function confirmedDelete(login) { - return confirm(sprintf(lang['userdelwarn'], '"' + login + '"')); -} - -function submitUser(action) { - var form = document.getElementById('userForm'); - var login = form.elements['login'].value.trim(); - if (!login) { - alert(lang['allrequired']); - return; - } - var pass = null; - var pass2 = null; - if (action != 'delete') { - pass = form.elements['pass'].value; - pass2 = form.elements['pass2'].value; - if (!pass || !pass2) { - alert(lang['allrequired']); - return; - } - if (pass != pass2) { - alert(lang['passnotmatch']); - return; - } - if (!pass_regex.test(pass)) { - alert(lang['passlenmin'] + '\n' + lang['passrules']); - return; - } - } else { - if (!confirmedDelete(login)) { - return; - } - } - var xhr = getXHR(); - xhr.onreadystatechange = function() { - if (xhr.readyState == 4) { - var error = true; - var message = ''; - if (xhr.status == 200) { - var xml = xhr.responseXML; - if (xml) { - var root = xml.getElementsByTagName('root'); - if (root.length && getNode(root[0], 'error') == 0) { - removeModal(); - alert(lang['actionsuccess']); - if (action == 'delete') { - // select current user in users form - var f = document.getElementsByName('user')[0]; - f.remove(f.selectedIndex); - selectUser(f); - } - error = false; - } else if (root.length) { - errorMsg = getNode(root[0], 'message'); - if (errorMsg) { message = errorMsg; } - } - } - } - if (error) { - alert(lang['actionfailure'] + '\n' + message); - } - xhr = null; - } - } - xhr.open('POST', 'utils/handleuser.php', true); - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - var params = 'action=' + action + '&login=' + encodeURIComponent(login) + '&pass=' + encodeURIComponent(pass); - params = params.replace(/%20/g, '+'); - xhr.send(params); - return; -} \ No newline at end of file diff --git a/js/api_gmaps.js b/js/api_gmaps.js deleted file mode 100644 index 76390e4..0000000 --- a/js/api_gmaps.js +++ /dev/null @@ -1,208 +0,0 @@ -/* μlogger - * - * Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net) - * - * This is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -// google maps -var map; -var polies = []; -var markers = []; -var popups = []; -var popup; -var polyOptions; -var mapOptions; -var loadedAPI = 'gmaps'; - -function init() { - if (gm_error) { return gm_authFailure(); } - google.maps.visualRefresh = true; - polyOptions = { - strokeColor: strokeColor, - strokeOpacity: strokeOpacity, - strokeWeight: strokeWeight - } - mapOptions = { - center: new google.maps.LatLng(init_latitude, init_longitude), - zoom: 8, - mapTypeId: google.maps.MapTypeId.ROADMAP, - scaleControl: true - }; - map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions); -} -function cleanup() { - map = undefined; - polies = undefined; - markers = undefined; - popups = undefined; - popup = undefined; - polyOptions = undefined; - mapOptions = undefined; - document.getElementById('map-canvas').innerHTML = ''; -} - -function displayTrack(xml, update) { - altitudes = {}; - var totalMeters = 0; - var totalSeconds = 0; - // init polyline - var poly = new google.maps.Polyline(polyOptions); - poly.setMap(map); - var path = poly.getPath(); - var latlngbounds = new google.maps.LatLngBounds(); - var positions = xml.getElementsByTagName('position'); - var posLen = positions.length; - for (var i = 0; i < posLen; i++) { - var p = parsePosition(positions[i], i); - totalMeters += p.distance; - totalSeconds += p.seconds; - p.totalMeters = totalMeters; - p.totalSeconds = totalSeconds; - p.coordinates = new google.maps.LatLng(p.latitude, p.longitude); - // set marker - setMarker(p, i, posLen); - // update polyline - path.push(p.coordinates); - latlngbounds.extend(p.coordinates); - } - if (update) { - map.fitBounds(latlngbounds); - if (i == 1) { - // only one point, zoom out - zListener = - google.maps.event.addListenerOnce(map, 'bounds_changed', function (event) { - if (this.getZoom()) { - this.setZoom(15); - } - }); - setTimeout(function () { google.maps.event.removeListener(zListener) }, 2000); - } - } - polies.push(poly); - - updateSummary(p.timestamp, totalMeters, totalSeconds); - if (p.tid != trackid) { - trackid = p.tid; - setTrack(trackid); - } - if (document.getElementById('bottom').style.display == 'block') { - // update altitudes chart - chart.clearChart(); - displayChart(); - } -} - -function clearMap() { - if (polies) { - for (var i = 0; i < polies.length; i++) { - polies[i].setMap(null); - } - } - if (markers) { - for (var i = 0; i < markers.length; i++) { - google.maps.event.removeListener(popups[i].listener); - popups[i].setMap(null); - markers[i].setMap(null); - } - } - markers.length = 0; - polies.length = 0; - popups.lentgth = 0; -} - -function setMarker(p, i, posLen) { - // marker - var marker = new google.maps.Marker({ - map: map, - position: new google.maps.LatLng(p.latitude, p.longitude), - title: (new Date(p.timestamp * 1000)).toLocaleString() - }); - if (latest == 1) { marker.setIcon('images/marker-red.png') } - else if (i == 0) { marker.setIcon('images/marker-green.png') } - else if (i == posLen - 1) { marker.setIcon('images/marker-red.png') } - else { marker.setIcon('images/marker-white.png') } - // popup - var content = getPopupHtml(p, i, posLen); - popup = new google.maps.InfoWindow(); - popup.listener = google.maps.event.addListener(marker, 'click', (function (marker, content) { - return function () { - popup.setContent(content); - popup.open(map, marker); - if (document.getElementById('bottom').style.display == 'block') { - var index = 0; - for (var key in altitudes) { - if (altitudes.hasOwnProperty(key) && key == i) { - chart.setSelection([{ row: index, column: null }]); - break; - } - index++; - } - } - } - })(marker, content)); - markers.push(marker); - popups.push(popup); -} - -function addChartEvent(chart, data) { - google.visualization.events.addListener(chart, 'select', function () { - if (popup) { popup.close(); clearTimeout(altTimeout); } - var selection = chart.getSelection()[0]; - if (selection) { - var id = data.getValue(selection.row, 0) - 1; - var icon = markers[id].getIcon(); - markers[id].setIcon('images/marker-gold.png'); - altTimeout = setTimeout(function () { markers[id].setIcon(icon); }, 2000); - } - }); -} - -//((52.20105108685229, 20.789387865580238), (52.292069558807135, 21.172192736185707)) -function getBounds() { - var bounds = map.getBounds(); - var lat_sw = bounds.getSouthWest().lat(); - var lon_sw = bounds.getSouthWest().lng(); - var lat_ne = bounds.getNorthEast().lat(); - var lon_ne = bounds.getNorthEast().lng(); - return [lon_sw, lat_sw, lon_ne, lat_ne]; -} - -function zoomToExtent() { - var latlngbounds = new google.maps.LatLngBounds(); - for (var i = 0; i < markers.length; i++) { - var coordinates = new google.maps.LatLng(markers[i].position.lat(), markers[i].position.lng()); - latlngbounds.extend(coordinates); - } - map.fitBounds(latlngbounds); -} - -function zoomToBounds(b) { - var sw = new google.maps.LatLng(b[1], b[0]); - var ne = new google.maps.LatLng(b[3], b[2]); - var bounds = new google.maps.LatLngBounds(sw, ne); - map.fitBounds(bounds); -} - -function gm_authFailure() { - gm_error = true; - message = sprintf(lang['apifailure'], 'Google Maps'); - message += '

' + lang['gmauthfailure']; - message += '

' + lang['gmapilink']; - showModal(message); -}; - -function updateSize() { - // ignore -} diff --git a/js/api_openlayers.js b/js/api_openlayers.js deleted file mode 100644 index dd9e808..0000000 --- a/js/api_openlayers.js +++ /dev/null @@ -1,431 +0,0 @@ -/* μlogger - * - * Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net) - * - * This is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -// openlayers 3+ -var map; -var layerTrack; -var layerMarkers; -var selectedLayer; -var olStyles; -var loadedAPI = 'openlayers'; - -function init() { - - addCss('css/ol.css', 'ol_css'); - - var controls = [ - new ol.control.Zoom(), - new ol.control.Rotate(), - new ol.control.ScaleLine(), - new ol.control.ZoomToExtent({ label: getExtentImg() }), - ]; - - var view = new ol.View({ - center: ol.proj.fromLonLat([init_longitude, init_latitude]), - zoom: 8 - }); - - map = new ol.Map({ - target: 'map-canvas', - controls: controls, - view: view - }); - - // default layer: OpenStreetMap - var osm = new ol.layer.Tile({ - name: 'OpenStreetMap', - visible: true, - source: new ol.source.OSM() - }); - map.addLayer(osm); - selectedLayer = osm; - - // add extra layers - for (var layerName in ol_layers) { - if (ol_layers.hasOwnProperty(layerName)) { - var layerUrl = ol_layers[layerName]; - var ol_layer = new ol.layer.Tile({ - name: layerName, - visible: false, - source: new ol.source.XYZ({ - url: layerUrl - }) - }); - map.addLayer(ol_layer); - } - } - - // init layers - var lineStyle = new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: hexToRGBA(strokeColor, strokeOpacity), - width: strokeWeight - }) - }); - layerTrack = new ol.layer.Vector({ - name: 'Track', - type: 'data', - source: new ol.source.Vector(), - style: lineStyle - }); - layerMarkers = new ol.layer.Vector({ - name: 'Markers', - type: 'data', - source: new ol.source.Vector() - }); - map.addLayer(layerTrack); - map.addLayer(layerMarkers); - - // styles - olStyles = {}; - var iconRed = new ol.style.Icon({ - anchor: [ 0.5, 1 ], - src: 'images/marker-red.png' - }); - var iconGreen = new ol.style.Icon({ - anchor: [ 0.5, 1 ], - src: 'images/marker-green.png' - }); - var iconWhite = new ol.style.Icon({ - anchor: [ 0.5, 1 ], - opacity: 0.7, - src: 'images/marker-white.png' - }); - var iconGold = new ol.style.Icon({ - anchor: [ 0.5, 1 ], - src: 'images/marker-gold.png' - }); - olStyles['red'] = new ol.style.Style({ - image: iconRed - }); - olStyles['green'] = new ol.style.Style({ - image: iconGreen - }); - olStyles['white'] = new ol.style.Style({ - image: iconWhite - }); - olStyles['gold'] = new ol.style.Style({ - image: iconGold - }); - - // popups - var popupContainer = document.createElement('div'); - popupContainer.id = 'popup'; - popupContainer.className = 'ol-popup'; - document.getElementsByTagName('body')[0].appendChild(popupContainer); - var popupCloser = document.createElement('a'); - popupCloser.id = 'popup-closer'; - popupCloser.className = 'ol-popup-closer'; - popupCloser.href = '#'; - popupContainer.appendChild(popupCloser); - var popupContent = document.createElement('div'); - popupContent.id = 'popup-content'; - popupContainer.appendChild(popupContent); - - var popup = new ol.Overlay({ - element: popupContainer, - autoPan: true, - autoPanAnimation: { - duration: 250 - } - }); - - popupCloser.onclick = function() { - popup.setPosition(undefined); - popupCloser.blur(); - return false; - }; - - // add click handler to map to show popup - map.on('click', function(e) { - var coordinate = e.coordinate; - var feature = map.forEachFeatureAtPixel(e.pixel, - function(feature, layer) { - if (layer.get('name') == 'Markers') { - return feature; - } - }); - if (feature) { - var p = feature.get('p'); - var i = feature.getId(); - var posLen = feature.get('posLen'); - // popup show - popup.setPosition(coordinate); - popupContent.innerHTML = getPopupHtml(p, i, posLen); - map.addOverlay(popup); - if (document.getElementById('bottom').style.display == 'block') { - var index = 0; - for (var key in altitudes) { - if (altitudes.hasOwnProperty(key) && key == i) { - chart.setSelection([{ row: index, column: null }]); - break; - } - index++; - } - } - } else { - // popup destroy - popup.setPosition(undefined); - } - }); - - // change mouse cursor when over marker - map.on('pointermove', function(e) { - var hit = map.forEachFeatureAtPixel(e.pixel, function(feature, layer) { - if (layer.get('name') == 'Markers') { - return true; - } else { - return false; - } - }); - if (hit) { - this.getTargetElement().style.cursor = 'pointer'; - } else { - this.getTargetElement().style.cursor = ''; - } - }); - - // layer switcher - var switcher = document.createElement('div'); - switcher.id = 'switcher'; - switcher.className = 'ol-control'; - document.getElementsByTagName('body')[0].appendChild(switcher); - var switcherContent = document.createElement('div'); - switcherContent.id = 'switcher-content'; - switcherContent.className = 'ol-layerswitcher'; - switcher.appendChild(switcherContent); - - map.getLayers().forEach(function (layer) { - var layerLabel = document.createElement('label'); - layerLabel.innerHTML = layer.get('name'); - switcherContent.appendChild(layerLabel); - - var layerRadio = document.createElement('input'); - if (layer.get('type') === 'data') { - layerRadio.type = 'checkbox'; - layerLabel.className = 'ol-datalayer'; - } else { - layerRadio.type = 'radio'; - } - layerRadio.name = 'layer'; - layerRadio.value = layer.get('name'); - layerRadio.onclick = switchLayer; - if (layer.getVisible()) { - layerRadio.checked = true; - } - layerLabel.insertBefore(layerRadio, layerLabel.childNodes[0]); - }); - - function switchLayer() { - var layerName = this.value; - map.getLayers().forEach(function (layer) { - if (layer.get('name') === layerName) { - if (layer.get('type') === 'data') { - if (layer.getVisible()) { - layer.setVisible(false); - } else { - layer.setVisible(true); - } - } else { - selectedLayer.setVisible(false); - selectedLayer = layer; - layer.setVisible(true); - } - return; - } - }); - }; - - var switcherButton = document.createElement('button'); - var layerImg = document.createElement('img'); - layerImg.src = 'images/layers.svg'; - layerImg.style.width = '60%'; - switcherButton.appendChild(layerImg); - - var switcherHandle = function() { - var el = document.getElementById('switcher'); - if (el.style.display === 'block') { - el.style.display = 'none'; - } else { - el.style.display = 'block'; - } - }; - - switcherButton.addEventListener('click', switcherHandle, false); - switcherButton.addEventListener('touchstart', switcherHandle, false); - - var element = document.createElement('div'); - element.className = 'ol-switcher-button ol-unselectable ol-control'; - element.appendChild(switcherButton); - - var switcherControl = new ol.control.Control({ - element: element - }); - map.addControl(switcherControl); -} - -function cleanup() { - map = undefined; - layerTrack = undefined; - layerMarkers = undefined; - selectedLayer = undefined; - olStyles = undefined; - removeElementById('popup'); - removeElementById('switcher'); - document.getElementById('map-canvas').innerHTML = ''; -} - - -function displayTrack(xml, update) { - altitudes = {}; - var totalMeters = 0; - var totalSeconds = 0; - var points = []; - var positions = xml.getElementsByTagName('position'); - var posLen = positions.length; - for (var i = 0; i < posLen; i++) { - var p = parsePosition(positions[i], i); - totalMeters += p.distance; - totalSeconds += p.seconds; - p.totalMeters = totalMeters; - p.totalSeconds = totalSeconds; - // set marker - setMarker(p, i, posLen); - // update polyline - var point = ol.proj.fromLonLat([p.longitude, p.latitude]); - points.push(point); - } - var lineString = new ol.geom.LineString(points); - - var lineFeature = new ol.Feature({ - geometry: lineString, - }); - - layerTrack.getSource().addFeature(lineFeature); - - var extent = layerTrack.getSource().getExtent(); - - map.getControls().forEach(function (el) { - if (el instanceof ol.control.ZoomToExtent) { - map.removeControl(el); - } - }); - - if (update) { - map.getView().fit(extent); - var zoom = map.getView().getZoom(); - if (zoom > 20) { - map.getView().setZoom(20); - extent = map.getView().calculateExtent(map.getSize()); - } - } - - var zoomToExtentControl = new ol.control.ZoomToExtent({ - extent: extent, - label: getExtentImg() - }); - map.addControl(zoomToExtentControl); - - updateSummary(p.timestamp, totalMeters, totalSeconds); - if (p.tid != trackid) { - trackid = p.tid; - setTrack(trackid); - } - if (document.getElementById('bottom').style.display == 'block') { - // update altitudes chart - chart.clearChart(); - displayChart(); - } -} - -function clearMap() { - if (layerTrack) { - layerTrack.getSource().clear(); - } - if (layerMarkers) { - layerMarkers.getSource().clear(); - } -} - -function setMarker(p, i, posLen) { - // marker - var marker = new ol.Feature({ - geometry: new ol.geom.Point(ol.proj.fromLonLat([p.longitude, p.latitude])) - }); - - if (latest == 1) { - var iconStyle = olStyles['red']; - } else if (i == 0) { - var iconStyle = olStyles['green']; - } else if (i == posLen - 1) { - var iconStyle = olStyles['red']; - } else { - var iconStyle = olStyles['white']; - } - marker.setStyle(iconStyle); - marker.setId(i); - marker.set('p', p); - marker.set('posLen', posLen); - layerMarkers.getSource().addFeature(marker); -} - -function addChartEvent(chart, data) { - google.visualization.events.addListener(chart, 'select', function () { - var selection = chart.getSelection()[0]; - if (selection) { - var id = data.getValue(selection.row, 0) - 1; - var marker = layerMarkers.getSource().getFeatureById(id); - var url = marker.get('src'); - var initStyle = marker.getStyle(); - var iconStyle = olStyles['gold']; - marker.setStyle(iconStyle); - altTimeout = setTimeout(function () { marker.setStyle(initStyle); }, 2000); - } - }); -} - -//20.597985430276808,52.15547181298076,21.363595171488573,52.33750879522563 -function getBounds() { - var extent = map.getView().calculateExtent(map.getSize()); - var bounds = ol.proj.transformExtent(extent, 'EPSG:900913', 'EPSG:4326'); - var lon_sw = bounds[0]; - var lat_sw = bounds[1]; - var lon_ne = bounds[2]; - var lat_ne = bounds[3]; - return [lon_sw, lat_sw, lon_ne, lat_ne]; -} - -function zoomToExtent() { - map.getView().fit(layerMarkers.getSource().getExtent()) -} - -function zoomToBounds(b) { - var bounds = ol.proj.transformExtent(b, 'EPSG:4326', 'EPSG:900913'); - map.getView().fit(bounds); -} - -function updateSize() { - map.updateSize(); -} - -function getExtentImg() { - var extentImg = document.createElement('img'); - extentImg.src = 'images/extent.svg'; - extentImg.style.width = '60%'; - return extentImg; -} diff --git a/js/dist/.gitignore b/js/dist/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/js/dist/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/js/main.js b/js/main.js deleted file mode 100644 index 5637a5f..0000000 --- a/js/main.js +++ /dev/null @@ -1,725 +0,0 @@ -/* μlogger - * - * Copyright(C) 2017 Bartek Fabiszewski (www.fabiszewski.net) - * - * This is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -// general stuff -var factor_kmh, unit_kmh, factor_m, unit_m, factor_km, unit_km; -if (units == 'imperial') { - factor_kmh = 0.62; //to mph - unit_kmh = 'mph'; - factor_m = 3.28; // to feet - unit_m = 'ft'; - factor_km = 0.62; // to miles - unit_km = 'mi'; -} else if (units == 'nautical') { - factor_kmh = 0.54; //to knots - unit_kmh = 'kt'; - factor_m = 1; // - unit_m = 'm'; - factor_km = 0.54; // to nautical miles - unit_km = 'nm'; -} else { - factor_kmh = 1; - unit_kmh = 'km/h'; - factor_m = 1; - unit_m = 'm'; - factor_km = 1; - unit_km = 'km'; -} -var latest = 0; -var live = 0; -var chart; -var altitudes = {}; -var altTimeout; -var gm_error = false; -var loadTime = 0; -var auto; -var savedBounds = null; - -function displayChart() { - if (chart) { google.visualization.events.removeAllListeners(chart); } - var data = new google.visualization.DataTable(); - data.addColumn('number', 'id'); - data.addColumn('number', lang['altitude']); - - for (var id in altitudes) { - if (altitudes.hasOwnProperty(id)) { - data.addRow([parseInt(id) + 1, Math.round((altitudes[id] * factor_m))]); - } - } - - var options = { - title: lang['altitude'] + ' (' + unit_m + ')', - hAxis: { textPosition: 'none' }, - legend: { position: 'none' } - }; - - chart = new google.visualization.LineChart(document.getElementById('chart')); - chart.draw(data, options); - - addChartEvent(chart, data); -} - -function toggleChart(i) { - var altLen = altitudes.length; - if (altLen <= 1) { return; } - var e = document.getElementById('bottom'); - if (arguments.length < 1) { - if (e.style.display == 'block') { i = 0 } - else { i = 1; } - } - if (i == 0) { - chart.clearChart(); - e.style.display = 'none'; - } else { - e.style.display = 'block'; - displayChart(); - } -} - -function toggleChartLink() { - var link = document.getElementById('altitudes'); - if (Object.keys(altitudes).length > 1) { - link.style.visibility = 'visible'; - } else { - link.style.visibility = 'hidden'; - } -} - -function toggleMenu(i) { - var emenu = document.getElementById('menu'); - var emain = document.getElementById('main'); - var ebutton = document.getElementById('menu-close'); - if (arguments.length < 1) { - if (ebutton.innerHTML == '»') { i = 0 } - else { i = 1; } - } - if (i == 0) { - emenu.style.width = '0'; - emain.style.marginRight = '0'; - ebutton.style.right = '0'; - ebutton.innerHTML = '«'; - } - else { - emenu.style.width = '165px'; - emain.style.marginRight = '165px'; - ebutton.style.right = '165px'; - ebutton.innerHTML = '»'; - } - updateSize(); -} - -function getXHR() { - var xmlhttp = null; - if (window.XMLHttpRequest) { - xmlhttp = new XMLHttpRequest(); - } - else { - xmlhttp = new ActiveXObject('Microsoft.XMLHTTP'); - } - return xmlhttp; -} - -function loadTrack(userid, trackid, update) { - var title = document.getElementById('track').getElementsByClassName('menutitle')[0]; - if (trackid < 0) { return; } - if (latest == 1) { trackid = 0; } - var xhr = getXHR(); - xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - if (xhr.status == 200) { - var xml = xhr.responseXML; - var positions = xml.getElementsByTagName('position'); - if (positions.length > 0) { - clearMap(); - displayTrack(xml, update); - toggleChartLink(); - } - } - xhr = null; - removeLoader(title); - } - } - xhr.open('GET', 'utils/getpositions.php?trackid=' + trackid + '&userid=' + userid + '&last=' + latest, true); - xhr.send(); - setLoader(title); -} - -function loadLastPositionAllUsers() { - var xhr = getXHR(); - xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - if (xhr.status == 200) { - clearMap(); - var xml = xhr.responseXML; - var positions = xml.getElementsByTagName('position'); - var posLen = positions.length; - var timestampMax = 0; - for (var i = 0; i < posLen; i++) { - var p = parsePosition(positions[i], i); - // set marker - setMarker(p, i, posLen); - if (p.timestamp > timestampMax) { - timestampMax = p.timestamp; - } - } - zoomToExtent(); - updateSummary(timestampMax); - } - xhr = null; - } - } - xhr.open('GET', 'utils/getpositions.php?last=' + latest, true); - xhr.send(); -} - -function parsePosition(p, id) { - // read data - var latitude = parseFloat(getNode(p, 'latitude')); - var longitude = parseFloat(getNode(p, 'longitude')); - var altitude = getNode(p, 'altitude'); // may be null - if (altitude != null) { - altitude = parseInt(altitude); - // save altitudes for chart - altitudes[id] = altitude; - } - var speed = getNode(p, 'speed'); // may be null - if (speed != null) { speed = parseInt(speed); } - var bearing = getNode(p, 'bearing'); // may be null - if (bearing != null) { bearing = parseInt(bearing); } - var accuracy = getNode(p, 'accuracy'); // may be null - if (accuracy != null) { accuracy = parseInt(accuracy); } - var provider = getNode(p, 'provider'); // may be null - var comments = getNode(p, 'comments'); // may be null - var username = getNode(p, 'username'); - var trackname = getNode(p, 'trackname'); - var tid = getNode(p, 'trackid'); - var timestamp = getNode(p, 'timestamp'); - var distance = parseInt(getNode(p, 'distance')); - var seconds = parseInt(getNode(p, 'seconds')); - return { - 'latitude': latitude, - 'longitude': longitude, - 'altitude': altitude, - 'speed': speed, - 'bearing': bearing, - 'accuracy': accuracy, - 'provider': provider, - 'comments': comments, - 'username': username, - 'trackname': trackname, - 'tid': tid, - 'timestamp': timestamp, - 'distance': distance, - 'seconds': seconds - }; -} - -function getPopupHtml(p, i, count) { - var date = '–––'; - var time = '–––'; - if (p.timestamp > 0) { - var d = new Date(p.timestamp * 1000); - date = d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2); - time = d.toTimeString(); - var offset; - if ((offset = time.indexOf(' ')) >= 0) { - time = time.substr(0, offset) + ' ' + time.substr(offset + 1) + ''; - } - } - var provider = ''; - if (p.provider == 'gps') { - provider = ' (' + lang['gps'] + ')'; - } else if (p.provider == 'network') { - provider = ' (' + lang['network'] + ')'; - } - var stats = ''; - if (latest == 0) { - stats = - '
' + - '' + lang['track'] + '
' + - '' + lang['ttime'] + ' ' + - p.totalSeconds.toHMS() + '
' + - '' + lang['aspeed'] + ' ' + - ((p.totalSeconds > 0) ? ((p.totalMeters / p.totalSeconds).toKmH() * factor_kmh).toFixed() : 0) + ' ' + unit_kmh + '
' + - '' + lang['tdistance'] + ' ' + - (p.totalMeters.toKm() * factor_km).toFixed(2) + ' ' + unit_km + '
' + '
'; - } - var popup = - ''; - return popup; -} - -function exportFile(type, userid, trackid) { - var url = 'utils/export.php?type=' + type + '&userid=' + userid + '&trackid=' + trackid; - window.location.assign(url); -} - -function importFile(input) { - var form = input.parentElement; - var title = form.parentElement.getElementsByClassName('menutitle')[0]; - var sizeMax = form.elements['MAX_FILE_SIZE'].value; - if (input.files && input.files.length == 1 && input.files[0].size > sizeMax) { - alert(sprintf(lang['isizefailure'], sizeMax)); - return; - } - var xhr = getXHR(); - xhr.onreadystatechange = function() { - if (xhr.readyState == 4) { - var error = true; - var message = ''; - if (xhr.status == 200) { - var xml = xhr.responseXML; - if (xml) { - var root = xml.getElementsByTagName('root'); - if (root.length && getNode(root[0], 'error') == 0) { - trackId = getNode(root[0], 'trackid'); - trackCnt = getNode(root[0], 'trackcnt'); - getTracks(userid, trackId); - if (trackCnt > 1) { - alert(sprintf(lang['imultiple'], trackCnt)); - } - error = false; - } else if (root.length) { - errorMsg = getNode(root[0], 'message'); - if (errorMsg) { message = errorMsg; } - } - } - } - if (error) { - alert(lang['actionfailure'] + '\n' + message); - } - removeLoader(title); - xhr = null; - } - } - xhr.open('POST', 'utils/import.php', true); - xhr.send(new FormData(form)); - input.value = ''; - setLoader(title); -} - -function setLoader(el) { - var s = el.textContent || el.innerText; - var newHTML = ''; - for (var i = 0, len = s.length; i < len; i++) { - newHTML += '' + s.charAt(i) + ''; - } - el.innerHTML = newHTML; -} - -function removeLoader(el) { - el.innerHTML = el.textContent || el.innerText; -} - -function updateSummary(timestamp, d, s) { - var t = document.getElementById('summary'); - if (latest == 0) { - t.innerHTML = '' + - '
' + lang['tdistance'] + ' ' + (d.toKm() * factor_km).toFixed(2) + ' ' + unit_km + '
' + - '
' + lang['ttime'] + ' ' + s.toHMS() + '
'; - } else { - var today = new Date(); - var d = new Date(timestamp * 1000); - var dateString = ''; - if (d.toDateString() != today.toDateString()) { - dateString += d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2); - dateString += '
'; - } - var timeString = d.toTimeString(); - var offset; - if ((offset = timeString.indexOf(' ')) >= 0) { - timeString = timeString.substr(0, offset) + ' ' + timeString.substr(offset + 1) + ''; - } - t.innerHTML = '' + dateString + timeString; - } -} - -function getNode(p, name) { - return ((p.getElementsByTagName(name)[0].childNodes[0]) ? p.getElementsByTagName(name)[0].childNodes[0].nodeValue : null); -} - -// seconds to (d) H:M:S -Number.prototype.toHMS = function() { - var s = this; - var d = Math.floor(s / 86400); - var h = Math.floor((s % 86400) / 3600); - var m = Math.floor(((s % 86400) % 3600) / 60); - s = ((s % 86400) % 3600) % 60; - - return ((d > 0) ? (d + ' d ') : '') + (('00' + h).slice(-2)) + ':' + (('00' + m).slice(-2)) + ':' + (('00' + s).slice(-2)) + ''; -}; - -// meters to km -Number.prototype.toKm = function() { - return Math.round(this / 10) / 100; -}; - -// m/s to km/h -Number.prototype.toKmH = function() { - return Math.round(this * 3600 / 10) / 100; -}; - -// toggle latest -function toggleLatest() { - var usersSelect = document.getElementsByName('user')[0]; - if (latest == 0) { - if (!hasAllUsers() && usersSelect && usersSelect.length > 2) { - usersSelect.options.add(new Option('- ' + lang['allusers'] + ' -', 'all'), usersSelect.options[1]); - } - latest = 1; - loadTrack(userid, 0, 1); - } else { - if (usersSelect && hasAllUsers()) { - if (isSelectedAllUsers()) { - usersSelect.selectedIndex = 0; - } - usersSelect.remove(1); - } - latest = 0; - loadTrack(userid, trackid, 1); - } -} - -function setTrack(t) { - document.getElementsByName('track')[0].value = t; -} - -function selectTrack(f) { - if (f.selectedIndex >= 0) { - trackid = f.options[f.selectedIndex].value; - } else { - trackid = 0; - } - document.getElementById('latest').checked = false; - if (latest == 1) { - toggleLatest(); - } else { - loadTrack(userid, trackid, 1); - } -} - -function selectUser(f) { - userid = f.options[f.selectedIndex].value; - if (isSelectedAllUsers()) { - clearOptions(document.getElementsByName('track')[0]); - loadLastPositionAllUsers(); - } else { - getTracks(userid); - } -} - -function getTracks(userid, trackid) { - var title = document.getElementById('track').getElementsByClassName('menutitle')[0]; - var xhr = getXHR(); - xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - if (xhr.status == 200) { - var xml = xhr.responseXML; - var trackSelect = document.getElementsByName('track')[0]; - clearOptions(trackSelect); - var tracks = xml.getElementsByTagName('track'); - if (tracks.length > 0) { - fillOptions(xml, userid, trackid); - } else { - clearMap(); - } - } - removeLoader(title); - xhr = null; - } - } - xhr.open('GET', 'utils/gettracks.php?userid=' + userid, true); - xhr.send(); - setLoader(title); -} - -function fillOptions(xml, uid, tid) { - var trackSelect = document.getElementsByName('track')[0]; - var tracks = xml.getElementsByTagName('track'); - var trackLen = tracks.length; - for (var i = 0; i < trackLen; i++) { - var trackid = getNode(tracks[i], 'trackid'); - var trackname = getNode(tracks[i], 'trackname'); - var option = document.createElement('option'); - option.value = trackid; - option.innerHTML = htmlEncode(trackname); - trackSelect.appendChild(option); - } - var defaultTrack = tid || getNode(tracks[0], 'trackid'); - var defaultUser = uid || userid; - loadTrack(defaultUser, defaultTrack, 1); -} - -function clearOptions(el) { - if (el.options) { - while (el.options.length) { - el.remove(0); - } - } -} - -function reload(userid, trackid) { - if (isSelectedAllUsers()) { - loadLastPositionAllUsers(); - } else { - loadTrack(userid, trackid, 0); - } -} - -function autoReload() { - if (live == 0) { - live = 1; - if (isSelectedAllUsers()) { - auto = setInterval(function () { loadLastPositionAllUsers(); }, interval * 1000); - } else { - auto = setInterval(function () { loadTrack(userid, trackid, 0); }, interval * 1000); - } - } else { - live = 0; - clearInterval(auto); - } -} - -function isSelectedAllUsers() { - var usersSelect = document.getElementsByName('user')[0]; - return usersSelect && usersSelect[usersSelect.selectedIndex].value == 'all'; -} - -function hasAllUsers() { - var usersSelect = document.getElementsByName('user')[0]; - if (usersSelect && usersSelect.length > 2 && usersSelect.options[1].value == 'all') { - return true; - } - return false; -} - -function setTime() { - var i = parseInt(prompt(lang['newinterval'])); - if (!isNaN(i) && i != interval) { - interval = i; - document.getElementById('auto').innerHTML = interval; - // if live tracking on, reload with new interval - if (live == 1) { - live = 0; - clearInterval(auto); - autoReload(); - } - // save current state as default - setCookie('interval', interval, 30); - } -} - -// dynamic change of map api -function loadMapAPI(api) { - if (api) { - mapapi = api; - try { - savedBounds = getBounds(); - } catch (e) { - savedBounds = null; - } - cleanup(); - } - removeElementById('mapapi'); - var urls = []; - if (mapapi == 'gmaps') { - addScript('js/api_gmaps.js', 'mapapi'); - urls.push('//maps.googleapis.com/maps/api/js?' + ((gkey !== null) ? ('key=' + gkey + '&') : '') + 'callback=init'); - } else { - addScript('js/api_openlayers.js', 'mapapi'); - urls.push('//cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList') - urls.push('js/ol.js'); - } - waitAndLoad(mapapi, urls); -} - -function waitAndLoad(api, urls) { - // wait till first script loaded - if (loadTime > 5000) { loadTime = 0; alert(sprintf(lang['apifailure'], api)); return; } - if (typeof loadedAPI === 'undefined' || loadedAPI !== api) { - setTimeout(function () { loadTime += 50; waitAndLoad(api, urls); }, 50); - return; - } - for (var i = 0; i < urls.length; i++) { - addScript(urls[i], 'mapapi_' + api + '_' + i); - } - loadTime = 0; - waitAndInit(api); -} - -function waitAndInit(api) { - // wait till main api loads - if (loadTime > 10000) { loadTime = 0; alert(sprintf(lang['apifailure'], api)); return; } - try { - init(); - } catch (e) { - setTimeout(function () { loadTime += 50; waitAndInit(api); }, 50); - return; - } - loadTime = 0; - var update = 1; - if (savedBounds) { - zoomToBounds(savedBounds); - update = 0; - } - if (latest && isSelectedAllUsers()) { - loadLastPositionAllUsers(); - } else { - loadTrack(userid, trackid, update); - } - // save current api as default - setCookie('api', api, 30); -} - -function addScript(url, id) { - if (id && document.getElementById(id)) { - return; - } - var tag = document.createElement('script'); - tag.type = 'text/javascript'; - tag.src = url; - if (id) { - tag.id = id; - } - document.getElementsByTagName('head')[0].appendChild(tag); -} - -function addCss(url, id) { - if (id && document.getElementById(id)) { - return; - } - var tag = document.createElement('link'); - tag.type = 'text/css'; - tag.rel = 'stylesheet'; - tag.href = url; - if (id) { - tag.id = id; - } - document.getElementsByTagName('head')[0].appendChild(tag); -} - -function removeElementById(id) { - var tag = document.getElementById(id); - if (tag && tag.parentNode) { - tag.parentNode.removeChild(tag); - } -} - -function setCookie(name, value, days) { - if (days) { - var date = new Date(); - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - var expires = '; expires=' + date.toGMTString(); - } else { - var expires = ''; - } - document.cookie = 'ulogger_' + name + '=' + value + expires + '; path=/'; -} - -function setLang(lang) { - setCookie('lang', lang, 30); - location.reload(); -} - -function setUnits(unit) { - units = unit; - setCookie('units', unit, 30); - location.reload(); -} - -function showModal(contentHTML) { - var div = document.createElement('div'); - div.setAttribute('id', 'modal'); - div.innerHTML = ''; - document.body.appendChild(div); - var modalBody = document.getElementById('modal-body'); - modalBody.innerHTML = contentHTML; -} - -function removeModal() { - document.body.removeChild(document.getElementById('modal')); -} - -function userMenu() { - var dropdown = document.getElementById('user_dropdown'); - if (dropdown.classList.contains('show')) { - dropdown.classList.remove('show'); - } else { - dropdown.classList.add('show'); - window.addEventListener('click', removeOnClick, true); - } -} - -function removeOnClick(event) { - var parent = event.target.parentElement; - var dropdown = document.getElementById('user_dropdown'); - dropdown.classList.remove('show'); - window.removeEventListener('click', removeOnClick, true); - if (!parent.classList.contains('dropdown')) { - event.stopPropagation(); - } -} - -// naive approach, only %s, %d supported -function sprintf() { - var args = Array.prototype.slice.call(arguments); - var format = args.shift(); - var i = 0; - return format.replace(/%%|%s|%d/g, function(match) { - if (match == '%%') { return '%'; } - return (typeof args[i] != 'undefined') ? args[i++] : match; - }); -}; - -function htmlEncode(s) { - return s.replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); -} - -// Convert hex string and opacity to an rgba string -function hexToRGBA(hex, opacity) { - return 'rgba(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16) }).concat(opacity||1).join(',') + ')'; -} - -if (!String.prototype.trim) { - String.prototype.trim = function () { - return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); - }; -} diff --git a/js/ol.js b/js/ol.js deleted file mode 100644 index 72e4ba1..0000000 --- a/js/ol.js +++ /dev/null @@ -1,2 +0,0 @@ -var ol=function(t){var e={};function i(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(n,r,function(e){return t[e]}.bind(null,r));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=83)}([function(t,e,i){"use strict";i.d(e,"b",function(){return s}),i.d(e,"c",function(){return a}),i.d(e,"d",function(){return h}),i.d(e,"e",function(){return c}),i.d(e,"f",function(){return l}),i.d(e,"g",function(){return u}),i.d(e,"h",function(){return p}),i.d(e,"i",function(){return d}),i.d(e,"j",function(){return f}),i.d(e,"k",function(){return _}),i.d(e,"l",function(){return g}),i.d(e,"m",function(){return v}),i.d(e,"n",function(){return y}),i.d(e,"o",function(){return m}),i.d(e,"p",function(){return b}),i.d(e,"q",function(){return O}),i.d(e,"r",function(){return E}),i.d(e,"s",function(){return x}),i.d(e,"t",function(){return R}),i.d(e,"u",function(){return S}),i.d(e,"v",function(){return I}),i.d(e,"w",function(){return j}),i.d(e,"x",function(){return w}),i.d(e,"y",function(){return L}),i.d(e,"z",function(){return M}),i.d(e,"A",function(){return P}),i.d(e,"B",function(){return F}),i.d(e,"C",function(){return A}),i.d(e,"D",function(){return D}),i.d(e,"E",function(){return N}),i.d(e,"F",function(){return k}),i.d(e,"H",function(){return G}),i.d(e,"I",function(){return Y}),i.d(e,"J",function(){return X}),i.d(e,"G",function(){return z}),i.d(e,"a",function(){return W});var n=i(9),r=i(54),o=i(27);function s(t){for(var e=f(),i=0,n=t.length;ir&&(c|=o.a.RIGHT),hs&&(c|=o.a.ABOVE),c===o.a.UNKNOWN&&(c=o.a.INTERSECTING),c}function f(){return[1/0,1/0,-1/0,-1/0]}function _(t,e,i,n,r){return r?(r[0]=t,r[1]=e,r[2]=i,r[3]=n,r):[t,e,i,n]}function g(t){return _(1/0,1/0,-1/0,-1/0,t)}function v(t,e){var i=t[0],n=t[1];return _(i,n,i,n,e)}function y(t,e){return T(g(e),t)}function m(t,e,i,n,r){return x(g(r),t,e,i,n)}function b(t,e){return t[0]==e[0]&&t[2]==e[2]&&t[1]==e[1]&&t[3]==e[3]}function O(t,e){return e[0]t[2]&&(t[2]=e[2]),e[1]t[3]&&(t[3]=e[3]),t}function E(t,e){e[0]t[2]&&(t[2]=e[0]),e[1]t[3]&&(t[3]=e[1])}function T(t,e){for(var i=0,n=e.length;ie[0]?n[0]=t[0]:n[0]=e[0],t[1]>e[1]?n[1]=t[1]:n[1]=e[1],t[2]=e[0]&&t[1]<=e[3]&&t[3]>=e[1]}function G(t){return t[2]=c&&a<=u),n||!(s&o.a.RIGHT)||r&o.a.RIGHT||(n=(h=v-(g-u)*y)>=l&&h<=p),n||!(s&o.a.BELOW)||r&o.a.BELOW||(n=(a=g-(v-l)/y)>=c&&a<=u),n||!(s&o.a.LEFT)||r&o.a.LEFT||(n=(h=v-(g-c)*y)>=l&&h<=p)}return n}function W(t,e,i){var n=[t[0],t[1],t[0],t[3],t[2],t[1],t[2],t[3]];return e(n,n,2),function(t,e,i){return _(Math.min.apply(null,t),Math.min.apply(null,e),Math.max.apply(null,t),Math.max.apply(null,e),i)}([n[0],n[2],n[4],n[6]],[n[1],n[3],n[5],n[7]],i)}},function(t,e,i){"use strict";i.d(e,"a",function(){return h}),i.d(e,"b",function(){return c}),i.d(e,"c",function(){return l}),i.d(e,"e",function(){return u}),i.d(e,"d",function(){return p});var n=i(11);function r(t,e,i,n){for(var r,o=0,s=t.length;o1?(i=r,n=o):c>0&&(i+=a*c,n+=h*c)}return s(t,e,i,n)}function s(t,e,i,n){var r=i-t,o=n-e;return r*r+o*o}function a(t){for(var e=t.length,i=0;ir&&(r=s,n=o)}if(0===r)return null;var a=t[n];t[n]=t[i],t[i]=a;for(var h=i+1;h=0;p--){u[p]=t[p][e]/t[p][p];for(var d=p-1;d>=0;d--)t[d][e]-=t[d][p]*u[p]}return u}function h(t){return 180*t/Math.PI}function c(t){return t*Math.PI/180}function l(t,e){var i=t%e;return i*e<0?i+e:i}function u(t,e,i){return t+i*(e-t)}},function(t,e,i){"use strict";e.a={IDLE:0,LOADING:1,LOADED:2,ERROR:3,EMPTY:4,ABORT:5}},function(t,e,i){"use strict";i.d(e,"c",function(){return o}),i.d(e,"e",function(){return s}),i.d(e,"g",function(){return c}),i.d(e,"a",function(){return l}),i.d(e,"f",function(){return u}),i.d(e,"h",function(){return p}),i.d(e,"b",function(){return d}),i.d(e,"d",function(){return f});var n=i(9),r=new Array(6);function o(){return[1,0,0,1,0,0]}function s(t){return h(t,1,0,0,1,0,0)}function a(t,e){var i=t[0],n=t[1],r=t[2],o=t[3],s=t[4],a=t[5],h=e[0],c=e[1],l=e[2],u=e[3],p=e[4],d=e[5];return t[0]=i*h+r*c,t[1]=n*h+o*c,t[2]=i*l+r*u,t[3]=n*l+o*u,t[4]=i*p+r*d+s,t[5]=n*p+o*d+a,t}function h(t,e,i,n,r,o,s){return t[0]=e,t[1]=i,t[2]=n,t[3]=r,t[4]=o,t[5]=s,t}function c(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function l(t,e){var i=e[0],n=e[1];return e[0]=t[0]*i+t[2]*n+t[4],e[1]=t[1]*i+t[3]*n+t[5],e}function u(t,e,i){return a(t,h(r,e,0,0,i,0,0))}function p(t,e,i){return a(t,h(r,1,0,0,1,e,i))}function d(t,e,i,n,r,o,s,a){var h=Math.sin(o),c=Math.cos(o);return t[0]=n*c,t[1]=r*h,t[2]=-n*h,t[3]=r*c,t[4]=s*n*c-a*n*h+e,t[5]=s*r*h+a*r*c+i,t}function f(t){var e=function(t){return t[0]*t[3]-t[1]*t[2]}(t);Object(n.a)(0!==e,32);var i=t[0],r=t[1],o=t[2],s=t[3],a=t[4],h=t[5];return t[0]=s/e,t[1]=-r/e,t[2]=-o/e,t[3]=i/e,t[4]=(o*h-s*a)/e,t[5]=-(i*h-r*a)/e,t}},function(t,e,i){"use strict";i.d(e,"a",function(){return r});var n=i(67);function r(t,e){if(!t)throw new n.a(e)}},function(t,e,i){"use strict";function n(t,e){var i=document.createElement("canvas");return t&&(i.width=t),e&&(i.height=e),i.getContext("2d")}function r(t){var e=t.offsetWidth,i=getComputedStyle(t);return e+=parseInt(i.marginLeft,10)+parseInt(i.marginRight,10)}function o(t){var e=t.offsetHeight,i=getComputedStyle(t);return e+=parseInt(i.marginTop,10)+parseInt(i.marginBottom,10)}function s(t,e){var i=e.parentNode;i&&i.replaceChild(t,e)}function a(t){return t&&t.parentNode?t.parentNode.removeChild(t):null}function h(t){for(;t.lastChild;)t.removeChild(t.lastChild)}i.d(e,"a",function(){return n}),i.d(e,"c",function(){return r}),i.d(e,"b",function(){return o}),i.d(e,"f",function(){return s}),i.d(e,"e",function(){return a}),i.d(e,"d",function(){return h})},function(t,e,i){"use strict";i.d(e,"a",function(){return n}),i.d(e,"b",function(){return r}),i.d(e,"c",function(){return o}),i.d(e,"d",function(){return s});var n="function"==typeof Object.assign?Object.assign:function(t,e){var i=arguments;if(void 0===t||null===t)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(t),r=1,o=arguments.length;r>1)],e))<0?a=n+1:(h=n,c=!o);return c?a:~a}function r(t,e){return t>e?1:t=0}function s(t,e,i){var n,r=t.length;if(t[0]<=e)return 0;if(e<=t[r-1])return r-1;if(i>0){for(n=1;n-1;return n&&t.splice(i,1),n}function l(t,e){var i=t.length;if(i!==e.length)return!1;for(var n=0;n0||i&&0===o)})}i.d(e,"a",function(){return n}),i.d(e,"g",function(){return r}),i.d(e,"d",function(){return o}),i.d(e,"f",function(){return s}),i.d(e,"i",function(){return a}),i.d(e,"c",function(){return h}),i.d(e,"h",function(){return c}),i.d(e,"b",function(){return l}),i.d(e,"j",function(){return u}),i.d(e,"e",function(){return p})},function(t,e,i){"use strict";i.r(e);var n=i(59),r=i(0),o=i(6),s=i(20),a=function(t){this.code_=t.code,this.units_=t.units,this.extent_=void 0!==t.extent?t.extent:null,this.worldExtent_=void 0!==t.worldExtent?t.worldExtent:null,this.axisOrientation_=void 0!==t.axisOrientation?t.axisOrientation:"enu",this.global_=void 0!==t.global&&t.global,this.canWrapX_=!(!this.global_||!this.extent_),this.getPointResolutionFunc_=t.getPointResolution,this.defaultTileGrid_=null,this.metersPerUnit_=t.metersPerUnit};a.prototype.canWrapX=function(){return this.canWrapX_},a.prototype.getCode=function(){return this.code_},a.prototype.getExtent=function(){return this.extent_},a.prototype.getUnits=function(){return this.units_},a.prototype.getMetersPerUnit=function(){return this.metersPerUnit_||s.a[this.units_]},a.prototype.getWorldExtent=function(){return this.worldExtent_},a.prototype.getAxisOrientation=function(){return this.axisOrientation_},a.prototype.isGlobal=function(){return this.global_},a.prototype.setGlobal=function(t){this.global_=t,this.canWrapX_=!(!t||!this.extent_)},a.prototype.getDefaultTileGrid=function(){return this.defaultTileGrid_},a.prototype.setDefaultTileGrid=function(t){this.defaultTileGrid_=t},a.prototype.setExtent=function(t){this.extent_=t,this.canWrapX_=!(!this.global_||!t)},a.prototype.setWorldExtent=function(t){this.worldExtent_=t},a.prototype.setGetPointResolution=function(t){this.getPointResolutionFunc_=t},a.prototype.getPointResolutionFunc=function(){return this.getPointResolutionFunc_};var h=a,c=6378137,l=Math.PI*c,u=[-l,-l,l,l],p=[-180,-85,180,85],d=function(t){function e(e){t.call(this,{code:e,units:s.b.METERS,extent:u,global:!0,worldExtent:p,getPointResolution:function(t,e){return t/Object(o.b)(e[1]/c)}})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(h),f=[new d("EPSG:3857"),new d("EPSG:102100"),new d("EPSG:102113"),new d("EPSG:900913"),new d("urn:ogc:def:crs:EPSG:6.18:3:3857"),new d("urn:ogc:def:crs:EPSG::3857"),new d("http://www.opengis.net/gml/srs/epsg.xml#3857")];function _(t,e,i){var n=t.length,r=i>1?i:2,o=e;void 0===o&&(o=r>2?t.slice():new Array(n));for(var s=l,a=0;as?h=s:h<-s&&(h=-s),o[a+1]=h}return o}function g(t,e,i){var n=t.length,r=i>1?i:2,o=e;void 0===o&&(o=r>2?t.slice():new Array(n));for(var s=0;s=2;--c)s[a+c]=e[a+c]}return s}}function A(t,e,i,n){var r=I(t),o=I(e);T(r,o,F(i)),T(o,r,F(n))}function D(t,e){return X(t,"EPSG:4326",void 0!==e?e:"EPSG:3857")}function N(t,e){var i=X(t,void 0!==e?e:"EPSG:3857","EPSG:4326"),n=i[0];return(n<-180||n>180)&&(i[0]=Object(o.d)(n+180,360)-180),i}function k(t,e){if(t===e)return!0;var i=t.getUnits()===e.getUnits();return t.getCode()===e.getCode()?i:G(t,e)===x&&i}function G(t,e){var i=function(t,e){var i;return t in E&&e in E[t]&&(i=E[t][e]),i}(t.getCode(),e.getCode());return i||(i=C),i}function Y(t,e){return G(I(t),I(e))}function X(t,e,i){return Y(e,i)(t,void 0,t.length)}function z(t,e,i){var n=Y(e,i);return Object(r.a)(t,n)}function W(t,e,i){return G(e,i)(t)}function K(){w(f),w(b),L(b,f,_,g)}i.d(e,"cloneTransform",function(){return x}),i.d(e,"identityTransform",function(){return C}),i.d(e,"addProjection",function(){return R}),i.d(e,"addProjections",function(){return S}),i.d(e,"get",function(){return I}),i.d(e,"getPointResolution",function(){return j}),i.d(e,"addEquivalentProjections",function(){return w}),i.d(e,"addEquivalentTransforms",function(){return L}),i.d(e,"clearAllProjections",function(){return M}),i.d(e,"createProjection",function(){return P}),i.d(e,"createTransformFromCoordinateTransform",function(){return F}),i.d(e,"addCoordinateTransforms",function(){return A}),i.d(e,"fromLonLat",function(){return D}),i.d(e,"toLonLat",function(){return N}),i.d(e,"equivalent",function(){return k}),i.d(e,"getTransformFromProjections",function(){return G}),i.d(e,"getTransform",function(){return Y}),i.d(e,"transform",function(){return X}),i.d(e,"transformExtent",function(){return z}),i.d(e,"transformWithProjections",function(){return W}),i.d(e,"addCommon",function(){return K}),i.d(e,"METERS_PER_UNIT",function(){return s.a}),i.d(e,"Projection",function(){return h}),K()},function(t,e,i){"use strict";function n(){return!0}function r(){return!1}function o(){}i.d(e,"b",function(){return n}),i.d(e,"a",function(){return r}),i.d(e,"c",function(){return o})},function(t,e,i){"use strict";e.a={IDLE:0,LOADING:1,LOADED:2,ERROR:3}},function(t,e,i){"use strict";i.d(e,"c",function(){return r}),i.d(e,"g",function(){return o}),i.d(e,"i",function(){return s}),i.d(e,"d",function(){return a}),i.d(e,"b",function(){return h}),i.d(e,"a",function(){return c}),i.d(e,"h",function(){return l}),i.d(e,"f",function(){return u}),i.d(e,"e",function(){return p});var n="undefined"!=typeof navigator?navigator.userAgent.toLowerCase():"",r=-1!==n.indexOf("firefox"),o=-1!==n.indexOf("safari")&&-1==n.indexOf("chrom"),s=-1!==n.indexOf("webkit")&&-1==n.indexOf("edge"),a=-1!==n.indexOf("macintosh"),h=window.devicePixelRatio||1,c=function(){var t=!1;try{t=!!document.createElement("canvas").getContext("2d").setLineDash}catch(t){}return t}(),l=(navigator,"ontouchstart"in window),u="PointerEvent"in window,p=!!navigator.msPointerEnabled},function(t,e,i){"use strict";i.d(e,"a",function(){return r});var n={DEGREES:"degrees",FEET:"ft",METERS:"m",PIXELS:"pixels",TILE_PIXELS:"tile-pixels",USFEET:"us-ft"},r={};r[n.DEGREES]=2*Math.PI*6370997/360,r[n.FEET]=.3048,r[n.METERS]=1,r[n.USFEET]=1200/3937,e.b=n},function(t,e,i){"use strict";function n(t){return Math.pow(t,3)}function r(t){return 1-n(1-t)}function o(t){return 3*t*t-2*t*t*t}function s(t){return t}i.d(e,"a",function(){return n}),i.d(e,"b",function(){return r}),i.d(e,"c",function(){return o}),i.d(e,"d",function(){return s})},function(t,e,i){"use strict";i.d(e,"b",function(){return r});var n=function(t){this.propagationStopped,this.type=t,this.target=null};function r(t){t.stopPropagation()}n.prototype.preventDefault=function(){this.propagationStopped=!0},n.prototype.stopPropagation=function(){this.propagationStopped=!0},e.a=n},function(t,e,i){"use strict";e.a={OPACITY:"opacity",VISIBLE:"visible",EXTENT:"extent",Z_INDEX:"zIndex",MAX_RESOLUTION:"maxResolution",MIN_RESOLUTION:"minResolution",SOURCE:"source"}},function(t,e,i){"use strict";e.a={XY:"XY",XYZ:"XYZ",XYM:"XYM",XYZM:"XYZM"}},function(t,e,i){"use strict";e.a={CENTER:"center",RESOLUTION:"resolution",ROTATION:"rotation"}},function(t,e,i){"use strict";var n=i(17),r=i(46),o=i(13),s=i(10),a=i(1),h=function(t){function e(e){t.call(this),this.element=e.element?e.element:null,this.target_=null,this.map_=null,this.listenerKeys=[],this.render=e.render?e.render:n.c,e.target&&this.setTarget(e.target)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.disposeInternal=function(){Object(s.e)(this.element),t.prototype.disposeInternal.call(this)},e.prototype.getMap=function(){return this.map_},e.prototype.setMap=function(t){this.map_&&Object(s.e)(this.element);for(var e=0,i=this.listenerKeys.length;e0;)this.pop()},e.prototype.extend=function(t){for(var e=0,i=t.length;e=0;--n)if(t[n]!=e[n]){i=!1;break}return i}function o(t,e){var i=Math.cos(e),n=Math.sin(e),r=t[0]*i-t[1]*n,o=t[1]*i+t[0]*n;return t[0]=r,t[1]=o,t}function s(t,e){return t[0]*=e,t[1]*=e,t}i.d(e,"a",function(){return n}),i.d(e,"b",function(){return r}),i.d(e,"c",function(){return o}),i.d(e,"d",function(){return s})},function(t,e,i){"use strict";var n=i(56),r=i(1),o=i(17),s=i(22),a=function(t){function e(){t.call(this),this.pendingRemovals_={},this.dispatching_={},this.listeners_={}}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.addEventListener=function(t,e){var i=this.listeners_[t];i||(i=this.listeners_[t]=[]),-1===i.indexOf(e)&&i.push(e)},e.prototype.dispatchEvent=function(t){var e="string"==typeof t?new s.a(t):t,i=e.type;e.target=this;var n,r=this.listeners_[i];if(r){i in this.dispatching_||(this.dispatching_[i]=0,this.pendingRemovals_[i]=0),++this.dispatching_[i];for(var a=0,h=r.length;a0},e.prototype.removeEventListener=function(t,e){var i=this.listeners_[t];if(i){var n=i.indexOf(e);t in this.pendingRemovals_?(i[n]=o.c,++this.pendingRemovals_[t]):(i.splice(n,1),0===i.length&&delete this.listeners_[t])}},e}(n.a);e.a=a},function(t,e,i){"use strict";i.d(e,"b",function(){return a}),i.d(e,"a",function(){return c}),i.d(e,"c",function(){return u});var n=i(9),r=i(6),o=/^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i,s=/^([a-z]*)$/i;function a(t){return"string"==typeof t?t:u(t)}var h=function(){var t={},e=0;return function(i){var r;if(t.hasOwnProperty(i))r=t[i];else{if(e>=1024){var a=0;for(var h in t)0==(3&a++)&&(delete t[h],--e)}r=function(t){var e,i,r,a,h;s.exec(t)&&(t=function(t){var e=document.createElement("div");if(e.style.color=t,""!==e.style.color){document.body.appendChild(e);var i=getComputedStyle(e).color;return document.body.removeChild(e),i}return""}(t));if(o.exec(t)){var c,u=t.length-1;c=u<=4?1:2;var p=4===u||8===u;e=parseInt(t.substr(1+0*c,c),16),i=parseInt(t.substr(1+1*c,c),16),r=parseInt(t.substr(1+2*c,c),16),a=p?parseInt(t.substr(1+3*c,c),16):255,1==c&&(e=(e<<4)+e,i=(i<<4)+i,r=(r<<4)+r,p&&(a=(a<<4)+a)),h=[e,i,r,a/255]}else 0==t.indexOf("rgba(")?l(h=t.slice(5,-1).split(",").map(Number)):0==t.indexOf("rgb(")?((h=t.slice(4,-1).split(",").map(Number)).push(1),l(h)):Object(n.a)(!1,14);return h}(i),t[i]=r,++e}return r}}();function c(t){return Array.isArray(t)?t:h(t)}function l(t){return t[0]=Object(r.a)(t[0]+.5|0,0,255),t[1]=Object(r.a)(t[1]+.5|0,0,255),t[2]=Object(r.a)(t[2]+.5|0,0,255),t[3]=Object(r.a)(t[3],0,1),t}function u(t){var e=t[0];e!=(0|e)&&(e=e+.5|0);var i=t[1];i!=(0|i)&&(i=i+.5|0);var n=t[2];return n!=(0|n)&&(n=n+.5|0),"rgba("+e+","+i+","+n+","+(void 0===t[3]?1:t[3])+")"}},function(t,e,i){"use strict";e.a={IMAGE:"IMAGE",TILE:"TILE",VECTOR_TILE:"VECTOR_TILE",VECTOR:"VECTOR"}},function(t,e,i){"use strict";e.a={POSTCOMPOSE:"postcompose",PRECOMPOSE:"precompose",RENDER:"render",RENDERCOMPLETE:"rendercomplete"}},function(t,e,i){"use strict";i.d(e,"a",function(){return r});var n=i(36);function r(t){return Array.isArray(t)?Object(n.c)(t):t}},function(t,e,i){"use strict";i.d(e,"b",function(){return n}),i.d(e,"a",function(){return r});var n=.5,r=!0},function(t,e,i){"use strict";function n(t){return t[0]>0&&t[1]>0}function r(t,e,i){return void 0===i&&(i=[0,0]),i[0]=t[0]*e+.5|0,i[1]=t[1]*e+.5|0,i}function o(t,e){return Array.isArray(t)?t:(void 0===e?e=[t,t]:e[0]=e[1]=t,e)}i.d(e,"a",function(){return n}),i.d(e,"b",function(){return r}),i.d(e,"c",function(){return o})},function(t,e,i){"use strict";e.a={UNDEFINED:"undefined",LOADING:"loading",READY:"ready",ERROR:"error"}},function(t,e,i){"use strict";e.a={PROPERTYCHANGE:"propertychange"}},function(t,e,i){"use strict";i.d(e,"b",function(){return d});var n=i(1),r=i(3),o=i(2),s=i(13),a=i(69),h=i(23),c=i(11),l=i(38),u=i(42),p=function(t){function e(e){var i=Object(c.a)({},e);delete i.source,t.call(this,i),this.mapPrecomposeKey_=null,this.mapRenderKey_=null,this.sourceChangeKey_=null,e.map&&this.setMap(e.map),Object(n.a)(this,Object(s.b)(h.a.SOURCE),this.handleSourcePropertyChange_,this);var r=e.source?e.source:null;this.setSource(r)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getLayersArray=function(t){var e=t||[];return e.push(this),e},e.prototype.getLayerStatesArray=function(t){var e=t||[];return e.push(this.getLayerState()),e},e.prototype.getSource=function(){return this.get(h.a.SOURCE)||null},e.prototype.getSourceState=function(){var t=this.getSource();return t?t.getState():u.a.UNDEFINED},e.prototype.handleSourceChange_=function(){this.changed()},e.prototype.handleSourcePropertyChange_=function(){this.sourceChangeKey_&&(Object(n.e)(this.sourceChangeKey_),this.sourceChangeKey_=null);var t=this.getSource();t&&(this.sourceChangeKey_=Object(n.a)(t,r.a.CHANGE,this.handleSourceChange_,this)),this.changed()},e.prototype.setMap=function(t){this.mapPrecomposeKey_&&(Object(n.e)(this.mapPrecomposeKey_),this.mapPrecomposeKey_=null),t||this.changed(),this.mapRenderKey_&&(Object(n.e)(this.mapRenderKey_),this.mapRenderKey_=null),t&&(this.mapPrecomposeKey_=Object(n.a)(t,l.a.PRECOMPOSE,function(t){var e=t,i=this.getLayerState();i.managed=!1,void 0===this.getZIndex()&&(i.zIndex=1/0),e.frameState.layerStatesArray.push(i),e.frameState.layerStates[Object(o.c)(this)]=i},this),this.mapRenderKey_=Object(n.a)(this,r.a.CHANGE,t.render,t),this.changed())},e.prototype.setSource=function(t){this.set(h.a.SOURCE,t)},e}(a.a);function d(t,e){return t.visible&&e>=t.minResolution&&eo&&(c-a)*(o-h)-(r-a)*(l-h)>0&&s++:l<=o&&(c-a)*(o-h)-(r-a)*(l-h)<0&&s--,a=c,h=l}return 0!==s}function s(t,e,i,n,r,s){if(0===i.length)return!1;if(!o(t,e,i[0],n,r,s))return!1;for(var a=1,h=i.length;a1)h=i;else{if(d>0){for(var f=0;fo&&(o=l),s=h,a=c}return o}function s(t,e,i,n,r){for(var s=0,a=i.length;s0;){for(var p=l.pop(),d=l.pop(),f=0,_=t[d],g=t[d+1],v=t[p],y=t[p+1],m=d+r;mf&&(u=m,f=E)}f>o&&(c[(u-e)/r]=1,d+r0&&g>f)&&(_<0&&v<_||_==v||_>0&&v>_)?(h=p,c=d):(s[a++]=h,s[a++]=c,l=h,u=c,h=p,c=d)}}return s[a++]=h,s[a++]=c,a}function a(t,e,i,n,r,o,a,h){for(var c=0,l=i.length;cthis.maxX&&(this.maxX=t.maxX),t.minYthis.maxY&&(this.maxY=t.maxY)},n.prototype.getHeight=function(){return this.maxY-this.minY+1},n.prototype.getSize=function(){return[this.getWidth(),this.getHeight()]},n.prototype.getWidth=function(){return this.maxX-this.minX+1},n.prototype.intersects=function(t){return this.minX<=t.maxX&&this.maxX>=t.minX&&this.minY<=t.maxY&&this.maxY>=t.minY},e.b=n},function(t,e,i){"use strict";var n=function(){this.disposed_=!1};n.prototype.dispose=function(){this.disposed_||(this.disposed_=!0,this.disposeInternal())},n.prototype.disposeInternal=function(){},e.a=n},function(t,e,i){"use strict";t.exports=r,t.exports.default=r;var n=i(93);function r(t,e){if(!(this instanceof r))return new r(t,e);this._maxEntries=Math.max(4,t||9),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),e&&this._initFormat(e),this.clear()}function o(t,e,i){if(!i)return e.indexOf(t);for(var n=0;n=t.minX&&e.maxY>=t.minY}function v(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function y(t,e,i,r,o){for(var s,a=[e,i];a.length;)(i=a.pop())-(e=a.pop())<=r||(s=e+Math.ceil((i-e)/r/2)*r,n(t,s,e,i,o),a.push(e,s,s,i))}r.prototype={all:function(){return this._all(this.data,[])},search:function(t){var e=this.data,i=[],n=this.toBBox;if(!g(t,e))return i;for(var r,o,s,a,h=[];e;){for(r=0,o=e.children.length;r=0&&o[e].children.length>this._maxEntries;)this._split(o,e),e--;this._adjustParentBBoxes(r,o,e)},_split:function(t,e){var i=t[e],n=i.children.length,r=this._minEntries;this._chooseSplitAxis(i,r,n);var o=this._chooseSplitIndex(i,r,n),a=v(i.children.splice(o,i.children.length-o));a.height=i.height,a.leaf=i.leaf,s(i,this.toBBox),s(a,this.toBBox),e?t[e-1].children.push(a):this._splitRoot(i,a)},_splitRoot:function(t,e){this.data=v([t,e]),this.data.height=t.height+1,this.data.leaf=!1,s(this.data,this.toBBox)},_chooseSplitIndex:function(t,e,i){var n,r,o,s,h,c,l,p;for(c=l=1/0,n=e;n<=i-e;n++)s=f(r=a(t,0,n,this.toBBox),o=a(t,n,i,this.toBBox)),h=u(r)+u(o),s=e;r--)o=t.children[r],h(l,t.leaf?s(o):o),u+=p(l);return u},_adjustParentBBoxes:function(t,e,i){for(var n=i;n>=0;n--)h(e[n],t)},_condense:function(t){for(var e,i=t.length-1;i>=0;i--)0===t[i].children.length?i>0?(e=t[i-1].children).splice(e.indexOf(t[i]),1):this.clear():s(t[i],this.toBBox)},_initFormat:function(t){var e=["return a"," - b",";"];this.compareMinX=new Function("a","b",e.join(t[0])),this.compareMinY=new Function("a","b",e.join(t[1])),this.toBBox=new Function("a","return {minX: a"+t[0]+", minY: a"+t[1]+", maxX: a"+t[2]+", maxY: a"+t[3]+"};")}}},function(t,e,i){"use strict";i.r(e);var n=i(2),r=function(t){var e=t||{};this.color_=void 0!==e.color?e.color:null,this.lineCap_=e.lineCap,this.lineDash_=void 0!==e.lineDash?e.lineDash:null,this.lineDashOffset_=e.lineDashOffset,this.lineJoin_=e.lineJoin,this.miterLimit_=e.miterLimit,this.width_=e.width,this.checksum_=void 0};r.prototype.clone=function(){var t=this.getColor();return new r({color:Array.isArray(t)?t.slice():t||void 0,lineCap:this.getLineCap(),lineDash:this.getLineDash()?this.getLineDash().slice():void 0,lineDashOffset:this.getLineDashOffset(),lineJoin:this.getLineJoin(),miterLimit:this.getMiterLimit(),width:this.getWidth()})},r.prototype.getColor=function(){return this.color_},r.prototype.getLineCap=function(){return this.lineCap_},r.prototype.getLineDash=function(){return this.lineDash_},r.prototype.getLineDashOffset=function(){return this.lineDashOffset_},r.prototype.getLineJoin=function(){return this.lineJoin_},r.prototype.getMiterLimit=function(){return this.miterLimit_},r.prototype.getWidth=function(){return this.width_},r.prototype.setColor=function(t){this.color_=t,this.checksum_=void 0},r.prototype.setLineCap=function(t){this.lineCap_=t,this.checksum_=void 0},r.prototype.setLineDash=function(t){this.lineDash_=t,this.checksum_=void 0},r.prototype.setLineDashOffset=function(t){this.lineDashOffset_=t,this.checksum_=void 0},r.prototype.setLineJoin=function(t){this.lineJoin_=t,this.checksum_=void 0},r.prototype.setMiterLimit=function(t){this.miterLimit_=t,this.checksum_=void 0},r.prototype.setWidth=function(t){this.width_=t,this.checksum_=void 0},r.prototype.getChecksum=function(){return void 0===this.checksum_&&(this.checksum_="s",this.color_?"string"==typeof this.color_?this.checksum_+=this.color_:this.checksum_+=Object(n.c)(this.color_):this.checksum_+="-",this.checksum_+=","+(void 0!==this.lineCap_?this.lineCap_.toString():"-")+","+(this.lineDash_?this.lineDash_.toString():"-")+","+(void 0!==this.lineDashOffset_?this.lineDashOffset_:"-")+","+(void 0!==this.lineJoin_?this.lineJoin_:"-")+","+(void 0!==this.miterLimit_?this.miterLimit_.toString():"-")+","+(void 0!==this.width_?this.width_.toString():"-")),this.checksum_},e.default=r},function(t,e,i){"use strict";i.d(e,"a",function(){return o}),i.d(e,"b",function(){return s});var n=i(6),r=(i(5),6371008.8);function o(t,e,i){var o=i||r,s=Object(n.i)(t[1]),a=Object(n.i)(e[1]),h=(a-s)/2,c=Object(n.i)(e[0]-t[0])/2,l=Math.sin(h)*Math.sin(h)+Math.sin(c)*Math.sin(c)*Math.cos(s)*Math.cos(a);return 2*o*Math.atan2(Math.sqrt(l),Math.sqrt(1-l))}function s(t,e,i,o){var s=o||r,a=Object(n.i)(t[1]),h=Object(n.i)(t[0]),c=e/s,l=Math.asin(Math.sin(a)*Math.cos(c)+Math.cos(a)*Math.sin(c)*Math.cos(i)),u=h+Math.atan2(Math.sin(i)*Math.sin(c)*Math.cos(a),Math.cos(c)-Math.sin(a)*Math.sin(l));return[Object(n.h)(u),Object(n.h)(l)]}},function(t,e,i){"use strict";i.d(e,"a",function(){return s});var n=i(36),r=function(){this.cache_={},this.cacheSize_=0,this.maxCacheSize_=32};function o(t,e,i){return e+":"+t+":"+(i?Object(n.b)(i):"null")}r.prototype.clear=function(){this.cache_={},this.cacheSize_=0},r.prototype.expire=function(){if(this.cacheSize_>this.maxCacheSize_){var t=0;for(var e in this.cache_){var i=this.cache_[e];0!=(3&t++)||i.hasListener()||(delete this.cache_[e],--this.cacheSize_)}}},r.prototype.get=function(t,e,i){var n=o(t,e,i);return n in this.cache_?this.cache_[n]:null},r.prototype.set=function(t,e,i,n){var r=o(t,e,i);this.cache_[r]=n,++this.cacheSize_},r.prototype.setSize=function(t){this.maxCacheSize_=t,this.expire()};var s=new r},function(t,e,i){"use strict";var n=i(1),r=i(35),o=i(19),s=i(30),a=function(t,e){this.dispatcher=t,this.mapping_=e};a.prototype.getEvents=function(){return Object.keys(this.mapping_)},a.prototype.getHandlerForEvent=function(t){return this.mapping_[t]};var h=a,c=1,l="mouse";function u(t){if(!this.isEventSimulatedFromTouch_(t)){c.toString()in this.pointerMap&&this.cancel(t);var e=g(t,this.dispatcher);this.pointerMap[c.toString()]=t,this.dispatcher.down(e,t)}}function p(t){if(!this.isEventSimulatedFromTouch_(t)){var e=g(t,this.dispatcher);this.dispatcher.move(e,t)}}function d(t){if(!this.isEventSimulatedFromTouch_(t)){var e=this.pointerMap[c.toString()];if(e&&e.button===t.button){var i=g(t,this.dispatcher);this.dispatcher.up(i,t),this.cleanupMouse()}}}function f(t){if(!this.isEventSimulatedFromTouch_(t)){var e=g(t,this.dispatcher);this.dispatcher.enterOver(e,t)}}function _(t){if(!this.isEventSimulatedFromTouch_(t)){var e=g(t,this.dispatcher);this.dispatcher.leaveOut(e,t)}}function g(t,e){var i=e.cloneEvent(t,t),n=i.preventDefault;return i.preventDefault=function(){t.preventDefault(),n()},i.pointerId=c,i.isPrimary=!0,i.pointerType=l,i}var v=function(t){function e(e){var i={mousedown:u,mousemove:p,mouseup:d,mouseover:f,mouseout:_};t.call(this,e,i),this.pointerMap=e.pointerMap,this.lastTouches=[]}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.isEventSimulatedFromTouch_=function(t){for(var e=this.lastTouches,i=t.clientX,n=t.clientY,r=0,o=e.length,s=void 0;r=e.length){for(var r=[],o=0;oE&&(l=(u+p)/2,Object(g.c)(t,e,i,r,l,_)&&(O=l,E=T)),u=p}return isNaN(O)&&(O=o[s]),a?(a.push(O,_,E),a):[O,_,E]}var y=i(70);function m(t,e,i,n){for(;e0}function O(t,e,i,n,r){for(var o=void 0!==r&&r,s=0,a=i.length;s0?(e.getAnimating()&&e.cancelAnimations(),e.animate({resolution:n,duration:this.duration_,easing:a.b})):e.setResolution(n)}}},e}(o.a);e.a=h},function(t,e,i){"use strict";var n=i(26),r=i(14),o=i(21),s=i(1),a=i(3),h=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),render:i.render||c,target:i.target});var n=void 0!==i.className?i.className:"ol-rotate",o=void 0!==i.label?i.label:"⇧";this.label_=null,"string"==typeof o?(this.label_=document.createElement("span"),this.label_.className="ol-compass",this.label_.textContent=o):(this.label_=o,this.label_.classList.add("ol-compass"));var h=i.tipLabel?i.tipLabel:"Reset rotation",l=document.createElement("button");l.className=n+"-reset",l.setAttribute("type","button"),l.title=h,l.appendChild(this.label_),Object(s.a)(l,a.a.CLICK,this.handleClick_,this);var u=n+" "+r.e+" "+r.b,p=this.element;p.className=u,p.appendChild(l),this.callResetNorth_=i.resetNorth?i.resetNorth:void 0,this.duration_=void 0!==i.duration?i.duration:250,this.autoHide_=void 0===i.autoHide||i.autoHide,this.rotation_=void 0,this.autoHide_&&this.element.classList.add(r.c)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleClick_=function(t){t.preventDefault(),void 0!==this.callResetNorth_?this.callResetNorth_():this.resetNorth_()},e.prototype.resetNorth_=function(){var t=this.getMap().getView();t&&void 0!==t.getRotation()&&(this.duration_>0?t.animate({rotation:0,duration:this.duration_,easing:o.b}):t.setRotation(0))},e}(n.a);function c(t){var e=t.frameState;if(e){var i=e.viewState.rotation;if(i!=this.rotation_){var n="rotate("+i+"rad)";if(this.autoHide_){var o=this.element.classList.contains(r.c);o||0!==i?o&&0!==i&&this.element.classList.remove(r.c):this.element.classList.add(r.c)}this.label_.style.msTransform=n,this.label_.style.webkitTransform=n,this.label_.style.transform=n}this.rotation_=i}}e.a=h},function(t,e,i){"use strict";var n=i(15),r=i(26),o=i(14),s=i(10),a=i(1),h=i(3),c=i(44),l=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),render:i.render||u,target:i.target}),this.ulElement_=document.createElement("ul"),this.collapsed_=void 0===i.collapsed||i.collapsed,this.overrideCollapsible_=void 0!==i.collapsible,this.collapsible_=void 0===i.collapsible||i.collapsible,this.collapsible_||(this.collapsed_=!1);var n=void 0!==i.className?i.className:"ol-attribution",r=void 0!==i.tipLabel?i.tipLabel:"Attributions",s=void 0!==i.collapseLabel?i.collapseLabel:"»";"string"==typeof s?(this.collapseLabel_=document.createElement("span"),this.collapseLabel_.textContent=s):this.collapseLabel_=s;var c=void 0!==i.label?i.label:"i";"string"==typeof c?(this.label_=document.createElement("span"),this.label_.textContent=c):this.label_=c;var l=this.collapsible_&&!this.collapsed_?this.collapseLabel_:this.label_,p=document.createElement("button");p.setAttribute("type","button"),p.title=r,p.appendChild(l),Object(a.a)(p,h.a.CLICK,this.handleClick_,this);var d=n+" "+o.e+" "+o.b+(this.collapsed_&&this.collapsible_?" "+o.a:"")+(this.collapsible_?"":" ol-uncollapsible"),f=this.element;f.className=d,f.appendChild(this.ulElement_),f.appendChild(p),this.renderedAttributions_=[],this.renderedVisible_=!0}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.collectSourceAttributions_=function(t){for(var e={},i=[],n=t.layerStatesArray,r=t.viewState.resolution,o=0,s=n.length;o0;if(this.renderedVisible_!=i&&(this.element.style.display=i?"":"none",this.renderedVisible_=i),!Object(n.b)(e,this.renderedAttributions_)){Object(s.d)(this.ulElement_);for(var r=0,o=e.length;r=s[0]&&a[2]<=s[2]||(a[1]>=s[1]&&a[3]<=s[3]||Object(o.a)(t,e,i,r,function(t,e){return Object(n.G)(s,t,e)}))))}function a(t,e,i,n,o){if(!function(t,e,i,n,o){return!!(s(t,e,i,n,o)||Object(r.b)(t,e,i,n,o[0],o[1])||Object(r.b)(t,e,i,n,o[0],o[3])||Object(r.b)(t,e,i,n,o[2],o[1])||Object(r.b)(t,e,i,n,o[2],o[3]))}(t,e,i[0],n,o))return!1;if(1===i.length)return!0;for(var a=1,h=i.length;athis.highWaterMark},e.prototype.clear=function(){this.count_=0,this.entries_={},this.oldest_=null,this.newest_=null,this.dispatchEvent(o.a.CLEAR)},e.prototype.containsKey=function(t){return this.entries_.hasOwnProperty(t)},e.prototype.forEach=function(t,e){for(var i=this.oldest_;i;)t.call(e,i.value_,i.key_,this),i=i.newer},e.prototype.get=function(t){var e=this.entries_[t];return Object(n.a)(void 0!==e,15),e===this.newest_?e.value_:(e===this.oldest_?(this.oldest_=this.oldest_.newer,this.oldest_.older=null):(e.newer.older=e.older,e.older.newer=e.newer),e.newer=null,e.older=this.newest_,this.newest_.newer=e,this.newest_=e,e.value_)},e.prototype.remove=function(t){var e=this.entries_[t];return Object(n.a)(void 0!==e,15),e===this.newest_?(this.newest_=e.older,this.newest_&&(this.newest_.newer=null)):e===this.oldest_?(this.oldest_=e.newer,this.oldest_&&(this.oldest_.older=null)):(e.newer.older=e.older,e.older.newer=e.newer),delete this.entries_[t],--this.count_,e.value_},e.prototype.getCount=function(){return this.count_},e.prototype.getKeys=function(){var t,e=new Array(this.count_),i=0;for(t=this.newest_;t;t=t.older)e[i++]=t.key_;return e},e.prototype.getValues=function(){var t,e=new Array(this.count_),i=0;for(t=this.newest_;t;t=t.older)e[i++]=t.value_;return e},e.prototype.peekLast=function(){return this.oldest_.value_},e.prototype.peekLastKey=function(){return this.oldest_.key_},e.prototype.peekFirstKey=function(){return this.newest_.key_},e.prototype.pop=function(){var t=this.oldest_;return delete this.entries_[t.key_],t.newer&&(t.newer.older=null),this.oldest_=t.newer,this.oldest_||(this.newest_=null),--this.count_,t.value_},e.prototype.replace=function(t,e){this.get(t),this.entries_[t].value_=e},e.prototype.set=function(t,e){Object(n.a)(!(t in this.entries_),16);var i={key_:t,newer:null,older:this.newest_,value_:e};this.newest_?this.newest_.newer=i:this.oldest_=i,this.newest_=i,this.entries_[t]=i,++this.count_},e.prototype.setSize=function(t){this.highWaterMark=t},e.prototype.prune=function(){for(;this.canExpireCache();)this.pop()},e}(r.a);e.a=s},function(t,e,i){"use strict";e.a={IMAGE:"image",VECTOR:"vector"}},function(t,e,i){"use strict";function n(t,e,i,n){for(var r=t[e],o=t[e+1],s=0,a=e+n;athis.moveTolerance_||Math.abs(t.clientY-this.down_.clientY)>this.moveTolerance_},e.prototype.disposeInternal=function(){this.relayedListenerKey_&&(Object(d.e)(this.relayedListenerKey_),this.relayedListenerKey_=null),this.pointerdownListenerKey_&&(Object(d.e)(this.pointerdownListenerKey_),this.pointerdownListenerKey_=null),this.dragListenerKeys_.forEach(d.e),this.dragListenerKeys_.length=0,this.documentPointerEventHandler_&&(this.documentPointerEventHandler_.dispose(),this.documentPointerEventHandler_=null),this.pointerEventHandler_&&(this.pointerEventHandler_.dispose(),this.pointerEventHandler_=null),t.prototype.disposeInternal.call(this)},e}(f.a),y=i(46),m=i(31),b=i(38),O=i(13),E=i(43),T=i(7),x=i(9),C=i(11),R=function(t,e){this.priorityFunction_=t,this.keyFunction_=e,this.elements_=[],this.priorities_=[],this.queuedElements_={}};R.prototype.clear=function(){this.elements_.length=0,this.priorities_.length=0,Object(C.b)(this.queuedElements_)},R.prototype.dequeue=function(){var t=this.elements_,e=this.priorities_,i=t[0];1==t.length?(t.length=0,e.length=0):(t[0]=t.pop(),e[0]=e.pop(),this.siftUp_(0));var n=this.keyFunction_(i);return delete this.queuedElements_[n],i},R.prototype.enqueue=function(t){Object(x.a)(!(this.keyFunction_(t)in this.queuedElements_),31);var e=this.priorityFunction_(t);return e!=1/0&&(this.elements_.push(t),this.priorities_.push(e),this.queuedElements_[this.keyFunction_(t)]=!0,this.siftDown_(0,this.elements_.length-1),!0)},R.prototype.getCount=function(){return this.elements_.length},R.prototype.getLeftChildIndex_=function(t){return 2*t+1},R.prototype.getRightChildIndex_=function(t){return 2*t+2},R.prototype.getParentIndex_=function(t){return t-1>>1},R.prototype.heapify_=function(){var t;for(t=(this.elements_.length>>1)-1;t>=0;t--)this.siftUp_(t)},R.prototype.isEmpty=function(){return 0===this.elements_.length},R.prototype.isKeyQueued=function(t){return t in this.queuedElements_},R.prototype.isQueued=function(t){return this.isKeyQueued(this.keyFunction_(t))},R.prototype.siftUp_=function(t){for(var e=this.elements_,i=this.priorities_,n=e.length,r=e[t],o=i[t],s=t;t>1;){var a=this.getLeftChildIndex_(t),h=this.getRightChildIndex_(t),c=ht;){var s=this.getParentIndex_(e);if(!(n[s]>o))break;i[e]=i[s],n[e]=n[s],e=s}i[e]=r,n[e]=o},R.prototype.reprioritize=function(){var t,e,i,n=this.priorityFunction_,r=this.elements_,o=this.priorities_,s=0,a=r.length;for(e=0;e0;)r=(n=this.dequeue()[0]).getKey(),(i=n.getState())===T.a.ABORT?s=!0:i!==T.a.IDLE||r in this.tilesLoadingKeys_||(this.tilesLoadingKeys_[r]=!0,++this.tilesLoading_,++o,n.load());0===o&&s&&this.tileChangeCallback_()},e}(R),I=i(82),j=i(12),w=i(10),L=i(0),M=i(17),P=i(69),F=i(42),A={LAYERS:"layers"},D=function(t){function e(e){var i=e||{},n=Object(C.a)({},i);delete n.layers;var o=i.layers;t.call(this,n),this.layersListenerKeys_=[],this.listenerKeys_={},Object(d.a)(this,Object(O.b)(A.LAYERS),this.handleLayersChanged_,this),o?Array.isArray(o)?o=new r.a(o.slice(),{unique:!0}):Object(x.a)("function"==typeof o.getArray,43):o=new r.a(void 0,{unique:!0}),this.setLayers(o)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleLayerChange_=function(){this.changed()},e.prototype.handleLayersChanged_=function(){this.layersListenerKeys_.forEach(d.e),this.layersListenerKeys_.length=0;var t=this.getLayers();for(var e in this.layersListenerKeys_.push(Object(d.a)(t,o.a.ADD,this.handleLayersAdd_,this),Object(d.a)(t,o.a.REMOVE,this.handleLayersRemove_,this)),this.listenerKeys_)this.listenerKeys_[e].forEach(d.e);Object(C.b)(this.listenerKeys_);for(var i=t.getArray(),r=0,s=i.length;r=0;i--){var n=e[i];if(n.getActive())if(!n.handleEvent(t))break}}},e.prototype.handlePostRender=function(){var t=this.frameState_,e=this.tileQueue_;if(!e.isEmpty()){var i=this.maxTilesLoading_,n=i;if(t){var r=t.viewHints;r[j.a.ANIMATING]&&(i=this.loadTilesWhileAnimating_?8:0,n=2),r[j.a.INTERACTING]&&(i=this.loadTilesWhileInteracting_?8:0,n=2)}e.getTilesLoading()0&&this.points_[i+2]>t;)i-=3;var n=this.points_[e+2]-this.points_[i+2];if(n<1e3/60)return!1;var r=this.points_[e]-this.points_[i],o=this.points_[e+1]-this.points_[i+1];return this.angle_=Math.atan2(o,r),this.initialVelocity_=Math.sqrt(r*r+o*o)/n,this.initialVelocity_>this.minVelocity_},X.prototype.getDistance=function(){return(this.minVelocity_-this.initialVelocity_)/this.decay_},X.prototype.getAngle=function(){return this.angle_};var z=X,W=i(21),K="active",U=i(6);function V(t,e,i,n){H(t,e=t.constrainRotation(e,0),i,n)}function H(t,e,i,n){if(void 0!==e){var r=t.getRotation(),o=t.getCenter();void 0!==r&&o&&n>0?t.animate({rotation:e,anchor:i,duration:n,easing:W.b}):t.rotate(e,i)}}function B(t,e,i,n){var r=t.getResolution(),o=t.constrainResolution(r,e,0);if(void 0!==o){var s=t.getResolutions();o=Object(U.a)(o,t.getMinResolution()||s[s.length-1],t.getMaxResolution()||s[0])}if(i&&void 0!==o&&o!==r){var a=t.getCenter(),h=t.calculateCenterZoom(o,i);h=t.constrainCenter(h),i=[(o*a[0]-r*h[0])/(o-r),(o*a[1]-r*h[1])/(o-r)]}Z(t,o,i,n)}function Z(t,e,i,n){if(e){var r=t.getResolution(),o=t.getCenter();if(void 0!==r&&o&&e!==r&&n)t.animate({resolution:e,anchor:i,duration:n,easing:W.b});else{if(i){var s=t.calculateCenterZoom(e,i);t.setCenter(s)}t.setResolution(e)}}}var q=function(t){function e(e){t.call(this),e.handleEvent&&(this.handleEvent=e.handleEvent),this.map_=null,this.setActive(!0)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getActive=function(){return this.get(K)},e.prototype.getMap=function(){return this.map_},e.prototype.handleEvent=function(t){return!0},e.prototype.setActive=function(t){this.set(K,t)},e.prototype.setMap=function(t){this.map_=t},e}(O.a);function J(t){var e=!1;if(t.type==u.DBLCLICK){var i=t.originalEvent,n=t.map,r=t.coordinate,o=i.shiftKey?-this.delta_:this.delta_;B(n.getView(),o,r,this.duration_),t.preventDefault(),e=!0}return!e}var Q=function(t){function e(e){t.call(this,{handleEvent:J});var i=e||{};this.delta_=i.delta?i.delta:1,this.duration_=void 0!==i.duration?i.duration:250}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(q),$=i(34),tt=function(t){var e=t.originalEvent;return e.altKey&&!(e.metaKey||e.ctrlKey)&&e.shiftKey},et=function(t){return t.target.getTargetElement()===document.activeElement},it=M.b,nt=function(t){var e=t.originalEvent;return 0==e.button&&!(c.i&&c.d&&e.ctrlKey)},rt=(M.a,function(t){var e=t.originalEvent;return!e.altKey&&!(e.metaKey||e.ctrlKey)&&!e.shiftKey}),ot=function(t){var e=t.originalEvent;return!e.altKey&&!(e.metaKey||e.ctrlKey)&&e.shiftKey},st=function(t){var e=t.originalEvent.target.tagName;return"INPUT"!==e&&"SELECT"!==e&&"TEXTAREA"!==e},at=function(t){var e=t.pointerEvent;return Object(x.a)(void 0!==e,56),"mouse"==e.pointerType};function ht(t){for(var e=t.length,i=0,n=0,r=0;r0}}else if(t.type==u.POINTERDOWN){var n=this.handleDownEvent(t);n&&t.preventDefault(),this.handlingDownUpSequence=n,e=this.stopDown(n)}else t.type==u.POINTERMOVE&&this.handleMoveEvent(t);return!e},e.prototype.handleMoveEvent=function(t){},e.prototype.handleUpEvent=function(t){return!1},e.prototype.stopDown=function(t){return t},e.prototype.updateTrackedPointers_=function(t){if(function(t){var e=t.type;return e===u.POINTERDOWN||e===u.POINTERDRAG||e===u.POINTERUP}(t)){var e=t.pointerEvent,i=e.pointerId.toString();t.type==u.POINTERUP?delete this.trackedPointers_[i]:t.type==u.POINTERDOWN?this.trackedPointers_[i]=e:i in this.trackedPointers_&&(this.trackedPointers_[i]=e),this.targetPointers=Object(C.c)(this.trackedPointers_)}},e}(q),lt=function(t){function e(e){t.call(this,{stopDown:M.a});var i=e||{};this.kinetic_=i.kinetic,this.lastCentroid=null,this.lastPointersCount_,this.panning_=!1,this.condition_=i.condition?i.condition:rt,this.noKinetic_=!1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleDragEvent=function(t){this.panning_||(this.panning_=!0,this.getMap().getView().setHint(j.a.INTERACTING,1));var e=this.targetPointers,i=ht(e);if(e.length==this.lastPointersCount_){if(this.kinetic_&&this.kinetic_.update(i[0],i[1]),this.lastCentroid){var n=this.lastCentroid[0]-i[0],r=i[1]-this.lastCentroid[1],o=t.map.getView(),s=[n,r];Object($.d)(s,o.getResolution()),Object($.c)(s,o.getRotation()),Object($.a)(s,o.getCenter()),s=o.constrainCenter(s),o.setCenter(s)}}else this.kinetic_&&this.kinetic_.begin();this.lastCentroid=i,this.lastPointersCount_=e.length},e.prototype.handleUpEvent=function(t){var e=t.map,i=e.getView();if(0===this.targetPointers.length){if(!this.noKinetic_&&this.kinetic_&&this.kinetic_.end()){var n=this.kinetic_.getDistance(),r=this.kinetic_.getAngle(),o=i.getCenter(),s=e.getPixelFromCoordinate(o),a=e.getCoordinateFromPixel([s[0]-n*Math.cos(r),s[1]-n*Math.sin(r)]);i.animate({center:i.constrainCenter(a),duration:500,easing:W.b})}return this.panning_&&(this.panning_=!1,i.setHint(j.a.INTERACTING,-1)),!1}return this.kinetic_&&this.kinetic_.begin(),this.lastCentroid=null,!0},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>0&&this.condition_(t)){var e=t.map.getView();return this.lastCentroid=null,e.getAnimating()&&e.setCenter(t.frameState.viewState.center),this.kinetic_&&this.kinetic_.begin(),this.noKinetic_=this.targetPointers.length>1,!0}return!1},e}(ct),ut=i(48),pt=function(t){function e(e){var i=e||{};t.call(this,{stopDown:M.a}),this.condition_=i.condition?i.condition:tt,this.lastAngle_=void 0,this.duration_=void 0!==i.duration?i.duration:250}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleDragEvent=function(t){if(at(t)){var e=t.map,i=e.getView();if(i.getConstraints().rotation!==ut.c){var n=e.getSize(),r=t.pixel,o=Math.atan2(n[1]/2-r[1],r[0]-n[0]/2);if(void 0!==this.lastAngle_){var s=o-this.lastAngle_;H(i,i.getRotation()-s)}this.lastAngle_=o}}},e.prototype.handleUpEvent=function(t){if(!at(t))return!0;var e=t.map.getView();return e.setHint(j.a.INTERACTING,-1),V(e,e.getRotation(),void 0,this.duration_),!1},e.prototype.handleDownEvent=function(t){return!!at(t)&&(!(!nt(t)||!this.condition_(t))&&(t.map.getView().setHint(j.a.INTERACTING,1),this.lastAngle_=void 0,!0))},e}(ct),dt=i(56),ft=i(62),_t=function(t){function e(e){t.call(this),this.geometry_=null,this.element_=document.createElement("div"),this.element_.style.position="absolute",this.element_.className="ol-box "+e,this.map_=null,this.startPixel_=null,this.endPixel_=null}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.disposeInternal=function(){this.setMap(null)},e.prototype.render_=function(){var t=this.startPixel_,e=this.endPixel_,i=this.element_.style;i.left=Math.min(t[0],e[0])+"px",i.top=Math.min(t[1],e[1])+"px",i.width=Math.abs(e[0]-t[0])+"px",i.height=Math.abs(e[1]-t[1])+"px"},e.prototype.setMap=function(t){if(this.map_){this.map_.getOverlayContainer().removeChild(this.element_);var e=this.element_.style;e.left=e.top=e.width=e.height="inherit"}this.map_=t,this.map_&&this.map_.getOverlayContainer().appendChild(this.element_)},e.prototype.setPixels=function(t,e){this.startPixel_=t,this.endPixel_=e,this.createOrUpdateGeometry(),this.render_()},e.prototype.createOrUpdateGeometry=function(){var t=this.startPixel_,e=this.endPixel_,i=[t,[t[0],e[1]],e,[e[0],t[1]]].map(this.map_.getCoordinateFromPixel,this.map_);i[4]=i[0].slice(),this.geometry_?this.geometry_.setCoordinates([i]):this.geometry_=new ft.a([i])},e.prototype.getGeometry=function(){return this.geometry_},e}(dt.a),gt="boxstart",vt="boxdrag",yt="boxend",mt=function(t){function e(e,i,n){t.call(this,e),this.coordinate=i,this.mapBrowserEvent=n}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(s.a);function bt(){var t=this.getMap(),e=t.getView(),i=t.getSize(),n=this.getGeometry().getExtent();if(this.out_){var r=e.calculateExtent(i),o=Object(L.n)([t.getPixelFromCoordinate(Object(L.v)(n)),t.getPixelFromCoordinate(Object(L.D)(n))]),s=e.getResolutionForExtent(o,i);Object(L.J)(r,1/s),n=r}var a=e.constrainResolution(e.getResolutionForExtent(n,i)),h=Object(L.x)(n);h=e.constrainCenter(h),e.animate({resolution:a,center:h,duration:this.duration_,easing:W.b})}var Ot=function(t){function e(e){var i=e||{},n=i.condition?i.condition:ot;t.call(this,{condition:n,className:i.className||"ol-dragzoom",onBoxEnd:bt}),this.duration_=void 0!==i.duration?i.duration:200,this.out_=void 0!==i.out&&i.out}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(function(t){function e(e){t.call(this);var i=e||{};this.box_=new _t(i.className||"ol-dragbox"),this.minArea_=void 0!==i.minArea?i.minArea:64,this.onBoxEnd_=i.onBoxEnd?i.onBoxEnd:M.c,this.startPixel_=null,this.condition_=i.condition?i.condition:it,this.boxEndCondition_=i.boxEndCondition?i.boxEndCondition:this.defaultBoxEndCondition}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.defaultBoxEndCondition=function(t,e,i){var n=i[0]-e[0],r=i[1]-e[1];return n*n+r*r>=this.minArea_},e.prototype.getGeometry=function(){return this.box_.getGeometry()},e.prototype.handleDragEvent=function(t){at(t)&&(this.box_.setPixels(this.startPixel_,t.pixel),this.dispatchEvent(new mt(vt,t.coordinate,t)))},e.prototype.handleUpEvent=function(t){return!at(t)||(this.box_.setMap(null),this.boxEndCondition_(t,this.startPixel_,t.pixel)&&(this.onBoxEnd_(t),this.dispatchEvent(new mt(yt,t.coordinate,t))),!1)},e.prototype.handleDownEvent=function(t){return!!at(t)&&(!(!nt(t)||!this.condition_(t))&&(this.startPixel_=t.pixel,this.box_.setMap(t.map),this.box_.setPixels(this.startPixel_,this.startPixel_),this.dispatchEvent(new mt(gt,t.coordinate,t)),!0))},e}(ct)),Et={LEFT:37,UP:38,RIGHT:39,DOWN:40};function Tt(t){var e=!1;if(t.type==l.a.KEYDOWN){var i=t.originalEvent.keyCode;if(this.condition_(t)&&(i==Et.DOWN||i==Et.LEFT||i==Et.RIGHT||i==Et.UP)){var n=t.map.getView(),r=n.getResolution()*this.pixelDelta_,o=0,s=0;i==Et.DOWN?s=-r:i==Et.LEFT?o=-r:i==Et.RIGHT?o=r:s=r;var a=[o,s];Object($.c)(a,n.getRotation()),function(t,e,i){var n=t.getCenter();if(n){var r=t.constrainCenter([n[0]+e[0],n[1]+e[1]]);i?t.animate({duration:i,easing:W.d,center:r}):t.setCenter(r)}}(n,a,this.duration_),t.preventDefault(),e=!0}}return!e}var xt=function(t){function e(e){t.call(this,{handleEvent:Tt});var i=e||{};this.defaultCondition_=function(t){return rt(t)&&st(t)},this.condition_=void 0!==i.condition?i.condition:this.defaultCondition_,this.duration_=void 0!==i.duration?i.duration:100,this.pixelDelta_=void 0!==i.pixelDelta?i.pixelDelta:128}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(q);function Ct(t){var e=!1;if(t.type==l.a.KEYDOWN||t.type==l.a.KEYPRESS){var i=t.originalEvent.charCode;if(this.condition_(t)&&(i=="+".charCodeAt(0)||i=="-".charCodeAt(0))){var n=t.map,r=i=="+".charCodeAt(0)?this.delta_:-this.delta_;B(n.getView(),r,void 0,this.duration_),t.preventDefault(),e=!0}}return!e}var Rt=function(t){function e(e){t.call(this,{handleEvent:Ct});var i=e||{};this.condition_=i.condition?i.condition:st,this.delta_=i.delta?i.delta:1,this.duration_=void 0!==i.duration?i.duration:100}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(q),St="trackpad",It="wheel",jt=function(t){function e(e){var i=e||{};t.call(this,i),this.delta_=0,this.duration_=void 0!==i.duration?i.duration:250,this.timeout_=void 0!==i.timeout?i.timeout:80,this.useAnchor_=void 0===i.useAnchor||i.useAnchor,this.constrainResolution_=i.constrainResolution||!1,this.condition_=i.condition?i.condition:it,this.lastAnchor_=null,this.startTime_=void 0,this.timeoutId_,this.mode_=void 0,this.trackpadEventGap_=400,this.trackpadTimeoutId_,this.trackpadDeltaPerZoom_=300,this.trackpadZoomBuffer_=1.5}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.decrementInteractingHint_=function(){this.trackpadTimeoutId_=void 0,this.getMap().getView().setHint(j.a.INTERACTING,-1)},e.prototype.handleEvent=function(t){if(!this.condition_(t))return!0;var e=t.type;if(e!==l.a.WHEEL&&e!==l.a.MOUSEWHEEL)return!0;t.preventDefault();var i,n=t.map,r=t.originalEvent;if(this.useAnchor_&&(this.lastAnchor_=t.coordinate),t.type==l.a.WHEEL?(i=r.deltaY,c.c&&r.deltaMode===WheelEvent.DOM_DELTA_PIXEL&&(i/=c.b),r.deltaMode===WheelEvent.DOM_DELTA_LINE&&(i*=40)):t.type==l.a.MOUSEWHEEL&&(i=-r.wheelDeltaY,c.g&&(i/=3)),0===i)return!1;var o=Date.now();if(void 0===this.startTime_&&(this.startTime_=o),(!this.mode_||o-this.startTime_>this.trackpadEventGap_)&&(this.mode_=Math.abs(i)<4?St:It),this.mode_===St){var s=n.getView();this.trackpadTimeoutId_?clearTimeout(this.trackpadTimeoutId_):s.setHint(j.a.INTERACTING,1),this.trackpadTimeoutId_=setTimeout(this.decrementInteractingHint_.bind(this),this.trackpadEventGap_);var a=s.getResolution()*Math.pow(2,i/this.trackpadDeltaPerZoom_),h=s.getMinResolution(),u=s.getMaxResolution(),p=0;if(au&&(a=Math.min(a,u*this.trackpadZoomBuffer_),p=-1),this.lastAnchor_){var d=s.calculateCenterZoom(a,this.lastAnchor_);s.setCenter(s.constrainCenter(d))}return s.setResolution(a),0===p&&this.constrainResolution_&&s.animate({resolution:s.constrainResolution(a,i>0?-1:1),easing:W.b,anchor:this.lastAnchor_,duration:this.duration_}),p>0?s.animate({resolution:h,easing:W.b,anchor:this.lastAnchor_,duration:500}):p<0&&s.animate({resolution:u,easing:W.b,anchor:this.lastAnchor_,duration:500}),this.startTime_=o,!1}this.delta_+=i;var f=Math.max(this.timeout_-(o-this.startTime_),0);return clearTimeout(this.timeoutId_),this.timeoutId_=setTimeout(this.handleWheelZoom_.bind(this,n),f),!1},e.prototype.handleWheelZoom_=function(t){var e=t.getView();e.getAnimating()&&e.cancelAnimations();B(e,-Object(U.a)(this.delta_,-1,1),this.lastAnchor_,this.duration_),this.mode_=void 0,this.delta_=0,this.lastAnchor_=null,this.startTime_=void 0,this.timeoutId_=void 0},e.prototype.setMouseAnchor=function(t){this.useAnchor_=t,t||(this.lastAnchor_=null)},e}(q),wt=function(t){function e(e){var i=e||{},n=i;n.stopDown||(n.stopDown=M.a),t.call(this,n),this.anchor_=null,this.lastAngle_=void 0,this.rotating_=!1,this.rotationDelta_=0,this.threshold_=void 0!==i.threshold?i.threshold:.3,this.duration_=void 0!==i.duration?i.duration:250}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleDragEvent=function(t){var e=0,i=this.targetPointers[0],n=this.targetPointers[1],r=Math.atan2(n.clientY-i.clientY,n.clientX-i.clientX);if(void 0!==this.lastAngle_){var o=r-this.lastAngle_;this.rotationDelta_+=o,!this.rotating_&&Math.abs(this.rotationDelta_)>this.threshold_&&(this.rotating_=!0),e=o}this.lastAngle_=r;var s=t.map,a=s.getView();if(a.getConstraints().rotation!==ut.c){var h=s.getViewport().getBoundingClientRect(),c=ht(this.targetPointers);if(c[0]-=h.left,c[1]-=h.top,this.anchor_=s.getCoordinateFromPixel(c),this.rotating_){var l=a.getRotation();s.render(),H(a,l+e,this.anchor_)}}},e.prototype.handleUpEvent=function(t){if(this.targetPointers.length<2){var e=t.map.getView();if(e.setHint(j.a.INTERACTING,-1),this.rotating_)V(e,e.getRotation(),this.anchor_,this.duration_);return!1}return!0},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>=2){var e=t.map;return this.anchor_=null,this.lastAngle_=void 0,this.rotating_=!1,this.rotationDelta_=0,this.handlingDownUpSequence||e.getView().setHint(j.a.INTERACTING,1),!0}return!1},e}(ct),Lt=function(t){function e(e){var i=e||{},n=i;n.stopDown||(n.stopDown=M.a),t.call(this,n),this.constrainResolution_=i.constrainResolution||!1,this.anchor_=null,this.duration_=void 0!==i.duration?i.duration:400,this.lastDistance_=void 0,this.lastScaleDelta_=1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleDragEvent=function(t){var e=1,i=this.targetPointers[0],n=this.targetPointers[1],r=i.clientX-n.clientX,o=i.clientY-n.clientY,s=Math.sqrt(r*r+o*o);void 0!==this.lastDistance_&&(e=this.lastDistance_/s),this.lastDistance_=s;var a=t.map,h=a.getView(),c=h.getResolution(),l=h.getMaxResolution(),u=h.getMinResolution(),p=c*e;p>l?(e=l/c,p=l):pe.getMaxResolution()){var n=this.lastScaleDelta_-1;!function(t,e,i,n,r){Z(t,e=t.constrainResolution(e,0,r),i,n)}(e,i,this.anchor_,this.duration_,n)}return!1}return!0},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>=2){var e=t.map;return this.anchor_=null,this.lastDistance_=void 0,this.lastScaleDelta_=1,this.handlingDownUpSequence||e.getView().setHint(j.a.INTERACTING,1),!0}return!1},e}(ct);var Mt=i(40),Pt=function(t){function e(e,i,n,r){t.call(this),this.extent=e,this.pixelRatio_=n,this.resolution=i,this.state=r}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.changed=function(){this.dispatchEvent(l.a.CHANGE)},e.prototype.getExtent=function(){return this.extent},e.prototype.getImage=function(){return Object(n.b)()},e.prototype.getPixelRatio=function(){return this.pixelRatio_},e.prototype.getResolution=function(){return this.resolution},e.prototype.getState=function(){return this.state},e.prototype.load=function(){Object(n.b)()},e}(f.a),Ft=i(18),At=function(t){function e(e,i,n,r,o){var s=void 0!==o?Ft.a.IDLE:Ft.a.LOADED;t.call(this,e,i,n,s),this.loader_=void 0!==o?o:null,this.canvas_=r,this.error_=null}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getError=function(){return this.error_},e.prototype.handleLoad_=function(t){t?(this.error_=t,this.state=Ft.a.ERROR):this.state=Ft.a.LOADED,this.changed()},e.prototype.load=function(){this.state==Ft.a.IDLE&&(this.state=Ft.a.LOADING,this.changed(),this.loader_(this.handleLoad_.bind(this)))},e.prototype.getImage=function(){return this.canvas_},e}(Pt),Dt=i(37),Nt=i(15),kt=i(73),Gt=i(14),Yt=i(44),Xt=function(t){function e(e,i,n,r,o){t.call(this,e),this.vectorContext=i,this.frameState=n,this.context=r,this.glContext=o}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(s.a),zt=i(4),Wt=i(39),Kt=i(5),Ut=i(45),Vt=i(33),Ht=function(){};Ht.prototype.drawCustom=function(t,e,i){},Ht.prototype.drawGeometry=function(t){},Ht.prototype.setStyle=function(t){},Ht.prototype.drawCircle=function(t,e){},Ht.prototype.drawFeature=function(t,e){},Ht.prototype.drawGeometryCollection=function(t,e){},Ht.prototype.drawLineString=function(t,e){},Ht.prototype.drawMultiLineString=function(t,e){},Ht.prototype.drawMultiPoint=function(t,e){},Ht.prototype.drawMultiPolygon=function(t,e){},Ht.prototype.drawPoint=function(t,e){},Ht.prototype.drawPolygon=function(t,e){},Ht.prototype.drawText=function(t,e){},Ht.prototype.setFillStrokeStyle=function(t,e){},Ht.prototype.setImageStyle=function(t,e){},Ht.prototype.setTextStyle=function(t,e){};var Bt=Ht,Zt=function(t){function e(e,i,n,r,o){t.call(this),this.context_=e,this.pixelRatio_=i,this.extent_=n,this.transform_=r,this.viewRotation_=o,this.contextFillState_=null,this.contextStrokeState_=null,this.contextTextState_=null,this.fillState_=null,this.strokeState_=null,this.image_=null,this.imageAnchorX_=0,this.imageAnchorY_=0,this.imageHeight_=0,this.imageOpacity_=0,this.imageOriginX_=0,this.imageOriginY_=0,this.imageRotateWithView_=!1,this.imageRotation_=0,this.imageScale_=0,this.imageWidth_=0,this.text_="",this.textOffsetX_=0,this.textOffsetY_=0,this.textRotateWithView_=!1,this.textRotation_=0,this.textScale_=0,this.textFillState_=null,this.textStrokeState_=null,this.textState_=null,this.pixelCoordinates_=[],this.tmpLocalTransform_=Object(k.c)()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.drawImages_=function(t,e,i,n){if(this.image_){var r=Object(Vt.c)(t,e,i,2,this.transform_,this.pixelCoordinates_),o=this.context_,s=this.tmpLocalTransform_,a=o.globalAlpha;1!=this.imageOpacity_&&(o.globalAlpha=a*this.imageOpacity_);var h=this.imageRotation_;this.imageRotateWithView_&&(h+=this.viewRotation_);for(var c=0,l=r.length;c=0;--h){var d=l[h],f=d.layer;if(Object(Yt.b)(d,c)&&o.call(s,f))if(a=this.getLayerRenderer(f).forEachLayerAtCoordinate(p,e,i,n,r))return a}},e.prototype.registerLayerRenderers=function(e){t.prototype.registerLayerRenderers.call(this,e);for(var i=0,n=e.length;if[2])d=[g+_*Math.ceil((f[0]-g)/_),t[1]]}var v,y=e.layerStatesArray;for(v=y.length-1;v>=0;--v){var m=y[v],b=m.layer;if(Object(Yt.b)(m,l)&&s.call(a,b)){var O=this.getLayerRenderer(b),E=b.getSource();if(E&&(h=O.forEachFeatureAtCoordinate(E.getWrapX()?d:t,e,i,u)),h)return h}}},e.prototype.forEachLayerAtPixel=function(t,e,i,r,o,s,a){return Object(n.b)()},e.prototype.hasFeatureAtCoordinate=function(t,e,i,n,r){return void 0!==this.forEachFeatureAtCoordinate(t,e,i,M.b,this,n,r)},e.prototype.getLayerRenderer=function(t){var e=Object(n.c)(t);if(e in this.layerRenderers_)return this.layerRenderers_[e];for(var i,r=0,o=this.layerRendererConstructors_.length;r=.5&&u>=.5&&i.drawImage(n,0,0,+n.width,+n.height,Math.round(h),Math.round(c),Math.round(l),Math.round(u)),i.globalAlpha=a,o&&i.restore()}this.postCompose(i,t,e)},e.prototype.getImage=function(){return Object(n.b)()},e.prototype.getImageTransform=function(){return Object(n.b)()},e.prototype.forEachLayerAtCoordinate=function(t,e,i,n,r){if(this.getImage()){var o=Object(k.a)(this.coordinateToCanvasPixelTransform,t.slice());Object($.d)(o,e.viewState.resolution/this.renderedResolution),this.hitCanvasContext_||(this.hitCanvasContext_=Object(w.a)(1,1)),this.hitCanvasContext_.clearRect(0,0,1,1),this.hitCanvasContext_.drawImage(this.getImage(),o[0],o[1],1,1,0,0,1,1);var s=this.hitCanvasContext_.getImageData(0,0,1,1).data;return s[3]>0?n.call(r,this.getLayer(),s):void 0}},e}(ee),ne=function(t){function e(i){if(t.call(this,i),this.image_=null,this.imageTransform_=Object(k.c)(),this.skippedFeatures_=[],this.vectorRenderer_=null,i.getType()===Dt.a.VECTOR)for(var n=0,r=$t.length;n0&&(this.newTiles_=!0):s.setState(T.a.LOADED)),this.isDrawableTile_(s)||(s=s.getInterimTile()),s},e.prototype.prepareFrame=function(t,e){var i=t.pixelRatio,r=t.size,o=t.viewState,s=o.projection,a=o.resolution,h=o.center,c=this.getLayer(),l=c.getSource(),u=l.getRevision(),p=l.getTileGridForProjection(s),d=p.getZForResolution(a,this.zDirection),f=p.getResolution(d),_=Math.round(a/f)||1,g=t.extent;if(void 0!==e.extent&&(g=Object(L.B)(g,e.extent)),Object(L.H)(g))return!1;var v=p.getTileRangeForExtentAndZ(g,d),y=p.getTileRangeExtent(d,v),m=l.getTilePixelRatio(i),b={};b[d]={};var O,E,x,C=this.createLoadedTileFinder(l,s,b),R=t.viewHints,S=R[j.a.ANIMATING]||R[j.a.INTERACTING],I=this.tmpExtent,w=this.tmpTileRange_;for(this.newTiles_=!1,E=v.minX;E<=v.maxX;++E)for(x=v.minY;x<=v.maxY;++x)if(!(Date.now()-t.time>16&&S)){if(O=this.getTile(d,E,x,i,s),this.isDrawableTile_(O)){var M=Object(n.c)(this);if(O.getState()==T.a.LOADED){b[d][O.tileCoord.toString()]=O;var P=O.inTransition(M);this.newTiles_||!P&&-1!==this.renderedTiles.indexOf(O)||(this.newTiles_=!0)}if(1===O.getAlpha(M,t.time))continue}var F=p.getTileCoordChildTileRange(O.tileCoord,w,I),A=!1;F&&(A=C(d+1,F)),A||p.forEachTileCoordParentTileRange(O.tileCoord,C,null,w,I)}var D=f*i/m*_;if(!(this.renderedResolution&&Date.now()-t.time>16&&S)&&(this.newTiles_||!this.renderedExtent_||!Object(L.g)(this.renderedExtent_,g)||this.renderedRevision!=u||_!=this.oversampling_||!S&&D!=this.renderedResolution)){var N=this.context;if(N){var G=l.getTilePixelSize(d,i,s),Y=Math.round(v.getWidth()*G[0]/_),X=Math.round(v.getHeight()*G[1]/_),z=N.canvas;z.width!=Y||z.height!=X?(this.oversampling_=_,z.width=Y,z.height=X):(this.renderedExtent_&&!Object(L.p)(y,this.renderedExtent_)&&N.clearRect(0,0,Y,X),_=this.oversampling_)}this.renderedTiles.length=0;var W,K,U,V,H,B,Z,q,J,Q,$=Object.keys(b).map(Number);for($.sort(function(t,e){return t===d?1:e===d?-1:t>e?1:t0},e.prototype.drawTileImage=function(t,e,i,r,o,s,a,h,c){var l=this.getTileImage(t);if(l){var u=Object(n.c)(this),p=c?t.getAlpha(u,e.time):1,d=this.getLayer().getSource();1!==p||d.getOpaque(e.viewState.projection)||this.context.clearRect(r,o,s,a);var f=p!==this.context.globalAlpha;f&&(this.context.save(),this.context.globalAlpha=p),this.context.drawImage(l,h,h,l.width-2*h,l.height-2*h,r,o,s,a),f&&this.context.restore(),1!==p?e.animate=!0:c&&t.endTransition(u)}},e.prototype.getImage=function(){var t=this.context;return t?t.canvas:null},e.prototype.getImageTransform=function(){return this.imageTransform_},e.prototype.getTileImage=function(t){return t.getImage()},e}(ie);se.handles=function(t){return t.getType()===Dt.a.TILE},se.create=function(t,e){return new se(e)},se.prototype.getLayer;var ae=se,he=i(57),ce=i.n(he),le=function(){};le.prototype.getReplay=function(t,e){return Object(n.b)()},le.prototype.isEmpty=function(){return Object(n.b)()},le.prototype.addDeclutter=function(t){return Object(n.b)()};var ue=le,pe={CIRCLE:"Circle",DEFAULT:"Default",IMAGE:"Image",LINE_STRING:"LineString",POLYGON:"Polygon",TEXT:"Text"},de=i(27),fe=i(47),_e=i(74);function ge(t,e,i,n,r,o,s,a){for(var h,c,l,u=[],p=t[e]>t[i-n],d=r.length,f=t[e],_=t[e+1],g=t[e+=n],v=t[e+1],y=0,m=Math.sqrt(Math.pow(g-f,2)+Math.pow(v-_,2)),b="",O=0,E=0;E0?-Math.PI:Math.PI),void 0!==l){var I=S-l;if(I+=I>Math.PI?-2*Math.PI:I<-Math.PI?2*Math.PI:0,Math.abs(I)>a)return null}var j=R/m,w=Object(U.c)(f,g,j),L=Object(U.c)(_,v,j);l==S?(p&&(h[0]=w,h[1]=L,h[2]=x/2),h[4]=b):(O=x,h=[w,L,x/2,S,b=T],p?u.unshift(h):u.push(h),l=S),s+=x}return u}var ve={BEGIN_GEOMETRY:0,BEGIN_PATH:1,CIRCLE:2,CLOSE_PATH:3,CUSTOM:4,DRAW_CHARS:5,DRAW_IMAGE:6,END_GEOMETRY:7,FILL:8,MOVE_TO_LINE_TO:9,SET_FILL_STYLE:10,SET_STROKE_STYLE:11,STROKE:12},ye=[ve.FILL],me=[ve.STROKE],be=[ve.BEGIN_PATH],Oe=[ve.CLOSE_PATH],Ee=ve,Te=[pe.POLYGON,pe.CIRCLE,pe.LINE_STRING,pe.IMAGE,pe.TEXT,pe.DEFAULT],xe={left:0,end:0,center:.5,right:1,start:1,top:0,middle:.5,hanging:.2,alphabetic:.8,ideographic:.8,bottom:1},Ce=Object(L.j)(),Re=Object(k.c)(),Se=function(t){function e(e,i,n,r,o,s){t.call(this),this.declutterTree=s,this.tolerance=e,this.maxExtent=i,this.overlaps=o,this.pixelRatio=r,this.maxLineWidth=0,this.resolution=n,this.alignFill_,this.beginGeometryInstruction1_=null,this.beginGeometryInstruction2_=null,this.bufferedMaxExtent_=null,this.instructions=[],this.coordinates=[],this.coordinateCache_={},this.renderedTransform_=Object(k.c)(),this.hitDetectionInstructions=[],this.pixelCoordinates_=null,this.state={},this.viewRotation_=0}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.replayTextBackground_=function(t,e,i,n,r,o,s){t.beginPath(),t.moveTo.apply(t,e),t.lineTo.apply(t,i),t.lineTo.apply(t,n),t.lineTo.apply(t,r),t.lineTo.apply(t,e),o&&(this.alignFill_=o[2],this.fill_(t)),s&&(this.setStrokeStyle_(t,s),t.stroke())},e.prototype.replayImage_=function(t,e,i,n,r,o,s,a,h,c,l,u,p,d,f,_,g,v){var y=g||v;e-=r*=p,i-=o*=p;var m,b,O,E,T=f+c>n.width?n.width-c:f,x=a+l>n.height?n.height-l:a,C=_[3]+T*p+_[1],R=_[0]+x*p+_[2],S=e-_[3],I=i-_[0];(y||0!==u)&&(m=[S,I],b=[S+C,I],O=[S+C,I+R],E=[S,I+R]);var j=null;if(0!==u){var w=e+r,M=i+o;j=Object(k.b)(Re,w,M,1,1,u,-w,-M),Object(L.l)(Ce),Object(L.r)(Ce,Object(k.a)(Re,m)),Object(L.r)(Ce,Object(k.a)(Re,b)),Object(L.r)(Ce,Object(k.a)(Re,O)),Object(L.r)(Ce,Object(k.a)(Re,E))}else Object(L.k)(S,I,S+C,I+R,Ce);var P=t.canvas,F=v?v[2]*p/2:0,A=Ce[0]-F<=P.width&&Ce[2]+F>=0&&Ce[1]-F<=P.height&&Ce[3]+F>=0;if(d&&(e=Math.round(e),i=Math.round(i)),s){if(!A&&1==s[4])return;Object(L.q)(s,Ce);var D=A?[t,j?j.slice(0):null,h,n,c,l,T,x,e,i,p]:null;D&&y&&D.push(g,v,m,b,O,E),s.push(D)}else A&&(y&&this.replayTextBackground_(t,m,b,O,E,g,v),Object(zt.n)(t,j,h,n,c,l,T,x,e,i,p))},e.prototype.applyPixelRatio=function(t){var e=this.pixelRatio;return 1==e?t:t.map(function(t){return t*e})},e.prototype.appendFlatCoordinates=function(t,e,i,n,r,o){var s=this.coordinates.length,a=this.getBufferedMaxExtent();o&&(e+=n);var h,c,l,u=[t[e],t[e+1]],p=[NaN,NaN],d=!0;for(h=e+n;h5){var i=t[4];if(1==i||i==t.length-5){var n={minX:t[0],minY:t[1],maxX:t[2],maxY:t[3],value:e};if(!this.declutterTree.collides(n)){this.declutterTree.insert(n);for(var r=5,o=t.length;r11&&this.replayTextBackground_(s[0],s[13],s[14],s[15],s[16],s[11],s[12]),zt.n.apply(void 0,s))}}t.length=5,Object(L.l)(t)}}},e.prototype.replay_=function(t,e,i,r,o,s,a){var h;this.pixelCoordinates_&&Object(Nt.b)(e,this.renderedTransform_)?h=this.pixelCoordinates_:(this.pixelCoordinates_||(this.pixelCoordinates_=[]),h=Object(Vt.c)(this.coordinates,0,this.coordinates.length,2,e,this.pixelCoordinates_),Object(k.g)(this.renderedTransform_,e));for(var c,l,u,p,d,f,_,g,v,y,m,b,O=!Object(C.d)(i),E=0,T=r.length,x=0,R=0,S=0,I=null,j=null,w=this.coordinateCache_,M=this.viewRotation_,P={context:t,pixelRatio:this.pixelRatio,resolution:this.resolution,rotation:M},F=this.instructions!=r||this.overlaps?0:200;EF&&(this.fill_(t),R=0),S>F&&(t.stroke(),S=0),R||S||(t.beginPath(),p=d=NaN),++E;break;case Ee.CIRCLE:var D=h[x=A[1]],N=h[x+1],G=h[x+2]-D,Y=h[x+3]-N,X=Math.sqrt(G*G+Y*Y);t.moveTo(D+X,N),t.arc(D,N,X,0,2*Math.PI,!0),++E;break;case Ee.CLOSE_PATH:t.closePath(),++E;break;case Ee.CUSTOM:x=A[1],c=A[2];var z=A[3],W=A[4],K=6==A.length?A[5]:void 0;P.geometry=z,P.feature=y,E in w||(w[E]=[]);var U=w[E];K?K(h,x,c,2,U):(U[0]=h[x],U[1]=h[x+1],U.length=2),W(U,P),++E;break;case Ee.DRAW_IMAGE:x=A[1],c=A[2],v=A[3],l=A[4],u=A[5],g=s?null:A[6];var V=A[7],H=A[8],B=A[9],Z=A[10],q=A[11],J=A[12],Q=A[13],$=A[14],tt=void 0,et=void 0,it=void 0;for(A.length>16?(tt=A[15],et=A[16],it=A[17]):(tt=zt.j,et=it=!1),q&&(J+=M);xthis.maxLineWidth&&(this.maxLineWidth=i.lineWidth,this.bufferedMaxExtent_=null)}else i.strokeStyle=void 0,i.lineCap=void 0,i.lineDash=null,i.lineDashOffset=void 0,i.lineJoin=void 0,i.lineWidth=void 0,i.miterLimit=void 0},e.prototype.createFill=function(t,e){var i=t.fillStyle,n=[Ee.SET_FILL_STYLE,i];return"string"!=typeof i&&n.push(!0),n},e.prototype.applyStroke=function(t){this.instructions.push(this.createStroke(t))},e.prototype.createStroke=function(t){return[Ee.SET_STROKE_STYLE,t.strokeStyle,t.lineWidth*this.pixelRatio,t.lineCap,t.lineJoin,t.miterLimit,this.applyPixelRatio(t.lineDash),t.lineDashOffset*this.pixelRatio]},e.prototype.updateFillStyle=function(t,e,i){var n=t.fillStyle;"string"==typeof n&&t.currentFillStyle==n||(void 0!==n&&this.instructions.push(e.call(this,t,i)),t.currentFillStyle=n)},e.prototype.updateStrokeStyle=function(t,e){var i=t.strokeStyle,n=t.lineCap,r=t.lineDash,o=t.lineDashOffset,s=t.lineJoin,a=t.lineWidth,h=t.miterLimit;(t.currentStrokeStyle!=i||t.currentLineCap!=n||r!=t.currentLineDash&&!Object(Nt.b)(t.currentLineDash,r)||t.currentLineDashOffset!=o||t.currentLineJoin!=s||t.currentLineWidth!=a||t.currentMiterLimit!=h)&&(void 0!==i&&e.call(this,t),t.currentStrokeStyle=i,t.currentLineCap=n,t.currentLineDash=r,t.currentLineDashOffset=o,t.currentLineJoin=s,t.currentLineWidth=a,t.currentMiterLimit=h)},e.prototype.endGeometry=function(t,e){this.beginGeometryInstruction1_[2]=this.instructions.length,this.beginGeometryInstruction1_=null,this.beginGeometryInstruction2_[2]=this.hitDetectionInstructions.length,this.beginGeometryInstruction2_=null;var i=[Ee.END_GEOMETRY,e];this.instructions.push(i),this.hitDetectionInstructions.push(i)},e.prototype.getBufferedMaxExtent=function(){if(!this.bufferedMaxExtent_&&(this.bufferedMaxExtent_=Object(L.d)(this.maxExtent),this.maxLineWidth>0)){var t=this.resolution*(this.maxLineWidth+1)/2;Object(L.c)(this.bufferedMaxExtent_,t,this.bufferedMaxExtent_)}return this.bufferedMaxExtent_},e}(Bt),Ie=function(t){function e(e,i,n,r,o,s){t.call(this,e,i,n,r,o,s),this.declutterGroup_=null,this.hitDetectionImage_=null,this.image_=null,this.anchorX_=void 0,this.anchorY_=void 0,this.height_=void 0,this.opacity_=void 0,this.originX_=void 0,this.originY_=void 0,this.rotateWithView_=void 0,this.rotation_=void 0,this.scale_=void 0,this.width_=void 0}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.drawCoordinates_=function(t,e,i,n){return this.appendFlatCoordinates(t,e,i,n,!1,!1)},e.prototype.drawPoint=function(t,e){if(this.image_){this.beginGeometry(t,e);var i=t.getFlatCoordinates(),n=t.getStride(),r=this.coordinates.length,o=this.drawCoordinates_(i,0,i.length,n);this.instructions.push([Ee.DRAW_IMAGE,r,o,this.image_,this.anchorX_,this.anchorY_,this.declutterGroup_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_*this.pixelRatio,this.width_]),this.hitDetectionInstructions.push([Ee.DRAW_IMAGE,r,o,this.hitDetectionImage_,this.anchorX_,this.anchorY_,this.declutterGroup_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_,this.width_]),this.endGeometry(t,e)}},e.prototype.drawMultiPoint=function(t,e){if(this.image_){this.beginGeometry(t,e);var i=t.getFlatCoordinates(),n=t.getStride(),r=this.coordinates.length,o=this.drawCoordinates_(i,0,i.length,n);this.instructions.push([Ee.DRAW_IMAGE,r,o,this.image_,this.anchorX_,this.anchorY_,this.declutterGroup_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_*this.pixelRatio,this.width_]),this.hitDetectionInstructions.push([Ee.DRAW_IMAGE,r,o,this.hitDetectionImage_,this.anchorX_,this.anchorY_,this.declutterGroup_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_,this.width_]),this.endGeometry(t,e)}},e.prototype.finish=function(){this.reverseHitDetectionInstructions(),this.anchorX_=void 0,this.anchorY_=void 0,this.hitDetectionImage_=null,this.image_=null,this.height_=void 0,this.scale_=void 0,this.opacity_=void 0,this.originX_=void 0,this.originY_=void 0,this.rotateWithView_=void 0,this.rotation_=void 0,this.width_=void 0},e.prototype.setImageStyle=function(t,e){var i=t.getAnchor(),n=t.getSize(),r=t.getHitDetectionImage(1),o=t.getImage(1),s=t.getOrigin();this.anchorX_=i[0],this.anchorY_=i[1],this.declutterGroup_=e,this.hitDetectionImage_=r,this.image_=o,this.height_=n[1],this.opacity_=t.getOpacity(),this.originX_=s[0],this.originY_=s[1],this.rotateWithView_=t.getRotateWithView(),this.rotation_=t.getRotation(),this.scale_=t.getScale(),this.width_=n[0]},e}(Se),je=function(t){function e(e,i,n,r,o,s){t.call(this,e,i,n,r,o,s)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.drawFlatCoordinates_=function(t,e,i,n){var r=this.coordinates.length,o=this.appendFlatCoordinates(t,e,i,n,!1,!1),s=[Ee.MOVE_TO_LINE_TO,r,o];return this.instructions.push(s),this.hitDetectionInstructions.push(s),i},e.prototype.drawLineString=function(t,e){var i=this.state,n=i.strokeStyle,r=i.lineWidth;if(void 0!==n&&void 0!==r){this.updateStrokeStyle(i,this.applyStroke),this.beginGeometry(t,e),this.hitDetectionInstructions.push([Ee.SET_STROKE_STYLE,i.strokeStyle,i.lineWidth,i.lineCap,i.lineJoin,i.miterLimit,i.lineDash,i.lineDashOffset],be);var o=t.getFlatCoordinates(),s=t.getStride();this.drawFlatCoordinates_(o,0,o.length,s),this.hitDetectionInstructions.push(me),this.endGeometry(t,e)}},e.prototype.drawMultiLineString=function(t,e){var i=this.state,n=i.strokeStyle,r=i.lineWidth;if(void 0!==n&&void 0!==r){this.updateStrokeStyle(i,this.applyStroke),this.beginGeometry(t,e),this.hitDetectionInstructions.push([Ee.SET_STROKE_STYLE,i.strokeStyle,i.lineWidth,i.lineCap,i.lineJoin,i.miterLimit,i.lineDash,i.lineDashOffset],be);for(var o=t.getEnds(),s=t.getFlatCoordinates(),a=t.getStride(),h=0,c=0,l=o.length;ct&&(v>g&&(g=v,f=y,_=o),v=0,y=o-r)),s=a,l=p,u=d),h=m,c=b}return(v+=a)>g?[y,o]:[f,_]}var Fe="line";var Ae={Circle:Me,Default:Se,Image:Ie,LineString:je,Polygon:Me,Text:function(t){function e(e,i,n,r,o,s){t.call(this,e,i,n,r,o,s),this.declutterGroup_,this.labels_=null,this.text_="",this.textOffsetX_=0,this.textOffsetY_=0,this.textRotateWithView_=void 0,this.textRotation_=0,this.textFillState_=null,this.fillStates={},this.textStrokeState_=null,this.strokeStates={},this.textState_={},this.textStates={},this.textKey_="",this.fillKey_="",this.strokeKey_="",this.widths_={},zt.o.prune()}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.drawText=function(t,e){var i=this.textFillState_,n=this.textStrokeState_,r=this.textState_;if(""!==this.text_&&r&&(i||n)){var o,s,a=this.coordinates.length,h=t.getType(),c=null,l=2,u=2;if(r.placement===Fe){if(!Object(L.F)(this.getBufferedMaxExtent(),t.getExtent()))return;var p;if(c=t.getFlatCoordinates(),u=t.getStride(),h==Kt.a.LINE_STRING)p=[c.length];else if(h==Kt.a.MULTI_LINE_STRING)p=t.getEnds();else if(h==Kt.a.POLYGON)p=t.getEnds().slice(0,1);else if(h==Kt.a.MULTI_POLYGON){var d=t.getEndss();for(p=[],o=0,s=d.length;o=O)&&c.push(E[o],E[o+1]);if(0==(l=c.length))return}l=this.appendFlatCoordinates(c,0,l,u,!1,!1),(r.backgroundFill||r.backgroundStroke)&&(this.setFillStrokeStyle(r.backgroundFill,r.backgroundStroke),r.backgroundFill&&(this.updateFillStyle(this.state,this.createFill,t),this.hitDetectionInstructions.push(this.createFill(this.state,t))),r.backgroundStroke&&(this.updateStrokeStyle(this.state,this.applyStroke),this.hitDetectionInstructions.push(this.createStroke(this.state)))),this.beginGeometry(t,e),this.drawTextImage_(b,a,l),this.endGeometry(t,e)}}},e.prototype.getImage=function(t,e,i,n){var r,o=n+e+t+i+this.pixelRatio;if(!zt.o.containsKey(o)){var s=n?this.strokeStates[n]||this.textStrokeState_:null,a=i?this.fillStates[i]||this.textFillState_:null,h=this.textStates[e]||this.textState_,l=this.pixelRatio,u=h.scale*l,p=xe[h.textAlign||zt.l],d=n&&s.lineWidth?s.lineWidth:0,f=t.split("\n"),_=f.length,g=[],v=function(t,e,i){for(var n=e.length,r=0,o=0;o=o;)ke(i,t+r,t+o),ke(i,t+o,t+r),ke(i,t-o,t+r),ke(i,t-r,t+o),ke(i,t-r,t-o),ke(i,t-o,t-r),ke(i,t+o,t-r),ke(i,t+r,t-o),2*((s+=1+2*++o)-r)+1>0&&(s+=1-2*(r-=1));return Ne[t]=i,i}(n);function f(t){for(var e=l.getImageData(0,0,h,h).data,i=0;i0){var r=void 0;return(!u||p!=pe.IMAGE&&p!=pe.TEXT||-1!==u.indexOf(t))&&(r=o(t)),r||void l.clearRect(0,0,h,h)}}this.declutterTree_&&(u=this.declutterTree_.all().map(function(t){return t.value}));var _,g,v,y,m,b=Object.keys(this.replaysByZIndex_).map(Number);for(b.sort(Nt.g),_=b.length-1;_>=0;--_){var O=b[_].toString();for(v=this.replaysByZIndex_[O],g=Te.length-1;g>=0;--g)if(void 0!==(y=v[p=Te[g]]))if(!s||p!=pe.IMAGE&&p!=pe.TEXT){if(m=y.replayHitDetection(l,c,i,r,f,a))return m}else{var E=s[O];E?E.push(y,c.slice(0)):s[O]=[y,c.slice(0)]}}},e.prototype.getClipCoords=function(t){var e=this.maxExtent_,i=e[0],n=e[1],r=e[2],o=e[3],s=[i,n,i,o,r,o,r,n];return Object(Vt.c)(s,0,8,2,t,s),s},e.prototype.getReplay=function(t,e){var i=void 0!==t?t.toString():"0",n=this.replaysByZIndex_[i];void 0===n&&(n={},this.replaysByZIndex_[i]=n);var r=n[e];void 0===r&&(r=new(0,Ae[e])(this.tolerance_,this.maxExtent_,this.resolution_,this.pixelRatio_,this.overlaps_,this.declutterTree_),n[e]=r);return r},e.prototype.getReplays=function(){return this.replaysByZIndex_},e.prototype.isEmpty=function(){return Object(C.d)(this.replaysByZIndex_)},e.prototype.replay=function(t,e,i,n,r,o,s){var a=Object.keys(this.replaysByZIndex_).map(Number);a.sort(Nt.g),t.save(),this.clip(t,e);var h,c,l,u,p,d,f=o||Te;for(h=0,c=a.length;h=r)for(n=r;nc[2];)M=F*++A,u=this.getTransform(e,M),f.replay(_,u,h,o,S),P-=F}if(Object(zt.s)(_,h,I/2,w/2),O&&this.dispatchRenderEvent(_,e,u),_!=t){if(m){var D=t.globalAlpha;t.globalAlpha=i.opacity,t.drawImage(_.canvas,-v,-y),t.globalAlpha=D}else t.drawImage(_.canvas,-v,-y);_.translate(-v,-y)}m||(_.globalAlpha=C)}d&&t.restore()},e.prototype.composeFrame=function(t,e,i){var n=this.getTransform(t,0);this.preCompose(i,t,n),this.compose(i,t,e),this.postCompose(i,t,e,n)},e.prototype.forEachFeatureAtCoordinate=function(t,e,i,r,o){if(this.replayGroup_){var s=e.viewState.resolution,a=e.viewState.rotation,h=this.getLayer(),c={};return this.replayGroup_.forEachFeatureAtCoordinate(t,s,a,i,{},function(t){var e=Object(n.c)(t);if(!(e in c))return c[e]=!0,r.call(o,t,h)},null)}},e.prototype.handleFontsChanged_=function(t){var e=this.getLayer();e.getVisible()&&this.replayGroup_&&e.changed()},e.prototype.handleStyleImageChange_=function(t){this.renderIfReadyAndVisible()},e.prototype.prepareFrame=function(t,e){var i=this.getLayer(),n=i.getSource(),r=t.viewHints[j.a.ANIMATING],o=t.viewHints[j.a.INTERACTING],s=i.getUpdateWhileAnimating(),a=i.getUpdateWhileInteracting();if(!this.dirty_&&!s&&r||!a&&o)return!0;var h=t.extent,c=t.viewState,l=c.projection,u=c.resolution,p=t.pixelRatio,d=i.getRevision(),f=i.getRenderBuffer(),_=i.getRenderOrder();void 0===_&&(_=ze);var g=Object(L.c)(h,f*u),v=c.projection.getExtent();if(n.getWrapX()&&c.projection.canWrapX()&&!Object(L.g)(v,t.extent)){var y=Object(L.E)(v),m=Math.max(Object(L.E)(g)/2,y);g[0]=v[0]-m,g[2]=v[2]+m}if(!this.dirty_&&this.renderedResolution_==u&&this.renderedRevision_==d&&this.renderedRenderOrder_==_&&Object(L.g)(this.renderedExtent_,g))return this.replayGroupChanged=!1,!0;this.replayGroup_=null,this.dirty_=!1;var b=new Ge(Ke(u,p),g,u,p,n.getOverlaps(),this.declutterTree_,i.getRenderBuffer());n.loadFeatures(g,u,l);var O=function(t){var e,n=t.getStyleFunction()||i.getStyleFunction();if(n&&(e=n(t,u)),e){var r=this.renderFeature(t,u,p,e,b);this.dirty_=this.dirty_||r}}.bind(this);if(_){var E=[];n.forEachFeatureInExtent(g,function(t){E.push(t)}),E.sort(_);for(var T=0,x=E.length;T=0;--b){var O=g[b];if(O.getState()!=T.a.ABORT)for(var E=O.tileCoord,x=v.getTileCoordExtent(E,this.tmpExtent)[0]-O.extent[0],C=void 0,R=0,S=O.tileKeys.length;R=this.transition_?1:Object(s.a)(n/this.transition_)},e.prototype.inTransition=function(t){return!!this.transition_&&-1!==this.transitionStarts_[t]},e.prototype.endTransition=function(t){this.transition_&&(this.transitionStarts_[t]=-1)},e}(a.a),l=i(10),u=i(1);function p(){var t=Object(l.a)(1,1);return t.fillStyle="rgba(0,0,0,0)",t.fillRect(0,0,1,1),t.canvas}var d=function(t){function e(e,i,n,r,o,s){t.call(this,e,i,s),this.crossOrigin_=r,this.src_=n,this.image_=new Image,null!==r&&(this.image_.crossOrigin=r),this.imageListenerKeys_=null,this.tileLoadFunction_=o}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.disposeInternal=function(){this.state==o.a.LOADING&&(this.unlistenImage_(),this.image_=p()),this.interimTile&&this.interimTile.dispose(),this.state=o.a.ABORT,this.changed(),t.prototype.disposeInternal.call(this)},e.prototype.getImage=function(){return this.image_},e.prototype.getKey=function(){return this.src_},e.prototype.handleImageError_=function(){this.state=o.a.ERROR,this.unlistenImage_(),this.image_=p(),this.changed()},e.prototype.handleImageLoad_=function(){var t=this.image_;t.naturalWidth&&t.naturalHeight?this.state=o.a.LOADED:this.state=o.a.EMPTY,this.unlistenImage_(),this.changed()},e.prototype.load=function(){this.state==o.a.ERROR&&(this.state=o.a.IDLE,this.image_=new Image,null!==this.crossOrigin_&&(this.image_.crossOrigin=this.crossOrigin_)),this.state==o.a.IDLE&&(this.state=o.a.LOADING,this.changed(),this.imageListenerKeys_=[Object(u.b)(this.image_,h.a.ERROR,this.handleImageError_,this),Object(u.b)(this.image_,h.a.LOAD,this.handleImageLoad_,this)],this.tileLoadFunction_(this,this.src_))},e.prototype.unlistenImage_=function(){this.imageListenerKeys_.forEach(u.e),this.imageListenerKeys_=null},e}(c);function f(t,e,i,n){return void 0!==n?(n[0]=t,n[1]=e,n[2]=i,n):[t,e,i]}function _(t,e,i){return t+"/"+e+"/"+i}function g(t){return _(t[0],t[1],t[2])}var v=function(t){function e(e){t.call(this,e)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.expireCache=function(t){for(;this.canExpireCache();){var e=this.peekLast(),i=e.tileCoord[0].toString();if(i in t&&t[i].contains(e.tileCoord))break;this.pop().dispose()}},e.prototype.pruneExceptNewestZ=function(){if(0!==this.getCount()){var t=function(t){return t.split("/").map(Number)}(this.peekFirstKey())[0];this.forEach(function(e){e.tileCoord[0]!==t&&(this.remove(g(e.tileCoord)),e.dispose())},this)}},e}(i(72).a),y=i(16),m=i(0),b=i(6);function O(t,e,i,n){var r=i-t,o=n-e,s=Math.sqrt(r*r+o*o);return[Math.round(i+r/s),Math.round(n+o/s)]}var E=function(t,e,i,n,r){this.sourceProj_=t,this.targetProj_=e;var o={},s=Object(y.getTransform)(this.targetProj_,this.sourceProj_);this.transformInv_=function(t){var e=t[0]+"/"+t[1];return o[e]||(o[e]=s(t)),o[e]},this.maxSourceExtent_=n,this.errorThresholdSquared_=r*r,this.triangles_=[],this.wrapsXInSource_=!1,this.canWrapXInSource_=this.sourceProj_.canWrapX()&&!!n&&!!this.sourceProj_.getExtent()&&Object(m.E)(n)==Object(m.E)(this.sourceProj_.getExtent()),this.sourceWorldWidth_=this.sourceProj_.getExtent()?Object(m.E)(this.sourceProj_.getExtent()):null,this.targetWorldWidth_=this.targetProj_.getExtent()?Object(m.E)(this.targetProj_.getExtent()):null;var a=Object(m.C)(i),h=Object(m.D)(i),c=Object(m.w)(i),l=Object(m.v)(i),u=this.transformInv_(a),p=this.transformInv_(h),d=this.transformInv_(c),f=this.transformInv_(l);if(this.addQuad_(a,h,c,l,u,p,d,f,10),this.wrapsXInSource_){var _=1/0;this.triangles_.forEach(function(t,e,i){_=Math.min(_,t.source[0][0],t.source[1][0],t.source[2][0])}),this.triangles_.forEach(function(t){if(Math.max(t.source[0][0],t.source[1][0],t.source[2][0])-_>this.sourceWorldWidth_/2){var e=[[t.source[0][0],t.source[0][1]],[t.source[1][0],t.source[1][1]],[t.source[2][0],t.source[2][1]]];e[0][0]-_>this.sourceWorldWidth_/2&&(e[0][0]-=this.sourceWorldWidth_),e[1][0]-_>this.sourceWorldWidth_/2&&(e[1][0]-=this.sourceWorldWidth_),e[2][0]-_>this.sourceWorldWidth_/2&&(e[2][0]-=this.sourceWorldWidth_);var i=Math.min(e[0][0],e[1][0],e[2][0]);Math.max(e[0][0],e[1][0],e[2][0])-i.5&&l<1,d=!1;if(h>0){if(this.targetProj_.isGlobal()&&this.targetWorldWidth_){var f=Object(m.b)([t,e,i,n]);d=Object(m.E)(f)/this.targetWorldWidth_>.25||d}!p&&this.sourceProj_.isGlobal()&&l&&(d=l>.25||d)}if(d||!this.maxSourceExtent_||Object(m.F)(c,this.maxSourceExtent_)){if(!(d||isFinite(r[0])&&isFinite(r[1])&&isFinite(o[0])&&isFinite(o[1])&&isFinite(s[0])&&isFinite(s[1])&&isFinite(a[0])&&isFinite(a[1]))){if(!(h>0))return;d=!0}if(h>0){if(!d){var _,g=[(t[0]+i[0])/2,(t[1]+i[1])/2],v=this.transformInv_(g);if(p)_=(Object(b.d)(r[0],u)+Object(b.d)(s[0],u))/2-Object(b.d)(v[0],u);else _=(r[0]+s[0])/2-v[0];var y=(r[1]+s[1])/2-v[1];d=_*_+y*y>this.errorThresholdSquared_}if(d){if(Math.abs(t[0]-i[0])<=Math.abs(t[1]-i[1])){var O=[(e[0]+i[0])/2,(e[1]+i[1])/2],E=this.transformInv_(O),T=[(n[0]+t[0])/2,(n[1]+t[1])/2],x=this.transformInv_(T);this.addQuad_(t,e,O,T,r,o,E,x,h-1),this.addQuad_(T,O,i,n,x,E,s,a,h-1)}else{var C=[(t[0]+e[0])/2,(t[1]+e[1])/2],R=this.transformInv_(C),S=[(i[0]+n[0])/2,(i[1]+n[1])/2],I=this.transformInv_(S);this.addQuad_(t,C,S,n,r,R,I,a,h-1),this.addQuad_(C,e,i,S,R,o,s,I,h-1)}return}}if(p){if(!this.canWrapXInSource_)return;this.wrapsXInSource_=!0}this.addTriangle_(t,i,n,r,s,a),this.addTriangle_(t,e,i,r,o,s)}},E.prototype.calculateSourceExtent=function(){var t=Object(m.j)();return this.triangles_.forEach(function(e,i,n){var r=e.source;Object(m.r)(t,r[0]),Object(m.r)(t,r[1]),Object(m.r)(t,r[2])}),t},E.prototype.getTriangles=function(){return this.triangles_};var T=E,x=function(t){function e(e,i,r,s,a,h,c,l,u,p,d){t.call(this,a,o.a.IDLE),this.renderEdges_=void 0!==d&&d,this.pixelRatio_=c,this.gutter_=l,this.canvas_=null,this.sourceTileGrid_=i,this.targetTileGrid_=s,this.wrappedTileCoord_=h||a,this.sourceTiles_=[],this.sourcesListenerKeys_=null,this.sourceZ_=0;var f=s.getTileCoordExtent(this.wrappedTileCoord_),_=this.targetTileGrid_.getExtent(),g=this.sourceTileGrid_.getExtent(),v=_?Object(m.B)(f,_):f;if(0!==Object(m.u)(v)){var O=e.getExtent();O&&(g=g?Object(m.B)(g,O):O);var E=s.getResolution(this.wrappedTileCoord_[0]),x=function(t,e,i,n){var r=Object(y.transform)(i,e,t),o=Object(y.getPointResolution)(e,n,i),s=e.getMetersPerUnit();void 0!==s&&(o*=s);var a=t.getMetersPerUnit();void 0!==a&&(o/=a);var h=t.getExtent();if(!h||Object(m.f)(h,r)){var c=Object(y.getPointResolution)(t,o,r)/o;isFinite(c)&&c>0&&(o/=c)}return o}(e,r,Object(m.x)(v),E);if(!isFinite(x)||x<=0)this.state=o.a.EMPTY;else{var C=void 0!==p?p:n.b;if(this.triangulation_=new T(e,r,v,g,x*C),0!==this.triangulation_.getTriangles().length){this.sourceZ_=i.getZForResolution(x);var R=this.triangulation_.calculateSourceExtent();if(g&&(e.canWrapX()?(R[1]=Object(b.a)(R[1],g[1],g[3]),R[3]=Object(b.a)(R[3],g[1],g[3])):R=Object(m.B)(R,g)),Object(m.u)(R)){for(var S=i.getTileRangeForExtentAndZ(R,this.sourceZ_),I=S.minX;I<=S.maxX;I++)for(var j=S.minY;j<=S.maxY;j++){var w=u(this.sourceZ_,I,j,c);w&&this.sourceTiles_.push(w)}0===this.sourceTiles_.length&&(this.state=o.a.EMPTY)}else this.state=o.a.EMPTY}else this.state=o.a.EMPTY}}else this.state=o.a.EMPTY}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.disposeInternal=function(){this.state==o.a.LOADING&&this.unlistenSources_(),t.prototype.disposeInternal.call(this)},e.prototype.getImage=function(){return this.canvas_},e.prototype.reproject_=function(){var t=[];if(this.sourceTiles_.forEach(function(e,i,n){e&&e.getState()==o.a.LOADED&&t.push({extent:this.sourceTileGrid_.getTileCoordExtent(e.tileCoord),image:e.getImage()})}.bind(this)),this.sourceTiles_.length=0,0===t.length)this.state=o.a.ERROR;else{var e=this.wrappedTileCoord_[0],i=this.targetTileGrid_.getTileSize(e),n="number"==typeof i?i:i[0],r="number"==typeof i?i:i[1],s=this.targetTileGrid_.getResolution(e),a=this.sourceTileGrid_.getResolution(this.sourceZ_),h=this.targetTileGrid_.getTileCoordExtent(this.wrappedTileCoord_);this.canvas_=function(t,e,i,n,r,o,s,a,h,c,u){var p=Object(l.a)(Math.round(i*t),Math.round(i*e));if(0===h.length)return p.canvas;p.scale(i,i);var d=Object(m.j)();h.forEach(function(t,e,i){Object(m.q)(d,t.extent)});var f=Object(m.E)(d),_=Object(m.A)(d),g=Object(l.a)(Math.round(i*f/n),Math.round(i*_/n)),v=i/n;h.forEach(function(t,e,i){var n=t.extent[0]-d[0],r=-(t.extent[3]-d[3]),o=Object(m.E)(t.extent),s=Object(m.A)(t.extent);g.drawImage(t.image,c,c,t.image.width-2*c,t.image.height-2*c,n*v,r*v,o*v,s*v)});var y=Object(m.C)(s);return a.getTriangles().forEach(function(t,e,r){var s=t.source,a=t.target,h=s[0][0],c=s[0][1],l=s[1][0],u=s[1][1],f=s[2][0],_=s[2][1],v=(a[0][0]-y[0])/o,m=-(a[0][1]-y[1])/o,E=(a[1][0]-y[0])/o,T=-(a[1][1]-y[1])/o,x=(a[2][0]-y[0])/o,C=-(a[2][1]-y[1])/o,R=h,S=c;h=0,c=0;var I=[[l-=R,u-=S,0,0,E-v],[f-=R,_-=S,0,0,x-v],[0,0,l,u,T-m],[0,0,f,_,C-m]],j=Object(b.e)(I);if(j){p.save(),p.beginPath();var w=(v+E+x)/3,L=(m+T+C)/3,M=O(w,L,v,m),P=O(w,L,E,T),F=O(w,L,x,C);p.moveTo(P[0],P[1]),p.lineTo(M[0],M[1]),p.lineTo(F[0],F[1]),p.clip(),p.transform(j[0],j[2],j[1],j[3],v,m),p.translate(d[0]-R,d[3]-S),p.scale(n/i,-n/i),p.drawImage(g.canvas,0,0),p.restore()}}),u&&(p.save(),p.strokeStyle="black",p.lineWidth=1,a.getTriangles().forEach(function(t,e,i){var n=t.target,r=(n[0][0]-y[0])/o,s=-(n[0][1]-y[1])/o,a=(n[1][0]-y[0])/o,h=-(n[1][1]-y[1])/o,c=(n[2][0]-y[0])/o,l=-(n[2][1]-y[1])/o;p.beginPath(),p.moveTo(a,h),p.lineTo(r,s),p.lineTo(c,l),p.closePath(),p.stroke()}),p.restore()),p.canvas}(n,r,this.pixelRatio_,a,this.sourceTileGrid_.getExtent(),s,h,this.triangulation_,t,this.gutter_,this.renderEdges_),this.state=o.a.LOADED}this.changed()},e.prototype.load=function(){if(this.state==o.a.IDLE){this.state=o.a.LOADING,this.changed();var t=0;this.sourcesListenerKeys_=[],this.sourceTiles_.forEach(function(e,i,n){var r=e.getState();if(r==o.a.IDLE||r==o.a.LOADING){t++;var s=Object(u.a)(e,h.a.CHANGE,function(i){var n=e.getState();n!=o.a.LOADED&&n!=o.a.ERROR&&n!=o.a.EMPTY||(Object(u.e)(s),0===--t&&(this.unlistenSources_(),this.reproject_()))},this);this.sourcesListenerKeys_.push(s)}}.bind(this)),this.sourceTiles_.forEach(function(t,e,i){t.getState()==o.a.IDLE&&t.load()}),0===t&&setTimeout(this.reproject_.bind(this),0)}},e.prototype.unlistenSources_=function(){this.sourcesListenerKeys_.forEach(u.e),this.sourcesListenerKeys_=null},e}(c),C=i(9);function R(t,e){var i=/\{z\}/g,n=/\{x\}/g,r=/\{y\}/g,o=/\{-y\}/g;return function(s,a,h){return s?t.replace(i,s[0].toString()).replace(n,s[1].toString()).replace(r,function(){return(-s[2]-1).toString()}).replace(o,function(){var t=s[0],i=e.getFullTileRange(t);return Object(C.a)(i,55),(i.getHeight()+s[2]).toString()}):void 0}}function S(t,e){for(var i=t.length,n=new Array(i),r=0;r=this.minZoom;){if(2===this.zoomFactor_?(s=Math.floor(s/2),a=Math.floor(a/2),o=Object(A.a)(s,s,a,a,n)):o=this.getTileRangeForExtentAndZ(h,c,n),e.call(i,c,o))return!0;--c}return!1},k.prototype.getExtent=function(){return this.extent_},k.prototype.getMaxZoom=function(){return this.maxZoom},k.prototype.getMinZoom=function(){return this.minZoom},k.prototype.getOrigin=function(t){return this.origin_?this.origin_:this.origins_[t]},k.prototype.getResolution=function(t){return this.resolutions_[t]},k.prototype.getResolutions=function(){return this.resolutions_},k.prototype.getTileCoordChildTileRange=function(t,e,i){if(t[0]i||i>e.getMaxZoom())return!1;var o,s=e.getExtent();return!(o=s?e.getTileRangeForExtentAndZ(s,i):e.getFullTileRange(i))||o.containsXY(n,r)}(t,n)?t:null},e.prototype.refresh=function(){this.tileCache.clear(),this.changed()},e.prototype.useTile=function(t,e,i,n){},e}(L.a),K=function(t){function e(e,i){t.call(this,e),this.tile=i}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(j.a),U="tileloadstart",V="tileloadend",H="tileloaderror";function B(t,e){t.getImage().src=e}var Z=function(t){function e(e){var i=e||{},n=void 0!==i.projection?i.projection:"EPSG:3857",r=void 0!==i.tileGrid?i.tileGrid:function(t){var e=t||{},i=e.extent||Object(y.get)("EPSG:3857").getExtent(),n={extent:i,minZoom:e.minZoom,tileSize:e.tileSize,resolutions:X(i,e.maxZoom,e.tileSize)};return new G(n)}({extent:z(n),maxZoom:i.maxZoom,minZoom:i.minZoom,tileSize:i.tileSize});t.call(this,{attributions:i.attributions,cacheSize:i.cacheSize,crossOrigin:i.crossOrigin,opaque:i.opaque,projection:n,reprojectionErrorThreshold:i.reprojectionErrorThreshold,tileGrid:r,tileLoadFunction:i.tileLoadFunction,tilePixelRatio:i.tilePixelRatio,tileUrlFunction:i.tileUrlFunction,url:i.url,urls:i.urls,wrapX:void 0===i.wrapX||i.wrapX,transition:i.transition,attributionsCollapsible:i.attributionsCollapsible})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(function(t){function e(e){t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,opaque:e.opaque,projection:e.projection,state:e.state,tileGrid:e.tileGrid,tileLoadFunction:e.tileLoadFunction?e.tileLoadFunction:B,tilePixelRatio:e.tilePixelRatio,tileUrlFunction:e.tileUrlFunction,url:e.url,urls:e.urls,wrapX:e.wrapX,transition:e.transition,key:e.key,attributionsCollapsible:e.attributionsCollapsible}),this.crossOrigin=void 0!==e.crossOrigin?e.crossOrigin:null,this.tileClass=void 0!==e.tileClass?e.tileClass:d,this.tileCacheForProjection={},this.tileGridForProjection={},this.reprojectionErrorThreshold_=e.reprojectionErrorThreshold,this.renderReprojectionEdges_=!1}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.canExpireCache=function(){if(!n.a)return t.prototype.canExpireCache.call(this);if(this.tileCache.canExpireCache())return!0;for(var e in this.tileCacheForProjection)if(this.tileCacheForProjection[e].canExpireCache())return!0;return!1},e.prototype.expireCache=function(e,i){if(n.a){var r=this.getTileCacheForProjection(e);for(var o in this.tileCache.expireCache(this.tileCache==r?i:{}),this.tileCacheForProjection){var s=this.tileCacheForProjection[o];s.expireCache(s==r?i:{})}}else t.prototype.expireCache.call(this,e,i)},e.prototype.getGutterForProjection=function(t){return n.a&&this.getProjection()&&t&&!Object(y.equivalent)(this.getProjection(),t)?0:this.getGutter()},e.prototype.getGutter=function(){return 0},e.prototype.getOpaque=function(e){return!(n.a&&this.getProjection()&&e&&!Object(y.equivalent)(this.getProjection(),e))&&t.prototype.getOpaque.call(this,e)},e.prototype.getTileGridForProjection=function(e){if(!n.a)return t.prototype.getTileGridForProjection.call(this,e);var i=this.getProjection();if(!this.tileGrid||i&&!Object(y.equivalent)(i,e)){var o=Object(r.c)(e);return o in this.tileGridForProjection||(this.tileGridForProjection[o]=Y(e)),this.tileGridForProjection[o]}return this.tileGrid},e.prototype.getTileCacheForProjection=function(e){if(!n.a)return t.prototype.getTileCacheForProjection.call(this,e);var i=this.getProjection();if(!i||Object(y.equivalent)(i,e))return this.tileCache;var o=Object(r.c)(e);return o in this.tileCacheForProjection||(this.tileCacheForProjection[o]=new v(this.tileCache.highWaterMark)),this.tileCacheForProjection[o]},e.prototype.createTile_=function(t,e,i,n,r,s){var a=[t,e,i],c=this.getTileCoordForTileUrlFunction(a,r),l=c?this.tileUrlFunction(c,n,r):void 0,p=new this.tileClass(a,void 0!==l?o.a.IDLE:o.a.EMPTY,void 0!==l?l:"",this.crossOrigin,this.tileLoadFunction,this.tileOptions);return p.key=s,Object(u.a)(p,h.a.CHANGE,this.handleTileChange,this),p},e.prototype.getTile=function(t,e,i,r,o){var s=this.getProjection();if(n.a&&s&&o&&!Object(y.equivalent)(s,o)){var a,h=this.getTileCacheForProjection(o),c=[t,e,i],l=g(c);h.containsKey(l)&&(a=h.get(l));var u=this.getKey();if(a&&a.key==u)return a;var p=this.getTileGridForProjection(s),d=this.getTileGridForProjection(o),f=this.getTileCoordForTileUrlFunction(c,o),_=new x(s,p,o,d,c,f,this.getTilePixelRatio(r),this.getGutter(),function(t,e,i,n){return this.getTileInternal(t,e,i,n,s)}.bind(this),this.reprojectionErrorThreshold_,this.renderReprojectionEdges_);return _.key=u,a?(_.interimTile=a,_.refreshInterimChain(),h.replace(l,_)):h.set(l,_),_}return this.getTileInternal(t,e,i,r,s||o)},e.prototype.getTileInternal=function(t,e,i,n,r){var s=null,a=_(t,e,i),h=this.getKey();if(this.tileCache.containsKey(a)){if((s=this.tileCache.get(a)).key!=h){var c=s;s=this.createTile_(t,e,i,n,r,h),c.getState()==o.a.IDLE?s.interimTile=c.interimTile:s.interimTile=c,s.refreshInterimChain(),this.tileCache.replace(a,s)}}else s=this.createTile_(t,e,i,n,r,h),this.tileCache.set(a,s);return s},e.prototype.setRenderReprojectionEdges=function(t){if(n.a&&this.renderReprojectionEdges_!=t){for(var e in this.renderReprojectionEdges_=t,this.tileCacheForProjection)this.tileCacheForProjection[e].clear();this.changed()}},e.prototype.setTileGridForProjection=function(t,e){if(n.a){var i=Object(y.get)(t);if(i){var o=Object(r.c)(i);o in this.tileGridForProjection||(this.tileGridForProjection[o]=e)}}},e}(function(t){function e(e){t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,opaque:e.opaque,projection:e.projection,state:e.state,tileGrid:e.tileGrid,tilePixelRatio:e.tilePixelRatio,wrapX:e.wrapX,transition:e.transition,key:e.key,attributionsCollapsible:e.attributionsCollapsible}),this.generateTileUrlFunction_=!e.tileUrlFunction,this.tileLoadFunction=e.tileLoadFunction,this.tileUrlFunction=e.tileUrlFunction?e.tileUrlFunction.bind(this):I,this.urls=null,e.urls?this.setUrls(e.urls):e.url&&this.setUrl(e.url),e.tileUrlFunction&&this.setTileUrlFunction(e.tileUrlFunction,this.key_),this.tileLoadingKeys_={}}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getTileLoadFunction=function(){return this.tileLoadFunction},e.prototype.getTileUrlFunction=function(){return this.tileUrlFunction},e.prototype.getUrls=function(){return this.urls},e.prototype.handleTileChange=function(t){var e,i=t.target,n=Object(r.c)(i),s=i.getState();s==o.a.LOADING?(this.tileLoadingKeys_[n]=!0,e=U):n in this.tileLoadingKeys_&&(delete this.tileLoadingKeys_[n],e=s==o.a.ERROR?H:s==o.a.LOADED||s==o.a.ABORT?V:void 0),void 0!=e&&this.dispatchEvent(new K(e,i))},e.prototype.setTileLoadFunction=function(t){this.tileCache.clear(),this.tileLoadFunction=t,this.changed()},e.prototype.setTileUrlFunction=function(t,e){this.tileUrlFunction=t,this.tileCache.pruneExceptNewestZ(),void 0!==e?this.setKey(e):this.changed()},e.prototype.setUrl=function(t){var e=this.urls=function(t){var e=[],i=/\{([a-z])-([a-z])\}/.exec(t);if(i){var n,r=i[1].charCodeAt(0),o=i[2].charCodeAt(0);for(n=r;n<=o;++n)e.push(t.replace(i[0],String.fromCharCode(n)));return e}if(i=i=/\{(\d+)-(\d+)\}/.exec(t)){for(var s=parseInt(i[2],10),a=parseInt(i[1],10);a<=s;a++)e.push(t.replace(i[0],a.toString()));return e}return e.push(t),e}(t);this.setUrls(e)},e.prototype.setUrls=function(t){this.urls=t;var e=t.join("\n");this.generateTileUrlFunction_?this.setTileUrlFunction(S(t,this.tileGrid),e):this.setKey(e)},e.prototype.useTile=function(t,e,i){var n=_(t,e,i);this.tileCache.containsKey(n)&&this.tileCache.get(n)},e}(W)));e.default=Z},function(t,e,i){"use strict";i.r(e);var n=i(53),r=i(2),o=i(17),s=i(6);function a(t){return t}var h=i(13),c=i(15);var l=i(48),u=i(12),p=i(25),d=i(9),f=i(34),_=i(21),g=i(0),v=i(5),y=i(62),m=i(11),b=i(16),O=i(20);i.d(e,"createCenterConstraint",function(){return C}),i.d(e,"createResolutionConstraint",function(){return R}),i.d(e,"createRotationConstraint",function(){return S}),i.d(e,"isNoopAnimation",function(){return I});var E=0,T=function(t){function e(e){t.call(this);var i=Object(m.a)({},e);this.hints_=[0,0],this.animations_=[],this.updateAnimationKey_,this.updateAnimations_=this.updateAnimations_.bind(this),this.projection_=Object(b.createProjection)(i.projection,"EPSG:3857"),this.applyOptions_(i)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.applyOptions_=function(t){var e={};e[p.a.CENTER]=void 0!==t.center?t.center:null;var i=R(t);this.maxResolution_=i.maxResolution,this.minResolution_=i.minResolution,this.zoomFactor_=i.zoomFactor,this.resolutions_=t.resolutions,this.minZoom_=i.minZoom;var n=C(t),r=i.constraint,o=S(t);this.constraints_={center:n,resolution:r,rotation:o},void 0!==t.resolution?e[p.a.RESOLUTION]=t.resolution:void 0!==t.zoom&&(e[p.a.RESOLUTION]=this.constrainResolution(this.maxResolution_,t.zoom-this.minZoom_),this.resolutions_&&(e[p.a.RESOLUTION]=Object(s.a)(Number(this.getResolution()||e[p.a.RESOLUTION]),this.minResolution_,this.maxResolution_))),e[p.a.ROTATION]=void 0!==t.rotation?t.rotation:0,this.setProperties(e),this.options_=t},e.prototype.getUpdatedOptions_=function(t){var e=Object(m.a)({},this.options_);return void 0!==e.resolution?e.resolution=this.getResolution():e.zoom=this.getZoom(),e.center=this.getCenter(),e.rotation=this.getRotation(),Object(m.a)({},e,t)},e.prototype.animate=function(t){var e,i=arguments,n=arguments.length;if(n>1&&"function"==typeof arguments[n-1]&&(e=arguments[n-1],--n),!this.isDef()){var r=arguments[n-1];return r.center&&this.setCenter(r.center),void 0!==r.zoom&&this.setZoom(r.zoom),void 0!==r.rotation&&this.setRotation(r.rotation),void(e&&x(e,!0))}for(var o=Date.now(),a=this.getCenter().slice(),h=this.getResolution(),c=this.getRotation(),l=[],p=0;p0},e.prototype.getInteracting=function(){return this.hints_[u.a.INTERACTING]>0},e.prototype.cancelAnimations=function(){this.setHint(u.a.ANIMATING,-this.hints_[u.a.ANIMATING]);for(var t=0,e=this.animations_.length;t=0;--i){for(var n=this.animations_[i],r=!0,o=0,a=n.length;o0?c/h.duration:1;l>=1?(h.complete=!0,l=1):r=!1;var d=h.easing(l);if(h.sourceCenter){var f=h.sourceCenter[0],_=h.sourceCenter[1],g=f+d*(h.targetCenter[0]-f),v=_+d*(h.targetCenter[1]-_);this.set(p.a.CENTER,[g,v])}if(h.sourceResolution&&h.targetResolution){var y=1===d?h.targetResolution:h.sourceResolution+d*(h.targetResolution-h.sourceResolution);h.anchor&&this.set(p.a.CENTER,this.calculateCenterZoom(y,h.anchor)),this.set(p.a.RESOLUTION,y)}if(void 0!==h.sourceRotation&&void 0!==h.targetRotation){var m=1===d?Object(s.d)(h.targetRotation+Math.PI,2*Math.PI)-Math.PI:h.sourceRotation+d*(h.targetRotation-h.sourceRotation);h.anchor&&this.set(p.a.CENTER,this.calculateCenterRotate(m,h.anchor)),this.set(p.a.ROTATION,m)}if(e=!0,!h.complete)break}}if(r){this.animations_[i]=null,this.setHint(u.a.ANIMATING,-1);var b=n[0].callback;b&&x(b,!0)}}this.animations_=this.animations_.filter(Boolean),e&&void 0===this.updateAnimationKey_&&(this.updateAnimationKey_=requestAnimationFrame(this.updateAnimations_))}},e.prototype.calculateCenterRotate=function(t,e){var i,n=this.getCenter();return void 0!==n&&(i=[n[0]-e[0],n[1]-e[1]],Object(f.c)(i,t-this.getRotation()),Object(f.a)(i,e)),i},e.prototype.calculateCenterZoom=function(t,e){var i,n=this.getCenter(),r=this.getResolution();void 0!==n&&void 0!==r&&(i=[e[0]-t*(e[0]-n[0])/r,e[1]-t*(e[1]-n[1])/r]);return i},e.prototype.getSizeFromViewport_=function(){var t=[100,100],e='.ol-viewport[data-view="'+Object(r.c)(this)+'"]',i=document.querySelector(e);if(i){var n=getComputedStyle(i);t[0]=parseInt(n.width,10),t[1]=parseInt(n.height,10)}return t},e.prototype.constrainCenter=function(t){return this.constraints_.center(t)},e.prototype.constrainResolution=function(t,e,i){var n=e||0,r=i||0;return this.constraints_.resolution(t,n,r)},e.prototype.constrainRotation=function(t,e){var i=e||0;return this.constraints_.rotation(t,i)},e.prototype.getCenter=function(){return this.get(p.a.CENTER)},e.prototype.getConstraints=function(){return this.constraints_},e.prototype.getHints=function(t){return void 0!==t?(t[0]=this.hints_[0],t[1]=this.hints_[1],t):this.hints_.slice()},e.prototype.calculateExtent=function(t){var e=t||this.getSizeFromViewport_(),i=this.getCenter();Object(d.a)(i,1);var n=this.getResolution();Object(d.a)(void 0!==n,2);var r=this.getRotation();return Object(d.a)(void 0!==r,3),Object(g.z)(i,n,r,e)},e.prototype.getMaxResolution=function(){return this.maxResolution_},e.prototype.getMinResolution=function(){return this.minResolution_},e.prototype.getMaxZoom=function(){return this.getZoomForResolution(this.minResolution_)},e.prototype.setMaxZoom=function(t){this.applyOptions_(this.getUpdatedOptions_({maxZoom:t}))},e.prototype.getMinZoom=function(){return this.getZoomForResolution(this.maxResolution_)},e.prototype.setMinZoom=function(t){this.applyOptions_(this.getUpdatedOptions_({minZoom:t}))},e.prototype.getProjection=function(){return this.projection_},e.prototype.getResolution=function(){return this.get(p.a.RESOLUTION)},e.prototype.getResolutions=function(){return this.resolutions_},e.prototype.getResolutionForExtent=function(t,e){var i=e||this.getSizeFromViewport_(),n=Object(g.E)(t)/i[0],r=Object(g.A)(t)/i[1];return Math.max(n,r)},e.prototype.getResolutionForValueFunction=function(t){var e=t||2,i=this.maxResolution_,n=this.minResolution_,r=Math.log(i/n)/Math.log(e);return function(t){return i/Math.pow(e,t*r)}},e.prototype.getRotation=function(){return this.get(p.a.ROTATION)},e.prototype.getValueForResolutionFunction=function(t){var e=t||2,i=this.maxResolution_,n=this.minResolution_,r=Math.log(i/n)/Math.log(e);return function(t){return Math.log(i/t)/Math.log(e)/r}},e.prototype.getState=function(t){var e=this.getCenter(),i=this.getProjection(),n=this.getResolution(),r=n/t,o=this.getRotation();return{center:[Math.round(e[0]/r)*r,Math.round(e[1]/r)*r],projection:void 0!==i?i:null,resolution:n,rotation:o,zoom:this.getZoom()}},e.prototype.getZoom=function(){var t,e=this.getResolution();return void 0!==e&&(t=this.getZoomForResolution(e)),t},e.prototype.getZoomForResolution=function(t){var e,i,n=this.minZoom_||0;if(this.resolutions_){var r=Object(c.f)(this.resolutions_,t,1);n=r,e=this.resolutions_[r],i=r==this.resolutions_.length-1?2:e/this.resolutions_[r+1]}else e=this.maxResolution_,i=this.zoomFactor_;return n+Math.log(e/t)/Math.log(i)},e.prototype.getResolutionForZoom=function(t){return this.constrainResolution(this.maxResolution_,t-this.minZoom_,0)},e.prototype.fit=function(t,e){var i,n=e||{},r=n.size;r||(r=this.getSizeFromViewport_()),Object(d.a)(Array.isArray(t)||"function"==typeof t.getSimplifiedGeometry,24),Array.isArray(t)?(Object(d.a)(!Object(g.H)(t),25),i=Object(y.b)(t)):t.getType()===v.a.CIRCLE?(t=t.getExtent(),(i=Object(y.b)(t)).rotate(this.getRotation(),Object(g.x)(t))):i=t;var s,a=void 0!==n.padding?n.padding:[0,0,0,0],h=void 0===n.constrainResolution||n.constrainResolution,c=void 0!==n.nearest&&n.nearest;s=void 0!==n.minResolution?n.minResolution:void 0!==n.maxZoom?this.constrainResolution(this.maxResolution_,n.maxZoom-this.minZoom_,0):0;for(var l=i.getFlatCoordinates(),u=this.getRotation(),p=Math.cos(-u),f=Math.sin(-u),_=1/0,m=1/0,b=-1/0,O=-1/0,E=i.getStride(),T=0,C=l.length;Te?1:0}return function(i,n,r,o,s){!function e(i,n,r,o,s){for(;o>r;){if(o-r>600){var a=o-r+1,h=n-r+1,c=Math.log(a),l=.5*Math.exp(2*c/3),u=.5*Math.sqrt(c*l*(a-l)/a)*(h-a/2<0?-1:1),p=Math.max(r,Math.floor(n-h*l/a+u)),d=Math.min(o,Math.floor(n+(a-h)*l/a+u));e(i,n,p,d,s)}var f=i[n],_=r,g=o;for(t(i,r,n),s(i[o],f)>0&&t(i,r,o);_0;)g--}0===s(i[r],f)?t(i,r,g):t(i,++g,o),g<=n&&(r=g+1),n<=g&&(o=g-1)}}(i,n,r||0,o||i.length-1,s||e)}}()},function(t,e,i){"use strict";i.r(e),i.d(e,"createStyleFunction",function(){return h});var n=i(9),r=i(1),o=i(3),s=i(13),a=function(t){function e(e){if(t.call(this),this.id_=void 0,this.geometryName_="geometry",this.style_=null,this.styleFunction_=void 0,this.geometryChangeKey_=null,Object(r.a)(this,Object(s.b)(this.geometryName_),this.handleGeometryChanged_,this),e)if("function"==typeof e.getSimplifiedGeometry){var i=e;this.setGeometry(i)}else{var n=e;this.setProperties(n)}}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.clone=function(){var t=new e(this.getProperties());t.setGeometryName(this.getGeometryName());var i=this.getGeometry();i&&t.setGeometry(i.clone());var n=this.getStyle();return n&&t.setStyle(n),t},e.prototype.getGeometry=function(){return this.get(this.geometryName_)},e.prototype.getId=function(){return this.id_},e.prototype.getGeometryName=function(){return this.geometryName_},e.prototype.getStyle=function(){return this.style_},e.prototype.getStyleFunction=function(){return this.styleFunction_},e.prototype.handleGeometryChange_=function(){this.changed()},e.prototype.handleGeometryChanged_=function(){this.geometryChangeKey_&&(Object(r.e)(this.geometryChangeKey_),this.geometryChangeKey_=null);var t=this.getGeometry();t&&(this.geometryChangeKey_=Object(r.a)(t,o.a.CHANGE,this.handleGeometryChange_,this)),this.changed()},e.prototype.setGeometry=function(t){this.set(this.geometryName_,t)},e.prototype.setStyle=function(t){this.style_=t,this.styleFunction_=t?h(t):void 0,this.changed()},e.prototype.setId=function(t){this.id_=t,this.changed()},e.prototype.setGeometryName=function(t){Object(r.c)(this,Object(s.b)(this.geometryName_),this.handleGeometryChanged_,this),this.geometryName_=t,Object(r.a)(this,Object(s.b)(this.geometryName_),this.handleGeometryChanged_,this),this.handleGeometryChanged_()},e}(s.a);function h(t){return"function"==typeof t?t:(Array.isArray(t)?e=t:(Object(n.a)("function"==typeof t.getZIndex,41),e=[t]),function(){return e});var e}e.default=a},function(t,e,i){"use strict";i.r(e);var n=i(37),r=i(44),o=i(73),s=i(11),a=i(77),h="renderOrder",c=function(t){function e(e){var i=e||{},r=Object(s.a)({},i);delete r.style,delete r.renderBuffer,delete r.updateWhileAnimating,delete r.updateWhileInteracting,t.call(this,r),this.declutter_=void 0!==i.declutter&&i.declutter,this.renderBuffer_=void 0!==i.renderBuffer?i.renderBuffer:100,this.style_=null,this.styleFunction_=void 0,this.setStyle(i.style),this.updateWhileAnimating_=void 0!==i.updateWhileAnimating&&i.updateWhileAnimating,this.updateWhileInteracting_=void 0!==i.updateWhileInteracting&&i.updateWhileInteracting,this.renderMode_=i.renderMode||o.a.VECTOR,this.type=n.a.VECTOR}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getDeclutter=function(){return this.declutter_},e.prototype.setDeclutter=function(t){this.declutter_=t},e.prototype.getRenderBuffer=function(){return this.renderBuffer_},e.prototype.getRenderOrder=function(){return this.get(h)},e.prototype.getStyle=function(){return this.style_},e.prototype.getStyleFunction=function(){return this.styleFunction_},e.prototype.getUpdateWhileAnimating=function(){return this.updateWhileAnimating_},e.prototype.getUpdateWhileInteracting=function(){return this.updateWhileInteracting_},e.prototype.setRenderOrder=function(t){this.set(h,t)},e.prototype.setStyle=function(t){this.style_=void 0!==t?t:a.createDefaultStyle,this.styleFunction_=null===t?void 0:Object(a.toFunction)(this.style_),this.changed()},e.prototype.getRenderMode=function(){return this.renderMode_},e}(r.a);c.prototype.getSource,e.default=c},function(t,e,i){"use strict";i.r(e),i.d(e,"ATTRIBUTION",function(){return n});var n='© OpenStreetMap contributors.',r=function(t){function e(e){var i,r=e||{};i=void 0!==r.attributions?r.attributions:[n];var o=void 0!==r.crossOrigin?r.crossOrigin:"anonymous",s=void 0!==r.url?r.url:"https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png";t.call(this,{attributions:i,cacheSize:r.cacheSize,crossOrigin:o,opaque:void 0===r.opaque||r.opaque,maxZoom:void 0!==r.maxZoom?r.maxZoom:19,reprojectionErrorThreshold:r.reprojectionErrorThreshold,tileLoadFunction:r.tileLoadFunction,url:s,wrapX:r.wrapX,attributionsCollapsible:!1})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e}(i(81).default);e.default=r},function(t,e,i){"use strict";i.r(e);var n=i(66),r=i(26),o=i(14),s=i(10),a=i(1),h=i(3),c=function(){var t;return function(){if(!t){var e=document.body;e.webkitRequestFullscreen?t="webkitfullscreenchange":e.mozRequestFullScreen?t="mozfullscreenchange":e.msRequestFullscreen?t="MSFullscreenChange":e.requestFullscreen&&(t="fullscreenchange")}return t}}();function l(){var t=document.body;return!!(t.webkitRequestFullscreen||t.mozRequestFullScreen&&document.mozFullScreenEnabled||t.msRequestFullscreen&&document.msFullscreenEnabled||t.requestFullscreen&&document.fullscreenEnabled)}function u(){return!!(document.webkitIsFullScreen||document.mozFullScreen||document.msFullscreenElement||document.fullscreenElement)}function p(t){t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.mozRequestFullScreen?t.mozRequestFullScreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen()}var d=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),target:i.target}),this.cssClassName_=void 0!==i.className?i.className:"ol-full-screen";var n=void 0!==i.label?i.label:"⤢";this.labelNode_="string"==typeof n?document.createTextNode(n):n;var r=void 0!==i.labelActive?i.labelActive:"×";this.labelActiveNode_="string"==typeof r?document.createTextNode(r):r,this.button_=document.createElement("button");var s=i.tipLabel?i.tipLabel:"Toggle full-screen";this.setClassName_(this.button_,u()),this.button_.setAttribute("type","button"),this.button_.title=s,this.button_.appendChild(this.labelNode_),Object(a.a)(this.button_,h.a.CLICK,this.handleClick_,this);var c=this.cssClassName_+" "+o.e+" "+o.b+" "+(l()?"":o.f),p=this.element;p.className=c,p.appendChild(this.button_),this.keys_=void 0!==i.keys&&i.keys,this.source_=i.source}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleClick_=function(t){t.preventDefault(),this.handleFullScreen_()},e.prototype.handleFullScreen_=function(){if(l()){var t,e=this.getMap();if(e)if(u())document.exitFullscreen?document.exitFullscreen():document.msExitFullscreen?document.msExitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.webkitExitFullscreen&&document.webkitExitFullscreen();else t=this.source_?"string"==typeof this.source_?document.getElementById(this.source_):this.source_:e.getTargetElement(),this.keys_?function(t){t.mozRequestFullScreenWithKeys?t.mozRequestFullScreenWithKeys():t.webkitRequestFullscreen?t.webkitRequestFullscreen():p(t)}(t):p(t)}},e.prototype.handleFullScreenChange_=function(){var t=this.getMap();u()?(this.setClassName_(this.button_,!0),Object(s.f)(this.labelActiveNode_,this.labelNode_)):(this.setClassName_(this.button_,!1),Object(s.f)(this.labelNode_,this.labelActiveNode_)),t&&t.updateSize()},e.prototype.setClassName_=function(t,e){var i=this.cssClassName_+"-true",n=this.cssClassName_+"-false",r=e?i:n;t.classList.remove(i),t.classList.remove(n),t.classList.add(r)},e.prototype.setMap=function(e){t.prototype.setMap.call(this,e),e&&this.listenerKeys.push(Object(a.a)(document,c(),this.handleFullScreenChange_,this))},e}(r.a),f=i(13),_=i(16),g="projection";function v(t){var e=t.frameState;e?this.mapProjection_!=e.viewState.projection&&(this.mapProjection_=e.viewState.projection,this.transform_=null):this.mapProjection_=null}var y=function(t){function e(e){var i=e||{},n=document.createElement("div");n.className=void 0!==i.className?i.className:"ol-mouse-position",t.call(this,{element:n,render:i.render||v,target:i.target}),Object(a.a)(this,Object(f.b)(g),this.handleProjectionChanged_,this),i.coordinateFormat&&this.setCoordinateFormat(i.coordinateFormat),i.projection&&this.setProjection(i.projection),this.undefinedHTML_=void 0!==i.undefinedHTML?i.undefinedHTML:" ",this.renderOnMouseOut_=!!this.undefinedHTML_,this.renderedHTML_=n.innerHTML,this.mapProjection_=null,this.transform_=null,this.lastMouseMovePixel_=null}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleProjectionChanged_=function(){this.transform_=null},e.prototype.getCoordinateFormat=function(){return this.get("coordinateFormat")},e.prototype.getProjection=function(){return this.get(g)},e.prototype.handleMouseMove=function(t){var e=this.getMap();this.lastMouseMovePixel_=e.getEventPixel(t),this.updateHTML_(this.lastMouseMovePixel_)},e.prototype.handleMouseOut=function(t){this.updateHTML_(null),this.lastMouseMovePixel_=null},e.prototype.setMap=function(e){if(t.prototype.setMap.call(this,e),e){var i=e.getViewport();this.listenerKeys.push(Object(a.a)(i,h.a.MOUSEMOVE,this.handleMouseMove,this),Object(a.a)(i,h.a.TOUCHSTART,this.handleMouseMove,this)),this.renderOnMouseOut_&&this.listenerKeys.push(Object(a.a)(i,h.a.MOUSEOUT,this.handleMouseOut,this),Object(a.a)(i,h.a.TOUCHEND,this.handleMouseOut,this))}},e.prototype.setCoordinateFormat=function(t){this.set("coordinateFormat",t)},e.prototype.setProjection=function(t){this.set(g,Object(_.get)(t))},e.prototype.updateHTML_=function(t){var e=this.undefinedHTML_;if(t&&this.mapProjection_){if(!this.transform_){var i=this.getProjection();this.transform_=i?Object(_.getTransformFromProjections)(this.mapProjection_,i):_.identityTransform}var n=this.getMap().getCoordinateFromPixel(t);if(n){this.transform_(n,n);var r=this.getCoordinateFormat();e=r?r(n):n.toString()}}this.renderedHTML_&&e===this.renderedHTML_||(this.element.innerHTML=e,this.renderedHTML_=e)},e}(r.a),m=i(28),b=i(80),O=i(46),E=i(31),T=i(43),x=i(79),C=i(32),R=i(25),S=i(34),I=i(0);function j(t){this.validateExtent_(),this.updateBox_()}var w=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),render:i.render||j,target:i.target}),this.collapsed_=void 0===i.collapsed||i.collapsed,this.collapsible_=void 0===i.collapsible||i.collapsible,this.collapsible_||(this.collapsed_=!1);var n=void 0!==i.className?i.className:"ol-overviewmap",r=void 0!==i.tipLabel?i.tipLabel:"Overview map",s=void 0!==i.collapseLabel?i.collapseLabel:"«";"string"==typeof s?(this.collapseLabel_=document.createElement("span"),this.collapseLabel_.textContent=s):this.collapseLabel_=s;var c=void 0!==i.label?i.label:"»";"string"==typeof c?(this.label_=document.createElement("span"),this.label_.textContent=c):this.label_=c;var l=this.collapsible_&&!this.collapsed_?this.collapseLabel_:this.label_,u=document.createElement("button");u.setAttribute("type","button"),u.title=r,u.appendChild(l),Object(a.a)(u,h.a.CLICK,this.handleClick_,this),this.ovmapDiv_=document.createElement("div"),this.ovmapDiv_.className="ol-overviewmap-map",this.ovmap_=new b.default({controls:new m.a,interactions:new m.a,view:i.view});var p=this.ovmap_;i.layers&&i.layers.forEach(function(t){p.addLayer(t)}.bind(this));var d=document.createElement("div");d.className="ol-overviewmap-box",d.style.boxSizing="border-box",this.boxOverlay_=new x.default({position:[0,0],positioning:C.a.BOTTOM_LEFT,element:d}),this.ovmap_.addOverlay(this.boxOverlay_);var f=n+" "+o.e+" "+o.b+(this.collapsed_&&this.collapsible_?" "+o.a:"")+(this.collapsible_?"":" ol-uncollapsible"),_=this.element;_.className=f,_.appendChild(this.ovmapDiv_),_.appendChild(u);var g=this,v=this.boxOverlay_,y=this.boxOverlay_.getElement(),O=function(t){var e=function(t){return{clientX:t.clientX-y.offsetWidth/2,clientY:t.clientY+y.offsetHeight/2}}(t),i=p.getEventCoordinate(e);v.setPosition(i)},E=function(t){var e=p.getEventCoordinate(t);g.getMap().getView().setCenter(e),window.removeEventListener("mousemove",O),window.removeEventListener("mouseup",E)};y.addEventListener("mousedown",function(){window.addEventListener("mousemove",O),window.addEventListener("mouseup",E)})}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.setMap=function(e){var i=this.getMap();if(e!==i){if(i){var n=i.getView();n&&this.unbindView_(n),this.ovmap_.setTarget(null)}if(t.prototype.setMap.call(this,e),e){this.ovmap_.setTarget(this.ovmapDiv_),this.listenerKeys.push(Object(a.a)(e,T.a.PROPERTYCHANGE,this.handleMapPropertyChange_,this)),0===this.ovmap_.getLayers().getLength()&&this.ovmap_.setLayerGroup(e.getLayerGroup());var r=e.getView();r&&(this.bindView_(r),r.isDef()&&(this.ovmap_.updateSize(),this.resetExtent_()))}}},e.prototype.handleMapPropertyChange_=function(t){if(t.key===E.a.VIEW){var e=t.oldValue;e&&this.unbindView_(e);var i=this.getMap().getView();this.bindView_(i)}},e.prototype.bindView_=function(t){Object(a.a)(t,Object(f.b)(R.a.ROTATION),this.handleRotationChanged_,this)},e.prototype.unbindView_=function(t){Object(a.c)(t,Object(f.b)(R.a.ROTATION),this.handleRotationChanged_,this)},e.prototype.handleRotationChanged_=function(){this.ovmap_.getView().setRotation(this.getMap().getView().getRotation())},e.prototype.validateExtent_=function(){var t=this.getMap(),e=this.ovmap_;if(t.isRendered()&&e.isRendered()){var i=t.getSize(),n=t.getView().calculateExtent(i),r=e.getSize(),o=e.getView().calculateExtent(r),s=e.getPixelFromCoordinate(Object(I.C)(n)),a=e.getPixelFromCoordinate(Object(I.w)(n)),h=Math.abs(s[0]-a[0]),c=Math.abs(s[1]-a[1]),l=r[0],u=r[1];h<.1*l||c<.1*u||h>.75*l||c>.75*u?this.resetExtent_():Object(I.g)(o,n)||this.recenter_()}},e.prototype.resetExtent_=function(){var t=this.getMap(),e=this.ovmap_,i=t.getSize(),n=t.getView().calculateExtent(i),r=e.getView(),o=Math.log(7.5)/Math.LN2,s=1/(.1*Math.pow(2,o/2));Object(I.J)(n,s),r.fit(n)},e.prototype.recenter_=function(){var t=this.getMap(),e=this.ovmap_,i=t.getView();e.getView().setCenter(i.getCenter())},e.prototype.updateBox_=function(){var t=this.getMap(),e=this.ovmap_;if(t.isRendered()&&e.isRendered()){var i=t.getSize(),n=t.getView(),r=e.getView(),o=n.getRotation(),s=this.boxOverlay_,a=this.boxOverlay_.getElement(),h=n.calculateExtent(i),c=r.getResolution(),l=Object(I.v)(h),u=Object(I.D)(h),p=this.calculateCoordinateRotate_(o,l);s.setPosition(p),a&&(a.style.width=Math.abs((l[0]-u[0])/c)+"px",a.style.height=Math.abs((u[1]-l[1])/c)+"px")}},e.prototype.calculateCoordinateRotate_=function(t,e){var i,n=this.getMap().getView().getCenter();return n&&(i=[e[0]-n[0],e[1]-n[1]],Object(S.c)(i,t),Object(S.a)(i,n)),i},e.prototype.handleClick_=function(t){t.preventDefault(),this.handleToggle_()},e.prototype.handleToggle_=function(){this.element.classList.toggle(o.a),this.collapsed_?Object(s.f)(this.collapseLabel_,this.label_):Object(s.f)(this.label_,this.collapseLabel_),this.collapsed_=!this.collapsed_;var t=this.ovmap_;this.collapsed_||t.isRendered()||(t.updateSize(),this.resetExtent_(),Object(a.b)(t,O.a.POSTRENDER,function(t){this.updateBox_()},this))},e.prototype.getCollapsible=function(){return this.collapsible_},e.prototype.setCollapsible=function(t){this.collapsible_!==t&&(this.collapsible_=t,this.element.classList.toggle("ol-uncollapsible"),!t&&this.collapsed_&&this.handleToggle_())},e.prototype.setCollapsed=function(t){this.collapsible_&&this.collapsed_!==t&&this.handleToggle_()},e.prototype.getCollapsed=function(){return this.collapsed_},e.prototype.getOverviewMap=function(){return this.ovmap_},e}(r.a),L=i(65),M=i(9),P=i(20),F="units",A={DEGREES:"degrees",IMPERIAL:"imperial",NAUTICAL:"nautical",METRIC:"metric",US:"us"},D=[1,2,5];function N(t){var e=t.frameState;this.viewState_=e?e.viewState:null,this.updateElement_()}var k=function(t){function e(e){var i=e||{},n=void 0!==i.className?i.className:"ol-scale-line";t.call(this,{element:document.createElement("div"),render:i.render||N,target:i.target}),this.innerElement_=document.createElement("div"),this.innerElement_.className=n+"-inner",this.element.className=n+" "+o.e,this.element.appendChild(this.innerElement_),this.viewState_=null,this.minWidth_=void 0!==i.minWidth?i.minWidth:64,this.renderedVisible_=!1,this.renderedWidth_=void 0,this.renderedHTML_="",Object(a.a)(this,Object(f.b)(F),this.handleUnitsChanged_,this),this.setUnits(i.units||A.METRIC)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.getUnits=function(){return this.get(F)},e.prototype.handleUnitsChanged_=function(){this.updateElement_()},e.prototype.setUnits=function(t){this.set(F,t)},e.prototype.updateElement_=function(){var t=this.viewState_;if(t){var e=t.center,i=t.projection,n=this.getUnits(),r=n==A.DEGREES?P.b.DEGREES:P.b.METERS,o=Object(_.getPointResolution)(i,t.resolution,e,r);i.getUnits()!=P.b.DEGREES&&i.getMetersPerUnit()&&r==P.b.METERS&&(o*=i.getMetersPerUnit());var s=this.minWidth_*o,a="";if(n==A.DEGREES){var h=P.a[P.b.DEGREES];i.getUnits()==P.b.DEGREES?s*=h:o/=h,s=this.minWidth_)break;++u}var p=c+" "+a;this.renderedHTML_!=p&&(this.innerElement_.innerHTML=p,this.renderedHTML_=p),this.renderedWidth_!=l&&(this.innerElement_.style.width=l+"px",this.renderedWidth_=l),this.renderedVisible_||(this.element.style.display="",this.renderedVisible_=!0)}else this.renderedVisible_&&(this.element.style.display="none",this.renderedVisible_=!1)},e}(r.a),G=i(64),Y=i(12),X=i(21),z=i(22),W=i(6),K=i(30),U=i(61),V={VERTICAL:0,HORIZONTAL:1};function H(t){if(t.frameState){this.sliderInitialized_||this.initSlider_();var e=t.frameState.viewState.resolution;e!==this.currentResolution_&&(this.currentResolution_=e,this.setThumbPosition_(e))}}var B=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),render:i.render||H}),this.dragListenerKeys_=[],this.currentResolution_=void 0,this.direction_=V.VERTICAL,this.dragging_,this.heightLimit_=0,this.widthLimit_=0,this.previousX_,this.previousY_,this.thumbSize_=null,this.sliderInitialized_=!1,this.duration_=void 0!==i.duration?i.duration:200;var n=void 0!==i.className?i.className:"ol-zoomslider",r=document.createElement("button");r.setAttribute("type","button"),r.className=n+"-thumb "+o.e;var s=this.element;s.className=n+" "+o.e+" "+o.b,s.appendChild(r),this.dragger_=new U.a(s),Object(a.a)(this.dragger_,K.a.POINTERDOWN,this.handleDraggerStart_,this),Object(a.a)(this.dragger_,K.a.POINTERMOVE,this.handleDraggerDrag_,this),Object(a.a)(this.dragger_,K.a.POINTERUP,this.handleDraggerEnd_,this),Object(a.a)(s,h.a.CLICK,this.handleContainerClick_,this),Object(a.a)(r,h.a.CLICK,z.b)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.disposeInternal=function(){this.dragger_.dispose(),t.prototype.disposeInternal.call(this)},e.prototype.setMap=function(e){t.prototype.setMap.call(this,e),e&&e.render()},e.prototype.initSlider_=function(){var t=this.element,e=t.offsetWidth,i=t.offsetHeight,n=t.firstElementChild,r=getComputedStyle(n),o=n.offsetWidth+parseFloat(r.marginRight)+parseFloat(r.marginLeft),s=n.offsetHeight+parseFloat(r.marginTop)+parseFloat(r.marginBottom);this.thumbSize_=[o,s],e>i?(this.direction_=V.HORIZONTAL,this.widthLimit_=e-o):(this.direction_=V.VERTICAL,this.heightLimit_=i-s),this.sliderInitialized_=!0},e.prototype.handleContainerClick_=function(t){var e=this.getMap().getView(),i=this.getRelativePosition_(t.offsetX-this.thumbSize_[0]/2,t.offsetY-this.thumbSize_[1]/2),n=this.getResolutionForPosition_(i);e.animate({resolution:e.constrainResolution(n),duration:this.duration_,easing:X.b})},e.prototype.handleDraggerStart_=function(t){if(!this.dragging_&&t.originalEvent.target===this.element.firstElementChild&&(this.getMap().getView().setHint(Y.a.INTERACTING,1),this.previousX_=t.clientX,this.previousY_=t.clientY,this.dragging_=!0,0===this.dragListenerKeys_.length)){var e=this.handleDraggerDrag_,i=this.handleDraggerEnd_;this.dragListenerKeys_.push(Object(a.a)(document,h.a.MOUSEMOVE,e,this),Object(a.a)(document,K.a.POINTERMOVE,e,this),Object(a.a)(document,h.a.MOUSEUP,i,this),Object(a.a)(document,K.a.POINTERUP,i,this))}},e.prototype.handleDraggerDrag_=function(t){if(this.dragging_){var e=this.element.firstElementChild,i=t.clientX-this.previousX_+parseFloat(e.style.left),n=t.clientY-this.previousY_+parseFloat(e.style.top),r=this.getRelativePosition_(i,n);this.currentResolution_=this.getResolutionForPosition_(r),this.getMap().getView().setResolution(this.currentResolution_),this.setThumbPosition_(this.currentResolution_),this.previousX_=t.clientX,this.previousY_=t.clientY}},e.prototype.handleDraggerEnd_=function(t){if(this.dragging_){var e=this.getMap().getView();e.setHint(Y.a.INTERACTING,-1),e.animate({resolution:e.constrainResolution(this.currentResolution_),duration:this.duration_,easing:X.b}),this.dragging_=!1,this.previousX_=void 0,this.previousY_=void 0,this.dragListenerKeys_.forEach(a.e),this.dragListenerKeys_.length=0}},e.prototype.setThumbPosition_=function(t){var e=this.getPositionForResolution_(t),i=this.element.firstElementChild;this.direction_==V.HORIZONTAL?i.style.left=this.widthLimit_*e+"px":i.style.top=this.heightLimit_*e+"px"},e.prototype.getRelativePosition_=function(t,e){var i;return i=this.direction_===V.HORIZONTAL?t/this.widthLimit_:e/this.heightLimit_,Object(W.a)(i,0,1)},e.prototype.getResolutionForPosition_=function(t){return this.getMap().getView().getResolutionForValueFunction()(1-t)},e.prototype.getPositionForResolution_=function(t){return 1-this.getMap().getView().getValueForResolutionFunction()(t)},e}(r.a),Z=function(t){function e(e){var i=e||{};t.call(this,{element:document.createElement("div"),target:i.target}),this.extent=i.extent?i.extent:null;var n=void 0!==i.className?i.className:"ol-zoom-extent",r=void 0!==i.label?i.label:"E",s=void 0!==i.tipLabel?i.tipLabel:"Fit to extent",c=document.createElement("button");c.setAttribute("type","button"),c.title=s,c.appendChild("string"==typeof r?document.createTextNode(r):r),Object(a.a)(c,h.a.CLICK,this.handleClick_,this);var l=n+" "+o.e+" "+o.b,u=this.element;u.className=l,u.appendChild(c)}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.handleClick_=function(t){t.preventDefault(),this.handleZoomToExtent()},e.prototype.handleZoomToExtent=function(){var t=this.getMap().getView(),e=this.extent?this.extent:t.getProjection().getExtent();t.fit(e)},e}(r.a),q=i(63);i.d(e,"Attribution",function(){return n.a}),i.d(e,"Control",function(){return r.a}),i.d(e,"FullScreen",function(){return d}),i.d(e,"MousePosition",function(){return y}),i.d(e,"OverviewMap",function(){return w}),i.d(e,"Rotate",function(){return L.a}),i.d(e,"ScaleLine",function(){return k}),i.d(e,"Zoom",function(){return G.a}),i.d(e,"ZoomSlider",function(){return B}),i.d(e,"ZoomToExtent",function(){return Z}),i.d(e,"defaults",function(){return q.a})},function(t,e,i){"use strict";i.r(e);var n=i(2),r=i(28),o=i(29),s=i(43),a=i(15),h=i(9),c=i(1),l=i(22),u=i(3),p=i(0),d=i(17),f={ARRAY_BUFFER:"arraybuffer",JSON:"json",TEXT:"text",XML:"xml"};function _(t,e){return function(t,e,i,n){return function(r,o,s){var a=new XMLHttpRequest;a.open("GET","function"==typeof t?t(r,o,s):t,!0),e.getType()==f.ARRAY_BUFFER&&(a.responseType="arraybuffer"),a.onload=function(t){if(!a.status||a.status>=200&&a.status<300){var r,o=e.getType();o==f.JSON||o==f.TEXT?r=a.responseText:o==f.XML?(r=a.responseXML)||(r=(new DOMParser).parseFromString(a.responseText,"application/xml")):o==f.ARRAY_BUFFER&&(r=a.response),r?i.call(this,e.readFeatures(r,{featureProjection:s}),e.readProjection(r),e.getLastExtent()):n.call(this)}else n.call(this)}.bind(this),a.onerror=function(){n.call(this)}.bind(this),a.send()}}(t,e,function(t,e){"function"==typeof this.addFeatures&&this.addFeatures(t)},d.c)}function g(t,e){return[[-1/0,-1/0,1/0,1/0]]}var v=i(11),y=i(76),m=i(42),b="addfeature",O="changefeature",E="clear",T="removefeature",x=i(57),C=i.n(x),R=function(t){this.rbush_=C()(t,void 0),this.items_={}};R.prototype.insert=function(t,e){var i={minX:t[0],minY:t[1],maxX:t[2],maxY:t[3],value:e};this.rbush_.insert(i),this.items_[Object(n.c)(e)]=i},R.prototype.load=function(t,e){for(var i=new Array(e.length),r=0,o=e.length;r0,6);var y=void 0!==i.src?r.a.IDLE:r.a.LOADED;this.color_=void 0!==i.color?Object(s.a)(i.color):null,this.iconImage_=function(t,e,i,n,r,o){var s=p.a.get(e,n,o);return s||(s=new d(t,e,i,n,r,o),p.a.set(e,n,o,s)),s}(_,v,g,this.crossOrigin_,y,this.color_),this.offset_=void 0!==i.offset?i.offset:[0,0],this.offsetOrigin_=void 0!==i.offsetOrigin?i.offsetOrigin:f.TOP_LEFT,this.origin_=null,this.size_=void 0!==i.size?i.size:null}return t&&(e.__proto__=t),e.prototype=Object.create(t&&t.prototype),e.prototype.constructor=e,e.prototype.clone=function(){return new e({anchor:this.anchor_.slice(),anchorOrigin:this.anchorOrigin_,anchorXUnits:this.anchorXUnits_,anchorYUnits:this.anchorYUnits_,crossOrigin:this.crossOrigin_,color:this.color_&&this.color_.slice?this.color_.slice():this.color_||void 0,src:this.getSrc(),offset:this.offset_.slice(),offsetOrigin:this.offsetOrigin_,size:null!==this.size_?this.size_.slice():void 0,opacity:this.getOpacity(),scale:this.getScale(),rotation:this.getRotation(),rotateWithView:this.getRotateWithView()})},e.prototype.getAnchor=function(){if(this.normalizedAnchor_)return this.normalizedAnchor_;var t=this.anchor_,e=this.getSize();if(this.anchorXUnits_==c.FRACTION||this.anchorYUnits_==c.FRACTION){if(!e)return null;t=this.anchor_.slice(),this.anchorXUnits_==c.FRACTION&&(t[0]*=e[0]),this.anchorYUnits_==c.FRACTION&&(t[1]*=e[1])}if(this.anchorOrigin_!=f.TOP_LEFT){if(!e)return null;t===this.anchor_&&(t=this.anchor_.slice()),this.anchorOrigin_!=f.TOP_RIGHT&&this.anchorOrigin_!=f.BOTTOM_RIGHT||(t[0]=-t[0]+e[0]),this.anchorOrigin_!=f.BOTTOM_LEFT&&this.anchorOrigin_!=f.BOTTOM_RIGHT||(t[1]=-t[1]+e[1])}return this.normalizedAnchor_=t,this.normalizedAnchor_},e.prototype.setAnchor=function(t){this.anchor_=t,this.normalizedAnchor_=null},e.prototype.getColor=function(){return this.color_},e.prototype.getImage=function(t){return this.iconImage_.getImage(t)},e.prototype.getImageSize=function(){return this.iconImage_.getSize()},e.prototype.getHitDetectionImageSize=function(){return this.getImageSize()},e.prototype.getImageState=function(){return this.iconImage_.getImageState()},e.prototype.getHitDetectionImage=function(t){return this.iconImage_.getHitDetectionImage(t)},e.prototype.getOrigin=function(){if(this.origin_)return this.origin_;var t=this.offset_;if(this.offsetOrigin_!=f.TOP_LEFT){var e=this.getSize(),i=this.iconImage_.getSize();if(!e||!i)return null;t=t.slice(),this.offsetOrigin_!=f.TOP_RIGHT&&this.offsetOrigin_!=f.BOTTOM_RIGHT||(t[0]=i[0]-e[0]-t[0]),this.offsetOrigin_!=f.BOTTOM_LEFT&&this.offsetOrigin_!=f.BOTTOM_RIGHT||(t[1]=i[1]-e[1]-t[1])}return this.origin_=t,this.origin_},e.prototype.getSrc=function(){return this.iconImage_.getSrc()},e.prototype.getSize=function(){return this.size_?this.size_:this.iconImage_.getSize()},e.prototype.listenImageChange=function(t,e){return Object(a.a)(this.iconImage_,h.a.CHANGE,t,e)},e.prototype.load=function(){this.iconImage_.load()},e.prototype.unlistenImageChange=function(t,e){Object(a.c)(this.iconImage_,h.a.CHANGE,t,e)},e}(i(75).a);e.default=_},function(t,e,i){"use strict";i.r(e);var n=i(15),r=i(0),o=i(24),s=i(5),a=i(45),h=i(50),c=i(51),l=i(47),u=i(6);function p(t,e,i,n,r,o){if(i==e)return null;var s;if(r>1;r} Extent\n * @api\n */\n\n/**\n * Build an extent that includes all given coordinates.\n *\n * @param {Array} coordinates Coordinates.\n * @return {Extent} Bounding extent.\n * @api\n */\nexport function boundingExtent(coordinates) {\n var extent = createEmpty();\n for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {Array} xs Xs.\n * @param {Array} ys Ys.\n * @param {Extent=} opt_extent Destination extent.\n * @private\n * @return {Extent} Extent.\n */\nfunction _boundingExtentXYs(xs, ys, opt_extent) {\n var minX = Math.min.apply(null, xs);\n var minY = Math.min.apply(null, ys);\n var maxX = Math.max.apply(null, xs);\n var maxY = Math.max.apply(null, ys);\n return createOrUpdate(minX, minY, maxX, maxY, opt_extent);\n}\n\n\n/**\n * Return extent increased by the provided value.\n * @param {Extent} extent Extent.\n * @param {number} value The amount by which the extent should be buffered.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n * @api\n */\nexport function buffer(extent, value, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0] - value;\n opt_extent[1] = extent[1] - value;\n opt_extent[2] = extent[2] + value;\n opt_extent[3] = extent[3] + value;\n return opt_extent;\n } else {\n return [\n extent[0] - value,\n extent[1] - value,\n extent[2] + value,\n extent[3] + value\n ];\n }\n}\n\n\n/**\n * Creates a clone of an extent.\n *\n * @param {Extent} extent Extent to clone.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} The clone.\n */\nexport function clone(extent, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0];\n opt_extent[1] = extent[1];\n opt_extent[2] = extent[2];\n opt_extent[3] = extent[3];\n return opt_extent;\n } else {\n return extent.slice();\n }\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {number} Closest squared distance.\n */\nexport function closestSquaredDistanceXY(extent, x, y) {\n var dx, dy;\n if (x < extent[0]) {\n dx = extent[0] - x;\n } else if (extent[2] < x) {\n dx = x - extent[2];\n } else {\n dx = 0;\n }\n if (y < extent[1]) {\n dy = extent[1] - y;\n } else if (extent[3] < y) {\n dy = y - extent[3];\n } else {\n dy = 0;\n }\n return dx * dx + dy * dy;\n}\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {Extent} extent Extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} The coordinate is contained in the extent.\n * @api\n */\nexport function containsCoordinate(extent, coordinate) {\n return containsXY(extent, coordinate[0], coordinate[1]);\n}\n\n\n/**\n * Check if one extent contains another.\n *\n * An extent is deemed contained if it lies completely within the other extent,\n * including if they share one or more edges.\n *\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {boolean} The second extent is contained by or on the edge of the\n * first.\n * @api\n */\nexport function containsExtent(extent1, extent2) {\n return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&\n extent1[1] <= extent2[1] && extent2[3] <= extent1[3];\n}\n\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {Extent} extent Extent.\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @return {boolean} The x, y values are contained in the extent.\n * @api\n */\nexport function containsXY(extent, x, y) {\n return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];\n}\n\n\n/**\n * Get the relationship between a coordinate and extent.\n * @param {Extent} extent The extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate The coordinate.\n * @return {Relationship} The relationship (bitwise compare with\n * import(\"./extent/Relationship.js\").Relationship).\n */\nexport function coordinateRelationship(extent, coordinate) {\n var minX = extent[0];\n var minY = extent[1];\n var maxX = extent[2];\n var maxY = extent[3];\n var x = coordinate[0];\n var y = coordinate[1];\n var relationship = Relationship.UNKNOWN;\n if (x < minX) {\n relationship = relationship | Relationship.LEFT;\n } else if (x > maxX) {\n relationship = relationship | Relationship.RIGHT;\n }\n if (y < minY) {\n relationship = relationship | Relationship.BELOW;\n } else if (y > maxY) {\n relationship = relationship | Relationship.ABOVE;\n }\n if (relationship === Relationship.UNKNOWN) {\n relationship = Relationship.INTERSECTING;\n }\n return relationship;\n}\n\n\n/**\n * Create an empty extent.\n * @return {Extent} Empty extent.\n * @api\n */\nexport function createEmpty() {\n return [Infinity, Infinity, -Infinity, -Infinity];\n}\n\n\n/**\n * Create a new extent or update the provided extent.\n * @param {number} minX Minimum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxX Maximum X.\n * @param {number} maxY Maximum Y.\n * @param {Extent=} opt_extent Destination extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdate(minX, minY, maxX, maxY, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = minX;\n opt_extent[1] = minY;\n opt_extent[2] = maxX;\n opt_extent[3] = maxY;\n return opt_extent;\n } else {\n return [minX, minY, maxX, maxY];\n }\n}\n\n\n/**\n * Create a new empty extent or make the provided one empty.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateEmpty(opt_extent) {\n return createOrUpdate(\n Infinity, Infinity, -Infinity, -Infinity, opt_extent);\n}\n\n\n/**\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromCoordinate(coordinate, opt_extent) {\n var x = coordinate[0];\n var y = coordinate[1];\n return createOrUpdate(x, y, x, y, opt_extent);\n}\n\n\n/**\n * @param {Array} coordinates Coordinates.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromCoordinates(coordinates, opt_extent) {\n var extent = createOrUpdateEmpty(opt_extent);\n return extendCoordinates(extent, coordinates);\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromFlatCoordinates(flatCoordinates, offset, end, stride, opt_extent) {\n var extent = createOrUpdateEmpty(opt_extent);\n return extendFlatCoordinates(extent, flatCoordinates, offset, end, stride);\n}\n\n/**\n * @param {Array>} rings Rings.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromRings(rings, opt_extent) {\n var extent = createOrUpdateEmpty(opt_extent);\n return extendRings(extent, rings);\n}\n\n\n/**\n * Determine if two extents are equivalent.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {boolean} The two extents are equivalent.\n * @api\n */\nexport function equals(extent1, extent2) {\n return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&\n extent1[1] == extent2[1] && extent1[3] == extent2[3];\n}\n\n\n/**\n * Modify an extent to include another extent.\n * @param {Extent} extent1 The extent to be modified.\n * @param {Extent} extent2 The extent that will be included in the first.\n * @return {Extent} A reference to the first (extended) extent.\n * @api\n */\nexport function extend(extent1, extent2) {\n if (extent2[0] < extent1[0]) {\n extent1[0] = extent2[0];\n }\n if (extent2[2] > extent1[2]) {\n extent1[2] = extent2[2];\n }\n if (extent2[1] < extent1[1]) {\n extent1[1] = extent2[1];\n }\n if (extent2[3] > extent1[3]) {\n extent1[3] = extent2[3];\n }\n return extent1;\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n */\nexport function extendCoordinate(extent, coordinate) {\n if (coordinate[0] < extent[0]) {\n extent[0] = coordinate[0];\n }\n if (coordinate[0] > extent[2]) {\n extent[2] = coordinate[0];\n }\n if (coordinate[1] < extent[1]) {\n extent[1] = coordinate[1];\n }\n if (coordinate[1] > extent[3]) {\n extent[3] = coordinate[1];\n }\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array} coordinates Coordinates.\n * @return {Extent} Extent.\n */\nexport function extendCoordinates(extent, coordinates) {\n for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {Extent} Extent.\n */\nexport function extendFlatCoordinates(extent, flatCoordinates, offset, end, stride) {\n for (; offset < end; offset += stride) {\n extendXY(extent, flatCoordinates[offset], flatCoordinates[offset + 1]);\n }\n return extent;\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array>} rings Rings.\n * @return {Extent} Extent.\n */\nexport function extendRings(extent, rings) {\n for (var i = 0, ii = rings.length; i < ii; ++i) {\n extendCoordinates(extent, rings[i]);\n }\n return extent;\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n */\nexport function extendXY(extent, x, y) {\n extent[0] = Math.min(extent[0], x);\n extent[1] = Math.min(extent[1], y);\n extent[2] = Math.max(extent[2], x);\n extent[3] = Math.max(extent[3], y);\n}\n\n\n/**\n * This function calls `callback` for each corner of the extent. If the\n * callback returns a truthy value the function returns that value\n * immediately. Otherwise the function returns `false`.\n * @param {Extent} extent Extent.\n * @param {function(this:T, import(\"./coordinate.js\").Coordinate): S} callback Callback.\n * @param {T=} opt_this Value to use as `this` when executing `callback`.\n * @return {S|boolean} Value.\n * @template S, T\n */\nexport function forEachCorner(extent, callback, opt_this) {\n var val;\n val = callback.call(opt_this, getBottomLeft(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getBottomRight(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getTopRight(extent));\n if (val) {\n return val;\n }\n val = callback.call(opt_this, getTopLeft(extent));\n if (val) {\n return val;\n }\n return false;\n}\n\n\n/**\n * Get the size of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Area.\n * @api\n */\nexport function getArea(extent) {\n var area = 0;\n if (!isEmpty(extent)) {\n area = getWidth(extent) * getHeight(extent);\n }\n return area;\n}\n\n\n/**\n * Get the bottom left coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Bottom left coordinate.\n * @api\n */\nexport function getBottomLeft(extent) {\n return [extent[0], extent[1]];\n}\n\n\n/**\n * Get the bottom right coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Bottom right coordinate.\n * @api\n */\nexport function getBottomRight(extent) {\n return [extent[2], extent[1]];\n}\n\n\n/**\n * Get the center coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Center.\n * @api\n */\nexport function getCenter(extent) {\n return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];\n}\n\n\n/**\n * Get a corner coordinate of an extent.\n * @param {Extent} extent Extent.\n * @param {Corner} corner Corner.\n * @return {import(\"./coordinate.js\").Coordinate} Corner coordinate.\n */\nexport function getCorner(extent, corner) {\n var coordinate;\n if (corner === Corner.BOTTOM_LEFT) {\n coordinate = getBottomLeft(extent);\n } else if (corner === Corner.BOTTOM_RIGHT) {\n coordinate = getBottomRight(extent);\n } else if (corner === Corner.TOP_LEFT) {\n coordinate = getTopLeft(extent);\n } else if (corner === Corner.TOP_RIGHT) {\n coordinate = getTopRight(extent);\n } else {\n assert(false, 13); // Invalid corner\n }\n return coordinate;\n}\n\n\n/**\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {number} Enlarged area.\n */\nexport function getEnlargedArea(extent1, extent2) {\n var minX = Math.min(extent1[0], extent2[0]);\n var minY = Math.min(extent1[1], extent2[1]);\n var maxX = Math.max(extent1[2], extent2[2]);\n var maxY = Math.max(extent1[3], extent2[3]);\n return (maxX - minX) * (maxY - minY);\n}\n\n\n/**\n * @param {import(\"./coordinate.js\").Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {import(\"./size.js\").Size} size Size.\n * @param {Extent=} opt_extent Destination extent.\n * @return {Extent} Extent.\n */\nexport function getForViewAndSize(center, resolution, rotation, size, opt_extent) {\n var dx = resolution * size[0] / 2;\n var dy = resolution * size[1] / 2;\n var cosRotation = Math.cos(rotation);\n var sinRotation = Math.sin(rotation);\n var xCos = dx * cosRotation;\n var xSin = dx * sinRotation;\n var yCos = dy * cosRotation;\n var ySin = dy * sinRotation;\n var x = center[0];\n var y = center[1];\n var x0 = x - xCos + ySin;\n var x1 = x - xCos - ySin;\n var x2 = x + xCos - ySin;\n var x3 = x + xCos + ySin;\n var y0 = y - xSin - yCos;\n var y1 = y - xSin + yCos;\n var y2 = y + xSin + yCos;\n var y3 = y + xSin - yCos;\n return createOrUpdate(\n Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),\n Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),\n opt_extent);\n}\n\n\n/**\n * Get the height of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Height.\n * @api\n */\nexport function getHeight(extent) {\n return extent[3] - extent[1];\n}\n\n\n/**\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {number} Intersection area.\n */\nexport function getIntersectionArea(extent1, extent2) {\n var intersection = getIntersection(extent1, extent2);\n return getArea(intersection);\n}\n\n\n/**\n * Get the intersection of two extents.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @param {Extent=} opt_extent Optional extent to populate with intersection.\n * @return {Extent} Intersecting extent.\n * @api\n */\nexport function getIntersection(extent1, extent2, opt_extent) {\n var intersection = opt_extent ? opt_extent : createEmpty();\n if (intersects(extent1, extent2)) {\n if (extent1[0] > extent2[0]) {\n intersection[0] = extent1[0];\n } else {\n intersection[0] = extent2[0];\n }\n if (extent1[1] > extent2[1]) {\n intersection[1] = extent1[1];\n } else {\n intersection[1] = extent2[1];\n }\n if (extent1[2] < extent2[2]) {\n intersection[2] = extent1[2];\n } else {\n intersection[2] = extent2[2];\n }\n if (extent1[3] < extent2[3]) {\n intersection[3] = extent1[3];\n } else {\n intersection[3] = extent2[3];\n }\n } else {\n createOrUpdateEmpty(intersection);\n }\n return intersection;\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @return {number} Margin.\n */\nexport function getMargin(extent) {\n return getWidth(extent) + getHeight(extent);\n}\n\n\n/**\n * Get the size (width, height) of an extent.\n * @param {Extent} extent The extent.\n * @return {import(\"./size.js\").Size} The extent size.\n * @api\n */\nexport function getSize(extent) {\n return [extent[2] - extent[0], extent[3] - extent[1]];\n}\n\n\n/**\n * Get the top left coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Top left coordinate.\n * @api\n */\nexport function getTopLeft(extent) {\n return [extent[0], extent[3]];\n}\n\n\n/**\n * Get the top right coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Top right coordinate.\n * @api\n */\nexport function getTopRight(extent) {\n return [extent[2], extent[3]];\n}\n\n\n/**\n * Get the width of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Width.\n * @api\n */\nexport function getWidth(extent) {\n return extent[2] - extent[0];\n}\n\n\n/**\n * Determine if one extent intersects another.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent.\n * @return {boolean} The two extents intersect.\n * @api\n */\nexport function intersects(extent1, extent2) {\n return extent1[0] <= extent2[2] &&\n extent1[2] >= extent2[0] &&\n extent1[1] <= extent2[3] &&\n extent1[3] >= extent2[1];\n}\n\n\n/**\n * Determine if an extent is empty.\n * @param {Extent} extent Extent.\n * @return {boolean} Is empty.\n * @api\n */\nexport function isEmpty(extent) {\n return extent[2] < extent[0] || extent[3] < extent[1];\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {Extent=} opt_extent Extent.\n * @return {Extent} Extent.\n */\nexport function returnOrUpdate(extent, opt_extent) {\n if (opt_extent) {\n opt_extent[0] = extent[0];\n opt_extent[1] = extent[1];\n opt_extent[2] = extent[2];\n opt_extent[3] = extent[3];\n return opt_extent;\n } else {\n return extent;\n }\n}\n\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} value Value.\n */\nexport function scaleFromCenter(extent, value) {\n var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);\n var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);\n extent[0] -= deltaX;\n extent[2] += deltaX;\n extent[1] -= deltaY;\n extent[3] += deltaY;\n}\n\n\n/**\n * Determine if the segment between two coordinates intersects (crosses,\n * touches, or is contained by) the provided extent.\n * @param {Extent} extent The extent.\n * @param {import(\"./coordinate.js\").Coordinate} start Segment start coordinate.\n * @param {import(\"./coordinate.js\").Coordinate} end Segment end coordinate.\n * @return {boolean} The segment intersects the extent.\n */\nexport function intersectsSegment(extent, start, end) {\n var intersects = false;\n var startRel = coordinateRelationship(extent, start);\n var endRel = coordinateRelationship(extent, end);\n if (startRel === Relationship.INTERSECTING ||\n endRel === Relationship.INTERSECTING) {\n intersects = true;\n } else {\n var minX = extent[0];\n var minY = extent[1];\n var maxX = extent[2];\n var maxY = extent[3];\n var startX = start[0];\n var startY = start[1];\n var endX = end[0];\n var endY = end[1];\n var slope = (endY - startY) / (endX - startX);\n var x, y;\n if (!!(endRel & Relationship.ABOVE) &&\n !(startRel & Relationship.ABOVE)) {\n // potentially intersects top\n x = endX - ((endY - maxY) / slope);\n intersects = x >= minX && x <= maxX;\n }\n if (!intersects && !!(endRel & Relationship.RIGHT) &&\n !(startRel & Relationship.RIGHT)) {\n // potentially intersects right\n y = endY - ((endX - maxX) * slope);\n intersects = y >= minY && y <= maxY;\n }\n if (!intersects && !!(endRel & Relationship.BELOW) &&\n !(startRel & Relationship.BELOW)) {\n // potentially intersects bottom\n x = endX - ((endY - minY) / slope);\n intersects = x >= minX && x <= maxX;\n }\n if (!intersects && !!(endRel & Relationship.LEFT) &&\n !(startRel & Relationship.LEFT)) {\n // potentially intersects left\n y = endY - ((endX - minX) * slope);\n intersects = y >= minY && y <= maxY;\n }\n\n }\n return intersects;\n}\n\n\n/**\n * Apply a transform function to the extent.\n * @param {Extent} extent Extent.\n * @param {import(\"./proj.js\").TransformFunction} transformFn Transform function.\n * Called with `[minX, minY, maxX, maxY]` extent coordinates.\n * @param {Extent=} opt_extent Destination extent.\n * @return {Extent} Extent.\n * @api\n */\nexport function applyTransform(extent, transformFn, opt_extent) {\n var coordinates = [\n extent[0], extent[1],\n extent[0], extent[3],\n extent[2], extent[1],\n extent[2], extent[3]\n ];\n transformFn(coordinates, coordinates, 2);\n var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];\n var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];\n return _boundingExtentXYs(xs, ys, opt_extent);\n}\n\n//# sourceMappingURL=extent.js.map","/**\n * @module ol/events\n */\nimport {clear} from './obj.js';\n\n\n/**\n * Key to use with {@link module:ol/Observable~Observable#unByKey}.\n * @typedef {Object} EventsKey\n * @property {Object} [bindTo]\n * @property {ListenerFunction} [boundListener]\n * @property {boolean} callOnce\n * @property {number} [deleteIndex]\n * @property {ListenerFunction} listener\n * @property {import(\"./events/Target.js\").EventTargetLike} target\n * @property {string} type\n * @api\n */\n\n\n/**\n * Listener function. This function is called with an event object as argument.\n * When the function returns `false`, event propagation will stop.\n *\n * @typedef {function((Event|import(\"./events/Event.js\").default)): (void|boolean)} ListenerFunction\n * @api\n */\n\n\n/**\n * @param {EventsKey} listenerObj Listener object.\n * @return {ListenerFunction} Bound listener.\n */\nexport function bindListener(listenerObj) {\n var boundListener = function(evt) {\n var listener = listenerObj.listener;\n var bindTo = listenerObj.bindTo || listenerObj.target;\n if (listenerObj.callOnce) {\n unlistenByKey(listenerObj);\n }\n return listener.call(bindTo, evt);\n };\n listenerObj.boundListener = boundListener;\n return boundListener;\n}\n\n\n/**\n * Finds the matching {@link module:ol/events~EventsKey} in the given listener\n * array.\n *\n * @param {!Array} listeners Array of listeners.\n * @param {!Function} listener The listener function.\n * @param {Object=} opt_this The `this` value inside the listener.\n * @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching\n * listener, for {@link module:ol/events~unlistenByKey}.\n * @return {EventsKey|undefined} The matching listener object.\n */\nexport function findListener(listeners, listener, opt_this, opt_setDeleteIndex) {\n var listenerObj;\n for (var i = 0, ii = listeners.length; i < ii; ++i) {\n listenerObj = listeners[i];\n if (listenerObj.listener === listener &&\n listenerObj.bindTo === opt_this) {\n if (opt_setDeleteIndex) {\n listenerObj.deleteIndex = i;\n }\n return listenerObj;\n }\n }\n return undefined;\n}\n\n\n/**\n * @param {import(\"./events/Target.js\").EventTargetLike} target Target.\n * @param {string} type Type.\n * @return {Array|undefined} Listeners.\n */\nexport function getListeners(target, type) {\n var listenerMap = getListenerMap(target);\n return listenerMap ? listenerMap[type] : undefined;\n}\n\n\n/**\n * Get the lookup of listeners.\n * @param {Object} target Target.\n * @param {boolean=} opt_create If a map should be created if it doesn't exist.\n * @return {!Object>} Map of\n * listeners by event type.\n */\nfunction getListenerMap(target, opt_create) {\n var listenerMap = target.ol_lm;\n if (!listenerMap && opt_create) {\n listenerMap = target.ol_lm = {};\n }\n return listenerMap;\n}\n\n\n/**\n * Remove the listener map from a target.\n * @param {Object} target Target.\n */\nfunction removeListenerMap(target) {\n delete target.ol_lm;\n}\n\n\n/**\n * Clean up all listener objects of the given type. All properties on the\n * listener objects will be removed, and if no listeners remain in the listener\n * map, it will be removed from the target.\n * @param {import(\"./events/Target.js\").EventTargetLike} target Target.\n * @param {string} type Type.\n */\nfunction removeListeners(target, type) {\n var listeners = getListeners(target, type);\n if (listeners) {\n for (var i = 0, ii = listeners.length; i < ii; ++i) {\n /** @type {import(\"./events/Target.js\").default} */ (target).\n removeEventListener(type, listeners[i].boundListener);\n clear(listeners[i]);\n }\n listeners.length = 0;\n var listenerMap = getListenerMap(target);\n if (listenerMap) {\n delete listenerMap[type];\n if (Object.keys(listenerMap).length === 0) {\n removeListenerMap(target);\n }\n }\n }\n}\n\n\n/**\n * Registers an event listener on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * This function efficiently binds a `listener` to a `this` object, and returns\n * a key for use with {@link module:ol/events~unlistenByKey}.\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @param {boolean=} opt_once If true, add the listener as one-off listener.\n * @return {EventsKey} Unique key for the listener.\n */\nexport function listen(target, type, listener, opt_this, opt_once) {\n var listenerMap = getListenerMap(target, true);\n var listeners = listenerMap[type];\n if (!listeners) {\n listeners = listenerMap[type] = [];\n }\n var listenerObj = findListener(listeners, listener, opt_this, false);\n if (listenerObj) {\n if (!opt_once) {\n // Turn one-off listener into a permanent one.\n listenerObj.callOnce = false;\n }\n } else {\n listenerObj = /** @type {EventsKey} */ ({\n bindTo: opt_this,\n callOnce: !!opt_once,\n listener: listener,\n target: target,\n type: type\n });\n /** @type {import(\"./events/Target.js\").default} */ (target).\n addEventListener(type, bindListener(listenerObj));\n listeners.push(listenerObj);\n }\n\n return listenerObj;\n}\n\n\n/**\n * Registers a one-off event listener on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * This function efficiently binds a `listener` as self-unregistering listener\n * to a `this` object, and returns a key for use with\n * {@link module:ol/events~unlistenByKey} in case the listener needs to be\n * unregistered before it is called.\n *\n * When {@link module:ol/events~listen} is called with the same arguments after this\n * function, the self-unregistering listener will be turned into a permanent\n * listener.\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @return {EventsKey} Key for unlistenByKey.\n */\nexport function listenOnce(target, type, listener, opt_this) {\n return listen(target, type, listener, opt_this, true);\n}\n\n\n/**\n * Unregisters an event listener on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * To return a listener, this function needs to be called with the exact same\n * arguments that were used for a previous {@link module:ol/events~listen} call.\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ListenerFunction} listener Listener.\n * @param {Object=} opt_this Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n */\nexport function unlisten(target, type, listener, opt_this) {\n var listeners = getListeners(target, type);\n if (listeners) {\n var listenerObj = findListener(listeners, listener, opt_this, true);\n if (listenerObj) {\n unlistenByKey(listenerObj);\n }\n }\n}\n\n\n/**\n * Unregisters event listeners on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * The argument passed to this function is the key returned from\n * {@link module:ol/events~listen} or {@link module:ol/events~listenOnce}.\n *\n * @param {EventsKey} key The key.\n */\nexport function unlistenByKey(key) {\n if (key && key.target) {\n /** @type {import(\"./events/Target.js\").default} */ (key.target).\n removeEventListener(key.type, key.boundListener);\n var listeners = getListeners(key.target, key.type);\n if (listeners) {\n var i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);\n if (i !== -1) {\n listeners.splice(i, 1);\n }\n if (listeners.length === 0) {\n removeListeners(key.target, key.type);\n }\n }\n clear(key);\n }\n}\n\n\n/**\n * Unregisters all event listeners on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Target.\n */\nexport function unlistenAll(target) {\n var listenerMap = getListenerMap(target);\n if (listenerMap) {\n for (var type in listenerMap) {\n removeListeners(target, type);\n }\n }\n}\n\n//# sourceMappingURL=events.js.map","/**\n * @module ol/util\n */\n\n/**\n * @return {?} Any return.\n */\nexport function abstract() {\n return /** @type {?} */ ((function() {\n throw new Error('Unimplemented abstract method.');\n })());\n}\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * Usage:\n *\n * function ParentClass(a, b) { }\n * ParentClass.prototype.foo = function(a) { }\n *\n * function ChildClass(a, b, c) {\n * // Call parent constructor\n * ParentClass.call(this, a, b);\n * }\n * inherits(ChildClass, ParentClass);\n *\n * var child = new ChildClass('a', 'b', 'see');\n * child.foo(); // This works.\n *\n * @param {!Function} childCtor Child constructor.\n * @param {!Function} parentCtor Parent constructor.\n * @function module:ol.inherits\n * @deprecated\n * @api\n */\nexport function inherits(childCtor, parentCtor) {\n childCtor.prototype = Object.create(parentCtor.prototype);\n childCtor.prototype.constructor = childCtor;\n}\n\n/**\n * Counter for getUid.\n * @type {number}\n * @private\n */\nvar uidCounter_ = 0;\n\n/**\n * Gets a unique ID for an object. This mutates the object so that further calls\n * with the same object as a parameter returns the same value. Unique IDs are generated\n * as a strictly increasing sequence. Adapted from goog.getUid.\n *\n * @param {Object} obj The object to get the unique ID for.\n * @return {string} The unique ID for the object.\n * @function module:ol.getUid\n * @api\n */\nexport function getUid(obj) {\n return obj.ol_uid || (obj.ol_uid = String(++uidCounter_));\n}\n\n/**\n * OpenLayers version.\n * @type {string}\n */\nexport var VERSION = '5.3.0';\n\n//# sourceMappingURL=util.js.map","/**\n * @module ol/events/EventType\n */\n\n/**\n * @enum {string}\n * @const\n */\nexport default {\n /**\n * Generic change event. Triggered when the revision counter is increased.\n * @event module:ol/events/Event~Event#change\n * @api\n */\n CHANGE: 'change',\n\n CLEAR: 'clear',\n CONTEXTMENU: 'contextmenu',\n CLICK: 'click',\n DBLCLICK: 'dblclick',\n DRAGENTER: 'dragenter',\n DRAGOVER: 'dragover',\n DROP: 'drop',\n ERROR: 'error',\n KEYDOWN: 'keydown',\n KEYPRESS: 'keypress',\n LOAD: 'load',\n MOUSEDOWN: 'mousedown',\n MOUSEMOVE: 'mousemove',\n MOUSEOUT: 'mouseout',\n MOUSEUP: 'mouseup',\n MOUSEWHEEL: 'mousewheel',\n MSPOINTERDOWN: 'MSPointerDown',\n RESIZE: 'resize',\n TOUCHSTART: 'touchstart',\n TOUCHMOVE: 'touchmove',\n TOUCHEND: 'touchend',\n WHEEL: 'wheel'\n};\n\n//# sourceMappingURL=EventType.js.map","/**\n * @module ol/render/canvas\n */\nimport {getFontFamilies} from '../css.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {clear} from '../obj.js';\nimport LRUCache from '../structs/LRUCache.js';\nimport {create as createTransform} from '../transform.js';\n\n\n/**\n * @typedef {Object} FillState\n * @property {import(\"../colorlike.js\").ColorLike} fillStyle\n */\n\n\n/**\n * @typedef {Object} FillStrokeState\n * @property {import(\"../colorlike.js\").ColorLike} [currentFillStyle]\n * @property {import(\"../colorlike.js\").ColorLike} [currentStrokeStyle]\n * @property {string} [currentLineCap]\n * @property {Array} currentLineDash\n * @property {number} [currentLineDashOffset]\n * @property {string} [currentLineJoin]\n * @property {number} [currentLineWidth]\n * @property {number} [currentMiterLimit]\n * @property {number} [lastStroke]\n * @property {import(\"../colorlike.js\").ColorLike} [fillStyle]\n * @property {import(\"../colorlike.js\").ColorLike} [strokeStyle]\n * @property {string} [lineCap]\n * @property {Array} lineDash\n * @property {number} [lineDashOffset]\n * @property {string} [lineJoin]\n * @property {number} [lineWidth]\n * @property {number} [miterLimit]\n */\n\n\n/**\n * @typedef {Object} StrokeState\n * @property {string} lineCap\n * @property {Array} lineDash\n * @property {number} lineDashOffset\n * @property {string} lineJoin\n * @property {number} lineWidth\n * @property {number} miterLimit\n * @property {import(\"../colorlike.js\").ColorLike} strokeStyle\n */\n\n\n/**\n * @typedef {Object} TextState\n * @property {string} font\n * @property {string} [textAlign]\n * @property {string} textBaseline\n * @property {string} [placement]\n * @property {number} [maxAngle]\n * @property {boolean} [overflow]\n * @property {import(\"../style/Fill.js\").default} [backgroundFill]\n * @property {import(\"../style/Stroke.js\").default} [backgroundStroke]\n * @property {number} [scale]\n * @property {Array} [padding]\n */\n\n\n/**\n * Container for decluttered replay instructions that need to be rendered or\n * omitted together, i.e. when styles render both an image and text, or for the\n * characters that form text along lines. The basic elements of this array are\n * `[minX, minY, maxX, maxY, count]`, where the first four entries are the\n * rendered extent of the group in pixel space. `count` is the number of styles\n * in the group, i.e. 2 when an image and a text are grouped, or 1 otherwise.\n * In addition to these four elements, declutter instruction arrays (i.e. the\n * arguments to {@link module:ol/render/canvas~drawImage} are appended to the array.\n * @typedef {Array<*>} DeclutterGroup\n */\n\n\n/**\n * @const\n * @type {string}\n */\nexport var defaultFont = '10px sans-serif';\n\n\n/**\n * @const\n * @type {import(\"../color.js\").Color}\n */\nexport var defaultFillStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nexport var defaultLineCap = 'round';\n\n\n/**\n * @const\n * @type {Array}\n */\nexport var defaultLineDash = [];\n\n\n/**\n * @const\n * @type {number}\n */\nexport var defaultLineDashOffset = 0;\n\n\n/**\n * @const\n * @type {string}\n */\nexport var defaultLineJoin = 'round';\n\n\n/**\n * @const\n * @type {number}\n */\nexport var defaultMiterLimit = 10;\n\n\n/**\n * @const\n * @type {import(\"../color.js\").Color}\n */\nexport var defaultStrokeStyle = [0, 0, 0, 1];\n\n\n/**\n * @const\n * @type {string}\n */\nexport var defaultTextAlign = 'center';\n\n\n/**\n * @const\n * @type {string}\n */\nexport var defaultTextBaseline = 'middle';\n\n\n/**\n * @const\n * @type {Array}\n */\nexport var defaultPadding = [0, 0, 0, 0];\n\n\n/**\n * @const\n * @type {number}\n */\nexport var defaultLineWidth = 1;\n\n\n/**\n * The label cache for text rendering. To change the default cache size of 2048\n * entries, use {@link module:ol/structs/LRUCache#setSize}.\n * @type {LRUCache}\n * @api\n */\nexport var labelCache = new LRUCache();\n\n\n/**\n * @type {!Object}\n */\nexport var checkedFonts = {};\n\n\n/**\n * @type {CanvasRenderingContext2D}\n */\nvar measureContext = null;\n\n\n/**\n * @type {!Object}\n */\nexport var textHeights = {};\n\n\n/**\n * Clears the label cache when a font becomes available.\n * @param {string} fontSpec CSS font spec.\n */\nexport var checkFont = (function() {\n var retries = 60;\n var checked = checkedFonts;\n var size = '32px ';\n var referenceFonts = ['monospace', 'serif'];\n var len = referenceFonts.length;\n var text = 'wmytzilWMYTZIL@#/&?$%10\\uF013';\n var interval, referenceWidth;\n\n function isAvailable(font) {\n var context = getMeasureContext();\n // Check weight ranges according to\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#Fallback_weights\n for (var weight = 100; weight <= 700; weight += 300) {\n var fontWeight = weight + ' ';\n var available = true;\n for (var i = 0; i < len; ++i) {\n var referenceFont = referenceFonts[i];\n context.font = fontWeight + size + referenceFont;\n referenceWidth = context.measureText(text).width;\n if (font != referenceFont) {\n context.font = fontWeight + size + font + ',' + referenceFont;\n var width = context.measureText(text).width;\n // If width and referenceWidth are the same, then the fallback was used\n // instead of the font we wanted, so the font is not available.\n available = available && width != referenceWidth;\n }\n }\n if (available) {\n // Consider font available when it is available in one weight range.\n //FIXME With this we miss rare corner cases, so we should consider\n //FIXME checking availability for each requested weight range.\n return true;\n }\n }\n return false;\n }\n\n function check() {\n var done = true;\n for (var font in checked) {\n if (checked[font] < retries) {\n if (isAvailable(font)) {\n checked[font] = retries;\n clear(textHeights);\n // Make sure that loaded fonts are picked up by Safari\n measureContext = null;\n labelCache.clear();\n } else {\n ++checked[font];\n done = false;\n }\n }\n }\n if (done) {\n clearInterval(interval);\n interval = undefined;\n }\n }\n\n return function(fontSpec) {\n var fontFamilies = getFontFamilies(fontSpec);\n if (!fontFamilies) {\n return;\n }\n for (var i = 0, ii = fontFamilies.length; i < ii; ++i) {\n var fontFamily = fontFamilies[i];\n if (!(fontFamily in checked)) {\n checked[fontFamily] = retries;\n if (!isAvailable(fontFamily)) {\n checked[fontFamily] = 0;\n if (interval === undefined) {\n interval = setInterval(check, 32);\n }\n }\n }\n }\n };\n})();\n\n\n/**\n * @return {CanvasRenderingContext2D} Measure context.\n */\nfunction getMeasureContext() {\n if (!measureContext) {\n measureContext = createCanvasContext2D(1, 1);\n }\n return measureContext;\n}\n\n\n/**\n * @param {string} font Font to use for measuring.\n * @return {import(\"../size.js\").Size} Measurement.\n */\nexport var measureTextHeight = (function() {\n var span;\n var heights = textHeights;\n return function(font) {\n var height = heights[font];\n if (height == undefined) {\n if (!span) {\n span = document.createElement('span');\n span.textContent = 'M';\n span.style.margin = span.style.padding = '0 !important';\n span.style.position = 'absolute !important';\n span.style.left = '-99999px !important';\n }\n span.style.font = font;\n document.body.appendChild(span);\n height = heights[font] = span.offsetHeight;\n document.body.removeChild(span);\n }\n return height;\n };\n})();\n\n\n/**\n * @param {string} font Font.\n * @param {string} text Text.\n * @return {number} Width.\n */\nexport function measureTextWidth(font, text) {\n var measureContext = getMeasureContext();\n if (font != measureContext.font) {\n measureContext.font = font;\n }\n return measureContext.measureText(text).width;\n}\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} rotation Rotation.\n * @param {number} offsetX X offset.\n * @param {number} offsetY Y offset.\n */\nexport function rotateAtOffset(context, rotation, offsetX, offsetY) {\n if (rotation !== 0) {\n context.translate(offsetX, offsetY);\n context.rotate(rotation);\n context.translate(-offsetX, -offsetY);\n }\n}\n\n\nexport var resetTransform = createTransform();\n\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {import(\"../transform.js\").Transform|null} transform Transform.\n * @param {number} opacity Opacity.\n * @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.\n * @param {number} originX Origin X.\n * @param {number} originY Origin Y.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} scale Scale.\n */\nexport function drawImage(context,\n transform, opacity, image, originX, originY, w, h, x, y, scale) {\n var alpha;\n if (opacity != 1) {\n alpha = context.globalAlpha;\n context.globalAlpha = alpha * opacity;\n }\n if (transform) {\n context.setTransform.apply(context, transform);\n }\n\n context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);\n\n if (alpha) {\n context.globalAlpha = alpha;\n }\n if (transform) {\n context.setTransform.apply(context, resetTransform);\n }\n}\n\n//# sourceMappingURL=canvas.js.map","/**\n * @module ol/geom/GeometryType\n */\n\n/**\n * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,\n * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,\n * `'GeometryCollection'`, `'Circle'`.\n * @enum {string}\n */\nexport default {\n POINT: 'Point',\n LINE_STRING: 'LineString',\n LINEAR_RING: 'LinearRing',\n POLYGON: 'Polygon',\n MULTI_POINT: 'MultiPoint',\n MULTI_LINE_STRING: 'MultiLineString',\n MULTI_POLYGON: 'MultiPolygon',\n GEOMETRY_COLLECTION: 'GeometryCollection',\n CIRCLE: 'Circle'\n};\n\n//# sourceMappingURL=GeometryType.js.map","/**\n * @module ol/math\n */\nimport {assert} from './asserts.js';\n\n/**\n * Takes a number and clamps it to within the provided bounds.\n * @param {number} value The input number.\n * @param {number} min The minimum value to return.\n * @param {number} max The maximum value to return.\n * @return {number} The input number if it is within bounds, or the nearest\n * number within the bounds.\n */\nexport function clamp(value, min, max) {\n return Math.min(Math.max(value, min), max);\n}\n\n\n/**\n * Return the hyperbolic cosine of a given number. The method will use the\n * native `Math.cosh` function if it is available, otherwise the hyperbolic\n * cosine will be calculated via the reference implementation of the Mozilla\n * developer network.\n *\n * @param {number} x X.\n * @return {number} Hyperbolic cosine of x.\n */\nexport var cosh = (function() {\n // Wrapped in a iife, to save the overhead of checking for the native\n // implementation on every invocation.\n var cosh;\n if ('cosh' in Math) {\n // The environment supports the native Math.cosh function, use it…\n cosh = Math.cosh;\n } else {\n // … else, use the reference implementation of MDN:\n cosh = function(x) {\n var y = /** @type {Math} */ (Math).exp(x);\n return (y + 1 / y) / 2;\n };\n }\n return cosh;\n}());\n\n\n/**\n * @param {number} x X.\n * @return {number} The smallest power of two greater than or equal to x.\n */\nexport function roundUpToPowerOfTwo(x) {\n assert(0 < x, 29); // `x` must be greater than `0`\n return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));\n}\n\n\n/**\n * Returns the square of the closest distance between the point (x, y) and the\n * line segment (x1, y1) to (x2, y2).\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredSegmentDistance(x, y, x1, y1, x2, y2) {\n var dx = x2 - x1;\n var dy = y2 - y1;\n if (dx !== 0 || dy !== 0) {\n var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n x1 = x2;\n y1 = y2;\n } else if (t > 0) {\n x1 += dx * t;\n y1 += dy * t;\n }\n }\n return squaredDistance(x, y, x1, y1);\n}\n\n\n/**\n * Returns the square of the distance between the points (x1, y1) and (x2, y2).\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredDistance(x1, y1, x2, y2) {\n var dx = x2 - x1;\n var dy = y2 - y1;\n return dx * dx + dy * dy;\n}\n\n\n/**\n * Solves system of linear equations using Gaussian elimination method.\n *\n * @param {Array>} mat Augmented matrix (n x n + 1 column)\n * in row-major order.\n * @return {Array} The resulting vector.\n */\nexport function solveLinearSystem(mat) {\n var n = mat.length;\n\n for (var i = 0; i < n; i++) {\n // Find max in the i-th column (ignoring i - 1 first rows)\n var maxRow = i;\n var maxEl = Math.abs(mat[i][i]);\n for (var r = i + 1; r < n; r++) {\n var absValue = Math.abs(mat[r][i]);\n if (absValue > maxEl) {\n maxEl = absValue;\n maxRow = r;\n }\n }\n\n if (maxEl === 0) {\n return null; // matrix is singular\n }\n\n // Swap max row with i-th (current) row\n var tmp = mat[maxRow];\n mat[maxRow] = mat[i];\n mat[i] = tmp;\n\n // Subtract the i-th row to make all the remaining rows 0 in the i-th column\n for (var j = i + 1; j < n; j++) {\n var coef = -mat[j][i] / mat[i][i];\n for (var k = i; k < n + 1; k++) {\n if (i == k) {\n mat[j][k] = 0;\n } else {\n mat[j][k] += coef * mat[i][k];\n }\n }\n }\n }\n\n // Solve Ax=b for upper triangular matrix A (mat)\n var x = new Array(n);\n for (var l = n - 1; l >= 0; l--) {\n x[l] = mat[l][n] / mat[l][l];\n for (var m = l - 1; m >= 0; m--) {\n mat[m][n] -= mat[m][l] * x[l];\n }\n }\n return x;\n}\n\n\n/**\n * Converts radians to to degrees.\n *\n * @param {number} angleInRadians Angle in radians.\n * @return {number} Angle in degrees.\n */\nexport function toDegrees(angleInRadians) {\n return angleInRadians * 180 / Math.PI;\n}\n\n\n/**\n * Converts degrees to radians.\n *\n * @param {number} angleInDegrees Angle in degrees.\n * @return {number} Angle in radians.\n */\nexport function toRadians(angleInDegrees) {\n return angleInDegrees * Math.PI / 180;\n}\n\n/**\n * Returns the modulo of a / b, depending on the sign of b.\n *\n * @param {number} a Dividend.\n * @param {number} b Divisor.\n * @return {number} Modulo.\n */\nexport function modulo(a, b) {\n var r = a % b;\n return r * b < 0 ? r + b : r;\n}\n\n/**\n * Calculates the linearly interpolated value of x between a and b.\n *\n * @param {number} a Number\n * @param {number} b Number\n * @param {number} x Value to be interpolated.\n * @return {number} Interpolated value.\n */\nexport function lerp(a, b, x) {\n return a + x * (b - a);\n}\n\n//# sourceMappingURL=math.js.map","/**\n * @module ol/TileState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n /**\n * Indicates that tile loading failed\n * @type {number}\n */\n ERROR: 3,\n EMPTY: 4,\n ABORT: 5\n};\n\n//# sourceMappingURL=TileState.js.map","/**\n * @module ol/transform\n */\nimport {assert} from './asserts.js';\n\n\n/**\n * An array representing an affine 2d transformation for use with\n * {@link module:ol/transform} functions. The array has 6 elements.\n * @typedef {!Array} Transform\n */\n\n\n/**\n * Collection of affine 2d transformation functions. The functions work on an\n * array of 6 elements. The element order is compatible with the [SVGMatrix\n * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is\n * a subset (elements a to f) of a 3×3 matrix:\n * ```\n * [ a c e ]\n * [ b d f ]\n * [ 0 0 1 ]\n * ```\n */\n\n\n/**\n * @private\n * @type {Transform}\n */\nvar tmp_ = new Array(6);\n\n\n/**\n * Create an identity transform.\n * @return {!Transform} Identity transform.\n */\nexport function create() {\n return [1, 0, 0, 1, 0, 0];\n}\n\n\n/**\n * Resets the given transform to an identity transform.\n * @param {!Transform} transform Transform.\n * @return {!Transform} Transform.\n */\nexport function reset(transform) {\n return set(transform, 1, 0, 0, 1, 0, 0);\n}\n\n\n/**\n * Multiply the underlying matrices of two transforms and return the result in\n * the first transform.\n * @param {!Transform} transform1 Transform parameters of matrix 1.\n * @param {!Transform} transform2 Transform parameters of matrix 2.\n * @return {!Transform} transform1 multiplied with transform2.\n */\nexport function multiply(transform1, transform2) {\n var a1 = transform1[0];\n var b1 = transform1[1];\n var c1 = transform1[2];\n var d1 = transform1[3];\n var e1 = transform1[4];\n var f1 = transform1[5];\n var a2 = transform2[0];\n var b2 = transform2[1];\n var c2 = transform2[2];\n var d2 = transform2[3];\n var e2 = transform2[4];\n var f2 = transform2[5];\n\n transform1[0] = a1 * a2 + c1 * b2;\n transform1[1] = b1 * a2 + d1 * b2;\n transform1[2] = a1 * c2 + c1 * d2;\n transform1[3] = b1 * c2 + d1 * d2;\n transform1[4] = a1 * e2 + c1 * f2 + e1;\n transform1[5] = b1 * e2 + d1 * f2 + f1;\n\n return transform1;\n}\n\n/**\n * Set the transform components a-f on a given transform.\n * @param {!Transform} transform Transform.\n * @param {number} a The a component of the transform.\n * @param {number} b The b component of the transform.\n * @param {number} c The c component of the transform.\n * @param {number} d The d component of the transform.\n * @param {number} e The e component of the transform.\n * @param {number} f The f component of the transform.\n * @return {!Transform} Matrix with transform applied.\n */\nexport function set(transform, a, b, c, d, e, f) {\n transform[0] = a;\n transform[1] = b;\n transform[2] = c;\n transform[3] = d;\n transform[4] = e;\n transform[5] = f;\n return transform;\n}\n\n\n/**\n * Set transform on one matrix from another matrix.\n * @param {!Transform} transform1 Matrix to set transform to.\n * @param {!Transform} transform2 Matrix to set transform from.\n * @return {!Transform} transform1 with transform from transform2 applied.\n */\nexport function setFromArray(transform1, transform2) {\n transform1[0] = transform2[0];\n transform1[1] = transform2[1];\n transform1[2] = transform2[2];\n transform1[3] = transform2[3];\n transform1[4] = transform2[4];\n transform1[5] = transform2[5];\n return transform1;\n}\n\n\n/**\n * Transforms the given coordinate with the given transform returning the\n * resulting, transformed coordinate. The coordinate will be modified in-place.\n *\n * @param {Transform} transform The transformation.\n * @param {import(\"./coordinate.js\").Coordinate|import(\"./pixel.js\").Pixel} coordinate The coordinate to transform.\n * @return {import(\"./coordinate.js\").Coordinate|import(\"./pixel.js\").Pixel} return coordinate so that operations can be\n * chained together.\n */\nexport function apply(transform, coordinate) {\n var x = coordinate[0];\n var y = coordinate[1];\n coordinate[0] = transform[0] * x + transform[2] * y + transform[4];\n coordinate[1] = transform[1] * x + transform[3] * y + transform[5];\n return coordinate;\n}\n\n\n/**\n * Applies rotation to the given transform.\n * @param {!Transform} transform Transform.\n * @param {number} angle Angle in radians.\n * @return {!Transform} The rotated transform.\n */\nexport function rotate(transform, angle) {\n var cos = Math.cos(angle);\n var sin = Math.sin(angle);\n return multiply(transform, set(tmp_, cos, sin, -sin, cos, 0, 0));\n}\n\n\n/**\n * Applies scale to a given transform.\n * @param {!Transform} transform Transform.\n * @param {number} x Scale factor x.\n * @param {number} y Scale factor y.\n * @return {!Transform} The scaled transform.\n */\nexport function scale(transform, x, y) {\n return multiply(transform, set(tmp_, x, 0, 0, y, 0, 0));\n}\n\n\n/**\n * Applies translation to the given transform.\n * @param {!Transform} transform Transform.\n * @param {number} dx Translation x.\n * @param {number} dy Translation y.\n * @return {!Transform} The translated transform.\n */\nexport function translate(transform, dx, dy) {\n return multiply(transform, set(tmp_, 1, 0, 0, 1, dx, dy));\n}\n\n\n/**\n * Creates a composite transform given an initial translation, scale, rotation, and\n * final translation (in that order only, not commutative).\n * @param {!Transform} transform The transform (will be modified in place).\n * @param {number} dx1 Initial translation x.\n * @param {number} dy1 Initial translation y.\n * @param {number} sx Scale factor x.\n * @param {number} sy Scale factor y.\n * @param {number} angle Rotation (in counter-clockwise radians).\n * @param {number} dx2 Final translation x.\n * @param {number} dy2 Final translation y.\n * @return {!Transform} The composite transform.\n */\nexport function compose(transform, dx1, dy1, sx, sy, angle, dx2, dy2) {\n var sin = Math.sin(angle);\n var cos = Math.cos(angle);\n transform[0] = sx * cos;\n transform[1] = sy * sin;\n transform[2] = -sx * sin;\n transform[3] = sy * cos;\n transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1;\n transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1;\n return transform;\n}\n\n\n/**\n * Invert the given transform.\n * @param {!Transform} transform Transform.\n * @return {!Transform} Inverse of the transform.\n */\nexport function invert(transform) {\n var det = determinant(transform);\n assert(det !== 0, 32); // Transformation matrix cannot be inverted\n\n var a = transform[0];\n var b = transform[1];\n var c = transform[2];\n var d = transform[3];\n var e = transform[4];\n var f = transform[5];\n\n transform[0] = d / det;\n transform[1] = -b / det;\n transform[2] = -c / det;\n transform[3] = a / det;\n transform[4] = (c * f - d * e) / det;\n transform[5] = -(a * f - b * e) / det;\n\n return transform;\n}\n\n\n/**\n * Returns the determinant of the given matrix.\n * @param {!Transform} mat Matrix.\n * @return {number} Determinant.\n */\nexport function determinant(mat) {\n return mat[0] * mat[3] - mat[1] * mat[2];\n}\n\n//# sourceMappingURL=transform.js.map","/**\n * @module ol/asserts\n */\nimport AssertionError from './AssertionError.js';\n\n/**\n * @param {*} assertion Assertion we expected to be truthy.\n * @param {number} errorCode Error code.\n */\nexport function assert(assertion, errorCode) {\n if (!assertion) {\n throw new AssertionError(errorCode);\n }\n}\n\n//# sourceMappingURL=asserts.js.map","/**\n * @module ol/dom\n */\n\n\n/**\n * Create an html canvas element and returns its 2d context.\n * @param {number=} opt_width Canvas width.\n * @param {number=} opt_height Canvas height.\n * @return {CanvasRenderingContext2D} The context.\n */\nexport function createCanvasContext2D(opt_width, opt_height) {\n var canvas = /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));\n if (opt_width) {\n canvas.width = opt_width;\n }\n if (opt_height) {\n canvas.height = opt_height;\n }\n return /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d'));\n}\n\n\n/**\n * Get the current computed width for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerWidth(true)`.\n * @param {!HTMLElement} element Element.\n * @return {number} The width.\n */\nexport function outerWidth(element) {\n var width = element.offsetWidth;\n var style = getComputedStyle(element);\n width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);\n\n return width;\n}\n\n\n/**\n * Get the current computed height for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerHeight(true)`.\n * @param {!HTMLElement} element Element.\n * @return {number} The height.\n */\nexport function outerHeight(element) {\n var height = element.offsetHeight;\n var style = getComputedStyle(element);\n height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);\n\n return height;\n}\n\n/**\n * @param {Node} newNode Node to replace old node\n * @param {Node} oldNode The node to be replaced\n */\nexport function replaceNode(newNode, oldNode) {\n var parent = oldNode.parentNode;\n if (parent) {\n parent.replaceChild(newNode, oldNode);\n }\n}\n\n/**\n * @param {Node} node The node to remove.\n * @returns {Node} The node that was removed or null.\n */\nexport function removeNode(node) {\n return node && node.parentNode ? node.parentNode.removeChild(node) : null;\n}\n\n/**\n * @param {Node} node The node to remove the children from.\n */\nexport function removeChildren(node) {\n while (node.lastChild) {\n node.removeChild(node.lastChild);\n }\n}\n\n//# sourceMappingURL=dom.js.map","/**\n * @module ol/obj\n */\n\n\n/**\n * Polyfill for Object.assign(). Assigns enumerable and own properties from\n * one or more source objects to a target object.\n * See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign.\n *\n * @param {!Object} target The target object.\n * @param {...Object} var_sources The source object(s).\n * @return {!Object} The modified target object.\n */\nexport var assign = (typeof Object.assign === 'function') ? Object.assign : function(target, var_sources) {\n var arguments$1 = arguments;\n\n if (target === undefined || target === null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var output = Object(target);\n for (var i = 1, ii = arguments.length; i < ii; ++i) {\n var source = arguments$1[i];\n if (source !== undefined && source !== null) {\n for (var key in source) {\n if (source.hasOwnProperty(key)) {\n output[key] = source[key];\n }\n }\n }\n }\n return output;\n};\n\n\n/**\n * Removes all properties from an object.\n * @param {Object} object The object to clear.\n */\nexport function clear(object) {\n for (var property in object) {\n delete object[property];\n }\n}\n\n\n/**\n * Get an array of property values from an object.\n * @param {Object} object The object from which to get the values.\n * @return {!Array} The property values.\n * @template K,V\n */\nexport function getValues(object) {\n var values = [];\n for (var property in object) {\n values.push(object[property]);\n }\n return values;\n}\n\n\n/**\n * Determine if an object has any properties.\n * @param {Object} object The object to check.\n * @return {boolean} The object is empty.\n */\nexport function isEmpty(object) {\n var property;\n for (property in object) {\n return false;\n }\n return !property;\n}\n\n//# sourceMappingURL=obj.js.map","/**\n * @module ol/ViewHint\n */\n\n/**\n * @enum {number}\n */\nexport default {\n ANIMATING: 0,\n INTERACTING: 1\n};\n\n//# sourceMappingURL=ViewHint.js.map","/**\n * @module ol/Object\n */\nimport {getUid} from './util.js';\nimport ObjectEventType from './ObjectEventType.js';\nimport Observable from './Observable.js';\nimport Event from './events/Event.js';\nimport {assign} from './obj.js';\n\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Object~BaseObject} instances are instances of this type.\n */\nexport var ObjectEvent = /*@__PURE__*/(function (Event) {\n function ObjectEvent(type, key, oldValue) {\n Event.call(this, type);\n\n /**\n * The name of the property whose value is changing.\n * @type {string}\n * @api\n */\n this.key = key;\n\n /**\n * The old value. To get the new value use `e.target.get(e.key)` where\n * `e` is the event object.\n * @type {*}\n * @api\n */\n this.oldValue = oldValue;\n\n }\n\n if ( Event ) ObjectEvent.__proto__ = Event;\n ObjectEvent.prototype = Object.create( Event && Event.prototype );\n ObjectEvent.prototype.constructor = ObjectEvent;\n\n return ObjectEvent;\n}(Event));\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Most non-trivial classes inherit from this.\n *\n * This extends {@link module:ol/Observable} with observable\n * properties, where each property is observable as well as the object as a\n * whole.\n *\n * Classes that inherit from this have pre-defined properties, to which you can\n * add your owns. The pre-defined properties are listed in this documentation as\n * 'Observable Properties', and have their own accessors; for example,\n * {@link module:ol/Map~Map} has a `target` property, accessed with\n * `getTarget()` and changed with `setTarget()`. Not all properties are however\n * settable. There are also general-purpose accessors `get()` and `set()`. For\n * example, `get('target')` is equivalent to `getTarget()`.\n *\n * The `set` accessors trigger a change event, and you can monitor this by\n * registering a listener. For example, {@link module:ol/View~View} has a\n * `center` property, so `view.on('change:center', function(evt) {...});` would\n * call the function whenever the value of the center property changes. Within\n * the function, `evt.target` would be the view, so `evt.target.getCenter()`\n * would return the new center.\n *\n * You can add your own observable properties with\n * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.\n * You can listen for changes on that property value with\n * `object.on('change:prop', listener)`. You can get a list of all\n * properties with {@link module:ol/Object~BaseObject#getProperties}.\n *\n * Note that the observable properties are separate from standard JS properties.\n * You can, for example, give your map object a title with\n * `map.title='New title'` and with `map.set('title', 'Another title')`. The\n * first will be a `hasOwnProperty`; the second will appear in\n * `getProperties()`. Only the second is observable.\n *\n * Properties can be deleted by using the unset method. E.g.\n * object.unset('foo').\n *\n * @fires ObjectEvent\n * @api\n */\nvar BaseObject = /*@__PURE__*/(function (Observable) {\n function BaseObject(opt_values) {\n Observable.call(this);\n\n // Call {@link module:ol/util~getUid} to ensure that the order of objects' ids is\n // the same as the order in which they were created. This also helps to\n // ensure that object properties are always added in the same order, which\n // helps many JavaScript engines generate faster code.\n getUid(this);\n\n /**\n * @private\n * @type {!Object}\n */\n this.values_ = {};\n\n if (opt_values !== undefined) {\n this.setProperties(opt_values);\n }\n }\n\n if ( Observable ) BaseObject.__proto__ = Observable;\n BaseObject.prototype = Object.create( Observable && Observable.prototype );\n BaseObject.prototype.constructor = BaseObject;\n\n /**\n * Gets a value.\n * @param {string} key Key name.\n * @return {*} Value.\n * @api\n */\n BaseObject.prototype.get = function get (key) {\n var value;\n if (this.values_.hasOwnProperty(key)) {\n value = this.values_[key];\n }\n return value;\n };\n\n /**\n * Get a list of object property names.\n * @return {Array} List of property names.\n * @api\n */\n BaseObject.prototype.getKeys = function getKeys () {\n return Object.keys(this.values_);\n };\n\n /**\n * Get an object of all property names and values.\n * @return {Object} Object.\n * @api\n */\n BaseObject.prototype.getProperties = function getProperties () {\n return assign({}, this.values_);\n };\n\n /**\n * @param {string} key Key name.\n * @param {*} oldValue Old value.\n */\n BaseObject.prototype.notify = function notify (key, oldValue) {\n var eventType;\n eventType = getChangeEventType(key);\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n eventType = ObjectEventType.PROPERTYCHANGE;\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n };\n\n /**\n * Sets a value.\n * @param {string} key Key name.\n * @param {*} value Value.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api\n */\n BaseObject.prototype.set = function set (key, value, opt_silent) {\n if (opt_silent) {\n this.values_[key] = value;\n } else {\n var oldValue = this.values_[key];\n this.values_[key] = value;\n if (oldValue !== value) {\n this.notify(key, oldValue);\n }\n }\n };\n\n /**\n * Sets a collection of key-value pairs. Note that this changes any existing\n * properties and adds new ones (it does not remove any existing properties).\n * @param {Object} values Values.\n * @param {boolean=} opt_silent Update without triggering an event.\n * @api\n */\n BaseObject.prototype.setProperties = function setProperties (values, opt_silent) {\n for (var key in values) {\n this.set(key, values[key], opt_silent);\n }\n };\n\n /**\n * Unsets a property.\n * @param {string} key Key name.\n * @param {boolean=} opt_silent Unset without triggering an event.\n * @api\n */\n BaseObject.prototype.unset = function unset (key, opt_silent) {\n if (key in this.values_) {\n var oldValue = this.values_[key];\n delete this.values_[key];\n if (!opt_silent) {\n this.notify(key, oldValue);\n }\n }\n };\n\n return BaseObject;\n}(Observable));\n\n\n/**\n * @type {Object}\n */\nvar changeEventTypeCache = {};\n\n\n/**\n * @param {string} key Key name.\n * @return {string} Change name.\n */\nexport function getChangeEventType(key) {\n return changeEventTypeCache.hasOwnProperty(key) ?\n changeEventTypeCache[key] :\n (changeEventTypeCache[key] = 'change:' + key);\n}\n\n\nexport default BaseObject;\n\n//# sourceMappingURL=Object.js.map","/**\n * @module ol/css\n */\n\n\n/**\n * The CSS class for hidden feature.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_HIDDEN = 'ol-hidden';\n\n\n/**\n * The CSS class that we'll give the DOM elements to have them selectable.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_SELECTABLE = 'ol-selectable';\n\n\n/**\n * The CSS class that we'll give the DOM elements to have them unselectable.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_UNSELECTABLE = 'ol-unselectable';\n\n\n/**\n * The CSS class for unsupported feature.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_UNSUPPORTED = 'ol-unsupported';\n\n\n/**\n * The CSS class for controls.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_CONTROL = 'ol-control';\n\n\n/**\n * The CSS class that we'll give the DOM elements that are collapsed, i.e.\n * to those elements which usually can be expanded.\n *\n * @const\n * @type {string}\n */\nexport var CLASS_COLLAPSED = 'ol-collapsed';\n\n\n/**\n * Get the list of font families from a font spec. Note that this doesn't work\n * for font families that have commas in them.\n * @param {string} The CSS font property.\n * @return {Object} The font families (or null if the input spec is invalid).\n */\nexport var getFontFamilies = (function() {\n var style;\n var cache = {};\n return function(font) {\n if (!style) {\n style = document.createElement('div').style;\n }\n if (!(font in cache)) {\n style.font = font;\n var family = style.fontFamily;\n style.font = '';\n if (!family) {\n return null;\n }\n cache[font] = family.split(/,\\s?/);\n }\n return cache[font];\n };\n})();\n\n//# sourceMappingURL=css.js.map","/**\n * @module ol/array\n */\n\n\n/**\n * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1.\n * https://github.com/darkskyapp/binary-search\n *\n * @param {Array<*>} haystack Items to search through.\n * @param {*} needle The item to look for.\n * @param {Function=} opt_comparator Comparator function.\n * @return {number} The index of the item if found, -1 if not.\n */\nexport function binarySearch(haystack, needle, opt_comparator) {\n var mid, cmp;\n var comparator = opt_comparator || numberSafeCompareFunction;\n var low = 0;\n var high = haystack.length;\n var found = false;\n\n while (low < high) {\n /* Note that \"(low + high) >>> 1\" may overflow, and results in a typecast\n * to double (which gives the wrong results). */\n mid = low + (high - low >> 1);\n cmp = +comparator(haystack[mid], needle);\n\n if (cmp < 0.0) { /* Too low. */\n low = mid + 1;\n\n } else { /* Key found or too high */\n high = mid;\n found = !cmp;\n }\n }\n\n /* Key not found. */\n return found ? low : ~low;\n}\n\n\n/**\n * Compare function for array sort that is safe for numbers.\n * @param {*} a The first object to be compared.\n * @param {*} b The second object to be compared.\n * @return {number} A negative number, zero, or a positive number as the first\n * argument is less than, equal to, or greater than the second.\n */\nexport function numberSafeCompareFunction(a, b) {\n return a > b ? 1 : a < b ? -1 : 0;\n}\n\n\n/**\n * Whether the array contains the given object.\n * @param {Array<*>} arr The array to test for the presence of the element.\n * @param {*} obj The object for which to test.\n * @return {boolean} The object is in the array.\n */\nexport function includes(arr, obj) {\n return arr.indexOf(obj) >= 0;\n}\n\n\n/**\n * @param {Array} arr Array.\n * @param {number} target Target.\n * @param {number} direction 0 means return the nearest, > 0\n * means return the largest nearest, < 0 means return the\n * smallest nearest.\n * @return {number} Index.\n */\nexport function linearFindNearest(arr, target, direction) {\n var n = arr.length;\n if (arr[0] <= target) {\n return 0;\n } else if (target <= arr[n - 1]) {\n return n - 1;\n } else {\n var i;\n if (direction > 0) {\n for (i = 1; i < n; ++i) {\n if (arr[i] < target) {\n return i - 1;\n }\n }\n } else if (direction < 0) {\n for (i = 1; i < n; ++i) {\n if (arr[i] <= target) {\n return i;\n }\n }\n } else {\n for (i = 1; i < n; ++i) {\n if (arr[i] == target) {\n return i;\n } else if (arr[i] < target) {\n if (arr[i - 1] - target < target - arr[i]) {\n return i - 1;\n } else {\n return i;\n }\n }\n }\n }\n return n - 1;\n }\n}\n\n\n/**\n * @param {Array<*>} arr Array.\n * @param {number} begin Begin index.\n * @param {number} end End index.\n */\nexport function reverseSubArray(arr, begin, end) {\n while (begin < end) {\n var tmp = arr[begin];\n arr[begin] = arr[end];\n arr[end] = tmp;\n ++begin;\n --end;\n }\n}\n\n\n/**\n * @param {Array} arr The array to modify.\n * @param {!Array|VALUE} data The elements or arrays of elements to add to arr.\n * @template VALUE\n */\nexport function extend(arr, data) {\n var extension = Array.isArray(data) ? data : [data];\n var length = extension.length;\n for (var i = 0; i < length; i++) {\n arr[arr.length] = extension[i];\n }\n}\n\n\n/**\n * @param {Array} arr The array to modify.\n * @param {VALUE} obj The element to remove.\n * @template VALUE\n * @return {boolean} If the element was removed.\n */\nexport function remove(arr, obj) {\n var i = arr.indexOf(obj);\n var found = i > -1;\n if (found) {\n arr.splice(i, 1);\n }\n return found;\n}\n\n\n/**\n * @param {Array} arr The array to search in.\n * @param {function(VALUE, number, ?) : boolean} func The function to compare.\n * @template VALUE\n * @return {VALUE|null} The element found or null.\n */\nexport function find(arr, func) {\n var length = arr.length >>> 0;\n var value;\n\n for (var i = 0; i < length; i++) {\n value = arr[i];\n if (func(value, i, arr)) {\n return value;\n }\n }\n return null;\n}\n\n\n/**\n * @param {Array|Uint8ClampedArray} arr1 The first array to compare.\n * @param {Array|Uint8ClampedArray} arr2 The second array to compare.\n * @return {boolean} Whether the two arrays are equal.\n */\nexport function equals(arr1, arr2) {\n var len1 = arr1.length;\n if (len1 !== arr2.length) {\n return false;\n }\n for (var i = 0; i < len1; i++) {\n if (arr1[i] !== arr2[i]) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * Sort the passed array such that the relative order of equal elements is preverved.\n * See https://en.wikipedia.org/wiki/Sorting_algorithm#Stability for details.\n * @param {Array<*>} arr The array to sort (modifies original).\n * @param {!function(*, *): number} compareFnc Comparison function.\n * @api\n */\nexport function stableSort(arr, compareFnc) {\n var length = arr.length;\n var tmp = Array(arr.length);\n var i;\n for (i = 0; i < length; i++) {\n tmp[i] = {index: i, value: arr[i]};\n }\n tmp.sort(function(a, b) {\n return compareFnc(a.value, b.value) || a.index - b.index;\n });\n for (i = 0; i < arr.length; i++) {\n arr[i] = tmp[i].value;\n }\n}\n\n\n/**\n * @param {Array<*>} arr The array to search in.\n * @param {Function} func Comparison function.\n * @return {number} Return index.\n */\nexport function findIndex(arr, func) {\n var index;\n var found = !arr.every(function(el, idx) {\n index = idx;\n return !func(el, idx, arr);\n });\n return found ? index : -1;\n}\n\n\n/**\n * @param {Array<*>} arr The array to test.\n * @param {Function=} opt_func Comparison function.\n * @param {boolean=} opt_strict Strictly sorted (default false).\n * @return {boolean} Return index.\n */\nexport function isSorted(arr, opt_func, opt_strict) {\n var compare = opt_func || numberSafeCompareFunction;\n return arr.every(function(currentVal, index) {\n if (index === 0) {\n return true;\n }\n var res = compare(arr[index - 1], currentVal);\n return !(res > 0 || opt_strict && res === 0);\n });\n}\n\n//# sourceMappingURL=array.js.map","/**\n * @module ol/proj/Projection\n */\nimport {METERS_PER_UNIT} from './Units.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} code The SRS identifier code, e.g. `EPSG:4326`.\n * @property {import(\"./Units.js\").default|string} [units] Units. Required unless a\n * proj4 projection is defined for `code`.\n * @property {import(\"../extent.js\").Extent} [extent] The validity extent for the SRS.\n * @property {string} [axisOrientation='enu'] The axis orientation as specified in Proj4.\n * @property {boolean} [global=false] Whether the projection is valid for the whole globe.\n * @property {number} [metersPerUnit] The meters per unit for the SRS.\n * If not provided, the `units` are used to get the meters per unit from the {@link module:ol/proj/Units~METERS_PER_UNIT}\n * lookup table.\n * @property {import(\"../extent.js\").Extent} [worldExtent] The world extent for the SRS.\n * @property {function(number, import(\"../coordinate.js\").Coordinate):number} [getPointResolution]\n * Function to determine resolution at a point. The function is called with a\n * `{number}` view resolution and an `{import(\"../coordinate.js\").Coordinate}` as arguments, and returns\n * the `{number}` resolution at the passed coordinate. If this is `undefined`,\n * the default {@link module:ol/proj#getPointResolution} function will be used.\n */\n\n\n/**\n * @classdesc\n * Projection definition class. One of these is created for each projection\n * supported in the application and stored in the {@link module:ol/proj} namespace.\n * You can use these in applications, but this is not required, as API params\n * and options use {@link module:ol/proj~ProjectionLike} which means the simple string\n * code will suffice.\n *\n * You can use {@link module:ol/proj~get} to retrieve the object for a particular\n * projection.\n *\n * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together\n * with the following aliases:\n * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,\n * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,\n * http://www.opengis.net/gml/srs/epsg.xml#4326,\n * urn:x-ogc:def:crs:EPSG:4326\n * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,\n * urn:ogc:def:crs:EPSG:6.18:3:3857,\n * http://www.opengis.net/gml/srs/epsg.xml#3857\n *\n * If you use [proj4js](https://github.com/proj4js/proj4js), aliases can\n * be added using `proj4.defs()`. After all required projection definitions are\n * added, call the {@link module:ol/proj/proj4~register} function.\n *\n * @api\n */\nvar Projection = function Projection(options) {\n /**\n * @private\n * @type {string}\n */\n this.code_ = options.code;\n\n /**\n * Units of projected coordinates. When set to `TILE_PIXELS`, a\n * `this.extent_` and `this.worldExtent_` must be configured properly for each\n * tile.\n * @private\n * @type {import(\"./Units.js\").default}\n */\n this.units_ = /** @type {import(\"./Units.js\").default} */ (options.units);\n\n /**\n * Validity extent of the projection in projected coordinates. For projections\n * with `TILE_PIXELS` units, this is the extent of the tile in\n * tile pixel space.\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.extent_ = options.extent !== undefined ? options.extent : null;\n\n /**\n * Extent of the world in EPSG:4326. For projections with\n * `TILE_PIXELS` units, this is the extent of the tile in\n * projected coordinate space.\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.worldExtent_ = options.worldExtent !== undefined ?\n options.worldExtent : null;\n\n /**\n * @private\n * @type {string}\n */\n this.axisOrientation_ = options.axisOrientation !== undefined ?\n options.axisOrientation : 'enu';\n\n /**\n * @private\n * @type {boolean}\n */\n this.global_ = options.global !== undefined ? options.global : false;\n\n /**\n * @private\n * @type {boolean}\n */\n this.canWrapX_ = !!(this.global_ && this.extent_);\n\n /**\n * @private\n * @type {function(number, import(\"../coordinate.js\").Coordinate):number|undefined}\n */\n this.getPointResolutionFunc_ = options.getPointResolution;\n\n /**\n * @private\n * @type {import(\"../tilegrid/TileGrid.js\").default}\n */\n this.defaultTileGrid_ = null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.metersPerUnit_ = options.metersPerUnit;\n};\n\n/**\n * @return {boolean} The projection is suitable for wrapping the x-axis\n */\nProjection.prototype.canWrapX = function canWrapX () {\n return this.canWrapX_;\n};\n\n/**\n * Get the code for this projection, e.g. 'EPSG:4326'.\n * @return {string} Code.\n * @api\n */\nProjection.prototype.getCode = function getCode () {\n return this.code_;\n};\n\n/**\n * Get the validity extent for this projection.\n * @return {import(\"../extent.js\").Extent} Extent.\n * @api\n */\nProjection.prototype.getExtent = function getExtent () {\n return this.extent_;\n};\n\n/**\n * Get the units of this projection.\n * @return {import(\"./Units.js\").default} Units.\n * @api\n */\nProjection.prototype.getUnits = function getUnits () {\n return this.units_;\n};\n\n/**\n * Get the amount of meters per unit of this projection.If the projection is\n * not configured with `metersPerUnit` or a units identifier, the return is\n * `undefined`.\n * @return {number|undefined} Meters.\n * @api\n */\nProjection.prototype.getMetersPerUnit = function getMetersPerUnit () {\n return this.metersPerUnit_ || METERS_PER_UNIT[this.units_];\n};\n\n/**\n * Get the world extent for this projection.\n * @return {import(\"../extent.js\").Extent} Extent.\n * @api\n */\nProjection.prototype.getWorldExtent = function getWorldExtent () {\n return this.worldExtent_;\n};\n\n/**\n * Get the axis orientation of this projection.\n * Example values are:\n * enu - the default easting, northing, elevation.\n * neu - northing, easting, up - useful for \"lat/long\" geographic coordinates,\n * or south orientated transverse mercator.\n * wnu - westing, northing, up - some planetary coordinate systems have\n * \"west positive\" coordinate systems\n * @return {string} Axis orientation.\n * @api\n */\nProjection.prototype.getAxisOrientation = function getAxisOrientation () {\n return this.axisOrientation_;\n};\n\n/**\n * Is this projection a global projection which spans the whole world?\n * @return {boolean} Whether the projection is global.\n * @api\n */\nProjection.prototype.isGlobal = function isGlobal () {\n return this.global_;\n};\n\n/**\n * Set if the projection is a global projection which spans the whole world\n * @param {boolean} global Whether the projection is global.\n * @api\n */\nProjection.prototype.setGlobal = function setGlobal (global) {\n this.global_ = global;\n this.canWrapX_ = !!(global && this.extent_);\n};\n\n/**\n * @return {import(\"../tilegrid/TileGrid.js\").default} The default tile grid.\n */\nProjection.prototype.getDefaultTileGrid = function getDefaultTileGrid () {\n return this.defaultTileGrid_;\n};\n\n/**\n * @param {import(\"../tilegrid/TileGrid.js\").default} tileGrid The default tile grid.\n */\nProjection.prototype.setDefaultTileGrid = function setDefaultTileGrid (tileGrid) {\n this.defaultTileGrid_ = tileGrid;\n};\n\n/**\n * Set the validity extent for this projection.\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @api\n */\nProjection.prototype.setExtent = function setExtent (extent) {\n this.extent_ = extent;\n this.canWrapX_ = !!(this.global_ && extent);\n};\n\n/**\n * Set the world extent for this projection.\n * @param {import(\"../extent.js\").Extent} worldExtent World extent\n * [minlon, minlat, maxlon, maxlat].\n * @api\n */\nProjection.prototype.setWorldExtent = function setWorldExtent (worldExtent) {\n this.worldExtent_ = worldExtent;\n};\n\n/**\n * Set the getPointResolution function (see {@link module:ol/proj~getPointResolution}\n * for this projection.\n * @param {function(number, import(\"../coordinate.js\").Coordinate):number} func Function\n * @api\n */\nProjection.prototype.setGetPointResolution = function setGetPointResolution (func) {\n this.getPointResolutionFunc_ = func;\n};\n\n/**\n * Get the custom point resolution function for this projection (if set).\n * @return {function(number, import(\"../coordinate.js\").Coordinate):number|undefined} The custom point\n * resolution function (if set).\n */\nProjection.prototype.getPointResolutionFunc = function getPointResolutionFunc () {\n return this.getPointResolutionFunc_;\n};\n\nexport default Projection;\n\n//# sourceMappingURL=Projection.js.map","/**\n * @module ol/proj/epsg3857\n */\nimport {cosh} from '../math.js';\nimport Projection from './Projection.js';\nimport Units from './Units.js';\n\n\n/**\n * Radius of WGS84 sphere\n *\n * @const\n * @type {number}\n */\nexport var RADIUS = 6378137;\n\n\n/**\n * @const\n * @type {number}\n */\nexport var HALF_SIZE = Math.PI * RADIUS;\n\n\n/**\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport var EXTENT = [\n -HALF_SIZE, -HALF_SIZE,\n HALF_SIZE, HALF_SIZE\n];\n\n\n/**\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport var WORLD_EXTENT = [-180, -85, 180, 85];\n\n\n/**\n * @classdesc\n * Projection object for web/spherical Mercator (EPSG:3857).\n */\nvar EPSG3857Projection = /*@__PURE__*/(function (Projection) {\n function EPSG3857Projection(code) {\n Projection.call(this, {\n code: code,\n units: Units.METERS,\n extent: EXTENT,\n global: true,\n worldExtent: WORLD_EXTENT,\n getPointResolution: function(resolution, point) {\n return resolution / cosh(point[1] / RADIUS);\n }\n });\n\n }\n\n if ( Projection ) EPSG3857Projection.__proto__ = Projection;\n EPSG3857Projection.prototype = Object.create( Projection && Projection.prototype );\n EPSG3857Projection.prototype.constructor = EPSG3857Projection;\n\n return EPSG3857Projection;\n}(Projection));\n\n\n/**\n * Projections equal to EPSG:3857.\n *\n * @const\n * @type {Array}\n */\nexport var PROJECTIONS = [\n new EPSG3857Projection('EPSG:3857'),\n new EPSG3857Projection('EPSG:102100'),\n new EPSG3857Projection('EPSG:102113'),\n new EPSG3857Projection('EPSG:900913'),\n new EPSG3857Projection('urn:ogc:def:crs:EPSG:6.18:3:3857'),\n new EPSG3857Projection('urn:ogc:def:crs:EPSG::3857'),\n new EPSG3857Projection('http://www.opengis.net/gml/srs/epsg.xml#3857')\n];\n\n\n/**\n * Transformation from EPSG:4326 to EPSG:3857.\n *\n * @param {Array} input Input array of coordinate values.\n * @param {Array=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array} Output array of coordinate values.\n */\nexport function fromEPSG4326(input, opt_output, opt_dimension) {\n var length = input.length;\n var dimension = opt_dimension > 1 ? opt_dimension : 2;\n var output = opt_output;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n var halfSize = HALF_SIZE;\n for (var i = 0; i < length; i += dimension) {\n output[i] = halfSize * input[i] / 180;\n var y = RADIUS *\n Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));\n if (y > halfSize) {\n y = halfSize;\n } else if (y < -halfSize) {\n y = -halfSize;\n }\n output[i + 1] = y;\n }\n return output;\n}\n\n\n/**\n * Transformation from EPSG:3857 to EPSG:4326.\n *\n * @param {Array} input Input array of coordinate values.\n * @param {Array=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension (default is `2`).\n * @return {Array} Output array of coordinate values.\n */\nexport function toEPSG4326(input, opt_output, opt_dimension) {\n var length = input.length;\n var dimension = opt_dimension > 1 ? opt_dimension : 2;\n var output = opt_output;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n for (var i = 0; i < length; i += dimension) {\n output[i] = 180 * input[i] / HALF_SIZE;\n output[i + 1] = 360 * Math.atan(\n Math.exp(input[i + 1] / RADIUS)) / Math.PI - 90;\n }\n return output;\n}\n\n//# sourceMappingURL=epsg3857.js.map","/**\n * @module ol/proj/epsg4326\n */\nimport Projection from './Projection.js';\nimport Units from './Units.js';\n\n\n/**\n * Semi-major radius of the WGS84 ellipsoid.\n *\n * @const\n * @type {number}\n */\nexport var RADIUS = 6378137;\n\n\n/**\n * Extent of the EPSG:4326 projection which is the whole world.\n *\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport var EXTENT = [-180, -90, 180, 90];\n\n\n/**\n * @const\n * @type {number}\n */\nexport var METERS_PER_UNIT = Math.PI * RADIUS / 180;\n\n\n/**\n * @classdesc\n * Projection object for WGS84 geographic coordinates (EPSG:4326).\n *\n * Note that OpenLayers does not strictly comply with the EPSG definition.\n * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).\n * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.\n */\nvar EPSG4326Projection = /*@__PURE__*/(function (Projection) {\n function EPSG4326Projection(code, opt_axisOrientation) {\n Projection.call(this, {\n code: code,\n units: Units.DEGREES,\n extent: EXTENT,\n axisOrientation: opt_axisOrientation,\n global: true,\n metersPerUnit: METERS_PER_UNIT,\n worldExtent: EXTENT\n });\n\n }\n\n if ( Projection ) EPSG4326Projection.__proto__ = Projection;\n EPSG4326Projection.prototype = Object.create( Projection && Projection.prototype );\n EPSG4326Projection.prototype.constructor = EPSG4326Projection;\n\n return EPSG4326Projection;\n}(Projection));\n\n\n/**\n * Projections equal to EPSG:4326.\n *\n * @const\n * @type {Array}\n */\nexport var PROJECTIONS = [\n new EPSG4326Projection('CRS:84'),\n new EPSG4326Projection('EPSG:4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:EPSG::4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:1.3:CRS84'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:2:84'),\n new EPSG4326Projection('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),\n new EPSG4326Projection('urn:x-ogc:def:crs:EPSG:4326', 'neu')\n];\n\n//# sourceMappingURL=epsg4326.js.map","/**\n * @module ol/proj/projections\n */\n\n\n/**\n * @type {Object}\n */\nvar cache = {};\n\n\n/**\n * Clear the projections cache.\n */\nexport function clear() {\n cache = {};\n}\n\n\n/**\n * Get a cached projection by code.\n * @param {string} code The code for the projection.\n * @return {import(\"./Projection.js\").default} The projection (if cached).\n */\nexport function get(code) {\n return cache[code] || null;\n}\n\n\n/**\n * Add a projection to the cache.\n * @param {string} code The projection code.\n * @param {import(\"./Projection.js\").default} projection The projection to cache.\n */\nexport function add(code, projection) {\n cache[code] = projection;\n}\n\n//# sourceMappingURL=projections.js.map","/**\n * @module ol/proj/transforms\n */\nimport {isEmpty} from '../obj.js';\n\n\n/**\n * @private\n * @type {!Object>}\n */\nvar transforms = {};\n\n\n/**\n * Clear the transform cache.\n */\nexport function clear() {\n transforms = {};\n}\n\n\n/**\n * Registers a conversion function to convert coordinates from the source\n * projection to the destination projection.\n *\n * @param {import(\"./Projection.js\").default} source Source.\n * @param {import(\"./Projection.js\").default} destination Destination.\n * @param {import(\"../proj.js\").TransformFunction} transformFn Transform.\n */\nexport function add(source, destination, transformFn) {\n var sourceCode = source.getCode();\n var destinationCode = destination.getCode();\n if (!(sourceCode in transforms)) {\n transforms[sourceCode] = {};\n }\n transforms[sourceCode][destinationCode] = transformFn;\n}\n\n\n/**\n * Unregisters the conversion function to convert coordinates from the source\n * projection to the destination projection. This method is used to clean up\n * cached transforms during testing.\n *\n * @param {import(\"./Projection.js\").default} source Source projection.\n * @param {import(\"./Projection.js\").default} destination Destination projection.\n * @return {import(\"../proj.js\").TransformFunction} transformFn The unregistered transform.\n */\nexport function remove(source, destination) {\n var sourceCode = source.getCode();\n var destinationCode = destination.getCode();\n var transform = transforms[sourceCode][destinationCode];\n delete transforms[sourceCode][destinationCode];\n if (isEmpty(transforms[sourceCode])) {\n delete transforms[sourceCode];\n }\n return transform;\n}\n\n\n/**\n * Get a transform given a source code and a destination code.\n * @param {string} sourceCode The code for the source projection.\n * @param {string} destinationCode The code for the destination projection.\n * @return {import(\"../proj.js\").TransformFunction|undefined} The transform function (if found).\n */\nexport function get(sourceCode, destinationCode) {\n var transform;\n if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {\n transform = transforms[sourceCode][destinationCode];\n }\n return transform;\n}\n\n//# sourceMappingURL=transforms.js.map","/**\n * @module ol/proj\n */\n\n/**\n * The ol/proj module stores:\n * * a list of {@link module:ol/proj/Projection}\n * objects, one for each projection supported by the application\n * * a list of transform functions needed to convert coordinates in one projection\n * into another.\n *\n * The static functions are the methods used to maintain these.\n * Each transform function can handle not only simple coordinate pairs, but also\n * large arrays of coordinates such as vector geometries.\n *\n * When loaded, the library adds projection objects for EPSG:4326 (WGS84\n * geographic coordinates) and EPSG:3857 (Web or Spherical Mercator, as used\n * for example by Bing Maps or OpenStreetMap), together with the relevant\n * transform functions.\n *\n * Additional transforms may be added by using the http://proj4js.org/\n * library (version 2.2 or later). You can use the full build supplied by\n * Proj4js, or create a custom build to support those projections you need; see\n * the Proj4js website for how to do this. You also need the Proj4js definitions\n * for the required projections. These definitions can be obtained from\n * https://epsg.io/, and are a JS function, so can be loaded in a script\n * tag (as in the examples) or pasted into your application.\n *\n * After all required projection definitions are added to proj4's registry (by\n * using `proj4.defs()`), simply call `register(proj4)` from the `ol/proj/proj4`\n * package. Existing transforms are not changed by this function. See\n * examples/wms-image-custom-proj for an example of this.\n *\n * Additional projection definitions can be registered with `proj4.defs()` any\n * time. Just make sure to call `register(proj4)` again; for example, with user-supplied data where you don't\n * know in advance what projections are needed, you can initially load minimal\n * support and then load whichever are requested.\n *\n * Note that Proj4js does not support projection extents. If you want to add\n * one for creating default tile grids, you can add it after the Projection\n * object has been created with `setExtent`, for example,\n * `get('EPSG:1234').setExtent(extent)`.\n *\n * In addition to Proj4js support, any transform functions can be added with\n * {@link module:ol/proj~addCoordinateTransforms}. To use this, you must first create\n * a {@link module:ol/proj/Projection} object for the new projection and add it with\n * {@link module:ol/proj~addProjection}. You can then add the forward and inverse\n * functions with {@link module:ol/proj~addCoordinateTransforms}. See\n * examples/wms-custom-proj for an example of this.\n *\n * Note that if no transforms are needed and you only need to define the\n * projection, just add a {@link module:ol/proj/Projection} with\n * {@link module:ol/proj~addProjection}. See examples/wms-no-proj for an example of\n * this.\n */\nimport {getDistance} from './sphere.js';\nimport {applyTransform} from './extent.js';\nimport {modulo} from './math.js';\nimport {toEPSG4326, fromEPSG4326, PROJECTIONS as EPSG3857_PROJECTIONS} from './proj/epsg3857.js';\nimport {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js';\nimport Projection from './proj/Projection.js';\nimport Units, {METERS_PER_UNIT} from './proj/Units.js';\nimport * as projections from './proj/projections.js';\nimport {add as addTransformFunc, clear as clearTransformFuncs, get as getTransformFunc} from './proj/transforms.js';\n\n\n/**\n * A projection as {@link module:ol/proj/Projection}, SRS identifier\n * string or undefined.\n * @typedef {Projection|string|undefined} ProjectionLike\n * @api\n */\n\n\n/**\n * A transform function accepts an array of input coordinate values, an optional\n * output array, and an optional dimension (default should be 2). The function\n * transforms the input coordinate values, populates the output array, and\n * returns the output array.\n *\n * @typedef {function(Array, Array=, number=): Array} TransformFunction\n * @api\n */\n\n\nexport {METERS_PER_UNIT};\n\nexport {Projection};\n\n/**\n * @param {Array} input Input coordinate array.\n * @param {Array=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array} Output coordinate array (new array, same coordinate\n * values).\n */\nexport function cloneTransform(input, opt_output, opt_dimension) {\n var output;\n if (opt_output !== undefined) {\n for (var i = 0, ii = input.length; i < ii; ++i) {\n opt_output[i] = input[i];\n }\n output = opt_output;\n } else {\n output = input.slice();\n }\n return output;\n}\n\n\n/**\n * @param {Array} input Input coordinate array.\n * @param {Array=} opt_output Output array of coordinate values.\n * @param {number=} opt_dimension Dimension.\n * @return {Array} Input coordinate array (same array as input).\n */\nexport function identityTransform(input, opt_output, opt_dimension) {\n if (opt_output !== undefined && input !== opt_output) {\n for (var i = 0, ii = input.length; i < ii; ++i) {\n opt_output[i] = input[i];\n }\n input = opt_output;\n }\n return input;\n}\n\n\n/**\n * Add a Projection object to the list of supported projections that can be\n * looked up by their code.\n *\n * @param {Projection} projection Projection instance.\n * @api\n */\nexport function addProjection(projection) {\n projections.add(projection.getCode(), projection);\n addTransformFunc(projection, projection, cloneTransform);\n}\n\n\n/**\n * @param {Array} projections Projections.\n */\nexport function addProjections(projections) {\n projections.forEach(addProjection);\n}\n\n\n/**\n * Fetches a Projection object for the code specified.\n *\n * @param {ProjectionLike} projectionLike Either a code string which is\n * a combination of authority and identifier such as \"EPSG:4326\", or an\n * existing projection object, or undefined.\n * @return {Projection} Projection object, or null if not in list.\n * @api\n */\nexport function get(projectionLike) {\n return typeof projectionLike === 'string' ?\n projections.get(/** @type {string} */ (projectionLike)) :\n (/** @type {Projection} */ (projectionLike) || null);\n}\n\n\n/**\n * Get the resolution of the point in degrees or distance units.\n * For projections with degrees as the unit this will simply return the\n * provided resolution. For other projections the point resolution is\n * by default estimated by transforming the 'point' pixel to EPSG:4326,\n * measuring its width and height on the normal sphere,\n * and taking the average of the width and height.\n * A custom function can be provided for a specific projection, either\n * by setting the `getPointResolution` option in the\n * {@link module:ol/proj/Projection~Projection} constructor or by using\n * {@link module:ol/proj/Projection~Projection#setGetPointResolution} to change an existing\n * projection object.\n * @param {ProjectionLike} projection The projection.\n * @param {number} resolution Nominal resolution in projection units.\n * @param {import(\"./coordinate.js\").Coordinate} point Point to find adjusted resolution at.\n * @param {Units=} opt_units Units to get the point resolution in.\n * Default is the projection's units.\n * @return {number} Point resolution.\n * @api\n */\nexport function getPointResolution(projection, resolution, point, opt_units) {\n projection = get(projection);\n var pointResolution;\n var getter = projection.getPointResolutionFunc();\n if (getter) {\n pointResolution = getter(resolution, point);\n } else {\n var units = projection.getUnits();\n if (units == Units.DEGREES && !opt_units || opt_units == Units.DEGREES) {\n pointResolution = resolution;\n } else {\n // Estimate point resolution by transforming the center pixel to EPSG:4326,\n // measuring its width and height on the normal sphere, and taking the\n // average of the width and height.\n var toEPSG4326 = getTransformFromProjections(projection, get('EPSG:4326'));\n var vertices = [\n point[0] - resolution / 2, point[1],\n point[0] + resolution / 2, point[1],\n point[0], point[1] - resolution / 2,\n point[0], point[1] + resolution / 2\n ];\n vertices = toEPSG4326(vertices, vertices, 2);\n var width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4));\n var height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8));\n pointResolution = (width + height) / 2;\n var metersPerUnit = opt_units ?\n METERS_PER_UNIT[opt_units] :\n projection.getMetersPerUnit();\n if (metersPerUnit !== undefined) {\n pointResolution /= metersPerUnit;\n }\n }\n }\n return pointResolution;\n}\n\n\n/**\n * Registers transformation functions that don't alter coordinates. Those allow\n * to transform between projections with equal meaning.\n *\n * @param {Array} projections Projections.\n * @api\n */\nexport function addEquivalentProjections(projections) {\n addProjections(projections);\n projections.forEach(function(source) {\n projections.forEach(function(destination) {\n if (source !== destination) {\n addTransformFunc(source, destination, cloneTransform);\n }\n });\n });\n}\n\n\n/**\n * Registers transformation functions to convert coordinates in any projection\n * in projection1 to any projection in projection2.\n *\n * @param {Array} projections1 Projections with equal\n * meaning.\n * @param {Array} projections2 Projections with equal\n * meaning.\n * @param {TransformFunction} forwardTransform Transformation from any\n * projection in projection1 to any projection in projection2.\n * @param {TransformFunction} inverseTransform Transform from any projection\n * in projection2 to any projection in projection1..\n */\nexport function addEquivalentTransforms(projections1, projections2, forwardTransform, inverseTransform) {\n projections1.forEach(function(projection1) {\n projections2.forEach(function(projection2) {\n addTransformFunc(projection1, projection2, forwardTransform);\n addTransformFunc(projection2, projection1, inverseTransform);\n });\n });\n}\n\n\n/**\n * Clear all cached projections and transforms.\n */\nexport function clearAllProjections() {\n projections.clear();\n clearTransformFuncs();\n}\n\n\n/**\n * @param {Projection|string|undefined} projection Projection.\n * @param {string} defaultCode Default code.\n * @return {Projection} Projection.\n */\nexport function createProjection(projection, defaultCode) {\n if (!projection) {\n return get(defaultCode);\n } else if (typeof projection === 'string') {\n return get(projection);\n } else {\n return (\n /** @type {Projection} */ (projection)\n );\n }\n}\n\n\n/**\n * Creates a {@link module:ol/proj~TransformFunction} from a simple 2D coordinate transform\n * function.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} coordTransform Coordinate\n * transform.\n * @return {TransformFunction} Transform function.\n */\nexport function createTransformFromCoordinateTransform(coordTransform) {\n return (\n /**\n * @param {Array} input Input.\n * @param {Array=} opt_output Output.\n * @param {number=} opt_dimension Dimension.\n * @return {Array} Output.\n */\n function(input, opt_output, opt_dimension) {\n var length = input.length;\n var dimension = opt_dimension !== undefined ? opt_dimension : 2;\n var output = opt_output !== undefined ? opt_output : new Array(length);\n for (var i = 0; i < length; i += dimension) {\n var point = coordTransform([input[i], input[i + 1]]);\n output[i] = point[0];\n output[i + 1] = point[1];\n for (var j = dimension - 1; j >= 2; --j) {\n output[i + j] = input[i + j];\n }\n }\n return output;\n });\n}\n\n\n/**\n * Registers coordinate transform functions to convert coordinates between the\n * source projection and the destination projection.\n * The forward and inverse functions convert coordinate pairs; this function\n * converts these into the functions used internally which also handle\n * extents and coordinate arrays.\n *\n * @param {ProjectionLike} source Source projection.\n * @param {ProjectionLike} destination Destination projection.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} forward The forward transform\n * function (that is, from the source projection to the destination\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} inverse The inverse transform\n * function (that is, from the destination projection to the source\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}.\n * @api\n */\nexport function addCoordinateTransforms(source, destination, forward, inverse) {\n var sourceProj = get(source);\n var destProj = get(destination);\n addTransformFunc(sourceProj, destProj, createTransformFromCoordinateTransform(forward));\n addTransformFunc(destProj, sourceProj, createTransformFromCoordinateTransform(inverse));\n}\n\n\n/**\n * Transforms a coordinate from longitude/latitude to a different projection.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate as longitude and latitude, i.e.\n * an array with longitude as 1st and latitude as 2nd element.\n * @param {ProjectionLike=} opt_projection Target projection. The\n * default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate projected to the target projection.\n * @api\n */\nexport function fromLonLat(coordinate, opt_projection) {\n return transform(coordinate, 'EPSG:4326',\n opt_projection !== undefined ? opt_projection : 'EPSG:3857');\n}\n\n\n/**\n * Transforms a coordinate to longitude/latitude.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Projected coordinate.\n * @param {ProjectionLike=} opt_projection Projection of the coordinate.\n * The default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate as longitude and latitude, i.e. an array\n * with longitude as 1st and latitude as 2nd element.\n * @api\n */\nexport function toLonLat(coordinate, opt_projection) {\n var lonLat = transform(coordinate,\n opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');\n var lon = lonLat[0];\n if (lon < -180 || lon > 180) {\n lonLat[0] = modulo(lon + 180, 360) - 180;\n }\n return lonLat;\n}\n\n\n/**\n * Checks if two projections are the same, that is every coordinate in one\n * projection does represent the same geographic point as the same coordinate in\n * the other projection.\n *\n * @param {Projection} projection1 Projection 1.\n * @param {Projection} projection2 Projection 2.\n * @return {boolean} Equivalent.\n * @api\n */\nexport function equivalent(projection1, projection2) {\n if (projection1 === projection2) {\n return true;\n }\n var equalUnits = projection1.getUnits() === projection2.getUnits();\n if (projection1.getCode() === projection2.getCode()) {\n return equalUnits;\n } else {\n var transformFunc = getTransformFromProjections(projection1, projection2);\n return transformFunc === cloneTransform && equalUnits;\n }\n}\n\n\n/**\n * Searches in the list of transform functions for the function for converting\n * coordinates from the source projection to the destination projection.\n *\n * @param {Projection} sourceProjection Source Projection object.\n * @param {Projection} destinationProjection Destination Projection\n * object.\n * @return {TransformFunction} Transform function.\n */\nexport function getTransformFromProjections(sourceProjection, destinationProjection) {\n var sourceCode = sourceProjection.getCode();\n var destinationCode = destinationProjection.getCode();\n var transformFunc = getTransformFunc(sourceCode, destinationCode);\n if (!transformFunc) {\n transformFunc = identityTransform;\n }\n return transformFunc;\n}\n\n\n/**\n * Given the projection-like objects, searches for a transformation\n * function to convert a coordinates array from the source projection to the\n * destination projection.\n *\n * @param {ProjectionLike} source Source.\n * @param {ProjectionLike} destination Destination.\n * @return {TransformFunction} Transform function.\n * @api\n */\nexport function getTransform(source, destination) {\n var sourceProjection = get(source);\n var destinationProjection = get(destination);\n return getTransformFromProjections(sourceProjection, destinationProjection);\n}\n\n\n/**\n * Transforms a coordinate from source projection to destination projection.\n * This returns a new coordinate (and does not modify the original).\n *\n * See {@link module:ol/proj~transformExtent} for extent transformation.\n * See the transform method of {@link module:ol/geom/Geometry~Geometry} and its\n * subclasses for geometry transforms.\n *\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {ProjectionLike} source Source projection-like.\n * @param {ProjectionLike} destination Destination projection-like.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate.\n * @api\n */\nexport function transform(coordinate, source, destination) {\n var transformFunc = getTransform(source, destination);\n return transformFunc(coordinate, undefined, coordinate.length);\n}\n\n\n/**\n * Transforms an extent from source projection to destination projection. This\n * returns a new extent (and does not modify the original).\n *\n * @param {import(\"./extent.js\").Extent} extent The extent to transform.\n * @param {ProjectionLike} source Source projection-like.\n * @param {ProjectionLike} destination Destination projection-like.\n * @return {import(\"./extent.js\").Extent} The transformed extent.\n * @api\n */\nexport function transformExtent(extent, source, destination) {\n var transformFunc = getTransform(source, destination);\n return applyTransform(extent, transformFunc);\n}\n\n\n/**\n * Transforms the given point to the destination projection.\n *\n * @param {import(\"./coordinate.js\").Coordinate} point Point.\n * @param {Projection} sourceProjection Source projection.\n * @param {Projection} destinationProjection Destination projection.\n * @return {import(\"./coordinate.js\").Coordinate} Point.\n */\nexport function transformWithProjections(point, sourceProjection, destinationProjection) {\n var transformFunc = getTransformFromProjections(sourceProjection, destinationProjection);\n return transformFunc(point);\n}\n\n/**\n * Add transforms to and from EPSG:4326 and EPSG:3857. This function is called\n * by when this module is executed and should only need to be called again after\n * `clearAllProjections()` is called (e.g. in tests).\n */\nexport function addCommon() {\n // Add transformations that don't alter coordinates to convert within set of\n // projections with equal meaning.\n addEquivalentProjections(EPSG3857_PROJECTIONS);\n addEquivalentProjections(EPSG4326_PROJECTIONS);\n // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like\n // coordinates and back.\n addEquivalentTransforms(EPSG4326_PROJECTIONS, EPSG3857_PROJECTIONS, fromEPSG4326, toEPSG4326);\n}\n\naddCommon();\n\n//# sourceMappingURL=proj.js.map","/**\n * @module ol/functions\n */\n\n/**\n * Always returns true.\n * @returns {boolean} true.\n */\nexport function TRUE() {\n return true;\n}\n\n/**\n * Always returns false.\n * @returns {boolean} false.\n */\nexport function FALSE() {\n return false;\n}\n\n/**\n * A reusable function, used e.g. as a default for callbacks.\n *\n * @return {void} Nothing.\n */\nexport function VOID() {}\n\n//# sourceMappingURL=functions.js.map","/**\n * @module ol/ImageState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n ERROR: 3\n};\n\n//# sourceMappingURL=ImageState.js.map","/**\n * @module ol/has\n */\n\nvar ua = typeof navigator !== 'undefined' ?\n navigator.userAgent.toLowerCase() : '';\n\n/**\n * User agent string says we are dealing with Firefox as browser.\n * @type {boolean}\n */\nexport var FIREFOX = ua.indexOf('firefox') !== -1;\n\n/**\n * User agent string says we are dealing with Safari as browser.\n * @type {boolean}\n */\nexport var SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') == -1;\n\n/**\n * User agent string says we are dealing with a WebKit engine.\n * @type {boolean}\n */\nexport var WEBKIT = ua.indexOf('webkit') !== -1 && ua.indexOf('edge') == -1;\n\n/**\n * User agent string says we are dealing with a Mac as platform.\n * @type {boolean}\n */\nexport var MAC = ua.indexOf('macintosh') !== -1;\n\n\n/**\n * The ratio between physical pixels and device-independent pixels\n * (dips) on the device (`window.devicePixelRatio`).\n * @const\n * @type {number}\n * @api\n */\nexport var DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;\n\n\n/**\n * True if the browser's Canvas implementation implements {get,set}LineDash.\n * @type {boolean}\n */\nexport var CANVAS_LINE_DASH = function() {\n var has = false;\n try {\n has = !!document.createElement('canvas').getContext('2d').setLineDash;\n } catch (e) {\n // pass\n }\n return has;\n}();\n\n\n/**\n * Is HTML5 geolocation supported in the current browser?\n * @const\n * @type {boolean}\n * @api\n */\nexport var GEOLOCATION = 'geolocation' in navigator;\n\n\n/**\n * True if browser supports touch events.\n * @const\n * @type {boolean}\n * @api\n */\nexport var TOUCH = 'ontouchstart' in window;\n\n\n/**\n * True if browser supports pointer events.\n * @const\n * @type {boolean}\n */\nexport var POINTER = 'PointerEvent' in window;\n\n\n/**\n * True if browser supports ms pointer events (IE 10).\n * @const\n * @type {boolean}\n */\nexport var MSPOINTER = !!(navigator.msPointerEnabled);\n\n\nexport {HAS as WEBGL} from './webgl.js';\n\n//# sourceMappingURL=has.js.map","/**\n * @module ol/proj/Units\n */\n\n/**\n * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or\n * `'us-ft'`.\n * @enum {string}\n */\nvar Units = {\n DEGREES: 'degrees',\n FEET: 'ft',\n METERS: 'm',\n PIXELS: 'pixels',\n TILE_PIXELS: 'tile-pixels',\n USFEET: 'us-ft'\n};\n\n\n/**\n * Meters per unit lookup table.\n * @const\n * @type {Object}\n * @api\n */\nexport var METERS_PER_UNIT = {};\n// use the radius of the Normal sphere\nMETERS_PER_UNIT[Units.DEGREES] = 2 * Math.PI * 6370997 / 360;\nMETERS_PER_UNIT[Units.FEET] = 0.3048;\nMETERS_PER_UNIT[Units.METERS] = 1;\nMETERS_PER_UNIT[Units.USFEET] = 1200 / 3937;\n\nexport default Units;\n\n//# sourceMappingURL=Units.js.map","/**\n * @module ol/easing\n */\n\n\n/**\n * Start slow and speed up.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function easeIn(t) {\n return Math.pow(t, 3);\n}\n\n\n/**\n * Start fast and slow down.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function easeOut(t) {\n return 1 - easeIn(1 - t);\n}\n\n\n/**\n * Start slow, speed up, and then slow down again.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function inAndOut(t) {\n return 3 * t * t - 2 * t * t * t;\n}\n\n\n/**\n * Maintain a constant speed over time.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function linear(t) {\n return t;\n}\n\n\n/**\n * Start slow, speed up, and at the very end slow down again. This has the\n * same general behavior as {@link module:ol/easing~inAndOut}, but the final\n * slowdown is delayed.\n * @param {number} t Input between 0 and 1.\n * @return {number} Output between 0 and 1.\n * @api\n */\nexport function upAndDown(t) {\n if (t < 0.5) {\n return inAndOut(2 * t);\n } else {\n return 1 - inAndOut(2 * (t - 0.5));\n }\n}\n\n//# sourceMappingURL=easing.js.map","/**\n * @module ol/events/Event\n */\n\n/**\n * @classdesc\n * Stripped down implementation of the W3C DOM Level 2 Event interface.\n * See https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface.\n *\n * This implementation only provides `type` and `target` properties, and\n * `stopPropagation` and `preventDefault` methods. It is meant as base class\n * for higher level events defined in the library, and works with\n * {@link module:ol/events/Target~Target}.\n */\nvar Event = function Event(type) {\n\n /**\n * @type {boolean}\n */\n this.propagationStopped;\n\n /**\n * The event type.\n * @type {string}\n * @api\n */\n this.type = type;\n\n /**\n * The event target.\n * @type {Object}\n * @api\n */\n this.target = null;\n};\n\n/**\n * Stop event propagation.\n * @api\n */\nEvent.prototype.preventDefault = function preventDefault () {\n this.propagationStopped = true;\n};\n\n/**\n * Stop event propagation.\n * @api\n */\nEvent.prototype.stopPropagation = function stopPropagation () {\n this.propagationStopped = true;\n};\n\n\n/**\n * @param {Event|import(\"./Event.js\").default} evt Event\n */\nexport function stopPropagation(evt) {\n evt.stopPropagation();\n}\n\n\n/**\n * @param {Event|import(\"./Event.js\").default} evt Event\n */\nexport function preventDefault(evt) {\n evt.preventDefault();\n}\n\nexport default Event;\n\n//# sourceMappingURL=Event.js.map","/**\n * @module ol/layer/Property\n */\n\n/**\n * @enum {string}\n */\nexport default {\n OPACITY: 'opacity',\n VISIBLE: 'visible',\n EXTENT: 'extent',\n Z_INDEX: 'zIndex',\n MAX_RESOLUTION: 'maxResolution',\n MIN_RESOLUTION: 'minResolution',\n SOURCE: 'source'\n};\n\n//# sourceMappingURL=Property.js.map","/**\n * @module ol/geom/GeometryLayout\n */\n\n/**\n * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')\n * or measure ('M') coordinate is available. Supported values are `'XY'`,\n * `'XYZ'`, `'XYM'`, `'XYZM'`.\n * @enum {string}\n */\nexport default {\n XY: 'XY',\n XYZ: 'XYZ',\n XYM: 'XYM',\n XYZM: 'XYZM'\n};\n\n//# sourceMappingURL=GeometryLayout.js.map","/**\n * @module ol/ViewProperty\n */\n\n/**\n * @enum {string}\n */\nexport default {\n CENTER: 'center',\n RESOLUTION: 'resolution',\n ROTATION: 'rotation'\n};\n\n//# sourceMappingURL=ViewProperty.js.map","/**\n * @module ol/control/Control\n */\nimport {VOID} from '../functions.js';\nimport MapEventType from '../MapEventType.js';\nimport BaseObject from '../Object.js';\nimport {removeNode} from '../dom.js';\nimport {listen, unlistenByKey} from '../events.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {HTMLElement} [element] The element is the control's\n * container element. This only needs to be specified if you're developing\n * a custom control.\n * @property {function(import(\"../MapEvent.js\").default)} [render] Function called when\n * the control should be re-rendered. This is called in a `requestAnimationFrame`\n * callback.\n * @property {HTMLElement|string} [target] Specify a target if you want\n * the control to be rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A control is a visible widget with a DOM element in a fixed position on the\n * screen. They can involve user input (buttons), or be informational only;\n * the position is determined using CSS. By default these are placed in the\n * container with CSS class name `ol-overlaycontainer-stopevent`, but can use\n * any outside DOM element.\n *\n * This is the base class for controls. You can use it for simple custom\n * controls by creating the element with listeners, creating an instance:\n * ```js\n * var myControl = new Control({element: myElement});\n * ```\n * and then adding this to the map.\n *\n * The main advantage of having this as a control rather than a simple separate\n * DOM element is that preventing propagation is handled for you. Controls\n * will also be objects in a {@link module:ol/Collection~Collection}, so you can use their methods.\n *\n * You can also extend this base for your own control class. See\n * examples/custom-controls for an example of how to do this.\n *\n * @api\n */\nvar Control = /*@__PURE__*/(function (BaseObject) {\n function Control(options) {\n\n BaseObject.call(this);\n\n /**\n * @protected\n * @type {HTMLElement}\n */\n this.element = options.element ? options.element : null;\n\n /**\n * @private\n * @type {HTMLElement}\n */\n this.target_ = null;\n\n /**\n * @private\n * @type {import(\"../PluggableMap.js\").default}\n */\n this.map_ = null;\n\n /**\n * @protected\n * @type {!Array}\n */\n this.listenerKeys = [];\n\n /**\n * @type {function(import(\"../MapEvent.js\").default)}\n */\n this.render = options.render ? options.render : VOID;\n\n if (options.target) {\n this.setTarget(options.target);\n }\n\n }\n\n if ( BaseObject ) Control.__proto__ = BaseObject;\n Control.prototype = Object.create( BaseObject && BaseObject.prototype );\n Control.prototype.constructor = Control;\n\n /**\n * @inheritDoc\n */\n Control.prototype.disposeInternal = function disposeInternal () {\n removeNode(this.element);\n BaseObject.prototype.disposeInternal.call(this);\n };\n\n /**\n * Get the map associated with this control.\n * @return {import(\"../PluggableMap.js\").default} Map.\n * @api\n */\n Control.prototype.getMap = function getMap () {\n return this.map_;\n };\n\n /**\n * Remove the control from its current map and attach it to the new map.\n * Subclasses may set up event handlers to get notified about changes to\n * the map here.\n * @param {import(\"../PluggableMap.js\").default} map Map.\n * @api\n */\n Control.prototype.setMap = function setMap (map) {\n if (this.map_) {\n removeNode(this.element);\n }\n for (var i = 0, ii = this.listenerKeys.length; i < ii; ++i) {\n unlistenByKey(this.listenerKeys[i]);\n }\n this.listenerKeys.length = 0;\n this.map_ = map;\n if (this.map_) {\n var target = this.target_ ?\n this.target_ : map.getOverlayContainerStopEvent();\n target.appendChild(this.element);\n if (this.render !== VOID) {\n this.listenerKeys.push(listen(map,\n MapEventType.POSTRENDER, this.render, this));\n }\n map.render();\n }\n };\n\n /**\n * This function is used to set a target element for the control. It has no\n * effect if it is called after the control has been added to the map (i.e.\n * after `setMap` is called on the control). If no `target` is set in the\n * options passed to the control constructor and if `setTarget` is not called\n * then the control is added to the map's overlay container.\n * @param {HTMLElement|string} target Target.\n * @api\n */\n Control.prototype.setTarget = function setTarget (target) {\n this.target_ = typeof target === 'string' ?\n document.getElementById(target) :\n target;\n };\n\n return Control;\n}(BaseObject));\n\n\nexport default Control;\n\n//# sourceMappingURL=Control.js.map","/**\n * @module ol/extent/Relationship\n */\n\n/**\n * Relationship to an extent.\n * @enum {number}\n */\nexport default {\n UNKNOWN: 0,\n INTERSECTING: 1,\n ABOVE: 2,\n RIGHT: 4,\n BELOW: 8,\n LEFT: 16\n};\n\n//# sourceMappingURL=Relationship.js.map","/**\n * @module ol/Collection\n */\nimport AssertionError from './AssertionError.js';\nimport CollectionEventType from './CollectionEventType.js';\nimport BaseObject from './Object.js';\nimport Event from './events/Event.js';\n\n\n/**\n * @enum {string}\n * @private\n */\nvar Property = {\n LENGTH: 'length'\n};\n\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Collection~Collection} instances are instances of this\n * type.\n */\nexport var CollectionEvent = /*@__PURE__*/(function (Event) {\n function CollectionEvent(type, opt_element) {\n Event.call(this, type);\n\n /**\n * The element that is added to or removed from the collection.\n * @type {*}\n * @api\n */\n this.element = opt_element;\n\n }\n\n if ( Event ) CollectionEvent.__proto__ = Event;\n CollectionEvent.prototype = Object.create( Event && Event.prototype );\n CollectionEvent.prototype.constructor = CollectionEvent;\n\n return CollectionEvent;\n}(Event));\n\n\n/**\n * @typedef {Object} Options\n * @property {boolean} [unique=false] Disallow the same item from being added to\n * the collection twice.\n */\n\n/**\n * @classdesc\n * An expanded version of standard JS Array, adding convenience methods for\n * manipulation. Add and remove changes to the Collection trigger a Collection\n * event. Note that this does not cover changes to the objects _within_ the\n * Collection; they trigger events on the appropriate object, not on the\n * Collection as a whole.\n *\n * @fires CollectionEvent\n *\n * @template T\n * @api\n */\nvar Collection = /*@__PURE__*/(function (BaseObject) {\n function Collection(opt_array, opt_options) {\n\n BaseObject.call(this);\n\n var options = opt_options || {};\n\n /**\n * @private\n * @type {boolean}\n */\n this.unique_ = !!options.unique;\n\n /**\n * @private\n * @type {!Array}\n */\n this.array_ = opt_array ? opt_array : [];\n\n if (this.unique_) {\n for (var i = 0, ii = this.array_.length; i < ii; ++i) {\n this.assertUnique_(this.array_[i], i);\n }\n }\n\n this.updateLength_();\n\n }\n\n if ( BaseObject ) Collection.__proto__ = BaseObject;\n Collection.prototype = Object.create( BaseObject && BaseObject.prototype );\n Collection.prototype.constructor = Collection;\n\n /**\n * Remove all elements from the collection.\n * @api\n */\n Collection.prototype.clear = function clear () {\n while (this.getLength() > 0) {\n this.pop();\n }\n };\n\n /**\n * Add elements to the collection. This pushes each item in the provided array\n * to the end of the collection.\n * @param {!Array} arr Array.\n * @return {Collection} This collection.\n * @api\n */\n Collection.prototype.extend = function extend (arr) {\n for (var i = 0, ii = arr.length; i < ii; ++i) {\n this.push(arr[i]);\n }\n return this;\n };\n\n /**\n * Iterate over each element, calling the provided callback.\n * @param {function(T, number, Array): *} f The function to call\n * for every element. This function takes 3 arguments (the element, the\n * index and the array). The return value is ignored.\n * @api\n */\n Collection.prototype.forEach = function forEach (f) {\n var array = this.array_;\n for (var i = 0, ii = array.length; i < ii; ++i) {\n f(array[i], i, array);\n }\n };\n\n /**\n * Get a reference to the underlying Array object. Warning: if the array\n * is mutated, no events will be dispatched by the collection, and the\n * collection's \"length\" property won't be in sync with the actual length\n * of the array.\n * @return {!Array} Array.\n * @api\n */\n Collection.prototype.getArray = function getArray () {\n return this.array_;\n };\n\n /**\n * Get the element at the provided index.\n * @param {number} index Index.\n * @return {T} Element.\n * @api\n */\n Collection.prototype.item = function item (index) {\n return this.array_[index];\n };\n\n /**\n * Get the length of this collection.\n * @return {number} The length of the array.\n * @observable\n * @api\n */\n Collection.prototype.getLength = function getLength () {\n return this.get(Property.LENGTH);\n };\n\n /**\n * Insert an element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\n Collection.prototype.insertAt = function insertAt (index, elem) {\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n this.array_.splice(index, 0, elem);\n this.updateLength_();\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.ADD, elem));\n };\n\n /**\n * Remove the last element of the collection and return it.\n * Return `undefined` if the collection is empty.\n * @return {T|undefined} Element.\n * @api\n */\n Collection.prototype.pop = function pop () {\n return this.removeAt(this.getLength() - 1);\n };\n\n /**\n * Insert the provided element at the end of the collection.\n * @param {T} elem Element.\n * @return {number} New length of the collection.\n * @api\n */\n Collection.prototype.push = function push (elem) {\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n var n = this.getLength();\n this.insertAt(n, elem);\n return this.getLength();\n };\n\n /**\n * Remove the first occurrence of an element from the collection.\n * @param {T} elem Element.\n * @return {T|undefined} The removed element or undefined if none found.\n * @api\n */\n Collection.prototype.remove = function remove (elem) {\n var arr = this.array_;\n for (var i = 0, ii = arr.length; i < ii; ++i) {\n if (arr[i] === elem) {\n return this.removeAt(i);\n }\n }\n return undefined;\n };\n\n /**\n * Remove the element at the provided index and return it.\n * Return `undefined` if the collection does not contain this index.\n * @param {number} index Index.\n * @return {T|undefined} Value.\n * @api\n */\n Collection.prototype.removeAt = function removeAt (index) {\n var prev = this.array_[index];\n this.array_.splice(index, 1);\n this.updateLength_();\n this.dispatchEvent(new CollectionEvent(CollectionEventType.REMOVE, prev));\n return prev;\n };\n\n /**\n * Set the element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\n Collection.prototype.setAt = function setAt (index, elem) {\n var n = this.getLength();\n if (index < n) {\n if (this.unique_) {\n this.assertUnique_(elem, index);\n }\n var prev = this.array_[index];\n this.array_[index] = elem;\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.REMOVE, prev));\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.ADD, elem));\n } else {\n for (var j = n; j < index; ++j) {\n this.insertAt(j, undefined);\n }\n this.insertAt(index, elem);\n }\n };\n\n /**\n * @private\n */\n Collection.prototype.updateLength_ = function updateLength_ () {\n this.set(Property.LENGTH, this.array_.length);\n };\n\n /**\n * @private\n * @param {T} elem Element.\n * @param {number=} opt_except Optional index to ignore.\n */\n Collection.prototype.assertUnique_ = function assertUnique_ (elem, opt_except) {\n for (var i = 0, ii = this.array_.length; i < ii; ++i) {\n if (this.array_[i] === elem && i !== opt_except) {\n throw new AssertionError(58);\n }\n }\n };\n\n return Collection;\n}(BaseObject));\n\n\nexport default Collection;\n\n//# sourceMappingURL=Collection.js.map","/**\n * @module ol/CollectionEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when an item is added to the collection.\n * @event module:ol/Collection.CollectionEvent#add\n * @api\n */\n ADD: 'add',\n /**\n * Triggered when an item is removed from the collection.\n * @event module:ol/Collection.CollectionEvent#remove\n * @api\n */\n REMOVE: 'remove'\n};\n\n//# sourceMappingURL=CollectionEventType.js.map","/**\n * @module ol/pointer/EventType\n */\n\n/**\n * Constants for event names.\n * @enum {string}\n */\nexport default {\n POINTERMOVE: 'pointermove',\n POINTERDOWN: 'pointerdown',\n POINTERUP: 'pointerup',\n POINTEROVER: 'pointerover',\n POINTEROUT: 'pointerout',\n POINTERENTER: 'pointerenter',\n POINTERLEAVE: 'pointerleave',\n POINTERCANCEL: 'pointercancel'\n};\n\n//# sourceMappingURL=EventType.js.map","/**\n * @module ol/MapProperty\n */\n\n/**\n * @enum {string}\n */\nexport default {\n LAYERGROUP: 'layergroup',\n SIZE: 'size',\n TARGET: 'target',\n VIEW: 'view'\n};\n\n//# sourceMappingURL=MapProperty.js.map","/**\n * @module ol/OverlayPositioning\n */\n\n/**\n * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`,\n * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,\n * `'top-center'`, `'top-right'`\n * @enum {string}\n */\nexport default {\n BOTTOM_LEFT: 'bottom-left',\n BOTTOM_CENTER: 'bottom-center',\n BOTTOM_RIGHT: 'bottom-right',\n CENTER_LEFT: 'center-left',\n CENTER_CENTER: 'center-center',\n CENTER_RIGHT: 'center-right',\n TOP_LEFT: 'top-left',\n TOP_CENTER: 'top-center',\n TOP_RIGHT: 'top-right'\n};\n\n//# sourceMappingURL=OverlayPositioning.js.map","/**\n * @module ol/geom/flat/transform\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../transform.js\").Transform} transform Transform.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function transform2D(flatCoordinates, offset, end, stride, transform, opt_dest) {\n var dest = opt_dest ? opt_dest : [];\n var i = 0;\n for (var j = offset; j < end; j += stride) {\n var x = flatCoordinates[j];\n var y = flatCoordinates[j + 1];\n dest[i++] = transform[0] * x + transform[2] * y + transform[4];\n dest[i++] = transform[1] * x + transform[3] * y + transform[5];\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} angle Angle.\n * @param {Array} anchor Rotation anchor point.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function rotate(flatCoordinates, offset, end, stride, angle, anchor, opt_dest) {\n var dest = opt_dest ? opt_dest : [];\n var cos = Math.cos(angle);\n var sin = Math.sin(angle);\n var anchorX = anchor[0];\n var anchorY = anchor[1];\n var i = 0;\n for (var j = offset; j < end; j += stride) {\n var deltaX = flatCoordinates[j] - anchorX;\n var deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + deltaX * cos - deltaY * sin;\n dest[i++] = anchorY + deltaX * sin + deltaY * cos;\n for (var k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * Scale the coordinates.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} sx Scale factor in the x-direction.\n * @param {number} sy Scale factor in the y-direction.\n * @param {Array} anchor Scale anchor point.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function scale(flatCoordinates, offset, end, stride, sx, sy, anchor, opt_dest) {\n var dest = opt_dest ? opt_dest : [];\n var anchorX = anchor[0];\n var anchorY = anchor[1];\n var i = 0;\n for (var j = offset; j < end; j += stride) {\n var deltaX = flatCoordinates[j] - anchorX;\n var deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + sx * deltaX;\n dest[i++] = anchorY + sy * deltaY;\n for (var k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function translate(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {\n var dest = opt_dest ? opt_dest : [];\n var i = 0;\n for (var j = offset; j < end; j += stride) {\n dest[i++] = flatCoordinates[j] + deltaX;\n dest[i++] = flatCoordinates[j + 1] + deltaY;\n for (var k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (opt_dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n//# sourceMappingURL=transform.js.map","/**\n * @module ol/coordinate\n */\nimport {modulo} from './math.js';\nimport {padNumber} from './string.js';\n\n\n/**\n * An array of numbers representing an xy coordinate. Example: `[16, 48]`.\n * @typedef {Array} Coordinate\n * @api\n */\n\n\n/**\n * A function that takes a {@link module:ol/coordinate~Coordinate} and\n * transforms it into a `{string}`.\n *\n * @typedef {function((Coordinate|undefined)): string} CoordinateFormat\n * @api\n */\n\n\n/**\n * Add `delta` to `coordinate`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {add} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * add(coord, [-2, 4]);\n * // coord is now [5.85, 51.983333]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {Coordinate} delta Delta.\n * @return {Coordinate} The input coordinate adjusted by\n * the given delta.\n * @api\n */\nexport function add(coordinate, delta) {\n coordinate[0] += delta[0];\n coordinate[1] += delta[1];\n return coordinate;\n}\n\n\n/**\n * Calculates the point closest to the passed coordinate on the passed circle.\n *\n * @param {Coordinate} coordinate The coordinate.\n * @param {import(\"./geom/Circle.js\").default} circle The circle.\n * @return {Coordinate} Closest point on the circumference.\n */\nexport function closestOnCircle(coordinate, circle) {\n var r = circle.getRadius();\n var center = circle.getCenter();\n var x0 = center[0];\n var y0 = center[1];\n var x1 = coordinate[0];\n var y1 = coordinate[1];\n\n var dx = x1 - x0;\n var dy = y1 - y0;\n if (dx === 0 && dy === 0) {\n dx = 1;\n }\n var d = Math.sqrt(dx * dx + dy * dy);\n\n var x = x0 + r * dx / d;\n var y = y0 + r * dy / d;\n\n return [x, y];\n}\n\n\n/**\n * Calculates the point closest to the passed coordinate on the passed segment.\n * This is the foot of the perpendicular of the coordinate to the segment when\n * the foot is on the segment, or the closest segment coordinate when the foot\n * is outside the segment.\n *\n * @param {Coordinate} coordinate The coordinate.\n * @param {Array} segment The two coordinates\n * of the segment.\n * @return {Coordinate} The foot of the perpendicular of\n * the coordinate to the segment.\n */\nexport function closestOnSegment(coordinate, segment) {\n var x0 = coordinate[0];\n var y0 = coordinate[1];\n var start = segment[0];\n var end = segment[1];\n var x1 = start[0];\n var y1 = start[1];\n var x2 = end[0];\n var y2 = end[1];\n var dx = x2 - x1;\n var dy = y2 - y1;\n var along = (dx === 0 && dy === 0) ? 0 :\n ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);\n var x, y;\n if (along <= 0) {\n x = x1;\n y = y1;\n } else if (along >= 1) {\n x = x2;\n y = y2;\n } else {\n x = x1 + along * dx;\n y = y1 + along * dy;\n }\n return [x, y];\n}\n\n\n/**\n * Returns a {@link module:ol/coordinate~CoordinateFormat} function that can be\n * used to format\n * a {Coordinate} to a string.\n *\n * Example without specifying the fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var stringifyFunc = createStringXY();\n * var out = stringifyFunc(coord);\n * // out is now '8, 48'\n *\n * Example with explicitly specifying 2 fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var stringifyFunc = createStringXY(2);\n * var out = stringifyFunc(coord);\n * // out is now '7.85, 47.98'\n *\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {CoordinateFormat} Coordinate format.\n * @api\n */\nexport function createStringXY(opt_fractionDigits) {\n return (\n /**\n * @param {Coordinate} coordinate Coordinate.\n * @return {string} String XY.\n */\n function(coordinate) {\n return toStringXY(coordinate, opt_fractionDigits);\n }\n );\n}\n\n\n/**\n * @param {string} hemispheres Hemispheres.\n * @param {number} degrees Degrees.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} String.\n */\nexport function degreesToStringHDMS(hemispheres, degrees, opt_fractionDigits) {\n var normalizedDegrees = modulo(degrees + 180, 360) - 180;\n var x = Math.abs(3600 * normalizedDegrees);\n var dflPrecision = opt_fractionDigits || 0;\n var precision = Math.pow(10, dflPrecision);\n\n var deg = Math.floor(x / 3600);\n var min = Math.floor((x - deg * 3600) / 60);\n var sec = x - (deg * 3600) - (min * 60);\n sec = Math.ceil(sec * precision) / precision;\n\n if (sec >= 60) {\n sec = 0;\n min += 1;\n }\n\n if (min >= 60) {\n min = 0;\n deg += 1;\n }\n\n return deg + '\\u00b0 ' + padNumber(min, 2) + '\\u2032 ' +\n padNumber(sec, 2, dflPrecision) + '\\u2033' +\n (normalizedDegrees == 0 ? '' : ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0));\n}\n\n\n/**\n * Transforms the given {@link module:ol/coordinate~Coordinate} to a string\n * using the given string template. The strings `{x}` and `{y}` in the template\n * will be replaced with the first and second coordinate values respectively.\n *\n * Example without specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var template = 'Coordinate is ({x}|{y}).';\n * var out = format(coord, template);\n * // out is now 'Coordinate is (8|48).'\n *\n * Example explicitly specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var template = 'Coordinate is ({x}|{y}).';\n * var out = format(coord, template, 2);\n * // out is now 'Coordinate is (7.85|47.98).'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {string} template A template string with `{x}` and `{y}` placeholders\n * that will be replaced by first and second coordinate values.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Formatted coordinate.\n * @api\n */\nexport function format(coordinate, template, opt_fractionDigits) {\n if (coordinate) {\n return template\n .replace('{x}', coordinate[0].toFixed(opt_fractionDigits))\n .replace('{y}', coordinate[1].toFixed(opt_fractionDigits));\n } else {\n return '';\n }\n}\n\n\n/**\n * @param {Coordinate} coordinate1 First coordinate.\n * @param {Coordinate} coordinate2 Second coordinate.\n * @return {boolean} The two coordinates are equal.\n */\nexport function equals(coordinate1, coordinate2) {\n var equals = true;\n for (var i = coordinate1.length - 1; i >= 0; --i) {\n if (coordinate1[i] != coordinate2[i]) {\n equals = false;\n break;\n }\n }\n return equals;\n}\n\n\n/**\n * Rotate `coordinate` by `angle`. `coordinate` is modified in place and\n * returned by the function.\n *\n * Example:\n *\n * import {rotate} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var rotateRadians = Math.PI / 2; // 90 degrees\n * rotate(coord, rotateRadians);\n * // coord is now [-47.983333, 7.85]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} angle Angle in radian.\n * @return {Coordinate} Coordinate.\n * @api\n */\nexport function rotate(coordinate, angle) {\n var cosAngle = Math.cos(angle);\n var sinAngle = Math.sin(angle);\n var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n coordinate[0] = x;\n coordinate[1] = y;\n return coordinate;\n}\n\n\n/**\n * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {scale as scaleCoordinate} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var scale = 1.2;\n * scaleCoordinate(coord, scale);\n * // coord is now [9.42, 57.5799996]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} scale Scale factor.\n * @return {Coordinate} Coordinate.\n */\nexport function scale(coordinate, scale) {\n coordinate[0] *= scale;\n coordinate[1] *= scale;\n return coordinate;\n}\n\n\n/**\n * @param {Coordinate} coord1 First coordinate.\n * @param {Coordinate} coord2 Second coordinate.\n * @return {number} Squared distance between coord1 and coord2.\n */\nexport function squaredDistance(coord1, coord2) {\n var dx = coord1[0] - coord2[0];\n var dy = coord1[1] - coord2[1];\n return dx * dx + dy * dy;\n}\n\n\n/**\n * @param {Coordinate} coord1 First coordinate.\n * @param {Coordinate} coord2 Second coordinate.\n * @return {number} Distance between coord1 and coord2.\n */\nexport function distance(coord1, coord2) {\n return Math.sqrt(squaredDistance(coord1, coord2));\n}\n\n\n/**\n * Calculate the squared distance from a coordinate to a line segment.\n *\n * @param {Coordinate} coordinate Coordinate of the point.\n * @param {Array} segment Line segment (2\n * coordinates).\n * @return {number} Squared distance from the point to the line segment.\n */\nexport function squaredDistanceToSegment(coordinate, segment) {\n return squaredDistance(coordinate,\n closestOnSegment(coordinate, segment));\n}\n\n\n/**\n * Format a geographic coordinate with the hemisphere, degrees, minutes, and\n * seconds.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringHDMS} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringHDMS(coord);\n * // out is now '47° 58′ 60″ N 7° 50′ 60″ E'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringHDMS} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringHDMS(coord, 1);\n * // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Hemisphere, degrees, minutes and seconds.\n * @api\n */\nexport function toStringHDMS(coordinate, opt_fractionDigits) {\n if (coordinate) {\n return degreesToStringHDMS('NS', coordinate[1], opt_fractionDigits) + ' ' +\n degreesToStringHDMS('EW', coordinate[0], opt_fractionDigits);\n } else {\n return '';\n }\n}\n\n\n/**\n * Format a coordinate as a comma delimited string.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringXY(coord);\n * // out is now '8, 48'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringXY} from 'ol/coordinate';\n *\n * var coord = [7.85, 47.983333];\n * var out = toStringXY(coord, 1);\n * // out is now '7.8, 48.0'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number=} opt_fractionDigits The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} XY.\n * @api\n */\nexport function toStringXY(coordinate, opt_fractionDigits) {\n return format(coordinate, '{x}, {y}', opt_fractionDigits);\n}\n\n//# sourceMappingURL=coordinate.js.map","/**\n * @module ol/events/Target\n */\nimport Disposable from '../Disposable.js';\nimport {unlistenAll} from '../events.js';\nimport {VOID} from '../functions.js';\nimport Event from './Event.js';\n\n\n/**\n * @typedef {EventTarget|Target} EventTargetLike\n */\n\n\n/**\n * @classdesc\n * A simplified implementation of the W3C DOM Level 2 EventTarget interface.\n * See https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget.\n *\n * There are two important simplifications compared to the specification:\n *\n * 1. The handling of `useCapture` in `addEventListener` and\n * `removeEventListener`. There is no real capture model.\n * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.\n * There is no event target hierarchy. When a listener calls\n * `stopPropagation` or `preventDefault` on an event object, it means that no\n * more listeners after this one will be called. Same as when the listener\n * returns false.\n */\nvar Target = /*@__PURE__*/(function (Disposable) {\n function Target() {\n\n Disposable.call(this);\n\n /**\n * @private\n * @type {!Object}\n */\n this.pendingRemovals_ = {};\n\n /**\n * @private\n * @type {!Object}\n */\n this.dispatching_ = {};\n\n /**\n * @private\n * @type {!Object>}\n */\n this.listeners_ = {};\n\n }\n\n if ( Disposable ) Target.__proto__ = Disposable;\n Target.prototype = Object.create( Disposable && Disposable.prototype );\n Target.prototype.constructor = Target;\n\n /**\n * @param {string} type Type.\n * @param {import(\"../events.js\").ListenerFunction} listener Listener.\n */\n Target.prototype.addEventListener = function addEventListener (type, listener) {\n var listeners = this.listeners_[type];\n if (!listeners) {\n listeners = this.listeners_[type] = [];\n }\n if (listeners.indexOf(listener) === -1) {\n listeners.push(listener);\n }\n };\n\n /**\n * Dispatches an event and calls all listeners listening for events\n * of this type. The event parameter can either be a string or an\n * Object with a `type` property.\n *\n * @param {{type: string,\n * target: (EventTargetLike|undefined),\n * propagationStopped: (boolean|undefined)}|\n * import(\"./Event.js\").default|string} event Event object.\n * @return {boolean|undefined} `false` if anyone called preventDefault on the\n * event object or if any of the listeners returned false.\n * @api\n */\n Target.prototype.dispatchEvent = function dispatchEvent (event) {\n var evt = typeof event === 'string' ? new Event(event) : event;\n var type = evt.type;\n evt.target = this;\n var listeners = this.listeners_[type];\n var propagate;\n if (listeners) {\n if (!(type in this.dispatching_)) {\n this.dispatching_[type] = 0;\n this.pendingRemovals_[type] = 0;\n }\n ++this.dispatching_[type];\n for (var i = 0, ii = listeners.length; i < ii; ++i) {\n if (listeners[i].call(this, evt) === false || evt.propagationStopped) {\n propagate = false;\n break;\n }\n }\n --this.dispatching_[type];\n if (this.dispatching_[type] === 0) {\n var pendingRemovals = this.pendingRemovals_[type];\n delete this.pendingRemovals_[type];\n while (pendingRemovals--) {\n this.removeEventListener(type, VOID);\n }\n delete this.dispatching_[type];\n }\n return propagate;\n }\n };\n\n /**\n * @inheritDoc\n */\n Target.prototype.disposeInternal = function disposeInternal () {\n unlistenAll(this);\n };\n\n /**\n * Get the listeners for a specified event type. Listeners are returned in the\n * order that they will be called in.\n *\n * @param {string} type Type.\n * @return {Array} Listeners.\n */\n Target.prototype.getListeners = function getListeners (type) {\n return this.listeners_[type];\n };\n\n /**\n * @param {string=} opt_type Type. If not provided,\n * `true` will be returned if this event target has any listeners.\n * @return {boolean} Has listeners.\n */\n Target.prototype.hasListener = function hasListener (opt_type) {\n return opt_type ?\n opt_type in this.listeners_ :\n Object.keys(this.listeners_).length > 0;\n };\n\n /**\n * @param {string} type Type.\n * @param {import(\"../events.js\").ListenerFunction} listener Listener.\n */\n Target.prototype.removeEventListener = function removeEventListener (type, listener) {\n var listeners = this.listeners_[type];\n if (listeners) {\n var index = listeners.indexOf(listener);\n if (type in this.pendingRemovals_) {\n // make listener a no-op, and remove later in #dispatchEvent()\n listeners[index] = VOID;\n ++this.pendingRemovals_[type];\n } else {\n listeners.splice(index, 1);\n if (listeners.length === 0) {\n delete this.listeners_[type];\n }\n }\n }\n };\n\n return Target;\n}(Disposable));\n\n\nexport default Target;\n\n//# sourceMappingURL=Target.js.map","/**\n * @module ol/color\n */\nimport {assert} from './asserts.js';\nimport {clamp} from './math.js';\n\n\n/**\n * A color represented as a short array [red, green, blue, alpha].\n * red, green, and blue should be integers in the range 0..255 inclusive.\n * alpha should be a float in the range 0..1 inclusive. If no alpha value is\n * given then `1` will be used.\n * @typedef {Array} Color\n * @api\n */\n\n\n/**\n * This RegExp matches # followed by 3, 4, 6, or 8 hex digits.\n * @const\n * @type {RegExp}\n * @private\n */\nvar HEX_COLOR_RE_ = /^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i;\n\n\n/**\n * Regular expression for matching potential named color style strings.\n * @const\n * @type {RegExp}\n * @private\n */\nvar NAMED_COLOR_RE_ = /^([a-z]*)$/i;\n\n\n/**\n * Return the color as an rgba string.\n * @param {Color|string} color Color.\n * @return {string} Rgba string.\n * @api\n */\nexport function asString(color) {\n if (typeof color === 'string') {\n return color;\n } else {\n return toString(color);\n }\n}\n\n/**\n * Return named color as an rgba string.\n * @param {string} color Named color.\n * @return {string} Rgb string.\n */\nfunction fromNamed(color) {\n var el = document.createElement('div');\n el.style.color = color;\n if (el.style.color !== '') {\n document.body.appendChild(el);\n var rgb = getComputedStyle(el).color;\n document.body.removeChild(el);\n return rgb;\n } else {\n return '';\n }\n}\n\n\n/**\n * @param {string} s String.\n * @return {Color} Color.\n */\nexport var fromString = (\n function() {\n\n // We maintain a small cache of parsed strings. To provide cheap LRU-like\n // semantics, whenever the cache grows too large we simply delete an\n // arbitrary 25% of the entries.\n\n /**\n * @const\n * @type {number}\n */\n var MAX_CACHE_SIZE = 1024;\n\n /**\n * @type {Object}\n */\n var cache = {};\n\n /**\n * @type {number}\n */\n var cacheSize = 0;\n\n return (\n /**\n * @param {string} s String.\n * @return {Color} Color.\n */\n function(s) {\n var color;\n if (cache.hasOwnProperty(s)) {\n color = cache[s];\n } else {\n if (cacheSize >= MAX_CACHE_SIZE) {\n var i = 0;\n for (var key in cache) {\n if ((i++ & 3) === 0) {\n delete cache[key];\n --cacheSize;\n }\n }\n }\n color = fromStringInternal_(s);\n cache[s] = color;\n ++cacheSize;\n }\n return color;\n }\n );\n\n })();\n\n/**\n * Return the color as an array. This function maintains a cache of calculated\n * arrays which means the result should not be modified.\n * @param {Color|string} color Color.\n * @return {Color} Color.\n * @api\n */\nexport function asArray(color) {\n if (Array.isArray(color)) {\n return color;\n } else {\n return fromString(color);\n }\n}\n\n/**\n * @param {string} s String.\n * @private\n * @return {Color} Color.\n */\nfunction fromStringInternal_(s) {\n var r, g, b, a, color;\n\n if (NAMED_COLOR_RE_.exec(s)) {\n s = fromNamed(s);\n }\n\n if (HEX_COLOR_RE_.exec(s)) { // hex\n var n = s.length - 1; // number of hex digits\n var d; // number of digits per channel\n if (n <= 4) {\n d = 1;\n } else {\n d = 2;\n }\n var hasAlpha = n === 4 || n === 8;\n r = parseInt(s.substr(1 + 0 * d, d), 16);\n g = parseInt(s.substr(1 + 1 * d, d), 16);\n b = parseInt(s.substr(1 + 2 * d, d), 16);\n if (hasAlpha) {\n a = parseInt(s.substr(1 + 3 * d, d), 16);\n } else {\n a = 255;\n }\n if (d == 1) {\n r = (r << 4) + r;\n g = (g << 4) + g;\n b = (b << 4) + b;\n if (hasAlpha) {\n a = (a << 4) + a;\n }\n }\n color = [r, g, b, a / 255];\n } else if (s.indexOf('rgba(') == 0) { // rgba()\n color = s.slice(5, -1).split(',').map(Number);\n normalize(color);\n } else if (s.indexOf('rgb(') == 0) { // rgb()\n color = s.slice(4, -1).split(',').map(Number);\n color.push(1);\n normalize(color);\n } else {\n assert(false, 14); // Invalid color\n }\n return color;\n}\n\n\n/**\n * TODO this function is only used in the test, we probably shouldn't export it\n * @param {Color} color Color.\n * @return {Color} Clamped color.\n */\nexport function normalize(color) {\n color[0] = clamp((color[0] + 0.5) | 0, 0, 255);\n color[1] = clamp((color[1] + 0.5) | 0, 0, 255);\n color[2] = clamp((color[2] + 0.5) | 0, 0, 255);\n color[3] = clamp(color[3], 0, 1);\n return color;\n}\n\n\n/**\n * @param {Color} color Color.\n * @return {string} String.\n */\nexport function toString(color) {\n var r = color[0];\n if (r != (r | 0)) {\n r = (r + 0.5) | 0;\n }\n var g = color[1];\n if (g != (g | 0)) {\n g = (g + 0.5) | 0;\n }\n var b = color[2];\n if (b != (b | 0)) {\n b = (b + 0.5) | 0;\n }\n var a = color[3] === undefined ? 1 : color[3];\n return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n}\n\n//# sourceMappingURL=color.js.map","/**\n * @module ol/LayerType\n */\n\n/**\n * A layer type used when creating layer renderers.\n * @enum {string}\n */\nexport default {\n IMAGE: 'IMAGE',\n TILE: 'TILE',\n VECTOR_TILE: 'VECTOR_TILE',\n VECTOR: 'VECTOR'\n};\n\n//# sourceMappingURL=LayerType.js.map","/**\n * @module ol/render/EventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * @event module:ol/render/Event~RenderEvent#postcompose\n * @api\n */\n POSTCOMPOSE: 'postcompose',\n /**\n * @event module:ol/render/Event~RenderEvent#precompose\n * @api\n */\n PRECOMPOSE: 'precompose',\n /**\n * @event module:ol/render/Event~RenderEvent#render\n * @api\n */\n RENDER: 'render',\n /**\n * Triggered when rendering is complete, i.e. all sources and tiles have\n * finished loading for the current viewport, and all tiles are faded in.\n * @event module:ol/render/Event~RenderEvent#rendercomplete\n * @api\n */\n RENDERCOMPLETE: 'rendercomplete'\n};\n\n//# sourceMappingURL=EventType.js.map","/**\n * @module ol/colorlike\n */\nimport {toString} from './color.js';\n\n\n/**\n * A type accepted by CanvasRenderingContext2D.fillStyle\n * or CanvasRenderingContext2D.strokeStyle.\n * Represents a color, pattern, or gradient. The origin for patterns and\n * gradients as fill style is an increment of 512 css pixels from map coordinate\n * `[0, 0]`. For seamless repeat patterns, width and height of the pattern image\n * must be a factor of two (2, 4, 8, ..., 512).\n *\n * @typedef {string|CanvasPattern|CanvasGradient} ColorLike\n * @api\n */\n\n\n/**\n * @param {import(\"./color.js\").Color|ColorLike} color Color.\n * @return {ColorLike} The color as an {@link ol/colorlike~ColorLike}.\n * @api\n */\nexport function asColorLike(color) {\n if (Array.isArray(color)) {\n return toString(color);\n } else {\n return color;\n }\n}\n\n//# sourceMappingURL=colorlike.js.map","/**\n * @module ol/reproj/common\n */\n\n/**\n * Default maximum allowed threshold (in pixels) for reprojection\n * triangulation.\n * @type {number}\n */\nexport var ERROR_THRESHOLD = 0.5;\n\n/**\n * Enable automatic reprojection of raster sources. Default is `true`.\n * TODO: decide if we want to expose this as a build flag or remove it\n * @type {boolean}\n */\nexport var ENABLE_RASTER_REPROJECTION = true;\n\n//# sourceMappingURL=common.js.map","/**\n * @module ol/size\n */\n\n\n/**\n * An array of numbers representing a size: `[width, height]`.\n * @typedef {Array} Size\n * @api\n */\n\n\n/**\n * Returns a buffered size.\n * @param {Size} size Size.\n * @param {number} num The amount by which to buffer.\n * @param {Size=} opt_size Optional reusable size array.\n * @return {Size} The buffered size.\n */\nexport function buffer(size, num, opt_size) {\n if (opt_size === undefined) {\n opt_size = [0, 0];\n }\n opt_size[0] = size[0] + 2 * num;\n opt_size[1] = size[1] + 2 * num;\n return opt_size;\n}\n\n\n/**\n * Determines if a size has a positive area.\n * @param {Size} size The size to test.\n * @return {boolean} The size has a positive area.\n */\nexport function hasArea(size) {\n return size[0] > 0 && size[1] > 0;\n}\n\n\n/**\n * Returns a size scaled by a ratio. The result will be an array of integers.\n * @param {Size} size Size.\n * @param {number} ratio Ratio.\n * @param {Size=} opt_size Optional reusable size array.\n * @return {Size} The scaled size.\n */\nexport function scale(size, ratio, opt_size) {\n if (opt_size === undefined) {\n opt_size = [0, 0];\n }\n opt_size[0] = (size[0] * ratio + 0.5) | 0;\n opt_size[1] = (size[1] * ratio + 0.5) | 0;\n return opt_size;\n}\n\n\n/**\n * Returns an `Size` array for the passed in number (meaning: square) or\n * `Size` array.\n * (meaning: non-square),\n * @param {number|Size} size Width and height.\n * @param {Size=} opt_size Optional reusable size array.\n * @return {Size} Size.\n * @api\n */\nexport function toSize(size, opt_size) {\n if (Array.isArray(size)) {\n return size;\n } else {\n if (opt_size === undefined) {\n opt_size = [size, size];\n } else {\n opt_size[0] = opt_size[1] = /** @type {number} */ (size);\n }\n return opt_size;\n }\n}\n\n//# sourceMappingURL=size.js.map","/**\n * @module ol/source/State\n */\n\n/**\n * @enum {string}\n * State of the source, one of 'undefined', 'loading', 'ready' or 'error'.\n */\nexport default {\n UNDEFINED: 'undefined',\n LOADING: 'loading',\n READY: 'ready',\n ERROR: 'error'\n};\n\n//# sourceMappingURL=State.js.map","/**\n * @module ol/ObjectEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when a property is changed.\n * @event module:ol/Object.ObjectEvent#propertychange\n * @api\n */\n PROPERTYCHANGE: 'propertychange'\n};\n\n//# sourceMappingURL=ObjectEventType.js.map","/**\n * @module ol/layer/Layer\n */\nimport {listen, unlistenByKey} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {getUid} from '../util.js';\nimport {getChangeEventType} from '../Object.js';\nimport BaseLayer from './Base.js';\nimport LayerProperty from './Property.js';\nimport {assign} from '../obj.js';\nimport RenderEventType from '../render/EventType.js';\nimport SourceState from '../source/State.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [opacity=1] Opacity (0, 1).\n * @property {boolean} [visible=true] Visibility.\n * @property {import(\"../extent.js\").Extent} [extent] The bounding extent for layer rendering. The layer will not be\n * rendered outside of this extent.\n * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers\n * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed\n * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`\n * method was used.\n * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be\n * visible.\n * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will\n * be visible.\n * @property {import(\"../source/Source.js\").default} [source] Source for this layer. If not provided to the constructor,\n * the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after\n * construction.\n * @property {import(\"../PluggableMap.js\").default} [map] Map.\n */\n\n\n/**\n * @typedef {Object} State\n * @property {import(\"./Base.js\").default} layer\n * @property {number} opacity\n * @property {SourceState} sourceState\n * @property {boolean} visible\n * @property {boolean} managed\n * @property {import(\"../extent.js\").Extent} [extent]\n * @property {number} zIndex\n * @property {number} maxResolution\n * @property {number} minResolution\n */\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * A visual representation of raster or vector map data.\n * Layers group together those properties that pertain to how the data is to be\n * displayed, irrespective of the source of that data.\n *\n * Layers are usually added to a map with {@link module:ol/Map#addLayer}. Components\n * like {@link module:ol/interaction/Select~Select} use unmanaged layers\n * internally. These unmanaged layers are associated with the map using\n * {@link module:ol/layer/Layer~Layer#setMap} instead.\n *\n * A generic `change` event is fired when the state of the source changes.\n *\n * @fires import(\"../render/Event.js\").RenderEvent\n */\nvar Layer = /*@__PURE__*/(function (BaseLayer) {\n function Layer(options) {\n\n var baseOptions = assign({}, options);\n delete baseOptions.source;\n\n BaseLayer.call(this, baseOptions);\n\n /**\n * @private\n * @type {?import(\"../events.js\").EventsKey}\n */\n this.mapPrecomposeKey_ = null;\n\n /**\n * @private\n * @type {?import(\"../events.js\").EventsKey}\n */\n this.mapRenderKey_ = null;\n\n /**\n * @private\n * @type {?import(\"../events.js\").EventsKey}\n */\n this.sourceChangeKey_ = null;\n\n if (options.map) {\n this.setMap(options.map);\n }\n\n listen(this,\n getChangeEventType(LayerProperty.SOURCE),\n this.handleSourcePropertyChange_, this);\n\n var source = options.source ? options.source : null;\n this.setSource(source);\n }\n\n if ( BaseLayer ) Layer.__proto__ = BaseLayer;\n Layer.prototype = Object.create( BaseLayer && BaseLayer.prototype );\n Layer.prototype.constructor = Layer;\n\n /**\n * @inheritDoc\n */\n Layer.prototype.getLayersArray = function getLayersArray (opt_array) {\n var array = opt_array ? opt_array : [];\n array.push(this);\n return array;\n };\n\n /**\n * @inheritDoc\n */\n Layer.prototype.getLayerStatesArray = function getLayerStatesArray (opt_states) {\n var states = opt_states ? opt_states : [];\n states.push(this.getLayerState());\n return states;\n };\n\n /**\n * Get the layer source.\n * @return {import(\"../source/Source.js\").default} The layer source (or `null` if not yet set).\n * @observable\n * @api\n */\n Layer.prototype.getSource = function getSource () {\n var source = this.get(LayerProperty.SOURCE);\n return (\n /** @type {import(\"../source/Source.js\").default} */ (source) || null\n );\n };\n\n /**\n * @inheritDoc\n */\n Layer.prototype.getSourceState = function getSourceState () {\n var source = this.getSource();\n return !source ? SourceState.UNDEFINED : source.getState();\n };\n\n /**\n * @private\n */\n Layer.prototype.handleSourceChange_ = function handleSourceChange_ () {\n this.changed();\n };\n\n /**\n * @private\n */\n Layer.prototype.handleSourcePropertyChange_ = function handleSourcePropertyChange_ () {\n if (this.sourceChangeKey_) {\n unlistenByKey(this.sourceChangeKey_);\n this.sourceChangeKey_ = null;\n }\n var source = this.getSource();\n if (source) {\n this.sourceChangeKey_ = listen(source,\n EventType.CHANGE, this.handleSourceChange_, this);\n }\n this.changed();\n };\n\n /**\n * Sets the layer to be rendered on top of other layers on a map. The map will\n * not manage this layer in its layers collection, and the callback in\n * {@link module:ol/Map#forEachLayerAtPixel} will receive `null` as layer. This\n * is useful for temporary layers. To remove an unmanaged layer from the map,\n * use `#setMap(null)`.\n *\n * To add the layer to a map and have it managed by the map, use\n * {@link module:ol/Map#addLayer} instead.\n * @param {import(\"../PluggableMap.js\").default} map Map.\n * @api\n */\n Layer.prototype.setMap = function setMap (map) {\n if (this.mapPrecomposeKey_) {\n unlistenByKey(this.mapPrecomposeKey_);\n this.mapPrecomposeKey_ = null;\n }\n if (!map) {\n this.changed();\n }\n if (this.mapRenderKey_) {\n unlistenByKey(this.mapRenderKey_);\n this.mapRenderKey_ = null;\n }\n if (map) {\n this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {\n var renderEvent = /** @type {import(\"../render/Event.js\").default} */ (evt);\n var layerState = this.getLayerState();\n layerState.managed = false;\n if (this.getZIndex() === undefined) {\n layerState.zIndex = Infinity;\n }\n renderEvent.frameState.layerStatesArray.push(layerState);\n renderEvent.frameState.layerStates[getUid(this)] = layerState;\n }, this);\n this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);\n this.changed();\n }\n };\n\n /**\n * Set the layer source.\n * @param {import(\"../source/Source.js\").default} source The layer source.\n * @observable\n * @api\n */\n Layer.prototype.setSource = function setSource (source) {\n this.set(LayerProperty.SOURCE, source);\n };\n\n return Layer;\n}(BaseLayer));\n\n\n/**\n * Return `true` if the layer is visible, and if the passed resolution is\n * between the layer's minResolution and maxResolution. The comparison is\n * inclusive for `minResolution` and exclusive for `maxResolution`.\n * @param {State} layerState Layer state.\n * @param {number} resolution Resolution.\n * @return {boolean} The layer is visible at the given resolution.\n */\nexport function visibleAtResolution(layerState, resolution) {\n return layerState.visible && resolution >= layerState.minResolution &&\n resolution < layerState.maxResolution;\n}\n\n\nexport default Layer;\n\n//# sourceMappingURL=Layer.js.map","/**\n * @module ol/geom/Geometry\n */\nimport {abstract} from '../util.js';\nimport BaseObject from '../Object.js';\nimport {createEmpty, getHeight, returnOrUpdate} from '../extent.js';\nimport {transform2D} from './flat/transform.js';\nimport {get as getProjection, getTransform} from '../proj.js';\nimport Units from '../proj/Units.js';\nimport {create as createTransform, compose as composeTransform} from '../transform.js';\n\n\n/**\n * @type {import(\"../transform.js\").Transform}\n */\nvar tmpTransform = createTransform();\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for vector geometries.\n *\n * To get notified of changes to the geometry, register a listener for the\n * generic `change` event on your geometry instance.\n *\n * @abstract\n * @api\n */\nvar Geometry = /*@__PURE__*/(function (BaseObject) {\n function Geometry() {\n\n BaseObject.call(this);\n\n /**\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.extent_ = createEmpty();\n\n /**\n * @private\n * @type {number}\n */\n this.extentRevision_ = -1;\n\n /**\n * @protected\n * @type {Object}\n */\n this.simplifiedGeometryCache = {};\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryRevision = 0;\n\n }\n\n if ( BaseObject ) Geometry.__proto__ = BaseObject;\n Geometry.prototype = Object.create( BaseObject && BaseObject.prototype );\n Geometry.prototype.constructor = Geometry;\n\n /**\n * Make a complete copy of the geometry.\n * @abstract\n * @return {!Geometry} Clone.\n */\n Geometry.prototype.clone = function clone () {\n return abstract();\n };\n\n /**\n * @abstract\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../coordinate.js\").Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\n Geometry.prototype.closestPointXY = function closestPointXY (x, y, closestPoint, minSquaredDistance) {\n return abstract();\n };\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\n Geometry.prototype.containsXY = function containsXY (x, y) {\n return false;\n };\n\n /**\n * Return the closest point of the geometry to the passed point as\n * {@link module:ol/coordinate~Coordinate coordinate}.\n * @param {import(\"../coordinate.js\").Coordinate} point Point.\n * @param {import(\"../coordinate.js\").Coordinate=} opt_closestPoint Closest point.\n * @return {import(\"../coordinate.js\").Coordinate} Closest point.\n * @api\n */\n Geometry.prototype.getClosestPoint = function getClosestPoint (point, opt_closestPoint) {\n var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];\n this.closestPointXY(point[0], point[1], closestPoint, Infinity);\n return closestPoint;\n };\n\n /**\n * Returns true if this geometry includes the specified coordinate. If the\n * coordinate is on the boundary of the geometry, returns false.\n * @param {import(\"../coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} Contains coordinate.\n * @api\n */\n Geometry.prototype.intersectsCoordinate = function intersectsCoordinate (coordinate) {\n return this.containsXY(coordinate[0], coordinate[1]);\n };\n\n /**\n * @abstract\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @protected\n * @return {import(\"../extent.js\").Extent} extent Extent.\n */\n Geometry.prototype.computeExtent = function computeExtent (extent) {\n return abstract();\n };\n\n /**\n * Get the extent of the geometry.\n * @param {import(\"../extent.js\").Extent=} opt_extent Extent.\n * @return {import(\"../extent.js\").Extent} extent Extent.\n * @api\n */\n Geometry.prototype.getExtent = function getExtent (opt_extent) {\n if (this.extentRevision_ != this.getRevision()) {\n this.extent_ = this.computeExtent(this.extent_);\n this.extentRevision_ = this.getRevision();\n }\n return returnOrUpdate(this.extent_, opt_extent);\n };\n\n /**\n * Rotate the geometry around a given coordinate. This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} angle Rotation angle in radians.\n * @param {import(\"../coordinate.js\").Coordinate} anchor The rotation center.\n * @api\n */\n Geometry.prototype.rotate = function rotate (angle, anchor) {\n abstract();\n };\n\n /**\n * Scale the geometry (with an optional origin). This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} sx The scaling factor in the x-direction.\n * @param {number=} opt_sy The scaling factor in the y-direction (defaults to\n * sx).\n * @param {import(\"../coordinate.js\").Coordinate=} opt_anchor The scale origin (defaults to the center\n * of the geometry extent).\n * @api\n */\n Geometry.prototype.scale = function scale (sx, opt_sy, opt_anchor) {\n abstract();\n };\n\n /**\n * Create a simplified version of this geometry. For linestrings, this uses\n * the the {@link\n * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm\n * Douglas Peucker} algorithm. For polygons, a quantization-based\n * simplification is used to preserve topology.\n * @param {number} tolerance The tolerance distance for simplification.\n * @return {Geometry} A new, simplified version of the original geometry.\n * @api\n */\n Geometry.prototype.simplify = function simplify (tolerance) {\n return this.getSimplifiedGeometry(tolerance * tolerance);\n };\n\n /**\n * Create a simplified version of this geometry using the Douglas Peucker\n * algorithm.\n * See https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm.\n * @abstract\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Geometry} Simplified geometry.\n */\n Geometry.prototype.getSimplifiedGeometry = function getSimplifiedGeometry (squaredTolerance) {\n return abstract();\n };\n\n /**\n * Get the type of this geometry.\n * @abstract\n * @return {import(\"./GeometryType.js\").default} Geometry type.\n */\n Geometry.prototype.getType = function getType () {\n return abstract();\n };\n\n /**\n * Apply a transform function to each coordinate of the geometry.\n * The geometry is modified in place.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n * @abstract\n * @param {import(\"../proj.js\").TransformFunction} transformFn Transform.\n */\n Geometry.prototype.applyTransform = function applyTransform (transformFn) {\n abstract();\n };\n\n /**\n * Test if the geometry and the passed extent intersect.\n * @abstract\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n */\n Geometry.prototype.intersectsExtent = function intersectsExtent (extent) {\n return abstract();\n };\n\n /**\n * Translate the geometry. This modifies the geometry coordinates in place. If\n * instead you want a new geometry, first `clone()` this geometry.\n * @abstract\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @api\n */\n Geometry.prototype.translate = function translate (deltaX, deltaY) {\n abstract();\n };\n\n /**\n * Transform each coordinate of the geometry from one coordinate reference\n * system to another. The geometry is modified in place.\n * For example, a line will be transformed to a line and a circle to a circle.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n *\n * @param {import(\"../proj.js\").ProjectionLike} source The current projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @param {import(\"../proj.js\").ProjectionLike} destination The desired projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @return {Geometry} This geometry. Note that original geometry is\n * modified in place.\n * @api\n */\n Geometry.prototype.transform = function transform (source, destination) {\n /** @type {import(\"../proj/Projection.js\").default} */\n var sourceProj = getProjection(source);\n var transformFn = sourceProj.getUnits() == Units.TILE_PIXELS ?\n function(inCoordinates, outCoordinates, stride) {\n var pixelExtent = sourceProj.getExtent();\n var projectedExtent = sourceProj.getWorldExtent();\n var scale = getHeight(projectedExtent) / getHeight(pixelExtent);\n composeTransform(tmpTransform,\n projectedExtent[0], projectedExtent[3],\n scale, -scale, 0,\n 0, 0);\n transform2D(inCoordinates, 0, inCoordinates.length, stride,\n tmpTransform, outCoordinates);\n return getTransform(sourceProj, destination)(inCoordinates, outCoordinates, stride);\n } :\n getTransform(sourceProj, destination);\n this.applyTransform(transformFn);\n return this;\n };\n\n return Geometry;\n}(BaseObject));\n\n\nexport default Geometry;\n\n//# sourceMappingURL=Geometry.js.map","/**\n * @module ol/geom/SimpleGeometry\n */\nimport {abstract} from '../util.js';\nimport {createOrUpdateFromFlatCoordinates, getCenter} from '../extent.js';\nimport Geometry from './Geometry.js';\nimport GeometryLayout from './GeometryLayout.js';\nimport {rotate, scale, translate, transform2D} from './flat/transform.js';\nimport {clear} from '../obj.js';\n\n/**\n * @classdesc\n * Abstract base class; only used for creating subclasses; do not instantiate\n * in apps, as cannot be rendered.\n *\n * @abstract\n * @api\n */\nvar SimpleGeometry = /*@__PURE__*/(function (Geometry) {\n function SimpleGeometry() {\n\n Geometry.call(this);\n\n /**\n * @protected\n * @type {GeometryLayout}\n */\n this.layout = GeometryLayout.XY;\n\n /**\n * @protected\n * @type {number}\n */\n this.stride = 2;\n\n /**\n * @protected\n * @type {Array}\n */\n this.flatCoordinates = null;\n\n }\n\n if ( Geometry ) SimpleGeometry.__proto__ = Geometry;\n SimpleGeometry.prototype = Object.create( Geometry && Geometry.prototype );\n SimpleGeometry.prototype.constructor = SimpleGeometry;\n\n /**\n * @inheritDoc\n */\n SimpleGeometry.prototype.computeExtent = function computeExtent (extent) {\n return createOrUpdateFromFlatCoordinates(this.flatCoordinates,\n 0, this.flatCoordinates.length, this.stride, extent);\n };\n\n /**\n * @abstract\n * @return {Array} Coordinates.\n */\n SimpleGeometry.prototype.getCoordinates = function getCoordinates () {\n return abstract();\n };\n\n /**\n * Return the first coordinate of the geometry.\n * @return {import(\"../coordinate.js\").Coordinate} First coordinate.\n * @api\n */\n SimpleGeometry.prototype.getFirstCoordinate = function getFirstCoordinate () {\n return this.flatCoordinates.slice(0, this.stride);\n };\n\n /**\n * @return {Array} Flat coordinates.\n */\n SimpleGeometry.prototype.getFlatCoordinates = function getFlatCoordinates () {\n return this.flatCoordinates;\n };\n\n /**\n * Return the last coordinate of the geometry.\n * @return {import(\"../coordinate.js\").Coordinate} Last point.\n * @api\n */\n SimpleGeometry.prototype.getLastCoordinate = function getLastCoordinate () {\n return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);\n };\n\n /**\n * Return the {@link module:ol/geom/GeometryLayout layout} of the geometry.\n * @return {GeometryLayout} Layout.\n * @api\n */\n SimpleGeometry.prototype.getLayout = function getLayout () {\n return this.layout;\n };\n\n /**\n * @inheritDoc\n */\n SimpleGeometry.prototype.getSimplifiedGeometry = function getSimplifiedGeometry (squaredTolerance) {\n if (this.simplifiedGeometryRevision != this.getRevision()) {\n clear(this.simplifiedGeometryCache);\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n this.simplifiedGeometryRevision = this.getRevision();\n }\n // If squaredTolerance is negative or if we know that simplification will not\n // have any effect then just return this.\n if (squaredTolerance < 0 ||\n (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&\n squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {\n return this;\n }\n var key = squaredTolerance.toString();\n if (this.simplifiedGeometryCache.hasOwnProperty(key)) {\n return this.simplifiedGeometryCache[key];\n } else {\n var simplifiedGeometry =\n this.getSimplifiedGeometryInternal(squaredTolerance);\n var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();\n if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {\n this.simplifiedGeometryCache[key] = simplifiedGeometry;\n return simplifiedGeometry;\n } else {\n // Simplification did not actually remove any coordinates. We now know\n // that any calls to getSimplifiedGeometry with a squaredTolerance less\n // than or equal to the current squaredTolerance will also not have any\n // effect. This allows us to short circuit simplification (saving CPU\n // cycles) and prevents the cache of simplified geometries from filling\n // up with useless identical copies of this geometry (saving memory).\n this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;\n return this;\n }\n }\n };\n\n /**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {SimpleGeometry} Simplified geometry.\n * @protected\n */\n SimpleGeometry.prototype.getSimplifiedGeometryInternal = function getSimplifiedGeometryInternal (squaredTolerance) {\n return this;\n };\n\n /**\n * @return {number} Stride.\n */\n SimpleGeometry.prototype.getStride = function getStride () {\n return this.stride;\n };\n\n /**\n * @param {GeometryLayout} layout Layout.\n * @param {Array} flatCoordinates Flat coordinates.\n */\n SimpleGeometry.prototype.setFlatCoordinates = function setFlatCoordinates (layout, flatCoordinates) {\n this.stride = getStrideForLayout(layout);\n this.layout = layout;\n this.flatCoordinates = flatCoordinates;\n };\n\n /**\n * @abstract\n * @param {!Array} coordinates Coordinates.\n * @param {GeometryLayout=} opt_layout Layout.\n */\n SimpleGeometry.prototype.setCoordinates = function setCoordinates (coordinates, opt_layout) {\n abstract();\n };\n\n /**\n * @param {GeometryLayout|undefined} layout Layout.\n * @param {Array} coordinates Coordinates.\n * @param {number} nesting Nesting.\n * @protected\n */\n SimpleGeometry.prototype.setLayout = function setLayout (layout, coordinates, nesting) {\n /** @type {number} */\n var stride;\n if (layout) {\n stride = getStrideForLayout(layout);\n } else {\n for (var i = 0; i < nesting; ++i) {\n if (coordinates.length === 0) {\n this.layout = GeometryLayout.XY;\n this.stride = 2;\n return;\n } else {\n coordinates = /** @type {Array} */ (coordinates[0]);\n }\n }\n stride = coordinates.length;\n layout = getLayoutForStride(stride);\n }\n this.layout = layout;\n this.stride = stride;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n SimpleGeometry.prototype.applyTransform = function applyTransform (transformFn) {\n if (this.flatCoordinates) {\n transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);\n this.changed();\n }\n };\n\n /**\n * @inheritDoc\n * @api\n */\n SimpleGeometry.prototype.rotate = function rotate$1 (angle, anchor) {\n var flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n var stride = this.getStride();\n rotate(\n flatCoordinates, 0, flatCoordinates.length,\n stride, angle, anchor, flatCoordinates);\n this.changed();\n }\n };\n\n /**\n * @inheritDoc\n * @api\n */\n SimpleGeometry.prototype.scale = function scale$1 (sx, opt_sy, opt_anchor) {\n var sy = opt_sy;\n if (sy === undefined) {\n sy = sx;\n }\n var anchor = opt_anchor;\n if (!anchor) {\n anchor = getCenter(this.getExtent());\n }\n var flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n var stride = this.getStride();\n scale(\n flatCoordinates, 0, flatCoordinates.length,\n stride, sx, sy, anchor, flatCoordinates);\n this.changed();\n }\n };\n\n /**\n * @inheritDoc\n * @api\n */\n SimpleGeometry.prototype.translate = function translate$1 (deltaX, deltaY) {\n var flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n var stride = this.getStride();\n translate(\n flatCoordinates, 0, flatCoordinates.length, stride,\n deltaX, deltaY, flatCoordinates);\n this.changed();\n }\n };\n\n return SimpleGeometry;\n}(Geometry));\n\n\n/**\n * @param {number} stride Stride.\n * @return {GeometryLayout} layout Layout.\n */\nfunction getLayoutForStride(stride) {\n var layout;\n if (stride == 2) {\n layout = GeometryLayout.XY;\n } else if (stride == 3) {\n layout = GeometryLayout.XYZ;\n } else if (stride == 4) {\n layout = GeometryLayout.XYZM;\n }\n return (\n /** @type {GeometryLayout} */ (layout)\n );\n}\n\n\n/**\n * @param {GeometryLayout} layout Layout.\n * @return {number} Stride.\n */\nexport function getStrideForLayout(layout) {\n var stride;\n if (layout == GeometryLayout.XY) {\n stride = 2;\n } else if (layout == GeometryLayout.XYZ || layout == GeometryLayout.XYM) {\n stride = 3;\n } else if (layout == GeometryLayout.XYZM) {\n stride = 4;\n }\n return /** @type {number} */ (stride);\n}\n\n\n/**\n * @param {SimpleGeometry} simpleGeometry Simple geometry.\n * @param {import(\"../transform.js\").Transform} transform Transform.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Transformed flat coordinates.\n */\nexport function transformGeom2D(simpleGeometry, transform, opt_dest) {\n var flatCoordinates = simpleGeometry.getFlatCoordinates();\n if (!flatCoordinates) {\n return null;\n } else {\n var stride = simpleGeometry.getStride();\n return transform2D(\n flatCoordinates, 0, flatCoordinates.length, stride,\n transform, opt_dest);\n }\n}\n\nexport default SimpleGeometry;\n\n//# sourceMappingURL=SimpleGeometry.js.map","/**\n * @module ol/MapEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n\n /**\n * Triggered after a map frame is rendered.\n * @event module:ol/MapEvent~MapEvent#postrender\n * @api\n */\n POSTRENDER: 'postrender',\n\n /**\n * Triggered when the map starts moving.\n * @event module:ol/MapEvent~MapEvent#movestart\n * @api\n */\n MOVESTART: 'movestart',\n\n /**\n * Triggered after the map is moved.\n * @event module:ol/MapEvent~MapEvent#moveend\n * @api\n */\n MOVEEND: 'moveend'\n\n};\n\n//# sourceMappingURL=MapEventType.js.map","/**\n * @module ol/geom/flat/inflate\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Array=} opt_coordinates Coordinates.\n * @return {Array} Coordinates.\n */\nexport function inflateCoordinates(flatCoordinates, offset, end, stride, opt_coordinates) {\n var coordinates = opt_coordinates !== undefined ? opt_coordinates : [];\n var i = 0;\n for (var j = offset; j < end; j += stride) {\n coordinates[i++] = flatCoordinates.slice(j, j + stride);\n }\n coordinates.length = i;\n return coordinates;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {Array>=} opt_coordinatess Coordinatess.\n * @return {Array>} Coordinatess.\n */\nexport function inflateCoordinatesArray(flatCoordinates, offset, ends, stride, opt_coordinatess) {\n var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : [];\n var i = 0;\n for (var j = 0, jj = ends.length; j < jj; ++j) {\n var end = ends[j];\n coordinatess[i++] = inflateCoordinates(\n flatCoordinates, offset, end, stride, coordinatess[i]);\n offset = end;\n }\n coordinatess.length = i;\n return coordinatess;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array>>=} opt_coordinatesss\n * Coordinatesss.\n * @return {Array>>} Coordinatesss.\n */\nexport function inflateMultiCoordinatesArray(flatCoordinates, offset, endss, stride, opt_coordinatesss) {\n var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : [];\n var i = 0;\n for (var j = 0, jj = endss.length; j < jj; ++j) {\n var ends = endss[j];\n coordinatesss[i++] = inflateCoordinatesArray(\n flatCoordinates, offset, ends, stride, coordinatesss[i]);\n offset = ends[ends.length - 1];\n }\n coordinatesss.length = i;\n return coordinatesss;\n}\n\n//# sourceMappingURL=inflate.js.map","/**\n * @module ol/rotationconstraint\n */\nimport {toRadians} from './math.js';\n\n\n/**\n * @typedef {function((number|undefined), number): (number|undefined)} Type\n */\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nexport function disable(rotation, delta) {\n if (rotation !== undefined) {\n return 0;\n } else {\n return undefined;\n }\n}\n\n\n/**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\nexport function none(rotation, delta) {\n if (rotation !== undefined) {\n return rotation + delta;\n } else {\n return undefined;\n }\n}\n\n\n/**\n * @param {number} n N.\n * @return {Type} Rotation constraint.\n */\nexport function createSnapToN(n) {\n var theta = 2 * Math.PI / n;\n return (\n /**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\n function(rotation, delta) {\n if (rotation !== undefined) {\n rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;\n return rotation;\n } else {\n return undefined;\n }\n });\n}\n\n\n/**\n * @param {number=} opt_tolerance Tolerance.\n * @return {Type} Rotation constraint.\n */\nexport function createSnapToZero(opt_tolerance) {\n var tolerance = opt_tolerance || toRadians(5);\n return (\n /**\n * @param {number|undefined} rotation Rotation.\n * @param {number} delta Delta.\n * @return {number|undefined} Rotation.\n */\n function(rotation, delta) {\n if (rotation !== undefined) {\n if (Math.abs(rotation + delta) <= tolerance) {\n return 0;\n } else {\n return rotation + delta;\n }\n } else {\n return undefined;\n }\n });\n}\n\n//# sourceMappingURL=rotationconstraint.js.map","/**\n * @module ol/geom/flat/contains\n */\nimport {forEachCorner} from '../../extent.js';\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} Contains extent.\n */\nexport function linearRingContainsExtent(flatCoordinates, offset, end, stride, extent) {\n var outside = forEachCorner(extent,\n /**\n * @param {import(\"../../coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} Contains (x, y).\n */\n function(coordinate) {\n return !linearRingContainsXY(flatCoordinates, offset, end, stride, coordinate[0], coordinate[1]);\n });\n return !outside;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingContainsXY(flatCoordinates, offset, end, stride, x, y) {\n // http://geomalgorithms.com/a03-_inclusion.html\n // Copyright 2000 softSurfer, 2012 Dan Sunday\n // This code may be freely used and modified for any purpose\n // providing that this copyright notice is included with it.\n // SoftSurfer makes no warranty for this code, and cannot be held\n // liable for any real or imagined damage resulting from its use.\n // Users of this code must verify correctness for their application.\n var wn = 0;\n var x1 = flatCoordinates[end - stride];\n var y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n var x2 = flatCoordinates[offset];\n var y2 = flatCoordinates[offset + 1];\n if (y1 <= y) {\n if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) {\n wn++;\n }\n } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) {\n wn--;\n }\n x1 = x2;\n y1 = y2;\n }\n return wn !== 0;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y) {\n if (ends.length === 0) {\n return false;\n }\n if (!linearRingContainsXY(flatCoordinates, offset, ends[0], stride, x, y)) {\n return false;\n }\n for (var i = 1, ii = ends.length; i < ii; ++i) {\n if (linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingssContainsXY(flatCoordinates, offset, endss, stride, x, y) {\n if (endss.length === 0) {\n return false;\n }\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n\n//# sourceMappingURL=contains.js.map","/**\n * @module ol/geom/flat/closest\n */\nimport {lerp, squaredDistance as squaredDx} from '../../math.js';\n\n\n/**\n * Returns the point on the 2D line segment flatCoordinates[offset1] to\n * flatCoordinates[offset2] that is closest to the point (x, y). Extra\n * dimensions are linearly interpolated.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset1 Offset 1.\n * @param {number} offset2 Offset 2.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n */\nfunction assignClosest(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {\n var x1 = flatCoordinates[offset1];\n var y1 = flatCoordinates[offset1 + 1];\n var dx = flatCoordinates[offset2] - x1;\n var dy = flatCoordinates[offset2 + 1] - y1;\n var offset;\n if (dx === 0 && dy === 0) {\n offset = offset1;\n } else {\n var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n offset = offset2;\n } else if (t > 0) {\n for (var i = 0; i < stride; ++i) {\n closestPoint[i] = lerp(flatCoordinates[offset1 + i],\n flatCoordinates[offset2 + i], t);\n }\n closestPoint.length = stride;\n return;\n } else {\n offset = offset1;\n }\n }\n for (var i$1 = 0; i$1 < stride; ++i$1) {\n closestPoint[i$1] = flatCoordinates[offset + i$1];\n }\n closestPoint.length = stride;\n}\n\n\n/**\n * Return the squared of the largest distance between any pair of consecutive\n * coordinates.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function maxSquaredDelta(flatCoordinates, offset, end, stride, max) {\n var x1 = flatCoordinates[offset];\n var y1 = flatCoordinates[offset + 1];\n for (offset += stride; offset < end; offset += stride) {\n var x2 = flatCoordinates[offset];\n var y2 = flatCoordinates[offset + 1];\n var squaredDelta = squaredDx(x1, y1, x2, y2);\n if (squaredDelta > max) {\n max = squaredDelta;\n }\n x1 = x2;\n y1 = y2;\n }\n return max;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function arrayMaxSquaredDelta(flatCoordinates, offset, ends, stride, max) {\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n max = maxSquaredDelta(\n flatCoordinates, offset, end, stride, max);\n offset = end;\n }\n return max;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function multiArrayMaxSquaredDelta(flatCoordinates, offset, endss, stride, max) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n max = arrayMaxSquaredDelta(\n flatCoordinates, offset, ends, stride, max);\n offset = ends[ends.length - 1];\n }\n return max;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestPoint(flatCoordinates, offset, end,\n stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n if (offset == end) {\n return minSquaredDistance;\n }\n var i, squaredDistance;\n if (maxDelta === 0) {\n // All points are identical, so just test the first point.\n squaredDistance = squaredDx(\n x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);\n if (squaredDistance < minSquaredDistance) {\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[offset + i];\n }\n closestPoint.length = stride;\n return squaredDistance;\n } else {\n return minSquaredDistance;\n }\n }\n var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n var index = offset + stride;\n while (index < end) {\n assignClosest(\n flatCoordinates, index - stride, index, stride, x, y, tmpPoint);\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n index += stride;\n } else {\n // Skip ahead multiple points, because we know that all the skipped\n // points cannot be any closer than the closest point we have found so\n // far. We know this because we know how close the current point is, how\n // close the closest point we have found so far is, and the maximum\n // distance between consecutive points. For example, if we're currently\n // at distance 10, the best we've found so far is 3, and that the maximum\n // distance between consecutive points is 2, then we'll need to skip at\n // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of\n // finding a closer point. We use Math.max(..., 1) to ensure that we\n // always advance at least one point, to avoid an infinite loop.\n index += stride * Math.max(\n ((Math.sqrt(squaredDistance) -\n Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);\n }\n }\n if (isRing) {\n // Check the closing segment.\n assignClosest(\n flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n }\n }\n return minSquaredDistance;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestArrayPoint(flatCoordinates, offset, ends,\n stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n minSquaredDistance = assignClosestPoint(\n flatCoordinates, offset, end, stride,\n maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n offset = end;\n }\n return minSquaredDistance;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array=} opt_tmpPoint Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestMultiArrayPoint(flatCoordinates, offset,\n endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,\n opt_tmpPoint) {\n var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n minSquaredDistance = assignClosestArrayPoint(\n flatCoordinates, offset, ends, stride,\n maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);\n offset = ends[ends.length - 1];\n }\n return minSquaredDistance;\n}\n\n//# sourceMappingURL=closest.js.map","/**\n * @module ol/geom/flat/deflate\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {import(\"../../coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinate(flatCoordinates, offset, coordinate, stride) {\n for (var i = 0, ii = coordinate.length; i < ii; ++i) {\n flatCoordinates[offset++] = coordinate[i];\n }\n return offset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} coordinates Coordinates.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinates(flatCoordinates, offset, coordinates, stride) {\n for (var i = 0, ii = coordinates.length; i < ii; ++i) {\n var coordinate = coordinates[i];\n for (var j = 0; j < stride; ++j) {\n flatCoordinates[offset++] = coordinate[j];\n }\n }\n return offset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} coordinatess Coordinatess.\n * @param {number} stride Stride.\n * @param {Array=} opt_ends Ends.\n * @return {Array} Ends.\n */\nexport function deflateCoordinatesArray(flatCoordinates, offset, coordinatess, stride, opt_ends) {\n var ends = opt_ends ? opt_ends : [];\n var i = 0;\n for (var j = 0, jj = coordinatess.length; j < jj; ++j) {\n var end = deflateCoordinates(\n flatCoordinates, offset, coordinatess[j], stride);\n ends[i++] = end;\n offset = end;\n }\n ends.length = i;\n return ends;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>>} coordinatesss Coordinatesss.\n * @param {number} stride Stride.\n * @param {Array>=} opt_endss Endss.\n * @return {Array>} Endss.\n */\nexport function deflateMultiCoordinatesArray(flatCoordinates, offset, coordinatesss, stride, opt_endss) {\n var endss = opt_endss ? opt_endss : [];\n var i = 0;\n for (var j = 0, jj = coordinatesss.length; j < jj; ++j) {\n var ends = deflateCoordinatesArray(\n flatCoordinates, offset, coordinatesss[j], stride, endss[i]);\n endss[i++] = ends;\n offset = ends[ends.length - 1];\n }\n endss.length = i;\n return endss;\n}\n\n//# sourceMappingURL=deflate.js.map","/**\n * @module ol/geom/flat/simplify\n */\n// Based on simplify-js https://github.com/mourner/simplify-js\n// Copyright (c) 2012, Vladimir Agafonkin\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//\n// 1. Redistributions of source code must retain the above copyright notice,\n// this list of conditions and the following disclaimer.\n//\n// 2. Redistributions in binary form must reproduce the above copyright\n// notice, this list of conditions and the following disclaimer in the\n// documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n// POSSIBILITY OF SUCH DAMAGE.\n\nimport {squaredSegmentDistance, squaredDistance} from '../../math.js';\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {boolean} highQuality Highest quality.\n * @param {Array=} opt_simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @return {Array} Simplified line string.\n */\nexport function simplifyLineString(flatCoordinates, offset, end,\n stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {\n var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ?\n opt_simplifiedFlatCoordinates : [];\n if (!highQuality) {\n end = radialDistance(flatCoordinates, offset, end,\n stride, squaredTolerance,\n simplifiedFlatCoordinates, 0);\n flatCoordinates = simplifiedFlatCoordinates;\n offset = 0;\n stride = 2;\n }\n simplifiedFlatCoordinates.length = douglasPeucker(\n flatCoordinates, offset, end, stride, squaredTolerance,\n simplifiedFlatCoordinates, 0);\n return simplifiedFlatCoordinates;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function douglasPeucker(flatCoordinates, offset, end,\n stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n var n = (end - offset) / stride;\n if (n < 3) {\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n /** @type {Array} */\n var markers = new Array(n);\n markers[0] = 1;\n markers[n - 1] = 1;\n /** @type {Array} */\n var stack = [offset, end - stride];\n var index = 0;\n while (stack.length > 0) {\n var last = stack.pop();\n var first = stack.pop();\n var maxSquaredDistance = 0;\n var x1 = flatCoordinates[first];\n var y1 = flatCoordinates[first + 1];\n var x2 = flatCoordinates[last];\n var y2 = flatCoordinates[last + 1];\n for (var i = first + stride; i < last; i += stride) {\n var x = flatCoordinates[i];\n var y = flatCoordinates[i + 1];\n var squaredDistance = squaredSegmentDistance(\n x, y, x1, y1, x2, y2);\n if (squaredDistance > maxSquaredDistance) {\n index = i;\n maxSquaredDistance = squaredDistance;\n }\n }\n if (maxSquaredDistance > squaredTolerance) {\n markers[(index - offset) / stride] = 1;\n if (first + stride < index) {\n stack.push(first, index);\n }\n if (index + stride < last) {\n stack.push(index, last);\n }\n }\n }\n for (var i$1 = 0; i$1 < n; ++i$1) {\n if (markers[i$1]) {\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i$1 * stride];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i$1 * stride + 1];\n }\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerArray(flatCoordinates, offset,\n ends, stride, squaredTolerance, simplifiedFlatCoordinates,\n simplifiedOffset, simplifiedEnds) {\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n simplifiedOffset = douglasPeucker(\n flatCoordinates, offset, end, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset);\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerMultiArray(\n flatCoordinates, offset, endss, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n var simplifiedEnds = [];\n simplifiedOffset = douglasPeuckerArray(\n flatCoordinates, offset, ends, stride, squaredTolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function radialDistance(flatCoordinates, offset, end,\n stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n if (end <= offset + stride) {\n // zero or one point, no simplification possible, so copy and return\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n var x1 = flatCoordinates[offset];\n var y1 = flatCoordinates[offset + 1];\n // copy first point\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n var x2 = x1;\n var y2 = y1;\n for (offset += stride; offset < end; offset += stride) {\n x2 = flatCoordinates[offset];\n y2 = flatCoordinates[offset + 1];\n if (squaredDistance(x1, y1, x2, y2) > squaredTolerance) {\n // copy point at offset\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n }\n }\n if (x2 != x1 || y2 != y1) {\n // copy last point\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {number} value Value.\n * @param {number} tolerance Tolerance.\n * @return {number} Rounded value.\n */\nexport function snap(value, tolerance) {\n return tolerance * Math.round(value / tolerance);\n}\n\n\n/**\n * Simplifies a line string using an algorithm designed by Tim Schaub.\n * Coordinates are snapped to the nearest value in a virtual grid and\n * consecutive duplicate coordinates are discarded. This effectively preserves\n * topology as the simplification of any subsection of a line string is\n * independent of the rest of the line string. This means that, for examples,\n * the common edge between two polygons will be simplified to the same line\n * string independently in both polygons. This implementation uses a single\n * pass over the coordinates and eliminates intermediate collinear points.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function quantize(flatCoordinates, offset, end, stride,\n tolerance, simplifiedFlatCoordinates, simplifiedOffset) {\n // do nothing if the line is empty\n if (offset == end) {\n return simplifiedOffset;\n }\n // snap the first coordinate (P1)\n var x1 = snap(flatCoordinates[offset], tolerance);\n var y1 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // add the first coordinate to the output\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n // find the next coordinate that does not snap to the same value as the first\n // coordinate (P2)\n var x2, y2;\n do {\n x2 = snap(flatCoordinates[offset], tolerance);\n y2 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n if (offset == end) {\n // all coordinates snap to the same value, the line collapses to a point\n // push the last snapped value anyway to ensure that the output contains\n // at least two points\n // FIXME should we really return at least two points anyway?\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n }\n } while (x2 == x1 && y2 == y1);\n while (offset < end) {\n // snap the next coordinate (P3)\n var x3 = snap(flatCoordinates[offset], tolerance);\n var y3 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // skip P3 if it is equal to P2\n if (x3 == x2 && y3 == y2) {\n continue;\n }\n // calculate the delta between P1 and P2\n var dx1 = x2 - x1;\n var dy1 = y2 - y1;\n // calculate the delta between P3 and P1\n var dx2 = x3 - x1;\n var dy2 = y3 - y1;\n // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from\n // P1 in the same direction then P2 is on the straight line between P1 and\n // P3\n if ((dx1 * dy2 == dy1 * dx2) &&\n ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&\n ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {\n // discard P2 and set P2 = P3\n x2 = x3;\n y2 = y3;\n continue;\n }\n // either P1, P2, and P3 are not colinear, or they are colinear but P3 is\n // between P3 and P1 or on the opposite half of the line to P2. add P2,\n // and continue with P1 = P2 and P2 = P3\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n x2 = x3;\n y2 = y3;\n }\n // add the last point (P2)\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function quantizeArray(\n flatCoordinates, offset, ends, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n simplifiedOffset = quantize(\n flatCoordinates, offset, end, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset);\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function quantizeMultiArray(\n flatCoordinates, offset, endss, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n var simplifiedEnds = [];\n simplifiedOffset = quantizeArray(\n flatCoordinates, offset, ends, stride,\n tolerance,\n simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n\n//# sourceMappingURL=simplify.js.map","/**\n * @module ol/tilegrid/common\n */\n\n/**\n * Default maximum zoom for default tile grids.\n * @type {number}\n */\nexport var DEFAULT_MAX_ZOOM = 42;\n\n/**\n * Default tile size.\n * @type {number}\n */\nexport var DEFAULT_TILE_SIZE = 256;\n\n//# sourceMappingURL=common.js.map","/**\n * @module ol/extent/Corner\n */\n\n/**\n * Extent corner.\n * @enum {string}\n */\nexport default {\n BOTTOM_LEFT: 'bottom-left',\n BOTTOM_RIGHT: 'bottom-right',\n TOP_LEFT: 'top-left',\n TOP_RIGHT: 'top-right'\n};\n\n//# sourceMappingURL=Corner.js.map","/**\n * @module ol/TileRange\n */\n\n/**\n * A representation of a contiguous block of tiles. A tile range is specified\n * by its min/max tile coordinates and is inclusive of coordinates.\n */\nvar TileRange = function TileRange(minX, maxX, minY, maxY) {\n\n /**\n * @type {number}\n */\n this.minX = minX;\n\n /**\n * @type {number}\n */\n this.maxX = maxX;\n\n /**\n * @type {number}\n */\n this.minY = minY;\n\n /**\n * @type {number}\n */\n this.maxY = maxY;\n\n};\n\n/**\n * @param {import(\"./tilecoord.js\").TileCoord} tileCoord Tile coordinate.\n * @return {boolean} Contains tile coordinate.\n */\nTileRange.prototype.contains = function contains (tileCoord) {\n return this.containsXY(tileCoord[1], tileCoord[2]);\n};\n\n/**\n * @param {TileRange} tileRange Tile range.\n * @return {boolean} Contains.\n */\nTileRange.prototype.containsTileRange = function containsTileRange (tileRange) {\n return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&\n this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;\n};\n\n/**\n * @param {number} x Tile coordinate x.\n * @param {number} y Tile coordinate y.\n * @return {boolean} Contains coordinate.\n */\nTileRange.prototype.containsXY = function containsXY (x, y) {\n return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;\n};\n\n/**\n * @param {TileRange} tileRange Tile range.\n * @return {boolean} Equals.\n */\nTileRange.prototype.equals = function equals (tileRange) {\n return this.minX == tileRange.minX && this.minY == tileRange.minY &&\n this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;\n};\n\n/**\n * @param {TileRange} tileRange Tile range.\n */\nTileRange.prototype.extend = function extend (tileRange) {\n if (tileRange.minX < this.minX) {\n this.minX = tileRange.minX;\n }\n if (tileRange.maxX > this.maxX) {\n this.maxX = tileRange.maxX;\n }\n if (tileRange.minY < this.minY) {\n this.minY = tileRange.minY;\n }\n if (tileRange.maxY > this.maxY) {\n this.maxY = tileRange.maxY;\n }\n};\n\n/**\n * @return {number} Height.\n */\nTileRange.prototype.getHeight = function getHeight () {\n return this.maxY - this.minY + 1;\n};\n\n/**\n * @return {import(\"./size.js\").Size} Size.\n */\nTileRange.prototype.getSize = function getSize () {\n return [this.getWidth(), this.getHeight()];\n};\n\n/**\n * @return {number} Width.\n */\nTileRange.prototype.getWidth = function getWidth () {\n return this.maxX - this.minX + 1;\n};\n\n/**\n * @param {TileRange} tileRange Tile range.\n * @return {boolean} Intersects.\n */\nTileRange.prototype.intersects = function intersects (tileRange) {\n return this.minX <= tileRange.maxX &&\n this.maxX >= tileRange.minX &&\n this.minY <= tileRange.maxY &&\n this.maxY >= tileRange.minY;\n};\n\n\n/**\n * @param {number} minX Minimum X.\n * @param {number} maxX Maximum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxY Maximum Y.\n * @param {TileRange=} tileRange TileRange.\n * @return {TileRange} Tile range.\n */\nexport function createOrUpdate(minX, maxX, minY, maxY, tileRange) {\n if (tileRange !== undefined) {\n tileRange.minX = minX;\n tileRange.maxX = maxX;\n tileRange.minY = minY;\n tileRange.maxY = maxY;\n return tileRange;\n } else {\n return new TileRange(minX, maxX, minY, maxY);\n }\n}\n\n\nexport default TileRange;\n\n//# sourceMappingURL=TileRange.js.map","/**\n * @module ol/Disposable\n */\n\n/**\n * @classdesc\n * Objects that need to clean up after themselves.\n */\nvar Disposable = function Disposable() {\n /**\n * The object has already been disposed.\n * @type {boolean}\n * @private\n */\n this.disposed_ = false;\n};\n\n/**\n * Clean up.\n */\nDisposable.prototype.dispose = function dispose () {\n if (!this.disposed_) {\n this.disposed_ = true;\n this.disposeInternal();\n }\n};\n\n/**\n * Extension point for disposable objects.\n * @protected\n */\nDisposable.prototype.disposeInternal = function disposeInternal () {};\n\nexport default Disposable;\n\n//# sourceMappingURL=Disposable.js.map","'use strict';\n\nmodule.exports = rbush;\nmodule.exports.default = rbush;\n\nvar quickselect = require('quickselect');\n\nfunction rbush(maxEntries, format) {\n if (!(this instanceof rbush)) return new rbush(maxEntries, format);\n\n // max entries in a node is 9 by default; min node fill is 40% for best performance\n this._maxEntries = Math.max(4, maxEntries || 9);\n this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));\n\n if (format) {\n this._initFormat(format);\n }\n\n this.clear();\n}\n\nrbush.prototype = {\n\n all: function () {\n return this._all(this.data, []);\n },\n\n search: function (bbox) {\n\n var node = this.data,\n result = [],\n toBBox = this.toBBox;\n\n if (!intersects(bbox, node)) return result;\n\n var nodesToSearch = [],\n i, len, child, childBBox;\n\n while (node) {\n for (i = 0, len = node.children.length; i < len; i++) {\n\n child = node.children[i];\n childBBox = node.leaf ? toBBox(child) : child;\n\n if (intersects(bbox, childBBox)) {\n if (node.leaf) result.push(child);\n else if (contains(bbox, childBBox)) this._all(child, result);\n else nodesToSearch.push(child);\n }\n }\n node = nodesToSearch.pop();\n }\n\n return result;\n },\n\n collides: function (bbox) {\n\n var node = this.data,\n toBBox = this.toBBox;\n\n if (!intersects(bbox, node)) return false;\n\n var nodesToSearch = [],\n i, len, child, childBBox;\n\n while (node) {\n for (i = 0, len = node.children.length; i < len; i++) {\n\n child = node.children[i];\n childBBox = node.leaf ? toBBox(child) : child;\n\n if (intersects(bbox, childBBox)) {\n if (node.leaf || contains(bbox, childBBox)) return true;\n nodesToSearch.push(child);\n }\n }\n node = nodesToSearch.pop();\n }\n\n return false;\n },\n\n load: function (data) {\n if (!(data && data.length)) return this;\n\n if (data.length < this._minEntries) {\n for (var i = 0, len = data.length; i < len; i++) {\n this.insert(data[i]);\n }\n return this;\n }\n\n // recursively build the tree with the given data from scratch using OMT algorithm\n var node = this._build(data.slice(), 0, data.length - 1, 0);\n\n if (!this.data.children.length) {\n // save as is if tree is empty\n this.data = node;\n\n } else if (this.data.height === node.height) {\n // split root if trees have the same height\n this._splitRoot(this.data, node);\n\n } else {\n if (this.data.height < node.height) {\n // swap trees if inserted one is bigger\n var tmpNode = this.data;\n this.data = node;\n node = tmpNode;\n }\n\n // insert the small tree into the large tree at appropriate level\n this._insert(node, this.data.height - node.height - 1, true);\n }\n\n return this;\n },\n\n insert: function (item) {\n if (item) this._insert(item, this.data.height - 1);\n return this;\n },\n\n clear: function () {\n this.data = createNode([]);\n return this;\n },\n\n remove: function (item, equalsFn) {\n if (!item) return this;\n\n var node = this.data,\n bbox = this.toBBox(item),\n path = [],\n indexes = [],\n i, parent, index, goingUp;\n\n // depth-first iterative tree traversal\n while (node || path.length) {\n\n if (!node) { // go up\n node = path.pop();\n parent = path[path.length - 1];\n i = indexes.pop();\n goingUp = true;\n }\n\n if (node.leaf) { // check current node\n index = findItem(item, node.children, equalsFn);\n\n if (index !== -1) {\n // item found, remove the item and condense tree upwards\n node.children.splice(index, 1);\n path.push(node);\n this._condense(path);\n return this;\n }\n }\n\n if (!goingUp && !node.leaf && contains(node, bbox)) { // go down\n path.push(node);\n indexes.push(i);\n i = 0;\n parent = node;\n node = node.children[0];\n\n } else if (parent) { // go right\n i++;\n node = parent.children[i];\n goingUp = false;\n\n } else node = null; // nothing found\n }\n\n return this;\n },\n\n toBBox: function (item) { return item; },\n\n compareMinX: compareNodeMinX,\n compareMinY: compareNodeMinY,\n\n toJSON: function () { return this.data; },\n\n fromJSON: function (data) {\n this.data = data;\n return this;\n },\n\n _all: function (node, result) {\n var nodesToSearch = [];\n while (node) {\n if (node.leaf) result.push.apply(result, node.children);\n else nodesToSearch.push.apply(nodesToSearch, node.children);\n\n node = nodesToSearch.pop();\n }\n return result;\n },\n\n _build: function (items, left, right, height) {\n\n var N = right - left + 1,\n M = this._maxEntries,\n node;\n\n if (N <= M) {\n // reached leaf level; return leaf\n node = createNode(items.slice(left, right + 1));\n calcBBox(node, this.toBBox);\n return node;\n }\n\n if (!height) {\n // target height of the bulk-loaded tree\n height = Math.ceil(Math.log(N) / Math.log(M));\n\n // target number of root entries to maximize storage utilization\n M = Math.ceil(N / Math.pow(M, height - 1));\n }\n\n node = createNode([]);\n node.leaf = false;\n node.height = height;\n\n // split the items into M mostly square tiles\n\n var N2 = Math.ceil(N / M),\n N1 = N2 * Math.ceil(Math.sqrt(M)),\n i, j, right2, right3;\n\n multiSelect(items, left, right, N1, this.compareMinX);\n\n for (i = left; i <= right; i += N1) {\n\n right2 = Math.min(i + N1 - 1, right);\n\n multiSelect(items, i, right2, N2, this.compareMinY);\n\n for (j = i; j <= right2; j += N2) {\n\n right3 = Math.min(j + N2 - 1, right2);\n\n // pack each entry recursively\n node.children.push(this._build(items, j, right3, height - 1));\n }\n }\n\n calcBBox(node, this.toBBox);\n\n return node;\n },\n\n _chooseSubtree: function (bbox, node, level, path) {\n\n var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;\n\n while (true) {\n path.push(node);\n\n if (node.leaf || path.length - 1 === level) break;\n\n minArea = minEnlargement = Infinity;\n\n for (i = 0, len = node.children.length; i < len; i++) {\n child = node.children[i];\n area = bboxArea(child);\n enlargement = enlargedArea(bbox, child) - area;\n\n // choose entry with the least area enlargement\n if (enlargement < minEnlargement) {\n minEnlargement = enlargement;\n minArea = area < minArea ? area : minArea;\n targetNode = child;\n\n } else if (enlargement === minEnlargement) {\n // otherwise choose one with the smallest area\n if (area < minArea) {\n minArea = area;\n targetNode = child;\n }\n }\n }\n\n node = targetNode || node.children[0];\n }\n\n return node;\n },\n\n _insert: function (item, level, isNode) {\n\n var toBBox = this.toBBox,\n bbox = isNode ? item : toBBox(item),\n insertPath = [];\n\n // find the best node for accommodating the item, saving all nodes along the path too\n var node = this._chooseSubtree(bbox, this.data, level, insertPath);\n\n // put the item into the node\n node.children.push(item);\n extend(node, bbox);\n\n // split on node overflow; propagate upwards if necessary\n while (level >= 0) {\n if (insertPath[level].children.length > this._maxEntries) {\n this._split(insertPath, level);\n level--;\n } else break;\n }\n\n // adjust bboxes along the insertion path\n this._adjustParentBBoxes(bbox, insertPath, level);\n },\n\n // split overflowed node into two\n _split: function (insertPath, level) {\n\n var node = insertPath[level],\n M = node.children.length,\n m = this._minEntries;\n\n this._chooseSplitAxis(node, m, M);\n\n var splitIndex = this._chooseSplitIndex(node, m, M);\n\n var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));\n newNode.height = node.height;\n newNode.leaf = node.leaf;\n\n calcBBox(node, this.toBBox);\n calcBBox(newNode, this.toBBox);\n\n if (level) insertPath[level - 1].children.push(newNode);\n else this._splitRoot(node, newNode);\n },\n\n _splitRoot: function (node, newNode) {\n // split root node\n this.data = createNode([node, newNode]);\n this.data.height = node.height + 1;\n this.data.leaf = false;\n calcBBox(this.data, this.toBBox);\n },\n\n _chooseSplitIndex: function (node, m, M) {\n\n var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;\n\n minOverlap = minArea = Infinity;\n\n for (i = m; i <= M - m; i++) {\n bbox1 = distBBox(node, 0, i, this.toBBox);\n bbox2 = distBBox(node, i, M, this.toBBox);\n\n overlap = intersectionArea(bbox1, bbox2);\n area = bboxArea(bbox1) + bboxArea(bbox2);\n\n // choose distribution with minimum overlap\n if (overlap < minOverlap) {\n minOverlap = overlap;\n index = i;\n\n minArea = area < minArea ? area : minArea;\n\n } else if (overlap === minOverlap) {\n // otherwise choose distribution with minimum area\n if (area < minArea) {\n minArea = area;\n index = i;\n }\n }\n }\n\n return index;\n },\n\n // sorts node children by the best axis for split\n _chooseSplitAxis: function (node, m, M) {\n\n var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,\n compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,\n xMargin = this._allDistMargin(node, m, M, compareMinX),\n yMargin = this._allDistMargin(node, m, M, compareMinY);\n\n // if total distributions margin value is minimal for x, sort by minX,\n // otherwise it's already sorted by minY\n if (xMargin < yMargin) node.children.sort(compareMinX);\n },\n\n // total margin of all possible split distributions where each node is at least m full\n _allDistMargin: function (node, m, M, compare) {\n\n node.children.sort(compare);\n\n var toBBox = this.toBBox,\n leftBBox = distBBox(node, 0, m, toBBox),\n rightBBox = distBBox(node, M - m, M, toBBox),\n margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),\n i, child;\n\n for (i = m; i < M - m; i++) {\n child = node.children[i];\n extend(leftBBox, node.leaf ? toBBox(child) : child);\n margin += bboxMargin(leftBBox);\n }\n\n for (i = M - m - 1; i >= m; i--) {\n child = node.children[i];\n extend(rightBBox, node.leaf ? toBBox(child) : child);\n margin += bboxMargin(rightBBox);\n }\n\n return margin;\n },\n\n _adjustParentBBoxes: function (bbox, path, level) {\n // adjust bboxes along the given tree path\n for (var i = level; i >= 0; i--) {\n extend(path[i], bbox);\n }\n },\n\n _condense: function (path) {\n // go through the path, removing empty nodes and updating bboxes\n for (var i = path.length - 1, siblings; i >= 0; i--) {\n if (path[i].children.length === 0) {\n if (i > 0) {\n siblings = path[i - 1].children;\n siblings.splice(siblings.indexOf(path[i]), 1);\n\n } else this.clear();\n\n } else calcBBox(path[i], this.toBBox);\n }\n },\n\n _initFormat: function (format) {\n // data format (minX, minY, maxX, maxY accessors)\n\n // uses eval-type function compilation instead of just accepting a toBBox function\n // because the algorithms are very sensitive to sorting functions performance,\n // so they should be dead simple and without inner calls\n\n var compareArr = ['return a', ' - b', ';'];\n\n this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));\n this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));\n\n this.toBBox = new Function('a',\n 'return {minX: a' + format[0] +\n ', minY: a' + format[1] +\n ', maxX: a' + format[2] +\n ', maxY: a' + format[3] + '};');\n }\n};\n\nfunction findItem(item, items, equalsFn) {\n if (!equalsFn) return items.indexOf(item);\n\n for (var i = 0; i < items.length; i++) {\n if (equalsFn(item, items[i])) return i;\n }\n return -1;\n}\n\n// calculate node's bbox from bboxes of its children\nfunction calcBBox(node, toBBox) {\n distBBox(node, 0, node.children.length, toBBox, node);\n}\n\n// min bounding rectangle of node children from k to p-1\nfunction distBBox(node, k, p, toBBox, destNode) {\n if (!destNode) destNode = createNode(null);\n destNode.minX = Infinity;\n destNode.minY = Infinity;\n destNode.maxX = -Infinity;\n destNode.maxY = -Infinity;\n\n for (var i = k, child; i < p; i++) {\n child = node.children[i];\n extend(destNode, node.leaf ? toBBox(child) : child);\n }\n\n return destNode;\n}\n\nfunction extend(a, b) {\n a.minX = Math.min(a.minX, b.minX);\n a.minY = Math.min(a.minY, b.minY);\n a.maxX = Math.max(a.maxX, b.maxX);\n a.maxY = Math.max(a.maxY, b.maxY);\n return a;\n}\n\nfunction compareNodeMinX(a, b) { return a.minX - b.minX; }\nfunction compareNodeMinY(a, b) { return a.minY - b.minY; }\n\nfunction bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }\nfunction bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }\n\nfunction enlargedArea(a, b) {\n return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *\n (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));\n}\n\nfunction intersectionArea(a, b) {\n var minX = Math.max(a.minX, b.minX),\n minY = Math.max(a.minY, b.minY),\n maxX = Math.min(a.maxX, b.maxX),\n maxY = Math.min(a.maxY, b.maxY);\n\n return Math.max(0, maxX - minX) *\n Math.max(0, maxY - minY);\n}\n\nfunction contains(a, b) {\n return a.minX <= b.minX &&\n a.minY <= b.minY &&\n b.maxX <= a.maxX &&\n b.maxY <= a.maxY;\n}\n\nfunction intersects(a, b) {\n return b.minX <= a.maxX &&\n b.minY <= a.maxY &&\n b.maxX >= a.minX &&\n b.maxY >= a.minY;\n}\n\nfunction createNode(children) {\n return {\n children: children,\n height: 1,\n leaf: true,\n minX: Infinity,\n minY: Infinity,\n maxX: -Infinity,\n maxY: -Infinity\n };\n}\n\n// sort an array so that items come in groups of n unsorted items, with groups sorted between each other;\n// combines selection algorithm with binary divide & conquer approach\n\nfunction multiSelect(arr, left, right, n, compare) {\n var stack = [left, right],\n mid;\n\n while (stack.length) {\n right = stack.pop();\n left = stack.pop();\n\n if (right - left <= n) continue;\n\n mid = left + Math.ceil((right - left) / n / 2) * n;\n quickselect(arr, mid, left, right, compare);\n\n stack.push(left, mid, mid, right);\n }\n}\n","/**\n * @module ol/style/Stroke\n */\nimport {getUid} from '../util.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} [color] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n * @property {string} [lineCap='round'] Line cap style: `butt`, `round`, or `square`.\n * @property {string} [lineJoin='round'] Line join style: `bevel`, `round`, or `miter`.\n * @property {Array} [lineDash] Line dash pattern. Default is `undefined` (no dash).\n * Please note that Internet Explorer 10 and lower do not support the `setLineDash` method on\n * the `CanvasRenderingContext2D` and therefore this option will have no visual effect in these browsers.\n * @property {number} [lineDashOffset=0] Line dash offset.\n * @property {number} [miterLimit=10] Miter limit.\n * @property {number} [width] Width.\n */\n\n\n/**\n * @classdesc\n * Set stroke style for vector features.\n * Note that the defaults given are the Canvas defaults, which will be used if\n * option is not defined. The `get` functions return whatever was entered in\n * the options; they will not return the default.\n * @api\n */\nvar Stroke = function Stroke(opt_options) {\n\n var options = opt_options || {};\n\n /**\n * @private\n * @type {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.lineCap_ = options.lineCap;\n\n /**\n * @private\n * @type {Array}\n */\n this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.lineDashOffset_ = options.lineDashOffset;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.lineJoin_ = options.lineJoin;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.miterLimit_ = options.miterLimit;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.width_ = options.width;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.checksum_ = undefined;\n};\n\n/**\n * Clones the style.\n * @return {Stroke} The cloned style.\n * @api\n */\nStroke.prototype.clone = function clone () {\n var color = this.getColor();\n return new Stroke({\n color: Array.isArray(color) ? color.slice() : color || undefined,\n lineCap: this.getLineCap(),\n lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined,\n lineDashOffset: this.getLineDashOffset(),\n lineJoin: this.getLineJoin(),\n miterLimit: this.getMiterLimit(),\n width: this.getWidth()\n });\n};\n\n/**\n * Get the stroke color.\n * @return {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} Color.\n * @api\n */\nStroke.prototype.getColor = function getColor () {\n return this.color_;\n};\n\n/**\n * Get the line cap type for the stroke.\n * @return {string|undefined} Line cap.\n * @api\n */\nStroke.prototype.getLineCap = function getLineCap () {\n return this.lineCap_;\n};\n\n/**\n * Get the line dash style for the stroke.\n * @return {Array} Line dash.\n * @api\n */\nStroke.prototype.getLineDash = function getLineDash () {\n return this.lineDash_;\n};\n\n/**\n * Get the line dash offset for the stroke.\n * @return {number|undefined} Line dash offset.\n * @api\n */\nStroke.prototype.getLineDashOffset = function getLineDashOffset () {\n return this.lineDashOffset_;\n};\n\n/**\n * Get the line join type for the stroke.\n * @return {string|undefined} Line join.\n * @api\n */\nStroke.prototype.getLineJoin = function getLineJoin () {\n return this.lineJoin_;\n};\n\n/**\n * Get the miter limit for the stroke.\n * @return {number|undefined} Miter limit.\n * @api\n */\nStroke.prototype.getMiterLimit = function getMiterLimit () {\n return this.miterLimit_;\n};\n\n/**\n * Get the stroke width.\n * @return {number|undefined} Width.\n * @api\n */\nStroke.prototype.getWidth = function getWidth () {\n return this.width_;\n};\n\n/**\n * Set the color.\n *\n * @param {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} color Color.\n * @api\n */\nStroke.prototype.setColor = function setColor (color) {\n this.color_ = color;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the line cap.\n *\n * @param {string|undefined} lineCap Line cap.\n * @api\n */\nStroke.prototype.setLineCap = function setLineCap (lineCap) {\n this.lineCap_ = lineCap;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the line dash.\n *\n * Please note that Internet Explorer 10 and lower [do not support][mdn] the\n * `setLineDash` method on the `CanvasRenderingContext2D` and therefore this\n * property will have no visual effect in these browsers.\n *\n * [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility\n *\n * @param {Array} lineDash Line dash.\n * @api\n */\nStroke.prototype.setLineDash = function setLineDash (lineDash) {\n this.lineDash_ = lineDash;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the line dash offset.\n *\n * @param {number|undefined} lineDashOffset Line dash offset.\n * @api\n */\nStroke.prototype.setLineDashOffset = function setLineDashOffset (lineDashOffset) {\n this.lineDashOffset_ = lineDashOffset;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the line join.\n *\n * @param {string|undefined} lineJoin Line join.\n * @api\n */\nStroke.prototype.setLineJoin = function setLineJoin (lineJoin) {\n this.lineJoin_ = lineJoin;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the miter limit.\n *\n * @param {number|undefined} miterLimit Miter limit.\n * @api\n */\nStroke.prototype.setMiterLimit = function setMiterLimit (miterLimit) {\n this.miterLimit_ = miterLimit;\n this.checksum_ = undefined;\n};\n\n/**\n * Set the width.\n *\n * @param {number|undefined} width Width.\n * @api\n */\nStroke.prototype.setWidth = function setWidth (width) {\n this.width_ = width;\n this.checksum_ = undefined;\n};\n\n/**\n * @return {string} The checksum.\n */\nStroke.prototype.getChecksum = function getChecksum () {\n if (this.checksum_ === undefined) {\n this.checksum_ = 's';\n if (this.color_) {\n if (typeof this.color_ === 'string') {\n this.checksum_ += this.color_;\n } else {\n this.checksum_ += getUid(this.color_);\n }\n } else {\n this.checksum_ += '-';\n }\n this.checksum_ += ',' +\n (this.lineCap_ !== undefined ?\n this.lineCap_.toString() : '-') + ',' +\n (this.lineDash_ ?\n this.lineDash_.toString() : '-') + ',' +\n (this.lineDashOffset_ !== undefined ?\n this.lineDashOffset_ : '-') + ',' +\n (this.lineJoin_ !== undefined ?\n this.lineJoin_ : '-') + ',' +\n (this.miterLimit_ !== undefined ?\n this.miterLimit_.toString() : '-') + ',' +\n (this.width_ !== undefined ?\n this.width_.toString() : '-');\n }\n\n return this.checksum_;\n};\n\nexport default Stroke;\n\n//# sourceMappingURL=Stroke.js.map","/**\n * @license\n * Latitude/longitude spherical geodesy formulae taken from\n * http://www.movable-type.co.uk/scripts/latlong.html\n * Licensed under CC-BY-3.0.\n */\n\n/**\n * @module ol/sphere\n */\nimport {toRadians, toDegrees} from './math.js';\nimport GeometryType from './geom/GeometryType.js';\n\n\n/**\n * Object literal with options for the {@link getLength} or {@link getArea}\n * functions.\n * @typedef {Object} SphereMetricOptions\n * @property {import(\"./proj.js\").ProjectionLike} [projection='EPSG:3857']\n * Projection of the geometry. By default, the geometry is assumed to be in\n * Web Mercator.\n * @property {number} [radius=6371008.8] Sphere radius. By default, the radius of the\n * earth is used (Clarke 1866 Authalic Sphere).\n */\n\n\n/**\n * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid.\n * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius\n * @type {number}\n */\nexport var DEFAULT_RADIUS = 6371008.8;\n\n\n/**\n * Get the great circle distance (in meters) between two geographic coordinates.\n * @param {Array} c1 Starting coordinate.\n * @param {Array} c2 Ending coordinate.\n * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {number} The great circle distance between the points (in meters).\n * @api\n */\nexport function getDistance(c1, c2, opt_radius) {\n var radius = opt_radius || DEFAULT_RADIUS;\n var lat1 = toRadians(c1[1]);\n var lat2 = toRadians(c2[1]);\n var deltaLatBy2 = (lat2 - lat1) / 2;\n var deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2;\n var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +\n Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *\n Math.cos(lat1) * Math.cos(lat2);\n return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n}\n\n\n/**\n * Get the cumulative great circle length of linestring coordinates (geographic).\n * @param {Array} coordinates Linestring coordinates.\n * @param {number} radius The sphere radius to use.\n * @return {number} The length (in meters).\n */\nfunction getLengthInternal(coordinates, radius) {\n var length = 0;\n for (var i = 0, ii = coordinates.length; i < ii - 1; ++i) {\n length += getDistance(coordinates[i], coordinates[i + 1], radius);\n }\n return length;\n}\n\n\n/**\n * Get the spherical length of a geometry. This length is the sum of the\n * great circle distances between coordinates. For polygons, the length is\n * the sum of all rings. For points, the length is zero. For multi-part\n * geometries, the length is the sum of the length of each part.\n * @param {import(\"./geom/Geometry.js\").default} geometry A geometry.\n * @param {SphereMetricOptions=} opt_options Options for the\n * length calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical length (in meters).\n * @api\n */\nexport function getLength(geometry, opt_options) {\n var options = opt_options || {};\n var radius = options.radius || DEFAULT_RADIUS;\n var projection = options.projection || 'EPSG:3857';\n var type = geometry.getType();\n if (type !== GeometryType.GEOMETRY_COLLECTION) {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n var length = 0;\n var coordinates, coords, i, ii, j, jj;\n switch (type) {\n case GeometryType.POINT:\n case GeometryType.MULTI_POINT: {\n break;\n }\n case GeometryType.LINE_STRING:\n case GeometryType.LINEAR_RING: {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (geometry).getCoordinates();\n length = getLengthInternal(coordinates, radius);\n break;\n }\n case GeometryType.MULTI_LINE_STRING:\n case GeometryType.POLYGON: {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n length += getLengthInternal(coordinates[i], radius);\n }\n break;\n }\n case GeometryType.MULTI_POLYGON: {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n for (j = 0, jj = coords.length; j < jj; ++j) {\n length += getLengthInternal(coords[j], radius);\n }\n }\n break;\n }\n case GeometryType.GEOMETRY_COLLECTION: {\n var geometries = /** @type {import(\"./geom/GeometryCollection.js\").default} */ (geometry).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n length += getLength(geometries[i], opt_options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return length;\n}\n\n\n/**\n * Returns the spherical area for a list of coordinates.\n *\n * [Reference](https://trs-new.jpl.nasa.gov/handle/2014/40409)\n * Robert. G. Chamberlain and William H. Duquette, \"Some Algorithms for\n * Polygons on a Sphere\", JPL Publication 07-03, Jet Propulsion\n * Laboratory, Pasadena, CA, June 2007\n *\n * @param {Array} coordinates List of coordinates of a linear\n * ring. If the ring is oriented clockwise, the area will be positive,\n * otherwise it will be negative.\n * @param {number} radius The sphere radius.\n * @return {number} Area (in square meters).\n */\nfunction getAreaInternal(coordinates, radius) {\n var area = 0;\n var len = coordinates.length;\n var x1 = coordinates[len - 1][0];\n var y1 = coordinates[len - 1][1];\n for (var i = 0; i < len; i++) {\n var x2 = coordinates[i][0];\n var y2 = coordinates[i][1];\n area += toRadians(x2 - x1) *\n (2 + Math.sin(toRadians(y1)) +\n Math.sin(toRadians(y2)));\n x1 = x2;\n y1 = y2;\n }\n return area * radius * radius / 2.0;\n}\n\n\n/**\n * Get the spherical area of a geometry. This is the area (in meters) assuming\n * that polygon edges are segments of great circles on a sphere.\n * @param {import(\"./geom/Geometry.js\").default} geometry A geometry.\n * @param {SphereMetricOptions=} opt_options Options for the area\n * calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical area (in square meters).\n * @api\n */\nexport function getArea(geometry, opt_options) {\n var options = opt_options || {};\n var radius = options.radius || DEFAULT_RADIUS;\n var projection = options.projection || 'EPSG:3857';\n var type = geometry.getType();\n if (type !== GeometryType.GEOMETRY_COLLECTION) {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n var area = 0;\n var coordinates, coords, i, ii, j, jj;\n switch (type) {\n case GeometryType.POINT:\n case GeometryType.MULTI_POINT:\n case GeometryType.LINE_STRING:\n case GeometryType.MULTI_LINE_STRING:\n case GeometryType.LINEAR_RING: {\n break;\n }\n case GeometryType.POLYGON: {\n coordinates = /** @type {import(\"./geom/Polygon.js\").default} */ (geometry).getCoordinates();\n area = Math.abs(getAreaInternal(coordinates[0], radius));\n for (i = 1, ii = coordinates.length; i < ii; ++i) {\n area -= Math.abs(getAreaInternal(coordinates[i], radius));\n }\n break;\n }\n case GeometryType.MULTI_POLYGON: {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (geometry).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n area += Math.abs(getAreaInternal(coords[0], radius));\n for (j = 1, jj = coords.length; j < jj; ++j) {\n area -= Math.abs(getAreaInternal(coords[j], radius));\n }\n }\n break;\n }\n case GeometryType.GEOMETRY_COLLECTION: {\n var geometries = /** @type {import(\"./geom/GeometryCollection.js\").default} */ (geometry).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n area += getArea(geometries[i], opt_options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return area;\n}\n\n\n/**\n * Returns the coordinate at the given distance and bearing from `c1`.\n *\n * @param {import(\"./coordinate.js\").Coordinate} c1 The origin point (`[lon, lat]` in degrees).\n * @param {number} distance The great-circle distance between the origin\n * point and the target point.\n * @param {number} bearing The bearing (in radians).\n * @param {number=} opt_radius The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {import(\"./coordinate.js\").Coordinate} The target point.\n */\nexport function offset(c1, distance, bearing, opt_radius) {\n var radius = opt_radius || DEFAULT_RADIUS;\n var lat1 = toRadians(c1[1]);\n var lon1 = toRadians(c1[0]);\n var dByR = distance / radius;\n var lat = Math.asin(\n Math.sin(lat1) * Math.cos(dByR) +\n Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));\n var lon = lon1 + Math.atan2(\n Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),\n Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));\n return [toDegrees(lon), toDegrees(lat)];\n}\n\n//# sourceMappingURL=sphere.js.map","/**\n * @module ol/style/IconImageCache\n */\nimport {asString} from '../color.js';\n\n/**\n * @classdesc\n * Singleton class. Available through {@link module:ol/style/IconImageCache~shared}.\n */\nvar IconImageCache = function IconImageCache() {\n\n /**\n * @type {!Object}\n * @private\n */\n this.cache_ = {};\n\n /**\n * @type {number}\n * @private\n */\n this.cacheSize_ = 0;\n\n /**\n * @type {number}\n * @private\n */\n this.maxCacheSize_ = 32;\n};\n\n/**\n* FIXME empty description for jsdoc\n*/\nIconImageCache.prototype.clear = function clear () {\n this.cache_ = {};\n this.cacheSize_ = 0;\n};\n\n/**\n* FIXME empty description for jsdoc\n*/\nIconImageCache.prototype.expire = function expire () {\n if (this.cacheSize_ > this.maxCacheSize_) {\n var i = 0;\n for (var key in this.cache_) {\n var iconImage = this.cache_[key];\n if ((i++ & 3) === 0 && !iconImage.hasListener()) {\n delete this.cache_[key];\n --this.cacheSize_;\n }\n }\n }\n};\n\n/**\n* @param {string} src Src.\n* @param {?string} crossOrigin Cross origin.\n* @param {import(\"../color.js\").Color} color Color.\n* @return {import(\"./IconImage.js\").default} Icon image.\n*/\nIconImageCache.prototype.get = function get (src, crossOrigin, color) {\n var key = getKey(src, crossOrigin, color);\n return key in this.cache_ ? this.cache_[key] : null;\n};\n\n/**\n* @param {string} src Src.\n* @param {?string} crossOrigin Cross origin.\n* @param {import(\"../color.js\").Color} color Color.\n* @param {import(\"./IconImage.js\").default} iconImage Icon image.\n*/\nIconImageCache.prototype.set = function set (src, crossOrigin, color, iconImage) {\n var key = getKey(src, crossOrigin, color);\n this.cache_[key] = iconImage;\n ++this.cacheSize_;\n};\n\n/**\n* Set the cache size of the icon cache. Default is `32`. Change this value when\n* your map uses more than 32 different icon images and you are not caching icon\n* styles on the application level.\n* @param {number} maxCacheSize Cache max size.\n* @api\n*/\nIconImageCache.prototype.setSize = function setSize (maxCacheSize) {\n this.maxCacheSize_ = maxCacheSize;\n this.expire();\n};\n\n\n/**\n * @param {string} src Src.\n * @param {?string} crossOrigin Cross origin.\n * @param {import(\"../color.js\").Color} color Color.\n * @return {string} Cache key.\n */\nfunction getKey(src, crossOrigin, color) {\n var colorString = color ? asString(color) : 'null';\n return crossOrigin + ':' + src + ':' + colorString;\n}\n\n\nexport default IconImageCache;\n\n\n/**\n * The {@link module:ol/style/IconImageCache~IconImageCache} for\n * {@link module:ol/style/Icon~Icon} images.\n * @api\n */\nexport var shared = new IconImageCache();\n\n//# sourceMappingURL=IconImageCache.js.map","/**\n * @module ol/pointer/EventSource\n */\n\nvar EventSource = function EventSource(dispatcher, mapping) {\n\n /**\n * @type {import(\"./PointerEventHandler.js\").default}\n */\n this.dispatcher = dispatcher;\n\n /**\n * @private\n * @const\n * @type {!Object}\n */\n this.mapping_ = mapping;\n};\n\n/**\n * List of events supported by this source.\n * @return {Array} Event names\n */\nEventSource.prototype.getEvents = function getEvents () {\n return Object.keys(this.mapping_);\n};\n\n/**\n * Returns the handler that should handle a given event type.\n * @param {string} eventType The event type.\n * @return {function(Event)} Handler\n */\nEventSource.prototype.getHandlerForEvent = function getHandlerForEvent (eventType) {\n return this.mapping_[eventType];\n};\n\nexport default EventSource;\n\n//# sourceMappingURL=EventSource.js.map","/**\n * @module ol/pointer/MouseSource\n */\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport EventSource from './EventSource.js';\n\n\n/**\n * @type {number}\n */\nexport var POINTER_ID = 1;\n\n\n/**\n * @type {string}\n */\nexport var POINTER_TYPE = 'mouse';\n\n\n/**\n * Radius around touchend that swallows mouse events.\n *\n * @type {number}\n */\nvar DEDUP_DIST = 25;\n\n/**\n * Handler for `mousedown`.\n *\n * @this {MouseSource}\n * @param {MouseEvent} inEvent The in event.\n */\nfunction mousedown(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n // TODO(dfreedman) workaround for some elements not sending mouseup\n // http://crbug/149091\n if (POINTER_ID.toString() in this.pointerMap) {\n this.cancel(inEvent);\n }\n var e = prepareEvent(inEvent, this.dispatcher);\n this.pointerMap[POINTER_ID.toString()] = inEvent;\n this.dispatcher.down(e, inEvent);\n }\n}\n\n/**\n * Handler for `mousemove`.\n *\n * @this {MouseSource}\n * @param {MouseEvent} inEvent The in event.\n */\nfunction mousemove(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n var e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.move(e, inEvent);\n }\n}\n\n/**\n * Handler for `mouseup`.\n *\n * @this {MouseSource}\n * @param {MouseEvent} inEvent The in event.\n */\nfunction mouseup(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n var p = this.pointerMap[POINTER_ID.toString()];\n\n if (p && p.button === inEvent.button) {\n var e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.up(e, inEvent);\n this.cleanupMouse();\n }\n }\n}\n\n/**\n * Handler for `mouseover`.\n *\n * @this {MouseSource}\n * @param {MouseEvent} inEvent The in event.\n */\nfunction mouseover(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n var e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.enterOver(e, inEvent);\n }\n}\n\n/**\n * Handler for `mouseout`.\n *\n * @this {MouseSource}\n * @param {MouseEvent} inEvent The in event.\n */\nfunction mouseout(inEvent) {\n if (!this.isEventSimulatedFromTouch_(inEvent)) {\n var e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.leaveOut(e, inEvent);\n }\n}\n\n\nvar MouseSource = /*@__PURE__*/(function (EventSource) {\n function MouseSource(dispatcher) {\n var mapping = {\n 'mousedown': mousedown,\n 'mousemove': mousemove,\n 'mouseup': mouseup,\n 'mouseover': mouseover,\n 'mouseout': mouseout\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object}\n */\n this.pointerMap = dispatcher.pointerMap;\n\n /**\n * @const\n * @type {Array}\n */\n this.lastTouches = [];\n }\n\n if ( EventSource ) MouseSource.__proto__ = EventSource;\n MouseSource.prototype = Object.create( EventSource && EventSource.prototype );\n MouseSource.prototype.constructor = MouseSource;\n\n /**\n * Detect if a mouse event was simulated from a touch by\n * checking if previously there was a touch event at the\n * same position.\n *\n * FIXME - Known problem with the native Android browser on\n * Samsung GT-I9100 (Android 4.1.2):\n * In case the page is scrolled, this function does not work\n * correctly when a canvas is used (WebGL or canvas renderer).\n * Mouse listeners on canvas elements (for this browser), create\n * two mouse events: One 'good' and one 'bad' one (on other browsers or\n * when a div is used, there is only one event). For the 'bad' one,\n * clientX/clientY and also pageX/pageY are wrong when the page\n * is scrolled. Because of that, this function can not detect if\n * the events were simulated from a touch event. As result, a\n * pointer event at a wrong position is dispatched, which confuses\n * the map interactions.\n * It is unclear, how one can get the correct position for the event\n * or detect that the positions are invalid.\n *\n * @private\n * @param {MouseEvent} inEvent The in event.\n * @return {boolean} True, if the event was generated by a touch.\n */\n MouseSource.prototype.isEventSimulatedFromTouch_ = function isEventSimulatedFromTouch_ (inEvent) {\n var lts = this.lastTouches;\n var x = inEvent.clientX;\n var y = inEvent.clientY;\n for (var i = 0, l = lts.length, t = (void 0); i < l && (t = lts[i]); i++) {\n // simulated mouse events will be swallowed near a primary touchend\n var dx = Math.abs(x - t[0]);\n var dy = Math.abs(y - t[1]);\n if (dx <= DEDUP_DIST && dy <= DEDUP_DIST) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Dispatches a `pointercancel` event.\n *\n * @param {Event} inEvent The in event.\n */\n MouseSource.prototype.cancel = function cancel (inEvent) {\n var e = prepareEvent(inEvent, this.dispatcher);\n this.dispatcher.cancel(e, inEvent);\n this.cleanupMouse();\n };\n\n /**\n * Remove the mouse from the list of active pointers.\n */\n MouseSource.prototype.cleanupMouse = function cleanupMouse () {\n delete this.pointerMap[POINTER_ID.toString()];\n };\n\n return MouseSource;\n}(EventSource));\n\n\n/**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @param {Event} inEvent The in event.\n * @param {import(\"./PointerEventHandler.js\").default} dispatcher Event handler.\n * @return {Object} The copied event.\n */\nexport function prepareEvent(inEvent, dispatcher) {\n var e = dispatcher.cloneEvent(inEvent, inEvent);\n\n // forward mouse preventDefault\n var pd = e.preventDefault;\n e.preventDefault = function() {\n inEvent.preventDefault();\n pd();\n };\n\n e.pointerId = POINTER_ID;\n e.isPrimary = true;\n e.pointerType = POINTER_TYPE;\n\n return e;\n}\n\n\nexport default MouseSource;\n\n//# sourceMappingURL=MouseSource.js.map","/**\n * @module ol/pointer/MsSource\n */\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport EventSource from './EventSource.js';\n\n\n/**\n * @const\n * @type {Array}\n */\nvar POINTER_TYPES = [\n '',\n 'unavailable',\n 'touch',\n 'pen',\n 'mouse'\n];\n\n/**\n * Handler for `msPointerDown`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerDown(inEvent) {\n this.pointerMap[inEvent.pointerId.toString()] = inEvent;\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.down(e, inEvent);\n}\n\n/**\n * Handler for `msPointerMove`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerMove(inEvent) {\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.move(e, inEvent);\n}\n\n/**\n * Handler for `msPointerUp`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerUp(inEvent) {\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.up(e, inEvent);\n this.cleanup(inEvent.pointerId);\n}\n\n/**\n * Handler for `msPointerOut`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerOut(inEvent) {\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.leaveOut(e, inEvent);\n}\n\n/**\n * Handler for `msPointerOver`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerOver(inEvent) {\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.enterOver(e, inEvent);\n}\n\n/**\n * Handler for `msPointerCancel`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msPointerCancel(inEvent) {\n var e = this.prepareEvent_(inEvent);\n this.dispatcher.cancel(e, inEvent);\n this.cleanup(inEvent.pointerId);\n}\n\n/**\n * Handler for `msLostPointerCapture`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msLostPointerCapture(inEvent) {\n var e = this.dispatcher.makeEvent('lostpointercapture', inEvent, inEvent);\n this.dispatcher.dispatchEvent(e);\n}\n\n/**\n * Handler for `msGotPointerCapture`.\n *\n * @this {MsSource}\n * @param {MSPointerEvent} inEvent The in event.\n */\nfunction msGotPointerCapture(inEvent) {\n var e = this.dispatcher.makeEvent('gotpointercapture', inEvent, inEvent);\n this.dispatcher.dispatchEvent(e);\n}\n\nvar MsSource = /*@__PURE__*/(function (EventSource) {\n function MsSource(dispatcher) {\n var mapping = {\n 'MSPointerDown': msPointerDown,\n 'MSPointerMove': msPointerMove,\n 'MSPointerUp': msPointerUp,\n 'MSPointerOut': msPointerOut,\n 'MSPointerOver': msPointerOver,\n 'MSPointerCancel': msPointerCancel,\n 'MSGotPointerCapture': msGotPointerCapture,\n 'MSLostPointerCapture': msLostPointerCapture\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object}\n */\n this.pointerMap = dispatcher.pointerMap;\n }\n\n if ( EventSource ) MsSource.__proto__ = EventSource;\n MsSource.prototype = Object.create( EventSource && EventSource.prototype );\n MsSource.prototype.constructor = MsSource;\n\n /**\n * Creates a copy of the original event that will be used\n * for the fake pointer event.\n *\n * @private\n * @param {MSPointerEvent} inEvent The in event.\n * @return {Object} The copied event.\n */\n MsSource.prototype.prepareEvent_ = function prepareEvent_ (inEvent) {\n /** @type {MSPointerEvent|Object} */\n var e = inEvent;\n if (typeof inEvent.pointerType === 'number') {\n e = this.dispatcher.cloneEvent(inEvent, inEvent);\n e.pointerType = POINTER_TYPES[inEvent.pointerType];\n }\n\n return e;\n };\n\n /**\n * Remove this pointer from the list of active pointers.\n * @param {number} pointerId Pointer identifier.\n */\n MsSource.prototype.cleanup = function cleanup (pointerId) {\n delete this.pointerMap[pointerId.toString()];\n };\n\n return MsSource;\n}(EventSource));\n\nexport default MsSource;\n\n//# sourceMappingURL=MsSource.js.map","/**\n * @module ol/pointer/NativeSource\n */\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport EventSource from './EventSource.js';\n\n/**\n * Handler for `pointerdown`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerDown(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `pointermove`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerMove(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `pointerup`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerUp(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `pointerout`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerOut(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `pointerover`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerOver(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `pointercancel`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction pointerCancel(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `lostpointercapture`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction lostPointerCapture(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\n/**\n * Handler for `gotpointercapture`.\n *\n * @this {NativeSource}\n * @param {Event} inEvent The in event.\n */\nfunction gotPointerCapture(inEvent) {\n this.dispatcher.fireNativeEvent(inEvent);\n}\n\nvar NativeSource = /*@__PURE__*/(function (EventSource) {\n function NativeSource(dispatcher) {\n var mapping = {\n 'pointerdown': pointerDown,\n 'pointermove': pointerMove,\n 'pointerup': pointerUp,\n 'pointerout': pointerOut,\n 'pointerover': pointerOver,\n 'pointercancel': pointerCancel,\n 'gotpointercapture': gotPointerCapture,\n 'lostpointercapture': lostPointerCapture\n };\n EventSource.call(this, dispatcher, mapping);\n }\n\n if ( EventSource ) NativeSource.__proto__ = EventSource;\n NativeSource.prototype = Object.create( EventSource && EventSource.prototype );\n NativeSource.prototype.constructor = NativeSource;\n\n return NativeSource;\n}(EventSource));\n\nexport default NativeSource;\n\n//# sourceMappingURL=NativeSource.js.map","/**\n * @module ol/pointer/PointerEvent\n */\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport _Event from '../events/Event.js';\n\n\n/**\n * Is the `buttons` property supported?\n * @type {boolean}\n */\nvar HAS_BUTTONS = false;\n\n\nvar PointerEvent = /*@__PURE__*/(function (_Event) {\n function PointerEvent(type, originalEvent, opt_eventDict) {\n _Event.call(this, type);\n\n /**\n * @const\n * @type {Event}\n */\n this.originalEvent = originalEvent;\n\n var eventDict = opt_eventDict ? opt_eventDict : {};\n\n /**\n * @type {number}\n */\n this.buttons = getButtons(eventDict);\n\n /**\n * @type {number}\n */\n this.pressure = getPressure(eventDict, this.buttons);\n\n // MouseEvent related properties\n\n /**\n * @type {boolean}\n */\n this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;\n\n /**\n * @type {boolean}\n */\n this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;\n\n /**\n * @type {Object}\n */\n this.view = 'view' in eventDict ? eventDict['view'] : null;\n\n /**\n * @type {number}\n */\n this.detail = 'detail' in eventDict ? eventDict['detail'] : null;\n\n /**\n * @type {number}\n */\n this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;\n\n /**\n * @type {number}\n */\n this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;\n\n /**\n * @type {number}\n */\n this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;\n\n /**\n * @type {number}\n */\n this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;\n\n /**\n * @type {boolean}\n */\n this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;\n\n /**\n * @type {boolean}\n */\n this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;\n\n /**\n * @type {number}\n */\n this.button = 'button' in eventDict ? eventDict['button'] : 0;\n\n /**\n * @type {Node}\n */\n this.relatedTarget = 'relatedTarget' in eventDict ?\n eventDict['relatedTarget'] : null;\n\n // PointerEvent related properties\n\n /**\n * @const\n * @type {number}\n */\n this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;\n\n /**\n * @type {number}\n */\n this.width = 'width' in eventDict ? eventDict['width'] : 0;\n\n /**\n * @type {number}\n */\n this.height = 'height' in eventDict ? eventDict['height'] : 0;\n\n /**\n * @type {number}\n */\n this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;\n\n /**\n * @type {number}\n */\n this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;\n\n /**\n * @type {string}\n */\n this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';\n\n /**\n * @type {number}\n */\n this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;\n\n /**\n * @type {boolean}\n */\n this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;\n\n // keep the semantics of preventDefault\n if (originalEvent.preventDefault) {\n this.preventDefault = function() {\n originalEvent.preventDefault();\n };\n }\n }\n\n if ( _Event ) PointerEvent.__proto__ = _Event;\n PointerEvent.prototype = Object.create( _Event && _Event.prototype );\n PointerEvent.prototype.constructor = PointerEvent;\n\n return PointerEvent;\n}(_Event));\n\n\n/**\n * @param {Object} eventDict The event dictionary.\n * @return {number} Button indicator.\n */\nfunction getButtons(eventDict) {\n // According to the w3c spec,\n // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button\n // MouseEvent.button == 0 can mean either no mouse button depressed, or the\n // left mouse button depressed.\n //\n // As of now, the only way to distinguish between the two states of\n // MouseEvent.button is by using the deprecated MouseEvent.which property, as\n // this maps mouse buttons to positive integers > 0, and uses 0 to mean that\n // no mouse button is held.\n //\n // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,\n // but initMouseEvent does not expose an argument with which to set\n // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set\n // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations\n // of app developers.\n //\n // The only way to propagate the correct state of MouseEvent.which and\n // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0\n // is to call initMouseEvent with a buttonArg value of -1.\n //\n // This is fixed with DOM Level 4's use of buttons\n var buttons;\n if (eventDict.buttons || HAS_BUTTONS) {\n buttons = eventDict.buttons;\n } else {\n switch (eventDict.which) {\n case 1: buttons = 1; break;\n case 2: buttons = 4; break;\n case 3: buttons = 2; break;\n default: buttons = 0;\n }\n }\n return buttons;\n}\n\n\n/**\n * @param {Object} eventDict The event dictionary.\n * @param {number} buttons Button indicator.\n * @return {number} The pressure.\n */\nfunction getPressure(eventDict, buttons) {\n // Spec requires that pointers without pressure specified use 0.5 for down\n // state and 0 for up state.\n var pressure = 0;\n if (eventDict.pressure) {\n pressure = eventDict.pressure;\n } else {\n pressure = buttons ? 0.5 : 0;\n }\n return pressure;\n}\n\n\n/**\n * Checks if the `buttons` property is supported.\n */\n(function() {\n try {\n var ev = new MouseEvent('click', {buttons: 1});\n HAS_BUTTONS = ev.buttons === 1;\n } catch (e) {\n // pass\n }\n})();\n\nexport default PointerEvent;\n\n//# sourceMappingURL=PointerEvent.js.map","/**\n * @module ol/pointer/TouchSource\n */\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {remove} from '../array.js';\nimport EventSource from './EventSource.js';\nimport {POINTER_ID} from './MouseSource.js';\n\n\n/**\n * @type {number}\n */\nvar CLICK_COUNT_TIMEOUT = 200;\n\n/**\n * @type {string}\n */\nvar POINTER_TYPE = 'touch';\n\n/**\n * Handler for `touchstart`, triggers `pointerover`,\n * `pointerenter` and `pointerdown` events.\n *\n * @this {TouchSource}\n * @param {TouchEvent} inEvent The in event.\n */\nfunction touchstart(inEvent) {\n this.vacuumTouches_(inEvent);\n this.setPrimaryTouch_(inEvent.changedTouches[0]);\n this.dedupSynthMouse_(inEvent);\n this.clickCount_++;\n this.processTouches_(inEvent, this.overDown_);\n}\n\n/**\n * Handler for `touchmove`.\n *\n * @this {TouchSource}\n * @param {TouchEvent} inEvent The in event.\n */\nfunction touchmove(inEvent) {\n this.processTouches_(inEvent, this.moveOverOut_);\n}\n\n/**\n * Handler for `touchend`, triggers `pointerup`,\n * `pointerout` and `pointerleave` events.\n *\n * @this {TouchSource}\n * @param {TouchEvent} inEvent The event.\n */\nfunction touchend(inEvent) {\n this.dedupSynthMouse_(inEvent);\n this.processTouches_(inEvent, this.upOut_);\n}\n\n/**\n * Handler for `touchcancel`, triggers `pointercancel`,\n * `pointerout` and `pointerleave` events.\n *\n * @this {TouchSource}\n * @param {TouchEvent} inEvent The in event.\n */\nfunction touchcancel(inEvent) {\n this.processTouches_(inEvent, this.cancelOut_);\n}\n\n\nvar TouchSource = /*@__PURE__*/(function (EventSource) {\n function TouchSource(dispatcher, mouseSource) {\n var mapping = {\n 'touchstart': touchstart,\n 'touchmove': touchmove,\n 'touchend': touchend,\n 'touchcancel': touchcancel\n };\n EventSource.call(this, dispatcher, mapping);\n\n /**\n * @const\n * @type {!Object}\n */\n this.pointerMap = dispatcher.pointerMap;\n\n /**\n * @const\n * @type {import(\"./MouseSource.js\").default}\n */\n this.mouseSource = mouseSource;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.firstTouchId_ = undefined;\n\n /**\n * @private\n * @type {number}\n */\n this.clickCount_ = 0;\n\n /**\n * @private\n * @type {?}\n */\n this.resetId_;\n\n /**\n * Mouse event timeout: This should be long enough to\n * ignore compat mouse events made by touch.\n * @private\n * @type {number}\n */\n this.dedupTimeout_ = 2500;\n }\n\n if ( EventSource ) TouchSource.__proto__ = EventSource;\n TouchSource.prototype = Object.create( EventSource && EventSource.prototype );\n TouchSource.prototype.constructor = TouchSource;\n\n /**\n * @private\n * @param {Touch} inTouch The in touch.\n * @return {boolean} True, if this is the primary touch.\n */\n TouchSource.prototype.isPrimaryTouch_ = function isPrimaryTouch_ (inTouch) {\n return this.firstTouchId_ === inTouch.identifier;\n };\n\n /**\n * Set primary touch if there are no pointers, or the only pointer is the mouse.\n * @param {Touch} inTouch The in touch.\n * @private\n */\n TouchSource.prototype.setPrimaryTouch_ = function setPrimaryTouch_ (inTouch) {\n var count = Object.keys(this.pointerMap).length;\n if (count === 0 || (count === 1 && POINTER_ID.toString() in this.pointerMap)) {\n this.firstTouchId_ = inTouch.identifier;\n this.cancelResetClickCount_();\n }\n };\n\n /**\n * @private\n * @param {PointerEvent} inPointer The in pointer object.\n */\n TouchSource.prototype.removePrimaryPointer_ = function removePrimaryPointer_ (inPointer) {\n if (inPointer.isPrimary) {\n this.firstTouchId_ = undefined;\n this.resetClickCount_();\n }\n };\n\n /**\n * @private\n */\n TouchSource.prototype.resetClickCount_ = function resetClickCount_ () {\n this.resetId_ = setTimeout(\n this.resetClickCountHandler_.bind(this),\n CLICK_COUNT_TIMEOUT);\n };\n\n /**\n * @private\n */\n TouchSource.prototype.resetClickCountHandler_ = function resetClickCountHandler_ () {\n this.clickCount_ = 0;\n this.resetId_ = undefined;\n };\n\n /**\n * @private\n */\n TouchSource.prototype.cancelResetClickCount_ = function cancelResetClickCount_ () {\n if (this.resetId_ !== undefined) {\n clearTimeout(this.resetId_);\n }\n };\n\n /**\n * @private\n * @param {TouchEvent} browserEvent Browser event\n * @param {Touch} inTouch Touch event\n * @return {PointerEvent} A pointer object.\n */\n TouchSource.prototype.touchToPointer_ = function touchToPointer_ (browserEvent, inTouch) {\n var e = this.dispatcher.cloneEvent(browserEvent, inTouch);\n // Spec specifies that pointerId 1 is reserved for Mouse.\n // Touch identifiers can start at 0.\n // Add 2 to the touch identifier for compatibility.\n e.pointerId = inTouch.identifier + 2;\n // TODO: check if this is necessary?\n //e.target = findTarget(e);\n e.bubbles = true;\n e.cancelable = true;\n e.detail = this.clickCount_;\n e.button = 0;\n e.buttons = 1;\n e.width = inTouch.radiusX || 0;\n e.height = inTouch.radiusY || 0;\n e.pressure = inTouch.force || 0.5;\n e.isPrimary = this.isPrimaryTouch_(inTouch);\n e.pointerType = POINTER_TYPE;\n\n // make sure that the properties that are different for\n // each `Touch` object are not copied from the BrowserEvent object\n e.clientX = inTouch.clientX;\n e.clientY = inTouch.clientY;\n e.screenX = inTouch.screenX;\n e.screenY = inTouch.screenY;\n\n return e;\n };\n\n /**\n * @private\n * @param {TouchEvent} inEvent Touch event\n * @param {function(TouchEvent, PointerEvent)} inFunction In function.\n */\n TouchSource.prototype.processTouches_ = function processTouches_ (inEvent, inFunction) {\n var touches = Array.prototype.slice.call(inEvent.changedTouches);\n var count = touches.length;\n function preventDefault() {\n inEvent.preventDefault();\n }\n for (var i = 0; i < count; ++i) {\n var pointer = this.touchToPointer_(inEvent, touches[i]);\n // forward touch preventDefaults\n pointer.preventDefault = preventDefault;\n inFunction.call(this, inEvent, pointer);\n }\n };\n\n /**\n * @private\n * @param {TouchList} touchList The touch list.\n * @param {number} searchId Search identifier.\n * @return {boolean} True, if the `Touch` with the given id is in the list.\n */\n TouchSource.prototype.findTouch_ = function findTouch_ (touchList, searchId) {\n var l = touchList.length;\n for (var i = 0; i < l; i++) {\n var touch = touchList[i];\n if (touch.identifier === searchId) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * In some instances, a touchstart can happen without a touchend. This\n * leaves the pointermap in a broken state.\n * Therefore, on every touchstart, we remove the touches that did not fire a\n * touchend event.\n * To keep state globally consistent, we fire a pointercancel for\n * this \"abandoned\" touch\n *\n * @private\n * @param {TouchEvent} inEvent The in event.\n */\n TouchSource.prototype.vacuumTouches_ = function vacuumTouches_ (inEvent) {\n var touchList = inEvent.touches;\n // pointerMap.getCount() should be < touchList.length here,\n // as the touchstart has not been processed yet.\n var keys = Object.keys(this.pointerMap);\n var count = keys.length;\n if (count >= touchList.length) {\n var d = [];\n for (var i = 0; i < count; ++i) {\n var key = Number(keys[i]);\n var value = this.pointerMap[key];\n // Never remove pointerId == 1, which is mouse.\n // Touch identifiers are 2 smaller than their pointerId, which is the\n // index in pointermap.\n if (key != POINTER_ID && !this.findTouch_(touchList, key - 2)) {\n d.push(value.out);\n }\n }\n for (var i$1 = 0; i$1 < d.length; ++i$1) {\n this.cancelOut_(inEvent, d[i$1]);\n }\n }\n };\n\n /**\n * @private\n * @param {TouchEvent} browserEvent The event.\n * @param {PointerEvent} inPointer The in pointer object.\n */\n TouchSource.prototype.overDown_ = function overDown_ (browserEvent, inPointer) {\n this.pointerMap[inPointer.pointerId] = {\n target: inPointer.target,\n out: inPointer,\n outTarget: inPointer.target\n };\n this.dispatcher.over(inPointer, browserEvent);\n this.dispatcher.enter(inPointer, browserEvent);\n this.dispatcher.down(inPointer, browserEvent);\n };\n\n /**\n * @private\n * @param {TouchEvent} browserEvent The event.\n * @param {PointerEvent} inPointer The in pointer.\n */\n TouchSource.prototype.moveOverOut_ = function moveOverOut_ (browserEvent, inPointer) {\n var event = inPointer;\n var pointer = this.pointerMap[event.pointerId];\n // a finger drifted off the screen, ignore it\n if (!pointer) {\n return;\n }\n var outEvent = pointer.out;\n var outTarget = pointer.outTarget;\n this.dispatcher.move(event, browserEvent);\n if (outEvent && outTarget !== event.target) {\n outEvent.relatedTarget = event.target;\n /** @type {Object} */ (event).relatedTarget = outTarget;\n // recover from retargeting by shadow\n outEvent.target = outTarget;\n if (event.target) {\n this.dispatcher.leaveOut(outEvent, browserEvent);\n this.dispatcher.enterOver(event, browserEvent);\n } else {\n // clean up case when finger leaves the screen\n /** @type {Object} */ (event).target = outTarget;\n /** @type {Object} */ (event).relatedTarget = null;\n this.cancelOut_(browserEvent, event);\n }\n }\n pointer.out = event;\n pointer.outTarget = event.target;\n };\n\n /**\n * @private\n * @param {TouchEvent} browserEvent An event.\n * @param {PointerEvent} inPointer The inPointer object.\n */\n TouchSource.prototype.upOut_ = function upOut_ (browserEvent, inPointer) {\n this.dispatcher.up(inPointer, browserEvent);\n this.dispatcher.out(inPointer, browserEvent);\n this.dispatcher.leave(inPointer, browserEvent);\n this.cleanUpPointer_(inPointer);\n };\n\n /**\n * @private\n * @param {TouchEvent} browserEvent The event.\n * @param {PointerEvent} inPointer The in pointer.\n */\n TouchSource.prototype.cancelOut_ = function cancelOut_ (browserEvent, inPointer) {\n this.dispatcher.cancel(inPointer, browserEvent);\n this.dispatcher.out(inPointer, browserEvent);\n this.dispatcher.leave(inPointer, browserEvent);\n this.cleanUpPointer_(inPointer);\n };\n\n /**\n * @private\n * @param {PointerEvent} inPointer The inPointer object.\n */\n TouchSource.prototype.cleanUpPointer_ = function cleanUpPointer_ (inPointer) {\n delete this.pointerMap[inPointer.pointerId];\n this.removePrimaryPointer_(inPointer);\n };\n\n /**\n * Prevent synth mouse events from creating pointer events.\n *\n * @private\n * @param {TouchEvent} inEvent The in event.\n */\n TouchSource.prototype.dedupSynthMouse_ = function dedupSynthMouse_ (inEvent) {\n var lts = this.mouseSource.lastTouches;\n var t = inEvent.changedTouches[0];\n // only the primary finger will synth mouse events\n if (this.isPrimaryTouch_(t)) {\n // remember x/y of last touch\n var lt = [t.clientX, t.clientY];\n lts.push(lt);\n\n setTimeout(function() {\n // remove touch after timeout\n remove(lts, lt);\n }, this.dedupTimeout_);\n }\n };\n\n return TouchSource;\n}(EventSource));\n\nexport default TouchSource;\n\n//# sourceMappingURL=TouchSource.js.map","/**\n * @module ol/pointer/PointerEventHandler\n */\n\n// Based on https://github.com/Polymer/PointerEvents\n\n// Copyright (c) 2013 The Polymer Authors. All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are\n// met:\n//\n// * Redistributions of source code must retain the above copyright\n// notice, this list of conditions and the following disclaimer.\n// * Redistributions in binary form must reproduce the above\n// copyright notice, this list of conditions and the following disclaimer\n// in the documentation and/or other materials provided with the\n// distribution.\n// * Neither the name of Google Inc. nor the names of its\n// contributors may be used to endorse or promote products derived from\n// this software without specific prior written permission.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n// \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport {listen, unlisten} from '../events.js';\nimport EventTarget from '../events/Target.js';\nimport {POINTER, MSPOINTER, TOUCH} from '../has.js';\nimport PointerEventType from './EventType.js';\nimport MouseSource, {prepareEvent as prepareMouseEvent} from './MouseSource.js';\nimport MsSource from './MsSource.js';\nimport NativeSource from './NativeSource.js';\nimport PointerEvent from './PointerEvent.js';\nimport TouchSource from './TouchSource.js';\n\n\n/**\n * Properties to copy when cloning an event, with default values.\n * @type {Array}\n */\nvar CLONE_PROPS = [\n // MouseEvent\n ['bubbles', false],\n ['cancelable', false],\n ['view', null],\n ['detail', null],\n ['screenX', 0],\n ['screenY', 0],\n ['clientX', 0],\n ['clientY', 0],\n ['ctrlKey', false],\n ['altKey', false],\n ['shiftKey', false],\n ['metaKey', false],\n ['button', 0],\n ['relatedTarget', null],\n // DOM Level 3\n ['buttons', 0],\n // PointerEvent\n ['pointerId', 0],\n ['width', 0],\n ['height', 0],\n ['pressure', 0],\n ['tiltX', 0],\n ['tiltY', 0],\n ['pointerType', ''],\n ['hwTimestamp', 0],\n ['isPrimary', false],\n // event instance\n ['type', ''],\n ['target', null],\n ['currentTarget', null],\n ['which', 0]\n];\n\n\nvar PointerEventHandler = /*@__PURE__*/(function (EventTarget) {\n function PointerEventHandler(element) {\n EventTarget.call(this);\n\n /**\n * @const\n * @private\n * @type {Element|HTMLDocument}\n */\n this.element_ = element;\n\n /**\n * @const\n * @type {!Object}\n */\n this.pointerMap = {};\n\n /**\n * @type {Object}\n * @private\n */\n this.eventMap_ = {};\n\n /**\n * @type {Array}\n * @private\n */\n this.eventSourceList_ = [];\n\n this.registerSources();\n }\n\n if ( EventTarget ) PointerEventHandler.__proto__ = EventTarget;\n PointerEventHandler.prototype = Object.create( EventTarget && EventTarget.prototype );\n PointerEventHandler.prototype.constructor = PointerEventHandler;\n\n /**\n * Set up the event sources (mouse, touch and native pointers)\n * that generate pointer events.\n */\n PointerEventHandler.prototype.registerSources = function registerSources () {\n if (POINTER) {\n this.registerSource('native', new NativeSource(this));\n } else if (MSPOINTER) {\n this.registerSource('ms', new MsSource(this));\n } else {\n var mouseSource = new MouseSource(this);\n this.registerSource('mouse', mouseSource);\n\n if (TOUCH) {\n this.registerSource('touch', new TouchSource(this, mouseSource));\n }\n }\n\n // register events on the viewport element\n this.register_();\n };\n\n /**\n * Add a new event source that will generate pointer events.\n *\n * @param {string} name A name for the event source\n * @param {import(\"./EventSource.js\").default} source The source event.\n */\n PointerEventHandler.prototype.registerSource = function registerSource (name, source) {\n var s = source;\n var newEvents = s.getEvents();\n\n if (newEvents) {\n newEvents.forEach(function(e) {\n var handler = s.getHandlerForEvent(e);\n\n if (handler) {\n this.eventMap_[e] = handler.bind(s);\n }\n }.bind(this));\n this.eventSourceList_.push(s);\n }\n };\n\n /**\n * Set up the events for all registered event sources.\n * @private\n */\n PointerEventHandler.prototype.register_ = function register_ () {\n var l = this.eventSourceList_.length;\n for (var i = 0; i < l; i++) {\n var eventSource = this.eventSourceList_[i];\n this.addEvents_(eventSource.getEvents());\n }\n };\n\n /**\n * Remove all registered events.\n * @private\n */\n PointerEventHandler.prototype.unregister_ = function unregister_ () {\n var l = this.eventSourceList_.length;\n for (var i = 0; i < l; i++) {\n var eventSource = this.eventSourceList_[i];\n this.removeEvents_(eventSource.getEvents());\n }\n };\n\n /**\n * Calls the right handler for a new event.\n * @private\n * @param {Event} inEvent Browser event.\n */\n PointerEventHandler.prototype.eventHandler_ = function eventHandler_ (inEvent) {\n var type = inEvent.type;\n var handler = this.eventMap_[type];\n if (handler) {\n handler(inEvent);\n }\n };\n\n /**\n * Setup listeners for the given events.\n * @private\n * @param {Array} events List of events.\n */\n PointerEventHandler.prototype.addEvents_ = function addEvents_ (events) {\n events.forEach(function(eventName) {\n listen(this.element_, eventName, this.eventHandler_, this);\n }.bind(this));\n };\n\n /**\n * Unregister listeners for the given events.\n * @private\n * @param {Array} events List of events.\n */\n PointerEventHandler.prototype.removeEvents_ = function removeEvents_ (events) {\n events.forEach(function(e) {\n unlisten(this.element_, e, this.eventHandler_, this);\n }.bind(this));\n };\n\n /**\n * Returns a snapshot of inEvent, with writable properties.\n *\n * @param {Event} event Browser event.\n * @param {Event|Touch} inEvent An event that contains\n * properties to copy.\n * @return {Object} An object containing shallow copies of\n * `inEvent`'s properties.\n */\n PointerEventHandler.prototype.cloneEvent = function cloneEvent (event, inEvent) {\n var eventCopy = {};\n for (var i = 0, ii = CLONE_PROPS.length; i < ii; i++) {\n var p = CLONE_PROPS[i][0];\n eventCopy[p] = event[p] || inEvent[p] || CLONE_PROPS[i][1];\n }\n\n return eventCopy;\n };\n\n // EVENTS\n\n\n /**\n * Triggers a 'pointerdown' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.down = function down (data, event) {\n this.fireEvent(PointerEventType.POINTERDOWN, data, event);\n };\n\n /**\n * Triggers a 'pointermove' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.move = function move (data, event) {\n this.fireEvent(PointerEventType.POINTERMOVE, data, event);\n };\n\n /**\n * Triggers a 'pointerup' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.up = function up (data, event) {\n this.fireEvent(PointerEventType.POINTERUP, data, event);\n };\n\n /**\n * Triggers a 'pointerenter' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.enter = function enter (data, event) {\n data.bubbles = false;\n this.fireEvent(PointerEventType.POINTERENTER, data, event);\n };\n\n /**\n * Triggers a 'pointerleave' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.leave = function leave (data, event) {\n data.bubbles = false;\n this.fireEvent(PointerEventType.POINTERLEAVE, data, event);\n };\n\n /**\n * Triggers a 'pointerover' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.over = function over (data, event) {\n data.bubbles = true;\n this.fireEvent(PointerEventType.POINTEROVER, data, event);\n };\n\n /**\n * Triggers a 'pointerout' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.out = function out (data, event) {\n data.bubbles = true;\n this.fireEvent(PointerEventType.POINTEROUT, data, event);\n };\n\n /**\n * Triggers a 'pointercancel' event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.cancel = function cancel (data, event) {\n this.fireEvent(PointerEventType.POINTERCANCEL, data, event);\n };\n\n /**\n * Triggers a combination of 'pointerout' and 'pointerleave' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.leaveOut = function leaveOut (data, event) {\n this.out(data, event);\n if (!this.contains_(data.target, data.relatedTarget)) {\n this.leave(data, event);\n }\n };\n\n /**\n * Triggers a combination of 'pointerover' and 'pointerevents' events.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.enterOver = function enterOver (data, event) {\n this.over(data, event);\n if (!this.contains_(data.target, data.relatedTarget)) {\n this.enter(data, event);\n }\n };\n\n /**\n * @private\n * @param {Element} container The container element.\n * @param {Element} contained The contained element.\n * @return {boolean} Returns true if the container element\n * contains the other element.\n */\n PointerEventHandler.prototype.contains_ = function contains_ (container, contained) {\n if (!container || !contained) {\n return false;\n }\n return container.contains(contained);\n };\n\n // EVENT CREATION AND TRACKING\n /**\n * Creates a new Event of type `inType`, based on the information in\n * `data`.\n *\n * @param {string} inType A string representing the type of event to create.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n * @return {PointerEvent} A PointerEvent of type `inType`.\n */\n PointerEventHandler.prototype.makeEvent = function makeEvent (inType, data, event) {\n return new PointerEvent(inType, event, data);\n };\n\n /**\n * Make and dispatch an event in one call.\n * @param {string} inType A string representing the type of event.\n * @param {Object} data Pointer event data.\n * @param {Event} event The event.\n */\n PointerEventHandler.prototype.fireEvent = function fireEvent (inType, data, event) {\n var e = this.makeEvent(inType, data, event);\n this.dispatchEvent(e);\n };\n\n /**\n * Creates a pointer event from a native pointer event\n * and dispatches this event.\n * @param {Event} event A platform event with a target.\n */\n PointerEventHandler.prototype.fireNativeEvent = function fireNativeEvent (event) {\n var e = this.makeEvent(event.type, event, event);\n this.dispatchEvent(e);\n };\n\n /**\n * Wrap a native mouse event into a pointer event.\n * This proxy method is required for the legacy IE support.\n * @param {string} eventType The pointer event type.\n * @param {Event} event The event.\n * @return {PointerEvent} The wrapped event.\n */\n PointerEventHandler.prototype.wrapMouseEvent = function wrapMouseEvent (eventType, event) {\n var pointerEvent = this.makeEvent(\n eventType, prepareMouseEvent(event, this), event);\n return pointerEvent;\n };\n\n /**\n * @inheritDoc\n */\n PointerEventHandler.prototype.disposeInternal = function disposeInternal () {\n this.unregister_();\n EventTarget.prototype.disposeInternal.call(this);\n };\n\n return PointerEventHandler;\n}(EventTarget));\n\nexport default PointerEventHandler;\n\n//# sourceMappingURL=PointerEventHandler.js.map","/**\n * @module ol/geom/flat/area\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRing(flatCoordinates, offset, end, stride) {\n var twiceArea = 0;\n var x1 = flatCoordinates[end - stride];\n var y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n var x2 = flatCoordinates[offset];\n var y2 = flatCoordinates[offset + 1];\n twiceArea += y1 * x2 - x1 * y2;\n x1 = x2;\n y1 = y2;\n }\n return twiceArea / 2;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRings(flatCoordinates, offset, ends, stride) {\n var area = 0;\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n area += linearRing(flatCoordinates, offset, end, stride);\n offset = end;\n }\n return area;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRingss(flatCoordinates, offset, endss, stride) {\n var area = 0;\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n area += linearRings(flatCoordinates, offset, ends, stride);\n offset = ends[ends.length - 1];\n }\n return area;\n}\n\n//# sourceMappingURL=area.js.map","/**\n * @module ol/geom/LinearRing\n */\nimport {closestSquaredDistanceXY} from '../extent.js';\nimport GeometryLayout from './GeometryLayout.js';\nimport GeometryType from './GeometryType.js';\nimport SimpleGeometry from './SimpleGeometry.js';\nimport {linearRing as linearRingArea} from './flat/area.js';\nimport {assignClosestPoint, maxSquaredDelta} from './flat/closest.js';\nimport {deflateCoordinates} from './flat/deflate.js';\nimport {inflateCoordinates} from './flat/inflate.js';\nimport {douglasPeucker} from './flat/simplify.js';\n\n/**\n * @classdesc\n * Linear ring geometry. Only used as part of polygon; cannot be rendered\n * on its own.\n *\n * @api\n */\nvar LinearRing = /*@__PURE__*/(function (SimpleGeometry) {\n function LinearRing(coordinates, opt_layout) {\n\n SimpleGeometry.call(this);\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n if (opt_layout !== undefined && !Array.isArray(coordinates[0])) {\n this.setFlatCoordinates(opt_layout, /** @type {Array} */ (coordinates));\n } else {\n this.setCoordinates(/** @type {Array} */ (coordinates), opt_layout);\n }\n\n }\n\n if ( SimpleGeometry ) LinearRing.__proto__ = SimpleGeometry;\n LinearRing.prototype = Object.create( SimpleGeometry && SimpleGeometry.prototype );\n LinearRing.prototype.constructor = LinearRing;\n\n /**\n * Make a complete copy of the geometry.\n * @return {!LinearRing} Clone.\n * @override\n * @api\n */\n LinearRing.prototype.clone = function clone () {\n return new LinearRing(this.flatCoordinates.slice(), this.layout);\n };\n\n /**\n * @inheritDoc\n */\n LinearRing.prototype.closestPointXY = function closestPointXY (x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(maxSquaredDelta(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestPoint(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n };\n\n /**\n * Return the area of the linear ring on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\n LinearRing.prototype.getArea = function getArea () {\n return linearRingArea(this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n };\n\n /**\n * Return the coordinates of the linear ring.\n * @return {Array} Coordinates.\n * @override\n * @api\n */\n LinearRing.prototype.getCoordinates = function getCoordinates () {\n return inflateCoordinates(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);\n };\n\n /**\n * @inheritDoc\n */\n LinearRing.prototype.getSimplifiedGeometryInternal = function getSimplifiedGeometryInternal (squaredTolerance) {\n var simplifiedFlatCoordinates = [];\n simplifiedFlatCoordinates.length = douglasPeucker(\n this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,\n squaredTolerance, simplifiedFlatCoordinates, 0);\n return new LinearRing(simplifiedFlatCoordinates, GeometryLayout.XY);\n };\n\n /**\n * @inheritDoc\n * @api\n */\n LinearRing.prototype.getType = function getType () {\n return GeometryType.LINEAR_RING;\n };\n\n /**\n * @inheritDoc\n */\n LinearRing.prototype.intersectsExtent = function intersectsExtent (extent) {\n return false;\n };\n\n /**\n * Set the coordinates of the linear ring.\n * @param {!Array} coordinates Coordinates.\n * @param {GeometryLayout=} opt_layout Layout.\n * @override\n * @api\n */\n LinearRing.prototype.setCoordinates = function setCoordinates (coordinates, opt_layout) {\n this.setLayout(opt_layout, coordinates, 1);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinates(\n this.flatCoordinates, 0, coordinates, this.stride);\n this.changed();\n };\n\n return LinearRing;\n}(SimpleGeometry));\n\n\nexport default LinearRing;\n\n//# sourceMappingURL=LinearRing.js.map","/**\n * @module ol/geom/flat/interiorpoint\n */\nimport {numberSafeCompareFunction} from '../../array.js';\nimport {linearRingsContainsXY} from './contains.js';\n\n\n/**\n * Calculates a point that is likely to lie in the interior of the linear rings.\n * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {Array} flatCenters Flat centers.\n * @param {number} flatCentersOffset Flat center offset.\n * @param {Array=} opt_dest Destination.\n * @return {Array} Destination point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointOfArray(flatCoordinates, offset,\n ends, stride, flatCenters, flatCentersOffset, opt_dest) {\n var i, ii, x, x1, x2, y1, y2;\n var y = flatCenters[flatCentersOffset + 1];\n /** @type {Array} */\n var intersections = [];\n // Calculate intersections with the horizontal line\n for (var r = 0, rr = ends.length; r < rr; ++r) {\n var end = ends[r];\n x1 = flatCoordinates[end - stride];\n y1 = flatCoordinates[end - stride + 1];\n for (i = offset; i < end; i += stride) {\n x2 = flatCoordinates[i];\n y2 = flatCoordinates[i + 1];\n if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {\n x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;\n intersections.push(x);\n }\n x1 = x2;\n y1 = y2;\n }\n }\n // Find the longest segment of the horizontal line that has its center point\n // inside the linear ring.\n var pointX = NaN;\n var maxSegmentLength = -Infinity;\n intersections.sort(numberSafeCompareFunction);\n x1 = intersections[0];\n for (i = 1, ii = intersections.length; i < ii; ++i) {\n x2 = intersections[i];\n var segmentLength = Math.abs(x2 - x1);\n if (segmentLength > maxSegmentLength) {\n x = (x1 + x2) / 2;\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n pointX = x;\n maxSegmentLength = segmentLength;\n }\n }\n x1 = x2;\n }\n if (isNaN(pointX)) {\n // There is no horizontal line that has its center point inside the linear\n // ring. Use the center of the the linear ring's extent.\n pointX = flatCenters[flatCentersOffset];\n }\n if (opt_dest) {\n opt_dest.push(pointX, y, maxSegmentLength);\n return opt_dest;\n } else {\n return [pointX, y, maxSegmentLength];\n }\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array} flatCenters Flat centers.\n * @return {Array} Interior points as XYM coordinates, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointsOfMultiArray(flatCoordinates, offset, endss, stride, flatCenters) {\n var interiorPoints = [];\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n interiorPoints = getInteriorPointOfArray(flatCoordinates,\n offset, ends, stride, flatCenters, 2 * i, interiorPoints);\n offset = ends[ends.length - 1];\n }\n return interiorPoints;\n}\n\n//# sourceMappingURL=interiorpoint.js.map","/**\n * @module ol/geom/flat/reverse\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nexport function coordinates(flatCoordinates, offset, end, stride) {\n while (offset < end - stride) {\n for (var i = 0; i < stride; ++i) {\n var tmp = flatCoordinates[offset + i];\n flatCoordinates[offset + i] = flatCoordinates[end - stride + i];\n flatCoordinates[end - stride + i] = tmp;\n }\n offset += stride;\n end -= stride;\n }\n}\n\n//# sourceMappingURL=reverse.js.map","/**\n * @module ol/geom/flat/orient\n */\nimport {coordinates as reverseCoordinates} from './reverse.js';\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean} Is clockwise.\n */\nexport function linearRingIsClockwise(flatCoordinates, offset, end, stride) {\n // http://tinyurl.com/clockwise-method\n // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp\n var edge = 0;\n var x1 = flatCoordinates[end - stride];\n var y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n var x2 = flatCoordinates[offset];\n var y2 = flatCoordinates[offset + 1];\n edge += (x2 - x1) * (y2 + y1);\n x1 = x2;\n y1 = y2;\n }\n return edge > 0;\n}\n\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingIsOriented(flatCoordinates, offset, ends, stride, opt_right) {\n var right = opt_right !== undefined ? opt_right : false;\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n var isClockwise = linearRingIsClockwise(\n flatCoordinates, offset, end, stride);\n if (i === 0) {\n if ((right && isClockwise) || (!right && !isClockwise)) {\n return false;\n }\n } else {\n if ((right && !isClockwise) || (!right && isClockwise)) {\n return false;\n }\n }\n offset = end;\n }\n return true;\n}\n\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `opt_right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingsAreOriented(flatCoordinates, offset, endss, stride, opt_right) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n if (!linearRingIsOriented(\n flatCoordinates, offset, endss[i], stride, opt_right)) {\n return false;\n }\n }\n return true;\n}\n\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRings(flatCoordinates, offset, ends, stride, opt_right) {\n var right = opt_right !== undefined ? opt_right : false;\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n var isClockwise = linearRingIsClockwise(\n flatCoordinates, offset, end, stride);\n var reverse = i === 0 ?\n (right && isClockwise) || (!right && !isClockwise) :\n (right && !isClockwise) || (!right && isClockwise);\n if (reverse) {\n reverseCoordinates(flatCoordinates, offset, end, stride);\n }\n offset = end;\n }\n return offset;\n}\n\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `opt_right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean=} opt_right Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRingsArray(flatCoordinates, offset, endss, stride, opt_right) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n offset = orientLinearRings(\n flatCoordinates, offset, endss[i], stride, opt_right);\n }\n return offset;\n}\n\n//# sourceMappingURL=orient.js.map","/**\n * @module ol/geom/Polygon\n */\nimport {extend} from '../array.js';\nimport {closestSquaredDistanceXY, getCenter} from '../extent.js';\nimport GeometryLayout from './GeometryLayout.js';\nimport GeometryType from './GeometryType.js';\nimport LinearRing from './LinearRing.js';\nimport Point from './Point.js';\nimport SimpleGeometry from './SimpleGeometry.js';\nimport {offset as sphereOffset} from '../sphere.js';\nimport {linearRings as linearRingsArea} from './flat/area.js';\nimport {assignClosestArrayPoint, arrayMaxSquaredDelta} from './flat/closest.js';\nimport {linearRingsContainsXY} from './flat/contains.js';\nimport {deflateCoordinatesArray} from './flat/deflate.js';\nimport {inflateCoordinatesArray} from './flat/inflate.js';\nimport {getInteriorPointOfArray} from './flat/interiorpoint.js';\nimport {intersectsLinearRingArray} from './flat/intersectsextent.js';\nimport {linearRingIsOriented, orientLinearRings} from './flat/orient.js';\nimport {quantizeArray} from './flat/simplify.js';\nimport {modulo} from '../math.js';\n\n/**\n * @classdesc\n * Polygon geometry.\n *\n * @api\n */\nvar Polygon = /*@__PURE__*/(function (SimpleGeometry) {\n function Polygon(coordinates, opt_layout, opt_ends) {\n\n SimpleGeometry.call(this);\n\n /**\n * @type {Array}\n * @private\n */\n this.ends_ = [];\n\n /**\n * @private\n * @type {number}\n */\n this.flatInteriorPointRevision_ = -1;\n\n /**\n * @private\n * @type {import(\"../coordinate.js\").Coordinate}\n */\n this.flatInteriorPoint_ = null;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.orientedRevision_ = -1;\n\n /**\n * @private\n * @type {Array}\n */\n this.orientedFlatCoordinates_ = null;\n\n if (opt_layout !== undefined && opt_ends) {\n this.setFlatCoordinates(opt_layout, /** @type {Array} */ (coordinates));\n this.ends_ = opt_ends;\n } else {\n this.setCoordinates(/** @type {Array>} */ (coordinates), opt_layout);\n }\n\n }\n\n if ( SimpleGeometry ) Polygon.__proto__ = SimpleGeometry;\n Polygon.prototype = Object.create( SimpleGeometry && SimpleGeometry.prototype );\n Polygon.prototype.constructor = Polygon;\n\n /**\n * Append the passed linear ring to this polygon.\n * @param {LinearRing} linearRing Linear ring.\n * @api\n */\n Polygon.prototype.appendLinearRing = function appendLinearRing (linearRing) {\n if (!this.flatCoordinates) {\n this.flatCoordinates = linearRing.getFlatCoordinates().slice();\n } else {\n extend(this.flatCoordinates, linearRing.getFlatCoordinates());\n }\n this.ends_.push(this.flatCoordinates.length);\n this.changed();\n };\n\n /**\n * Make a complete copy of the geometry.\n * @return {!Polygon} Clone.\n * @override\n * @api\n */\n Polygon.prototype.clone = function clone () {\n return new Polygon(this.flatCoordinates.slice(), this.layout, this.ends_.slice());\n };\n\n /**\n * @inheritDoc\n */\n Polygon.prototype.closestPointXY = function closestPointXY (x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(arrayMaxSquaredDelta(\n this.flatCoordinates, 0, this.ends_, this.stride, 0));\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestArrayPoint(\n this.flatCoordinates, 0, this.ends_, this.stride,\n this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);\n };\n\n /**\n * @inheritDoc\n */\n Polygon.prototype.containsXY = function containsXY (x, y) {\n return linearRingsContainsXY(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);\n };\n\n /**\n * Return the area of the polygon on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\n Polygon.prototype.getArea = function getArea () {\n return linearRingsArea(this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);\n };\n\n /**\n * Get the coordinate array for this geometry. This array has the structure\n * of a GeoJSON coordinate array for polygons.\n *\n * @param {boolean=} opt_right Orient coordinates according to the right-hand\n * rule (counter-clockwise for exterior and clockwise for interior rings).\n * If `false`, coordinates will be oriented according to the left-hand rule\n * (clockwise for exterior and counter-clockwise for interior rings).\n * By default, coordinate orientation will depend on how the geometry was\n * constructed.\n * @return {Array>} Coordinates.\n * @override\n * @api\n */\n Polygon.prototype.getCoordinates = function getCoordinates (opt_right) {\n var flatCoordinates;\n if (opt_right !== undefined) {\n flatCoordinates = this.getOrientedFlatCoordinates().slice();\n orientLinearRings(\n flatCoordinates, 0, this.ends_, this.stride, opt_right);\n } else {\n flatCoordinates = this.flatCoordinates;\n }\n\n return inflateCoordinatesArray(\n flatCoordinates, 0, this.ends_, this.stride);\n };\n\n /**\n * @return {Array} Ends.\n */\n Polygon.prototype.getEnds = function getEnds () {\n return this.ends_;\n };\n\n /**\n * @return {Array} Interior point.\n */\n Polygon.prototype.getFlatInteriorPoint = function getFlatInteriorPoint () {\n if (this.flatInteriorPointRevision_ != this.getRevision()) {\n var flatCenter = getCenter(this.getExtent());\n this.flatInteriorPoint_ = getInteriorPointOfArray(\n this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,\n flatCenter, 0);\n this.flatInteriorPointRevision_ = this.getRevision();\n }\n return this.flatInteriorPoint_;\n };\n\n /**\n * Return an interior point of the polygon.\n * @return {Point} Interior point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n * @api\n */\n Polygon.prototype.getInteriorPoint = function getInteriorPoint () {\n return new Point(this.getFlatInteriorPoint(), GeometryLayout.XYM);\n };\n\n /**\n * Return the number of rings of the polygon, this includes the exterior\n * ring and any interior rings.\n *\n * @return {number} Number of rings.\n * @api\n */\n Polygon.prototype.getLinearRingCount = function getLinearRingCount () {\n return this.ends_.length;\n };\n\n /**\n * Return the Nth linear ring of the polygon geometry. Return `null` if the\n * given index is out of range.\n * The exterior linear ring is available at index `0` and the interior rings\n * at index `1` and beyond.\n *\n * @param {number} index Index.\n * @return {LinearRing} Linear ring.\n * @api\n */\n Polygon.prototype.getLinearRing = function getLinearRing (index) {\n if (index < 0 || this.ends_.length <= index) {\n return null;\n }\n return new LinearRing(this.flatCoordinates.slice(\n index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]), this.layout);\n };\n\n /**\n * Return the linear rings of the polygon.\n * @return {Array} Linear rings.\n * @api\n */\n Polygon.prototype.getLinearRings = function getLinearRings () {\n var layout = this.layout;\n var flatCoordinates = this.flatCoordinates;\n var ends = this.ends_;\n var linearRings = [];\n var offset = 0;\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n var end = ends[i];\n var linearRing = new LinearRing(flatCoordinates.slice(offset, end), layout);\n linearRings.push(linearRing);\n offset = end;\n }\n return linearRings;\n };\n\n /**\n * @return {Array} Oriented flat coordinates.\n */\n Polygon.prototype.getOrientedFlatCoordinates = function getOrientedFlatCoordinates () {\n if (this.orientedRevision_ != this.getRevision()) {\n var flatCoordinates = this.flatCoordinates;\n if (linearRingIsOriented(\n flatCoordinates, 0, this.ends_, this.stride)) {\n this.orientedFlatCoordinates_ = flatCoordinates;\n } else {\n this.orientedFlatCoordinates_ = flatCoordinates.slice();\n this.orientedFlatCoordinates_.length =\n orientLinearRings(\n this.orientedFlatCoordinates_, 0, this.ends_, this.stride);\n }\n this.orientedRevision_ = this.getRevision();\n }\n return this.orientedFlatCoordinates_;\n };\n\n /**\n * @inheritDoc\n */\n Polygon.prototype.getSimplifiedGeometryInternal = function getSimplifiedGeometryInternal (squaredTolerance) {\n var simplifiedFlatCoordinates = [];\n var simplifiedEnds = [];\n simplifiedFlatCoordinates.length = quantizeArray(\n this.flatCoordinates, 0, this.ends_, this.stride,\n Math.sqrt(squaredTolerance),\n simplifiedFlatCoordinates, 0, simplifiedEnds);\n return new Polygon(simplifiedFlatCoordinates, GeometryLayout.XY, simplifiedEnds);\n };\n\n /**\n * @inheritDoc\n * @api\n */\n Polygon.prototype.getType = function getType () {\n return GeometryType.POLYGON;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n Polygon.prototype.intersectsExtent = function intersectsExtent (extent) {\n return intersectsLinearRingArray(\n this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);\n };\n\n /**\n * Set the coordinates of the polygon.\n * @param {!Array>} coordinates Coordinates.\n * @param {GeometryLayout=} opt_layout Layout.\n * @override\n * @api\n */\n Polygon.prototype.setCoordinates = function setCoordinates (coordinates, opt_layout) {\n this.setLayout(opt_layout, coordinates, 2);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n var ends = deflateCoordinatesArray(\n this.flatCoordinates, 0, coordinates, this.stride, this.ends_);\n this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];\n this.changed();\n };\n\n return Polygon;\n}(SimpleGeometry));\n\n\nexport default Polygon;\n\n\n/**\n * Create an approximation of a circle on the surface of a sphere.\n * @param {import(\"../coordinate.js\").Coordinate} center Center (`[lon, lat]` in degrees).\n * @param {number} radius The great-circle distance from the center to\n * the polygon vertices.\n * @param {number=} opt_n Optional number of vertices for the resulting\n * polygon. Default is `32`.\n * @param {number=} opt_sphereRadius Optional radius for the sphere (defaults to\n * the Earth's mean radius using the WGS84 ellipsoid).\n * @return {Polygon} The \"circular\" polygon.\n * @api\n */\nexport function circular(center, radius, opt_n, opt_sphereRadius) {\n var n = opt_n ? opt_n : 32;\n /** @type {Array} */\n var flatCoordinates = [];\n for (var i = 0; i < n; ++i) {\n extend(flatCoordinates, sphereOffset(center, radius, 2 * Math.PI * i / n, opt_sphereRadius));\n }\n flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);\n return new Polygon(flatCoordinates, GeometryLayout.XY, [flatCoordinates.length]);\n}\n\n\n/**\n * Create a polygon from an extent. The layout used is `XY`.\n * @param {import(\"../extent.js\").Extent} extent The extent.\n * @return {Polygon} The polygon.\n * @api\n */\nexport function fromExtent(extent) {\n var minX = extent[0];\n var minY = extent[1];\n var maxX = extent[2];\n var maxY = extent[3];\n var flatCoordinates =\n [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];\n return new Polygon(flatCoordinates, GeometryLayout.XY, [flatCoordinates.length]);\n}\n\n\n/**\n * Create a regular polygon from a circle.\n * @param {import(\"./Circle.js\").default} circle Circle geometry.\n * @param {number=} opt_sides Number of sides of the polygon. Default is 32.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n * radians. Default is 0.\n * @return {Polygon} Polygon geometry.\n * @api\n */\nexport function fromCircle(circle, opt_sides, opt_angle) {\n var sides = opt_sides ? opt_sides : 32;\n var stride = circle.getStride();\n var layout = circle.getLayout();\n var center = circle.getCenter();\n var arrayLength = stride * (sides + 1);\n var flatCoordinates = new Array(arrayLength);\n for (var i = 0; i < arrayLength; i += stride) {\n flatCoordinates[i] = 0;\n flatCoordinates[i + 1] = 0;\n for (var j = 2; j < stride; j++) {\n flatCoordinates[i + j] = center[j];\n }\n }\n var ends = [flatCoordinates.length];\n var polygon = new Polygon(flatCoordinates, layout, ends);\n makeRegular(polygon, center, circle.getRadius(), opt_angle);\n return polygon;\n}\n\n\n/**\n * Modify the coordinates of a polygon to make it a regular polygon.\n * @param {Polygon} polygon Polygon geometry.\n * @param {import(\"../coordinate.js\").Coordinate} center Center of the regular polygon.\n * @param {number} radius Radius of the regular polygon.\n * @param {number=} opt_angle Start angle for the first vertex of the polygon in\n * radians. Default is 0.\n */\nexport function makeRegular(polygon, center, radius, opt_angle) {\n var flatCoordinates = polygon.getFlatCoordinates();\n var stride = polygon.getStride();\n var sides = flatCoordinates.length / stride - 1;\n var startAngle = opt_angle ? opt_angle : 0;\n for (var i = 0; i <= sides; ++i) {\n var offset = i * stride;\n var angle = startAngle + (modulo(i, sides) * 2 * Math.PI / sides);\n flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));\n flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));\n }\n polygon.changed();\n}\n\n//# sourceMappingURL=Polygon.js.map","/**\n * @module ol/control/util\n */\nimport Collection from '../Collection.js';\nimport Attribution from './Attribution.js';\nimport Rotate from './Rotate.js';\nimport Zoom from './Zoom.js';\n\n\n/**\n * @typedef {Object} DefaultsOptions\n * @property {boolean} [attribution=true] Include\n * {@link module:ol/control/Attribution~Attribution}.\n * @property {import(\"./Attribution.js\").Options} [attributionOptions]\n * Options for {@link module:ol/control/Attribution~Attribution}.\n * @property {boolean} [rotate=true] Include\n * {@link module:ol/control/Rotate~Rotate}.\n * @property {import(\"./Rotate.js\").Options} [rotateOptions] Options\n * for {@link module:ol/control/Rotate~Rotate}.\n * @property {boolean} [zoom] Include {@link module:ol/control/Zoom~Zoom}.\n * @property {import(\"./Zoom.js\").Options} [zoomOptions] Options for\n * {@link module:ol/control/Zoom~Zoom}.\n * @api\n */\n\n\n/**\n * Set of controls included in maps by default. Unless configured otherwise,\n * this returns a collection containing an instance of each of the following\n * controls:\n * * {@link module:ol/control/Zoom~Zoom}\n * * {@link module:ol/control/Rotate~Rotate}\n * * {@link module:ol/control/Attribution~Attribution}\n *\n * @param {DefaultsOptions=} opt_options\n * Defaults options.\n * @return {Collection}\n * Controls.\n * @function module:ol/control.defaults\n * @api\n */\nexport function defaults(opt_options) {\n\n var options = opt_options ? opt_options : {};\n\n var controls = new Collection();\n\n var zoomControl = options.zoom !== undefined ? options.zoom : true;\n if (zoomControl) {\n controls.push(new Zoom(options.zoomOptions));\n }\n\n var rotateControl = options.rotate !== undefined ? options.rotate : true;\n if (rotateControl) {\n controls.push(new Rotate(options.rotateOptions));\n }\n\n var attributionControl = options.attribution !== undefined ?\n options.attribution : true;\n if (attributionControl) {\n controls.push(new Attribution(options.attributionOptions));\n }\n\n return controls;\n}\n\n//# sourceMappingURL=util.js.map","/**\n * @module ol/control/Zoom\n */\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport Control from './Control.js';\nimport {CLASS_CONTROL, CLASS_UNSELECTABLE} from '../css.js';\nimport {easeOut} from '../easing.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [duration=250] Animation duration in milliseconds.\n * @property {string} [className='ol-zoom'] CSS class name.\n * @property {string|HTMLElement} [zoomInLabel='+'] Text label to use for the zoom-in\n * button. Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string|HTMLElement} [zoomOutLabel='-'] Text label to use for the zoom-out button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string} [zoomInTipLabel='Zoom in'] Text label to use for the button tip.\n * @property {string} [zoomOutTipLabel='Zoom out'] Text label to use for the button tip.\n * @property {number} [delta=1] The zoom delta applied on each click.\n * @property {HTMLElement|string} [target] Specify a target if you want the control to be\n * rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A control with 2 buttons, one for zoom in and one for zoom out.\n * This control is one of the default controls of a map. To style this control\n * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.\n *\n * @api\n */\nvar Zoom = /*@__PURE__*/(function (Control) {\n function Zoom(opt_options) {\n\n var options = opt_options ? opt_options : {};\n\n Control.call(this, {\n element: document.createElement('div'),\n target: options.target\n });\n\n var className = options.className !== undefined ? options.className : 'ol-zoom';\n\n var delta = options.delta !== undefined ? options.delta : 1;\n\n var zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';\n var zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\\u2212';\n\n var zoomInTipLabel = options.zoomInTipLabel !== undefined ?\n options.zoomInTipLabel : 'Zoom in';\n var zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?\n options.zoomOutTipLabel : 'Zoom out';\n\n var inElement = document.createElement('button');\n inElement.className = className + '-in';\n inElement.setAttribute('type', 'button');\n inElement.title = zoomInTipLabel;\n inElement.appendChild(\n typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel\n );\n\n listen(inElement, EventType.CLICK, this.handleClick_.bind(this, delta));\n\n var outElement = document.createElement('button');\n outElement.className = className + '-out';\n outElement.setAttribute('type', 'button');\n outElement.title = zoomOutTipLabel;\n outElement.appendChild(\n typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel\n );\n\n listen(outElement, EventType.CLICK, this.handleClick_.bind(this, -delta));\n\n var cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;\n var element = this.element;\n element.className = cssClasses;\n element.appendChild(inElement);\n element.appendChild(outElement);\n\n /**\n * @type {number}\n * @private\n */\n this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n }\n\n if ( Control ) Zoom.__proto__ = Control;\n Zoom.prototype = Object.create( Control && Control.prototype );\n Zoom.prototype.constructor = Zoom;\n\n /**\n * @param {number} delta Zoom delta.\n * @param {MouseEvent} event The event to handle\n * @private\n */\n Zoom.prototype.handleClick_ = function handleClick_ (delta, event) {\n event.preventDefault();\n this.zoomByDelta_(delta);\n };\n\n /**\n * @param {number} delta Zoom delta.\n * @private\n */\n Zoom.prototype.zoomByDelta_ = function zoomByDelta_ (delta) {\n var map = this.getMap();\n var view = map.getView();\n if (!view) {\n // the map does not have a view, so we can't act\n // upon it\n return;\n }\n var currentResolution = view.getResolution();\n if (currentResolution) {\n var newResolution = view.constrainResolution(currentResolution, delta);\n if (this.duration_ > 0) {\n if (view.getAnimating()) {\n view.cancelAnimations();\n }\n view.animate({\n resolution: newResolution,\n duration: this.duration_,\n easing: easeOut\n });\n } else {\n view.setResolution(newResolution);\n }\n }\n };\n\n return Zoom;\n}(Control));\n\n\nexport default Zoom;\n\n//# sourceMappingURL=Zoom.js.map","/**\n * @module ol/control/Rotate\n */\nimport Control from './Control.js';\nimport {CLASS_CONTROL, CLASS_HIDDEN, CLASS_UNSELECTABLE} from '../css.js';\nimport {easeOut} from '../easing.js';\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} [className='ol-rotate'] CSS class name.\n * @property {string|HTMLElement} [label='⇧'] Text label to use for the rotate button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string} [tipLabel='Reset rotation'] Text label to use for the rotate tip.\n * @property {number} [duration=250] Animation duration in milliseconds.\n * @property {boolean} [autoHide=true] Hide the control when rotation is 0.\n * @property {function(import(\"../MapEvent.js\").default)} [render] Function called when the control should\n * be re-rendered. This is called in a `requestAnimationFrame` callback.\n * @property {function()} [resetNorth] Function called when the control is clicked.\n * This will override the default `resetNorth`.\n * @property {HTMLElement|string} [target] Specify a target if you want the control to be\n * rendered outside of the map's viewport.\n */\n\n\n/**\n * @classdesc\n * A button control to reset rotation to 0.\n * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css\n * selector is added to the button when the rotation is 0.\n *\n * @api\n */\nvar Rotate = /*@__PURE__*/(function (Control) {\n function Rotate(opt_options) {\n\n var options = opt_options ? opt_options : {};\n\n Control.call(this, {\n element: document.createElement('div'),\n render: options.render || render,\n target: options.target\n });\n\n var className = options.className !== undefined ? options.className : 'ol-rotate';\n\n var label = options.label !== undefined ? options.label : '\\u21E7';\n\n /**\n * @type {HTMLElement}\n * @private\n */\n this.label_ = null;\n\n if (typeof label === 'string') {\n this.label_ = document.createElement('span');\n this.label_.className = 'ol-compass';\n this.label_.textContent = label;\n } else {\n this.label_ = label;\n this.label_.classList.add('ol-compass');\n }\n\n var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';\n\n var button = document.createElement('button');\n button.className = className + '-reset';\n button.setAttribute('type', 'button');\n button.title = tipLabel;\n button.appendChild(this.label_);\n\n listen(button, EventType.CLICK, this.handleClick_, this);\n\n var cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL;\n var element = this.element;\n element.className = cssClasses;\n element.appendChild(button);\n\n this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;\n\n /**\n * @type {number}\n * @private\n */\n this.duration_ = options.duration !== undefined ? options.duration : 250;\n\n /**\n * @type {boolean}\n * @private\n */\n this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.rotation_ = undefined;\n\n if (this.autoHide_) {\n this.element.classList.add(CLASS_HIDDEN);\n }\n\n }\n\n if ( Control ) Rotate.__proto__ = Control;\n Rotate.prototype = Object.create( Control && Control.prototype );\n Rotate.prototype.constructor = Rotate;\n\n /**\n * @param {MouseEvent} event The event to handle\n * @private\n */\n Rotate.prototype.handleClick_ = function handleClick_ (event) {\n event.preventDefault();\n if (this.callResetNorth_ !== undefined) {\n this.callResetNorth_();\n } else {\n this.resetNorth_();\n }\n };\n\n /**\n * @private\n */\n Rotate.prototype.resetNorth_ = function resetNorth_ () {\n var map = this.getMap();\n var view = map.getView();\n if (!view) {\n // the map does not have a view, so we can't act\n // upon it\n return;\n }\n if (view.getRotation() !== undefined) {\n if (this.duration_ > 0) {\n view.animate({\n rotation: 0,\n duration: this.duration_,\n easing: easeOut\n });\n } else {\n view.setRotation(0);\n }\n }\n };\n\n return Rotate;\n}(Control));\n\n\n/**\n * Update the rotate control element.\n * @param {import(\"../MapEvent.js\").default} mapEvent Map event.\n * @this {Rotate}\n * @api\n */\nexport function render(mapEvent) {\n var frameState = mapEvent.frameState;\n if (!frameState) {\n return;\n }\n var rotation = frameState.viewState.rotation;\n if (rotation != this.rotation_) {\n var transform = 'rotate(' + rotation + 'rad)';\n if (this.autoHide_) {\n var contains = this.element.classList.contains(CLASS_HIDDEN);\n if (!contains && rotation === 0) {\n this.element.classList.add(CLASS_HIDDEN);\n } else if (contains && rotation !== 0) {\n this.element.classList.remove(CLASS_HIDDEN);\n }\n }\n this.label_.style.msTransform = transform;\n this.label_.style.webkitTransform = transform;\n this.label_.style.transform = transform;\n }\n this.rotation_ = rotation;\n}\n\nexport default Rotate;\n\n//# sourceMappingURL=Rotate.js.map","/**\n * @module ol/control/Attribution\n */\nimport {equals} from '../array.js';\nimport Control from './Control.js';\nimport {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_COLLAPSED} from '../css.js';\nimport {removeChildren, replaceNode} from '../dom.js';\nimport {listen} from '../events.js';\nimport EventType from '../events/EventType.js';\nimport {visibleAtResolution} from '../layer/Layer.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {string} [className='ol-attribution'] CSS class name.\n * @property {HTMLElement|string} [target] Specify a target if you\n * want the control to be rendered outside of the map's\n * viewport.\n * @property {boolean} [collapsible] Specify if attributions can\n * be collapsed. If not specified, sources control this behavior with their\n * `attributionsCollapsible` setting.\n * @property {boolean} [collapsed=true] Specify if attributions should\n * be collapsed at startup.\n * @property {string} [tipLabel='Attributions'] Text label to use for the button tip.\n * @property {string} [label='i'] Text label to use for the\n * collapsed attributions button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {string|HTMLElement} [collapseLabel='»'] Text label to use\n * for the expanded attributions button.\n * Instead of text, also an element (e.g. a `span` element) can be used.\n * @property {function(import(\"../MapEvent.js\").default)} [render] Function called when\n * the control should be re-rendered. This is called in a `requestAnimationFrame`\n * callback.\n */\n\n\n/**\n * @classdesc\n * Control to show all the attributions associated with the layer sources\n * in the map. This control is one of the default controls included in maps.\n * By default it will show in the bottom right portion of the map, but this can\n * be changed by using a css selector for `.ol-attribution`.\n *\n * @api\n */\nvar Attribution = /*@__PURE__*/(function (Control) {\n function Attribution(opt_options) {\n\n var options = opt_options ? opt_options : {};\n\n Control.call(this, {\n element: document.createElement('div'),\n render: options.render || render,\n target: options.target\n });\n\n /**\n * @private\n * @type {HTMLElement}\n */\n this.ulElement_ = document.createElement('ul');\n\n /**\n * @private\n * @type {boolean}\n */\n this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;\n\n /**\n * @private\n * @type {boolean}\n */\n this.overrideCollapsible_ = options.collapsible !== undefined;\n\n /**\n * @private\n * @type {boolean}\n */\n this.collapsible_ = options.collapsible !== undefined ?\n options.collapsible : true;\n\n if (!this.collapsible_) {\n this.collapsed_ = false;\n }\n\n var className = options.className !== undefined ? options.className : 'ol-attribution';\n\n var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';\n\n var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\\u00BB';\n\n if (typeof collapseLabel === 'string') {\n /**\n * @private\n * @type {HTMLElement}\n */\n this.collapseLabel_ = document.createElement('span');\n this.collapseLabel_.textContent = collapseLabel;\n } else {\n this.collapseLabel_ = collapseLabel;\n }\n\n var label = options.label !== undefined ? options.label : 'i';\n\n if (typeof label === 'string') {\n /**\n * @private\n * @type {HTMLElement}\n */\n this.label_ = document.createElement('span');\n this.label_.textContent = label;\n } else {\n this.label_ = label;\n }\n\n\n var activeLabel = (this.collapsible_ && !this.collapsed_) ?\n this.collapseLabel_ : this.label_;\n var button = document.createElement('button');\n button.setAttribute('type', 'button');\n button.title = tipLabel;\n button.appendChild(activeLabel);\n\n listen(button, EventType.CLICK, this.handleClick_, this);\n\n var cssClasses = className + ' ' + CLASS_UNSELECTABLE + ' ' + CLASS_CONTROL +\n (this.collapsed_ && this.collapsible_ ? ' ' + CLASS_COLLAPSED : '') +\n (this.collapsible_ ? '' : ' ol-uncollapsible');\n var element = this.element;\n element.className = cssClasses;\n element.appendChild(this.ulElement_);\n element.appendChild(button);\n\n /**\n * A list of currently rendered resolutions.\n * @type {Array}\n * @private\n */\n this.renderedAttributions_ = [];\n\n /**\n * @private\n * @type {boolean}\n */\n this.renderedVisible_ = true;\n\n }\n\n if ( Control ) Attribution.__proto__ = Control;\n Attribution.prototype = Object.create( Control && Control.prototype );\n Attribution.prototype.constructor = Attribution;\n\n /**\n * Collect a list of visible attributions and set the collapsible state.\n * @param {import(\"../PluggableMap.js\").FrameState} frameState Frame state.\n * @return {Array} Attributions.\n * @private\n */\n Attribution.prototype.collectSourceAttributions_ = function collectSourceAttributions_ (frameState) {\n /**\n * Used to determine if an attribution already exists.\n * @type {!Object}\n */\n var lookup = {};\n\n /**\n * A list of visible attributions.\n * @type {Array}\n */\n var visibleAttributions = [];\n\n var layerStatesArray = frameState.layerStatesArray;\n var resolution = frameState.viewState.resolution;\n for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {\n var layerState = layerStatesArray[i];\n if (!visibleAtResolution(layerState, resolution)) {\n continue;\n }\n\n var source = /** @type {import(\"../layer/Layer.js\").default} */ (layerState.layer).getSource();\n if (!source) {\n continue;\n }\n\n var attributionGetter = source.getAttributions();\n if (!attributionGetter) {\n continue;\n }\n\n var attributions = attributionGetter(frameState);\n if (!attributions) {\n continue;\n }\n\n if (!this.overrideCollapsible_ && source.getAttributionsCollapsible() === false) {\n this.setCollapsible(false);\n }\n\n if (Array.isArray(attributions)) {\n for (var j = 0, jj = attributions.length; j < jj; ++j) {\n if (!(attributions[j] in lookup)) {\n visibleAttributions.push(attributions[j]);\n lookup[attributions[j]] = true;\n }\n }\n } else {\n if (!(attributions in lookup)) {\n visibleAttributions.push(attributions);\n lookup[attributions] = true;\n }\n }\n }\n return visibleAttributions;\n };\n\n /**\n * @private\n * @param {?import(\"../PluggableMap.js\").FrameState} frameState Frame state.\n */\n Attribution.prototype.updateElement_ = function updateElement_ (frameState) {\n if (!frameState) {\n if (this.renderedVisible_) {\n this.element.style.display = 'none';\n this.renderedVisible_ = false;\n }\n return;\n }\n\n var attributions = this.collectSourceAttributions_(frameState);\n\n var visible = attributions.length > 0;\n if (this.renderedVisible_ != visible) {\n this.element.style.display = visible ? '' : 'none';\n this.renderedVisible_ = visible;\n }\n\n if (equals(attributions, this.renderedAttributions_)) {\n return;\n }\n\n removeChildren(this.ulElement_);\n\n // append the attributions\n for (var i = 0, ii = attributions.length; i < ii; ++i) {\n var element = document.createElement('li');\n element.innerHTML = attributions[i];\n this.ulElement_.appendChild(element);\n }\n\n this.renderedAttributions_ = attributions;\n };\n\n /**\n * @param {MouseEvent} event The event to handle\n * @private\n */\n Attribution.prototype.handleClick_ = function handleClick_ (event) {\n event.preventDefault();\n this.handleToggle_();\n };\n\n /**\n * @private\n */\n Attribution.prototype.handleToggle_ = function handleToggle_ () {\n this.element.classList.toggle(CLASS_COLLAPSED);\n if (this.collapsed_) {\n replaceNode(this.collapseLabel_, this.label_);\n } else {\n replaceNode(this.label_, this.collapseLabel_);\n }\n this.collapsed_ = !this.collapsed_;\n };\n\n /**\n * Return `true` if the attribution is collapsible, `false` otherwise.\n * @return {boolean} True if the widget is collapsible.\n * @api\n */\n Attribution.prototype.getCollapsible = function getCollapsible () {\n return this.collapsible_;\n };\n\n /**\n * Set whether the attribution should be collapsible.\n * @param {boolean} collapsible True if the widget is collapsible.\n * @api\n */\n Attribution.prototype.setCollapsible = function setCollapsible (collapsible) {\n if (this.collapsible_ === collapsible) {\n return;\n }\n this.collapsible_ = collapsible;\n this.element.classList.toggle('ol-uncollapsible');\n if (!collapsible && this.collapsed_) {\n this.handleToggle_();\n }\n };\n\n /**\n * Collapse or expand the attribution according to the passed parameter. Will\n * not do anything if the attribution isn't collapsible or if the current\n * collapsed state is already the one requested.\n * @param {boolean} collapsed True if the widget is collapsed.\n * @api\n */\n Attribution.prototype.setCollapsed = function setCollapsed (collapsed) {\n if (!this.collapsible_ || this.collapsed_ === collapsed) {\n return;\n }\n this.handleToggle_();\n };\n\n /**\n * Return `true` when the attribution is currently collapsed or `false`\n * otherwise.\n * @return {boolean} True if the widget is collapsed.\n * @api\n */\n Attribution.prototype.getCollapsed = function getCollapsed () {\n return this.collapsed_;\n };\n\n return Attribution;\n}(Control));\n\n\n/**\n * Update the attribution element.\n * @param {import(\"../MapEvent.js\").default} mapEvent Map event.\n * @this {Attribution}\n * @api\n */\nexport function render(mapEvent) {\n this.updateElement_(mapEvent.frameState);\n}\n\n\nexport default Attribution;\n\n//# sourceMappingURL=Attribution.js.map","/**\n * @module ol/AssertionError\n */\nimport {VERSION} from './util.js';\n\n/**\n * Error object thrown when an assertion failed. This is an ECMA-262 Error,\n * extended with a `code` property.\n * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error.\n */\nvar AssertionError = /*@__PURE__*/(function (Error) {\n function AssertionError(code) {\n var path = VERSION === 'latest' ? VERSION : 'v' + VERSION.split('-')[0];\n var message = 'Assertion failed. See https://openlayers.org/en/' + path +\n '/doc/errors/#' + code + ' for details.';\n\n Error.call(this, message);\n\n /**\n * Error code. The meaning of the code can be found on\n * https://openlayers.org/en/latest/doc/errors/ (replace `latest` with\n * the version found in the OpenLayers script's header comment if a version\n * other than the latest is used).\n * @type {number}\n * @api\n */\n this.code = code;\n\n /**\n * @type {string}\n */\n this.name = 'AssertionError';\n\n // Re-assign message, see https://github.com/Rich-Harris/buble/issues/40\n this.message = message;\n }\n\n if ( Error ) AssertionError.__proto__ = Error;\n AssertionError.prototype = Object.create( Error && Error.prototype );\n AssertionError.prototype.constructor = AssertionError;\n\n return AssertionError;\n}(Error));\n\nexport default AssertionError;\n\n//# sourceMappingURL=AssertionError.js.map","/**\n * @module ol/Observable\n */\nimport {listen, unlistenByKey, unlisten, listenOnce} from './events.js';\nimport EventTarget from './events/Target.js';\nimport EventType from './events/EventType.js';\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * An event target providing convenient methods for listener registration\n * and unregistration. A generic `change` event is always available through\n * {@link module:ol/Observable~Observable#changed}.\n *\n * @fires import(\"./events/Event.js\").Event\n * @api\n */\nvar Observable = /*@__PURE__*/(function (EventTarget) {\n function Observable() {\n\n EventTarget.call(this);\n\n /**\n * @private\n * @type {number}\n */\n this.revision_ = 0;\n\n }\n\n if ( EventTarget ) Observable.__proto__ = EventTarget;\n Observable.prototype = Object.create( EventTarget && EventTarget.prototype );\n Observable.prototype.constructor = Observable;\n\n /**\n * Increases the revision counter and dispatches a 'change' event.\n * @api\n */\n Observable.prototype.changed = function changed () {\n ++this.revision_;\n this.dispatchEvent(EventType.CHANGE);\n };\n\n /**\n * Get the version number for this object. Each time the object is modified,\n * its version number will be incremented.\n * @return {number} Revision.\n * @api\n */\n Observable.prototype.getRevision = function getRevision () {\n return this.revision_;\n };\n\n /**\n * Listen for a certain type of event.\n * @param {string|Array} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @return {import(\"./events.js\").EventsKey|Array} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\n Observable.prototype.on = function on (type, listener) {\n if (Array.isArray(type)) {\n var len = type.length;\n var keys = new Array(len);\n for (var i = 0; i < len; ++i) {\n keys[i] = listen(this, type[i], listener);\n }\n return keys;\n } else {\n return listen(this, /** @type {string} */ (type), listener);\n }\n };\n\n /**\n * Listen once for a certain type of event.\n * @param {string|Array} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @return {import(\"./events.js\").EventsKey|Array} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\n Observable.prototype.once = function once (type, listener) {\n if (Array.isArray(type)) {\n var len = type.length;\n var keys = new Array(len);\n for (var i = 0; i < len; ++i) {\n keys[i] = listenOnce(this, type[i], listener);\n }\n return keys;\n } else {\n return listenOnce(this, /** @type {string} */ (type), listener);\n }\n };\n\n /**\n * Unlisten for a certain type of event.\n * @param {string|Array} type The event type or array of event types.\n * @param {function(?): ?} listener The listener function.\n * @api\n */\n Observable.prototype.un = function un (type, listener) {\n if (Array.isArray(type)) {\n for (var i = 0, ii = type.length; i < ii; ++i) {\n unlisten(this, type[i], listener);\n }\n return;\n } else {\n unlisten(this, /** @type {string} */ (type), listener);\n }\n };\n\n return Observable;\n}(EventTarget));\n\n\n/**\n * Removes an event listener using the key returned by `on()` or `once()`.\n * @param {import(\"./events.js\").EventsKey|Array} key The key returned by `on()`\n * or `once()` (or an array of keys).\n * @api\n */\nexport function unByKey(key) {\n if (Array.isArray(key)) {\n for (var i = 0, ii = key.length; i < ii; ++i) {\n unlistenByKey(key[i]);\n }\n } else {\n unlistenByKey(/** @type {import(\"./events.js\").EventsKey} */ (key));\n }\n}\n\n\nexport default Observable;\n\n//# sourceMappingURL=Observable.js.map","/**\n * @module ol/layer/Base\n */\nimport {abstract} from '../util.js';\nimport BaseObject from '../Object.js';\nimport LayerProperty from './Property.js';\nimport {clamp} from '../math.js';\nimport {assign} from '../obj.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} [opacity=1] Opacity (0, 1).\n * @property {boolean} [visible=true] Visibility.\n * @property {import(\"../extent.js\").Extent} [extent] The bounding extent for layer rendering. The layer will not be\n * rendered outside of this extent.\n * @property {number} [zIndex] The z-index for layer rendering. At rendering time, the layers\n * will be ordered, first by Z-index and then by position. When `undefined`, a `zIndex` of 0 is assumed\n * for layers that are added to the map's `layers` collection, or `Infinity` when the layer's `setMap()`\n * method was used.\n * @property {number} [minResolution] The minimum resolution (inclusive) at which this layer will be\n * visible.\n * @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will\n * be visible.\n */\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Note that with {@link module:ol/layer/Base} and all its subclasses, any property set in\n * the options is set as a {@link module:ol/Object} property on the layer object, so\n * is observable, and has get/set accessors.\n *\n * @api\n */\nvar BaseLayer = /*@__PURE__*/(function (BaseObject) {\n function BaseLayer(options) {\n\n BaseObject.call(this);\n\n /**\n * @type {Object}\n */\n var properties = assign({}, options);\n properties[LayerProperty.OPACITY] =\n options.opacity !== undefined ? options.opacity : 1;\n properties[LayerProperty.VISIBLE] =\n options.visible !== undefined ? options.visible : true;\n properties[LayerProperty.Z_INDEX] = options.zIndex;\n properties[LayerProperty.MAX_RESOLUTION] =\n options.maxResolution !== undefined ? options.maxResolution : Infinity;\n properties[LayerProperty.MIN_RESOLUTION] =\n options.minResolution !== undefined ? options.minResolution : 0;\n\n this.setProperties(properties);\n\n /**\n * @type {import(\"./Layer.js\").State}\n * @private\n */\n this.state_ = null;\n\n /**\n * The layer type.\n * @type {import(\"../LayerType.js\").default}\n * @protected;\n */\n this.type;\n\n }\n\n if ( BaseObject ) BaseLayer.__proto__ = BaseObject;\n BaseLayer.prototype = Object.create( BaseObject && BaseObject.prototype );\n BaseLayer.prototype.constructor = BaseLayer;\n\n /**\n * Get the layer type (used when creating a layer renderer).\n * @return {import(\"../LayerType.js\").default} The layer type.\n */\n BaseLayer.prototype.getType = function getType () {\n return this.type;\n };\n\n /**\n * @return {import(\"./Layer.js\").State} Layer state.\n */\n BaseLayer.prototype.getLayerState = function getLayerState () {\n /** @type {import(\"./Layer.js\").State} */\n var state = this.state_ || /** @type {?} */ ({\n layer: this,\n managed: true\n });\n state.opacity = clamp(this.getOpacity(), 0, 1);\n state.sourceState = this.getSourceState();\n state.visible = this.getVisible();\n state.extent = this.getExtent();\n state.zIndex = this.getZIndex() || 0;\n state.maxResolution = this.getMaxResolution();\n state.minResolution = Math.max(this.getMinResolution(), 0);\n this.state_ = state;\n\n return state;\n };\n\n /**\n * @abstract\n * @param {Array=} opt_array Array of layers (to be\n * modified in place).\n * @return {Array} Array of layers.\n */\n BaseLayer.prototype.getLayersArray = function getLayersArray (opt_array) {\n return abstract();\n };\n\n /**\n * @abstract\n * @param {Array=} opt_states Optional list of layer\n * states (to be modified in place).\n * @return {Array} List of layer states.\n */\n BaseLayer.prototype.getLayerStatesArray = function getLayerStatesArray (opt_states) {\n return abstract();\n };\n\n /**\n * Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it\n * will be visible regardless of extent.\n * @return {import(\"../extent.js\").Extent|undefined} The layer extent.\n * @observable\n * @api\n */\n BaseLayer.prototype.getExtent = function getExtent () {\n return (\n /** @type {import(\"../extent.js\").Extent|undefined} */ (this.get(LayerProperty.EXTENT))\n );\n };\n\n /**\n * Return the maximum resolution of the layer.\n * @return {number} The maximum resolution of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.getMaxResolution = function getMaxResolution () {\n return /** @type {number} */ (this.get(LayerProperty.MAX_RESOLUTION));\n };\n\n /**\n * Return the minimum resolution of the layer.\n * @return {number} The minimum resolution of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.getMinResolution = function getMinResolution () {\n return /** @type {number} */ (this.get(LayerProperty.MIN_RESOLUTION));\n };\n\n /**\n * Return the opacity of the layer (between 0 and 1).\n * @return {number} The opacity of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.getOpacity = function getOpacity () {\n return /** @type {number} */ (this.get(LayerProperty.OPACITY));\n };\n\n /**\n * @abstract\n * @return {import(\"../source/State.js\").default} Source state.\n */\n BaseLayer.prototype.getSourceState = function getSourceState () {\n return abstract();\n };\n\n /**\n * Return the visibility of the layer (`true` or `false`).\n * @return {boolean} The visibility of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.getVisible = function getVisible () {\n return /** @type {boolean} */ (this.get(LayerProperty.VISIBLE));\n };\n\n /**\n * Return the Z-index of the layer, which is used to order layers before\n * rendering. The default Z-index is 0.\n * @return {number} The Z-index of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.getZIndex = function getZIndex () {\n return /** @type {number} */ (this.get(LayerProperty.Z_INDEX));\n };\n\n /**\n * Set the extent at which the layer is visible. If `undefined`, the layer\n * will be visible at all extents.\n * @param {import(\"../extent.js\").Extent|undefined} extent The extent of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setExtent = function setExtent (extent) {\n this.set(LayerProperty.EXTENT, extent);\n };\n\n /**\n * Set the maximum resolution at which the layer is visible.\n * @param {number} maxResolution The maximum resolution of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setMaxResolution = function setMaxResolution (maxResolution) {\n this.set(LayerProperty.MAX_RESOLUTION, maxResolution);\n };\n\n /**\n * Set the minimum resolution at which the layer is visible.\n * @param {number} minResolution The minimum resolution of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setMinResolution = function setMinResolution (minResolution) {\n this.set(LayerProperty.MIN_RESOLUTION, minResolution);\n };\n\n /**\n * Set the opacity of the layer, allowed values range from 0 to 1.\n * @param {number} opacity The opacity of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setOpacity = function setOpacity (opacity) {\n this.set(LayerProperty.OPACITY, opacity);\n };\n\n /**\n * Set the visibility of the layer (`true` or `false`).\n * @param {boolean} visible The visibility of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setVisible = function setVisible (visible) {\n this.set(LayerProperty.VISIBLE, visible);\n };\n\n /**\n * Set Z-index of the layer, which is used to order layers before rendering.\n * The default Z-index is 0.\n * @param {number} zindex The z-index of the layer.\n * @observable\n * @api\n */\n BaseLayer.prototype.setZIndex = function setZIndex (zindex) {\n this.set(LayerProperty.Z_INDEX, zindex);\n };\n\n return BaseLayer;\n}(BaseObject));\n\n\nexport default BaseLayer;\n\n//# sourceMappingURL=Base.js.map","/**\n * @module ol/geom/flat/intersectsextent\n */\nimport {containsExtent, createEmpty, extendFlatCoordinates, intersects, intersectsSegment} from '../../extent.js';\nimport {linearRingContainsXY, linearRingContainsExtent} from './contains.js';\nimport {forEach as forEachSegment} from './segments.js';\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineString(flatCoordinates, offset, end, stride, extent) {\n var coordinatesExtent = extendFlatCoordinates(\n createEmpty(), flatCoordinates, offset, end, stride);\n if (!intersects(extent, coordinatesExtent)) {\n return false;\n }\n if (containsExtent(extent, coordinatesExtent)) {\n return true;\n }\n if (coordinatesExtent[0] >= extent[0] &&\n coordinatesExtent[2] <= extent[2]) {\n return true;\n }\n if (coordinatesExtent[1] >= extent[1] &&\n coordinatesExtent[3] <= extent[3]) {\n return true;\n }\n return forEachSegment(flatCoordinates, offset, end, stride,\n /**\n * @param {import(\"../../coordinate.js\").Coordinate} point1 Start point.\n * @param {import(\"../../coordinate.js\").Coordinate} point2 End point.\n * @return {boolean} `true` if the segment and the extent intersect,\n * `false` otherwise.\n */\n function(point1, point2) {\n return intersectsSegment(extent, point1, point2);\n });\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineStringArray(flatCoordinates, offset, ends, stride, extent) {\n for (var i = 0, ii = ends.length; i < ii; ++i) {\n if (intersectsLineString(\n flatCoordinates, offset, ends[i], stride, extent)) {\n return true;\n }\n offset = ends[i];\n }\n return false;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRing(flatCoordinates, offset, end, stride, extent) {\n if (intersectsLineString(\n flatCoordinates, offset, end, stride, extent)) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[0], extent[1])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[0], extent[3])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[2], extent[1])) {\n return true;\n }\n if (linearRingContainsXY(flatCoordinates, offset, end, stride, extent[2], extent[3])) {\n return true;\n }\n return false;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingArray(flatCoordinates, offset, ends, stride, extent) {\n if (!intersectsLinearRing(\n flatCoordinates, offset, ends[0], stride, extent)) {\n return false;\n }\n if (ends.length === 1) {\n return true;\n }\n for (var i = 1, ii = ends.length; i < ii; ++i) {\n if (linearRingContainsExtent(flatCoordinates, ends[i - 1], ends[i], stride, extent)) {\n if (!intersectsLineString(flatCoordinates, ends[i - 1], ends[i], stride, extent)) {\n return false;\n }\n }\n }\n return true;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingMultiArray(flatCoordinates, offset, endss, stride, extent) {\n for (var i = 0, ii = endss.length; i < ii; ++i) {\n var ends = endss[i];\n if (intersectsLinearRingArray(\n flatCoordinates, offset, ends, stride, extent)) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n\n//# sourceMappingURL=intersectsextent.js.map","/**\n * @module ol/geom/flat/segments\n */\n\n\n/**\n * This function calls `callback` for each segment of the flat coordinates\n * array. If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {function(this: S, import(\"../../coordinate.js\").Coordinate, import(\"../../coordinate.js\").Coordinate): T} callback Function\n * called for each segment.\n * @param {S=} opt_this The object to be used as the value of 'this'\n * within callback.\n * @return {T|boolean} Value.\n * @template T,S\n */\nexport function forEach(flatCoordinates, offset, end, stride, callback, opt_this) {\n var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];\n var point2 = [];\n var ret;\n for (; (offset + stride) < end; offset += stride) {\n point2[0] = flatCoordinates[offset + stride];\n point2[1] = flatCoordinates[offset + stride + 1];\n ret = callback.call(opt_this, point1, point2);\n if (ret) {\n return ret;\n }\n point1[0] = point2[0];\n point1[1] = point2[1];\n }\n return false;\n}\n\n//# sourceMappingURL=segments.js.map","/**\n * @module ol/structs/LRUCache\n */\n\nimport {assert} from '../asserts.js';\nimport EventTarget from '../events/Target.js';\nimport EventType from '../events/EventType.js';\n\n\n/**\n * @typedef {Object} Entry\n * @property {string} key_\n * @property {Object} newer\n * @property {Object} older\n * @property {*} value_\n */\n\n\n/**\n * @classdesc\n * Implements a Least-Recently-Used cache where the keys do not conflict with\n * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring\n * items from the cache is the responsibility of the user.\n *\n * @fires import(\"../events/Event.js\").Event\n * @template T\n */\nvar LRUCache = /*@__PURE__*/(function (EventTarget) {\n function LRUCache(opt_highWaterMark) {\n\n EventTarget.call(this);\n\n /**\n * @type {number}\n */\n this.highWaterMark = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;\n\n /**\n * @private\n * @type {number}\n */\n this.count_ = 0;\n\n /**\n * @private\n * @type {!Object}\n */\n this.entries_ = {};\n\n /**\n * @private\n * @type {?Entry}\n */\n this.oldest_ = null;\n\n /**\n * @private\n * @type {?Entry}\n */\n this.newest_ = null;\n\n }\n\n if ( EventTarget ) LRUCache.__proto__ = EventTarget;\n LRUCache.prototype = Object.create( EventTarget && EventTarget.prototype );\n LRUCache.prototype.constructor = LRUCache;\n\n\n /**\n * @return {boolean} Can expire cache.\n */\n LRUCache.prototype.canExpireCache = function canExpireCache () {\n return this.getCount() > this.highWaterMark;\n };\n\n\n /**\n * FIXME empty description for jsdoc\n */\n LRUCache.prototype.clear = function clear () {\n this.count_ = 0;\n this.entries_ = {};\n this.oldest_ = null;\n this.newest_ = null;\n this.dispatchEvent(EventType.CLEAR);\n };\n\n\n /**\n * @param {string} key Key.\n * @return {boolean} Contains key.\n */\n LRUCache.prototype.containsKey = function containsKey (key) {\n return this.entries_.hasOwnProperty(key);\n };\n\n\n /**\n * @param {function(this: S, T, string, LRUCache): ?} f The function\n * to call for every entry from the oldest to the newer. This function takes\n * 3 arguments (the entry value, the entry key and the LRUCache object).\n * The return value is ignored.\n * @param {S=} opt_this The object to use as `this` in `f`.\n * @template S\n */\n LRUCache.prototype.forEach = function forEach (f, opt_this) {\n var entry = this.oldest_;\n while (entry) {\n f.call(opt_this, entry.value_, entry.key_, this);\n entry = entry.newer;\n }\n };\n\n\n /**\n * @param {string} key Key.\n * @return {T} Value.\n */\n LRUCache.prototype.get = function get (key) {\n var entry = this.entries_[key];\n assert(entry !== undefined,\n 15); // Tried to get a value for a key that does not exist in the cache\n if (entry === this.newest_) {\n return entry.value_;\n } else if (entry === this.oldest_) {\n this.oldest_ = /** @type {Entry} */ (this.oldest_.newer);\n this.oldest_.older = null;\n } else {\n entry.newer.older = entry.older;\n entry.older.newer = entry.newer;\n }\n entry.newer = null;\n entry.older = this.newest_;\n this.newest_.newer = entry;\n this.newest_ = entry;\n return entry.value_;\n };\n\n\n /**\n * Remove an entry from the cache.\n * @param {string} key The entry key.\n * @return {T} The removed entry.\n */\n LRUCache.prototype.remove = function remove (key) {\n var entry = this.entries_[key];\n assert(entry !== undefined, 15); // Tried to get a value for a key that does not exist in the cache\n if (entry === this.newest_) {\n this.newest_ = /** @type {Entry} */ (entry.older);\n if (this.newest_) {\n this.newest_.newer = null;\n }\n } else if (entry === this.oldest_) {\n this.oldest_ = /** @type {Entry} */ (entry.newer);\n if (this.oldest_) {\n this.oldest_.older = null;\n }\n } else {\n entry.newer.older = entry.older;\n entry.older.newer = entry.newer;\n }\n delete this.entries_[key];\n --this.count_;\n return entry.value_;\n };\n\n\n /**\n * @return {number} Count.\n */\n LRUCache.prototype.getCount = function getCount () {\n return this.count_;\n };\n\n\n /**\n * @return {Array} Keys.\n */\n LRUCache.prototype.getKeys = function getKeys () {\n var keys = new Array(this.count_);\n var i = 0;\n var entry;\n for (entry = this.newest_; entry; entry = entry.older) {\n keys[i++] = entry.key_;\n }\n return keys;\n };\n\n\n /**\n * @return {Array} Values.\n */\n LRUCache.prototype.getValues = function getValues () {\n var values = new Array(this.count_);\n var i = 0;\n var entry;\n for (entry = this.newest_; entry; entry = entry.older) {\n values[i++] = entry.value_;\n }\n return values;\n };\n\n\n /**\n * @return {T} Last value.\n */\n LRUCache.prototype.peekLast = function peekLast () {\n return this.oldest_.value_;\n };\n\n\n /**\n * @return {string} Last key.\n */\n LRUCache.prototype.peekLastKey = function peekLastKey () {\n return this.oldest_.key_;\n };\n\n\n /**\n * Get the key of the newest item in the cache. Throws if the cache is empty.\n * @return {string} The newest key.\n */\n LRUCache.prototype.peekFirstKey = function peekFirstKey () {\n return this.newest_.key_;\n };\n\n\n /**\n * @return {T} value Value.\n */\n LRUCache.prototype.pop = function pop () {\n var entry = this.oldest_;\n delete this.entries_[entry.key_];\n if (entry.newer) {\n entry.newer.older = null;\n }\n this.oldest_ = /** @type {Entry} */ (entry.newer);\n if (!this.oldest_) {\n this.newest_ = null;\n }\n --this.count_;\n return entry.value_;\n };\n\n\n /**\n * @param {string} key Key.\n * @param {T} value Value.\n */\n LRUCache.prototype.replace = function replace (key, value) {\n this.get(key); // update `newest_`\n this.entries_[key].value_ = value;\n };\n\n\n /**\n * @param {string} key Key.\n * @param {T} value Value.\n */\n LRUCache.prototype.set = function set (key, value) {\n assert(!(key in this.entries_),\n 16); // Tried to set a value for a key that is used already\n var entry = /** @type {Entry} */ ({\n key_: key,\n newer: null,\n older: this.newest_,\n value_: value\n });\n if (!this.newest_) {\n this.oldest_ = entry;\n } else {\n this.newest_.newer = entry;\n }\n this.newest_ = entry;\n this.entries_[key] = entry;\n ++this.count_;\n };\n\n\n /**\n * Set a maximum number of entries for the cache.\n * @param {number} size Cache size.\n * @api\n */\n LRUCache.prototype.setSize = function setSize (size) {\n this.highWaterMark = size;\n };\n\n\n /**\n * Prune the cache.\n */\n LRUCache.prototype.prune = function prune () {\n while (this.canExpireCache()) {\n this.pop();\n }\n };\n\n return LRUCache;\n}(EventTarget));\n\nexport default LRUCache;\n\n//# sourceMappingURL=LRUCache.js.map","/**\n * @module ol/layer/VectorRenderType\n */\n\n/**\n * @enum {string}\n * Render mode for vector layers:\n * * `'image'`: Vector layers are rendered as images. Great performance, but\n * point symbols and texts are always rotated with the view and pixels are\n * scaled during zoom animations.\n * * `'vector'`: Vector layers are rendered as vectors. Most accurate rendering\n * even during animations, but slower performance.\n * @api\n */\nexport default {\n IMAGE: 'image',\n VECTOR: 'vector'\n};\n\n//# sourceMappingURL=VectorRenderType.js.map","/**\n * @module ol/geom/flat/length\n */\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Length.\n */\nexport function lineStringLength(flatCoordinates, offset, end, stride) {\n var x1 = flatCoordinates[offset];\n var y1 = flatCoordinates[offset + 1];\n var length = 0;\n for (var i = offset + stride; i < end; i += stride) {\n var x2 = flatCoordinates[i];\n var y2 = flatCoordinates[i + 1];\n length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n x1 = x2;\n y1 = y2;\n }\n return length;\n}\n\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Perimeter.\n */\nexport function linearRingLength(flatCoordinates, offset, end, stride) {\n var perimeter = lineStringLength(flatCoordinates, offset, end, stride);\n var dx = flatCoordinates[end - stride] - flatCoordinates[offset];\n var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];\n perimeter += Math.sqrt(dx * dx + dy * dy);\n return perimeter;\n}\n\n//# sourceMappingURL=length.js.map","/**\n * @module ol/style/Image\n */\nimport {abstract} from '../util.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {number} opacity\n * @property {boolean} rotateWithView\n * @property {number} rotation\n * @property {number} scale\n */\n\n\n/**\n * @classdesc\n * A base class used for creating subclasses and not instantiated in\n * apps. Base class for {@link module:ol/style/Icon~Icon}, {@link module:ol/style/Circle~CircleStyle} and\n * {@link module:ol/style/RegularShape~RegularShape}.\n * @abstract\n * @api\n */\nvar ImageStyle = function ImageStyle(options) {\n\n /**\n * @private\n * @type {number}\n */\n this.opacity_ = options.opacity;\n\n /**\n * @private\n * @type {boolean}\n */\n this.rotateWithView_ = options.rotateWithView;\n\n /**\n * @private\n * @type {number}\n */\n this.rotation_ = options.rotation;\n\n /**\n * @private\n * @type {number}\n */\n this.scale_ = options.scale;\n\n};\n\n/**\n * Clones the style.\n * @return {ImageStyle} The cloned style.\n * @api\n */\nImageStyle.prototype.clone = function clone () {\n return new ImageStyle({\n opacity: this.getOpacity(),\n scale: this.getScale(),\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView()\n });\n};\n\n/**\n * Get the symbolizer opacity.\n * @return {number} Opacity.\n * @api\n */\nImageStyle.prototype.getOpacity = function getOpacity () {\n return this.opacity_;\n};\n\n/**\n * Determine whether the symbolizer rotates with the map.\n * @return {boolean} Rotate with map.\n * @api\n */\nImageStyle.prototype.getRotateWithView = function getRotateWithView () {\n return this.rotateWithView_;\n};\n\n/**\n * Get the symoblizer rotation.\n * @return {number} Rotation.\n * @api\n */\nImageStyle.prototype.getRotation = function getRotation () {\n return this.rotation_;\n};\n\n/**\n * Get the symbolizer scale.\n * @return {number} Scale.\n * @api\n */\nImageStyle.prototype.getScale = function getScale () {\n return this.scale_;\n};\n\n/**\n * This method is deprecated and always returns false.\n * @return {boolean} false.\n * @deprecated\n * @api\n */\nImageStyle.prototype.getSnapToPixel = function getSnapToPixel () {\n return false;\n};\n\n/**\n * Get the anchor point in pixels. The anchor determines the center point for the\n * symbolizer.\n * @abstract\n * @return {Array} Anchor.\n */\nImageStyle.prototype.getAnchor = function getAnchor () {\n return abstract();\n};\n\n/**\n * Get the image element for the symbolizer.\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} Image element.\n */\nImageStyle.prototype.getImage = function getImage (pixelRatio) {\n return abstract();\n};\n\n/**\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement|HTMLVideoElement|HTMLImageElement} Image element.\n */\nImageStyle.prototype.getHitDetectionImage = function getHitDetectionImage (pixelRatio) {\n return abstract();\n};\n\n/**\n * @abstract\n * @return {import(\"../ImageState.js\").default} Image state.\n */\nImageStyle.prototype.getImageState = function getImageState () {\n return abstract();\n};\n\n/**\n * @abstract\n * @return {import(\"../size.js\").Size} Image size.\n */\nImageStyle.prototype.getImageSize = function getImageSize () {\n return abstract();\n};\n\n/**\n * @abstract\n * @return {import(\"../size.js\").Size} Size of the hit-detection image.\n */\nImageStyle.prototype.getHitDetectionImageSize = function getHitDetectionImageSize () {\n return abstract();\n};\n\n/**\n * Get the origin of the symbolizer.\n * @abstract\n * @return {Array} Origin.\n */\nImageStyle.prototype.getOrigin = function getOrigin () {\n return abstract();\n};\n\n/**\n * Get the size of the symbolizer (in pixels).\n * @abstract\n * @return {import(\"../size.js\").Size} Size.\n */\nImageStyle.prototype.getSize = function getSize () {\n return abstract();\n};\n\n/**\n * Set the opacity.\n *\n * @param {number} opacity Opacity.\n * @api\n */\nImageStyle.prototype.setOpacity = function setOpacity (opacity) {\n this.opacity_ = opacity;\n};\n\n/**\n * Set whether to rotate the style with the view.\n *\n * @param {boolean} rotateWithView Rotate with map.\n * @api\n */\nImageStyle.prototype.setRotateWithView = function setRotateWithView (rotateWithView) {\n this.rotateWithView_ = rotateWithView;\n};\n\n/**\n * Set the rotation.\n *\n * @param {number} rotation Rotation.\n * @api\n */\nImageStyle.prototype.setRotation = function setRotation (rotation) {\n this.rotation_ = rotation;\n};\n/**\n * Set the scale.\n *\n * @param {number} scale Scale.\n * @api\n */\nImageStyle.prototype.setScale = function setScale (scale) {\n this.scale_ = scale;\n};\n\n/**\n * This method is deprecated and does nothing.\n * @param {boolean} snapToPixel Snap to pixel?\n * @deprecated\n * @api\n */\nImageStyle.prototype.setSnapToPixel = function setSnapToPixel (snapToPixel) {};\n\n/**\n * @abstract\n * @param {function(this: T, import(\"../events/Event.js\").default)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @return {import(\"../events.js\").EventsKey|undefined} Listener key.\n * @template T\n */\nImageStyle.prototype.listenImageChange = function listenImageChange (listener, thisArg) {\n return abstract();\n};\n\n/**\n * Load not yet loaded URI.\n * @abstract\n */\nImageStyle.prototype.load = function load () {\n abstract();\n};\n\n/**\n * @abstract\n * @param {function(this: T, import(\"../events/Event.js\").default)} listener Listener function.\n * @param {T} thisArg Value to use as `this` when executing `listener`.\n * @template T\n */\nImageStyle.prototype.unlistenImageChange = function unlistenImageChange (listener, thisArg) {\n abstract();\n};\n\nexport default ImageStyle;\n\n//# sourceMappingURL=Image.js.map","/**\n * @module ol/source/Source\n */\nimport {abstract} from '../util.js';\nimport BaseObject from '../Object.js';\nimport {get as getProjection} from '../proj.js';\nimport SourceState from './State.js';\n\n\n/**\n * A function that returns a string or an array of strings representing source\n * attributions.\n *\n * @typedef {function(import(\"../PluggableMap.js\").FrameState): (string|Array)} Attribution\n */\n\n\n/**\n * A type that can be used to provide attribution information for data sources.\n *\n * It represents either\n * * a simple string (e.g. `'© Acme Inc.'`)\n * * an array of simple strings (e.g. `['© Acme Inc.', '© Bacme Inc.']`)\n * * a function that returns a string or array of strings (`{@link module:ol/source/Source~Attribution}`)\n *\n * @typedef {string|Array|Attribution} AttributionLike\n */\n\n\n/**\n * @typedef {Object} Options\n * @property {AttributionLike} [attributions]\n * @property {boolean} [attributionsCollapsible=true] Attributions are collapsible.\n * @property {import(\"../proj.js\").ProjectionLike} projection\n * @property {SourceState} [state='ready']\n * @property {boolean} [wrapX=false]\n */\n\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for {@link module:ol/layer/Layer~Layer} sources.\n *\n * A generic `change` event is triggered when the state of the source changes.\n * @abstract\n * @api\n */\nvar Source = /*@__PURE__*/(function (BaseObject) {\n function Source(options) {\n\n BaseObject.call(this);\n\n /**\n * @private\n * @type {import(\"../proj/Projection.js\").default}\n */\n this.projection_ = getProjection(options.projection);\n\n /**\n * @private\n * @type {?Attribution}\n */\n this.attributions_ = adaptAttributions(options.attributions);\n\n /**\n * @private\n * @type {boolean}\n */\n this.attributionsCollapsible_ = options.attributionsCollapsible !== undefined ?\n options.attributionsCollapsible : true;\n\n /**\n * This source is currently loading data. Sources that defer loading to the\n * map's tile queue never set this to `true`.\n * @type {boolean}\n */\n this.loading = false;\n\n /**\n * @private\n * @type {SourceState}\n */\n this.state_ = options.state !== undefined ?\n options.state : SourceState.READY;\n\n /**\n * @private\n * @type {boolean}\n */\n this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false;\n\n }\n\n if ( BaseObject ) Source.__proto__ = BaseObject;\n Source.prototype = Object.create( BaseObject && BaseObject.prototype );\n Source.prototype.constructor = Source;\n\n /**\n * Get the attribution function for the source.\n * @return {?Attribution} Attribution function.\n */\n Source.prototype.getAttributions = function getAttributions () {\n return this.attributions_;\n };\n\n /**\n * @return {boolean} Aattributions are collapsible.\n */\n Source.prototype.getAttributionsCollapsible = function getAttributionsCollapsible () {\n return this.attributionsCollapsible_;\n };\n\n /**\n * Get the projection of the source.\n * @return {import(\"../proj/Projection.js\").default} Projection.\n * @api\n */\n Source.prototype.getProjection = function getProjection () {\n return this.projection_;\n };\n\n /**\n * @abstract\n * @return {Array|undefined} Resolutions.\n */\n Source.prototype.getResolutions = function getResolutions () {\n return abstract();\n };\n\n /**\n * Get the state of the source, see {@link module:ol/source/State~State} for possible states.\n * @return {SourceState} State.\n * @api\n */\n Source.prototype.getState = function getState () {\n return this.state_;\n };\n\n /**\n * @return {boolean|undefined} Wrap X.\n */\n Source.prototype.getWrapX = function getWrapX () {\n return this.wrapX_;\n };\n\n /**\n * Refreshes the source and finally dispatches a 'change' event.\n * @api\n */\n Source.prototype.refresh = function refresh () {\n this.changed();\n };\n\n /**\n * Set the attributions of the source.\n * @param {AttributionLike|undefined} attributions Attributions.\n * Can be passed as `string`, `Array`, `{@link module:ol/source/Source~Attribution}`,\n * or `undefined`.\n * @api\n */\n Source.prototype.setAttributions = function setAttributions (attributions) {\n this.attributions_ = adaptAttributions(attributions);\n this.changed();\n };\n\n /**\n * Set the state of the source.\n * @param {SourceState} state State.\n * @protected\n */\n Source.prototype.setState = function setState (state) {\n this.state_ = state;\n this.changed();\n };\n\n return Source;\n}(BaseObject));\n\n\n/**\n * Turns the attributions option into an attributions function.\n * @param {AttributionLike|undefined} attributionLike The attribution option.\n * @return {?Attribution} An attribution function (or null).\n */\nfunction adaptAttributions(attributionLike) {\n if (!attributionLike) {\n return null;\n }\n if (Array.isArray(attributionLike)) {\n return function(frameState) {\n return attributionLike;\n };\n }\n\n if (typeof attributionLike === 'function') {\n return attributionLike;\n }\n\n return function(frameState) {\n return [attributionLike];\n };\n}\n\n\nexport default Source;\n\n//# sourceMappingURL=Source.js.map","/**\n * @module ol/style/Circle\n */\n\nimport RegularShape from './RegularShape.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {import(\"./Fill.js\").default} [fill] Fill style.\n * @property {number} radius Circle radius.\n * @property {import(\"./Stroke.js\").default} [stroke] Stroke style.\n * @property {import(\"./AtlasManager.js\").default} [atlasManager] The atlas manager to use for this circle.\n * When using WebGL it is recommended to use an atlas manager to avoid texture switching. If an atlas manager is given,\n * the circle is added to an atlas. By default no atlas manager is used.\n */\n\n\n/**\n * @classdesc\n * Set circle style for vector features.\n * @api\n */\nvar CircleStyle = /*@__PURE__*/(function (RegularShape) {\n function CircleStyle(opt_options) {\n\n var options = opt_options || /** @type {Options} */ ({});\n\n RegularShape.call(this, {\n points: Infinity,\n fill: options.fill,\n radius: options.radius,\n stroke: options.stroke,\n atlasManager: options.atlasManager\n });\n\n }\n\n if ( RegularShape ) CircleStyle.__proto__ = RegularShape;\n CircleStyle.prototype = Object.create( RegularShape && RegularShape.prototype );\n CircleStyle.prototype.constructor = CircleStyle;\n\n /**\n * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {CircleStyle} The cloned style.\n * @override\n * @api\n */\n CircleStyle.prototype.clone = function clone () {\n var style = new CircleStyle({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n radius: this.getRadius(),\n atlasManager: this.atlasManager_\n });\n style.setOpacity(this.getOpacity());\n style.setScale(this.getScale());\n return style;\n };\n\n /**\n * Set the circle radius.\n *\n * @param {number} radius Circle radius.\n * @api\n */\n CircleStyle.prototype.setRadius = function setRadius (radius) {\n this.radius_ = radius;\n this.render_(this.atlasManager_);\n };\n\n return CircleStyle;\n}(RegularShape));\n\n\nexport default CircleStyle;\n\n//# sourceMappingURL=Circle.js.map","/**\n * @module ol/style/RegularShape\n */\n\nimport {asString} from '../color.js';\nimport {asColorLike} from '../colorlike.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {CANVAS_LINE_DASH} from '../has.js';\nimport ImageState from '../ImageState.js';\nimport {defaultStrokeStyle, defaultFillStyle, defaultLineCap, defaultLineWidth, defaultLineJoin, defaultMiterLimit} from '../render/canvas.js';\nimport ImageStyle from './Image.js';\n\n\n/**\n * Specify radius for regular polygons, or radius1 and radius2 for stars.\n * @typedef {Object} Options\n * @property {import(\"./Fill.js\").default} [fill] Fill style.\n * @property {number} points Number of points for stars and regular polygons. In case of a polygon, the number of points\n * is the number of sides.\n * @property {number} [radius] Radius of a regular polygon.\n * @property {number} [radius1] Outer radius of a star.\n * @property {number} [radius2] Inner radius of a star.\n * @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's point facing up.\n * @property {import(\"./Stroke.js\").default} [stroke] Stroke style.\n * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).\n * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.\n * @property {import(\"./AtlasManager.js\").default} [atlasManager] The atlas manager to use for this symbol. When\n * using WebGL it is recommended to use an atlas manager to avoid texture switching. If an atlas manager is given, the\n * symbol is added to an atlas. By default no atlas manager is used.\n */\n\n\n/**\n * @typedef {Object} RenderOptions\n * @property {import(\"../colorlike.js\").ColorLike} [strokeStyle]\n * @property {number} strokeWidth\n * @property {number} size\n * @property {string} lineCap\n * @property {Array} lineDash\n * @property {number} lineDashOffset\n * @property {string} lineJoin\n * @property {number} miterLimit\n */\n\n\n/**\n * @classdesc\n * Set regular shape style for vector features. The resulting shape will be\n * a regular polygon when `radius` is provided, or a star when `radius1` and\n * `radius2` are provided.\n * @api\n */\nvar RegularShape = /*@__PURE__*/(function (ImageStyle) {\n function RegularShape(options) {\n /**\n * @type {boolean}\n */\n var rotateWithView = options.rotateWithView !== undefined ?\n options.rotateWithView : false;\n\n ImageStyle.call(this, {\n opacity: 1,\n rotateWithView: rotateWithView,\n rotation: options.rotation !== undefined ? options.rotation : 0,\n scale: 1\n });\n\n /**\n * @private\n * @type {Array}\n */\n this.checksums_ = null;\n\n /**\n * @private\n * @type {HTMLCanvasElement}\n */\n this.canvas_ = null;\n\n /**\n * @private\n * @type {HTMLCanvasElement}\n */\n this.hitDetectionCanvas_ = null;\n\n /**\n * @private\n * @type {import(\"./Fill.js\").default}\n */\n this.fill_ = options.fill !== undefined ? options.fill : null;\n\n /**\n * @private\n * @type {Array}\n */\n this.origin_ = [0, 0];\n\n /**\n * @private\n * @type {number}\n */\n this.points_ = options.points;\n\n /**\n * @protected\n * @type {number}\n */\n this.radius_ = /** @type {number} */ (options.radius !== undefined ?\n options.radius : options.radius1);\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.radius2_ = options.radius2;\n\n /**\n * @private\n * @type {number}\n */\n this.angle_ = options.angle !== undefined ? options.angle : 0;\n\n /**\n * @private\n * @type {import(\"./Stroke.js\").default}\n */\n this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n /**\n * @private\n * @type {Array}\n */\n this.anchor_ = null;\n\n /**\n * @private\n * @type {import(\"../size.js\").Size}\n */\n this.size_ = null;\n\n /**\n * @private\n * @type {import(\"../size.js\").Size}\n */\n this.imageSize_ = null;\n\n /**\n * @private\n * @type {import(\"../size.js\").Size}\n */\n this.hitDetectionImageSize_ = null;\n\n /**\n * @protected\n * @type {import(\"./AtlasManager.js\").default|undefined}\n */\n this.atlasManager_ = options.atlasManager;\n\n this.render_(this.atlasManager_);\n\n }\n\n if ( ImageStyle ) RegularShape.__proto__ = ImageStyle;\n RegularShape.prototype = Object.create( ImageStyle && ImageStyle.prototype );\n RegularShape.prototype.constructor = RegularShape;\n\n /**\n * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.\n * @return {RegularShape} The cloned style.\n * @api\n */\n RegularShape.prototype.clone = function clone () {\n var style = new RegularShape({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n points: this.getPoints(),\n radius: this.getRadius(),\n radius2: this.getRadius2(),\n angle: this.getAngle(),\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n atlasManager: this.atlasManager_\n });\n style.setOpacity(this.getOpacity());\n style.setScale(this.getScale());\n return style;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n RegularShape.prototype.getAnchor = function getAnchor () {\n return this.anchor_;\n };\n\n /**\n * Get the angle used in generating the shape.\n * @return {number} Shape's rotation in radians.\n * @api\n */\n RegularShape.prototype.getAngle = function getAngle () {\n return this.angle_;\n };\n\n /**\n * Get the fill style for the shape.\n * @return {import(\"./Fill.js\").default} Fill style.\n * @api\n */\n RegularShape.prototype.getFill = function getFill () {\n return this.fill_;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.getHitDetectionImage = function getHitDetectionImage (pixelRatio) {\n return this.hitDetectionCanvas_;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n RegularShape.prototype.getImage = function getImage (pixelRatio) {\n return this.canvas_;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.getImageSize = function getImageSize () {\n return this.imageSize_;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.getHitDetectionImageSize = function getHitDetectionImageSize () {\n return this.hitDetectionImageSize_;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.getImageState = function getImageState () {\n return ImageState.LOADED;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n RegularShape.prototype.getOrigin = function getOrigin () {\n return this.origin_;\n };\n\n /**\n * Get the number of points for generating the shape.\n * @return {number} Number of points for stars and regular polygons.\n * @api\n */\n RegularShape.prototype.getPoints = function getPoints () {\n return this.points_;\n };\n\n /**\n * Get the (primary) radius for the shape.\n * @return {number} Radius.\n * @api\n */\n RegularShape.prototype.getRadius = function getRadius () {\n return this.radius_;\n };\n\n /**\n * Get the secondary radius for the shape.\n * @return {number|undefined} Radius2.\n * @api\n */\n RegularShape.prototype.getRadius2 = function getRadius2 () {\n return this.radius2_;\n };\n\n /**\n * @inheritDoc\n * @api\n */\n RegularShape.prototype.getSize = function getSize () {\n return this.size_;\n };\n\n /**\n * Get the stroke style for the shape.\n * @return {import(\"./Stroke.js\").default} Stroke style.\n * @api\n */\n RegularShape.prototype.getStroke = function getStroke () {\n return this.stroke_;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.listenImageChange = function listenImageChange (listener, thisArg) {\n return undefined;\n };\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.load = function load () {};\n\n /**\n * @inheritDoc\n */\n RegularShape.prototype.unlistenImageChange = function unlistenImageChange (listener, thisArg) {};\n\n /**\n * @protected\n * @param {import(\"./AtlasManager.js\").default|undefined} atlasManager An atlas manager.\n */\n RegularShape.prototype.render_ = function render_ (atlasManager) {\n var imageSize;\n var lineCap = '';\n var lineJoin = '';\n var miterLimit = 0;\n var lineDash = null;\n var lineDashOffset = 0;\n var strokeStyle;\n var strokeWidth = 0;\n\n if (this.stroke_) {\n strokeStyle = this.stroke_.getColor();\n if (strokeStyle === null) {\n strokeStyle = defaultStrokeStyle;\n }\n strokeStyle = asColorLike(strokeStyle);\n strokeWidth = this.stroke_.getWidth();\n if (strokeWidth === undefined) {\n strokeWidth = defaultLineWidth;\n }\n lineDash = this.stroke_.getLineDash();\n lineDashOffset = this.stroke_.getLineDashOffset();\n if (!CANVAS_LINE_DASH) {\n lineDash = null;\n lineDashOffset = 0;\n }\n lineJoin = this.stroke_.getLineJoin();\n if (lineJoin === undefined) {\n lineJoin = defaultLineJoin;\n }\n lineCap = this.stroke_.getLineCap();\n if (lineCap === undefined) {\n lineCap = defaultLineCap;\n }\n miterLimit = this.stroke_.getMiterLimit();\n if (miterLimit === undefined) {\n miterLimit = defaultMiterLimit;\n }\n }\n\n var size = 2 * (this.radius_ + strokeWidth) + 1;\n\n /** @type {RenderOptions} */\n var renderOptions = {\n strokeStyle: strokeStyle,\n strokeWidth: strokeWidth,\n size: size,\n lineCap: lineCap,\n lineDash: lineDash,\n lineDashOffset: lineDashOffset,\n lineJoin: lineJoin,\n miterLimit: miterLimit\n };\n\n if (atlasManager === undefined) {\n // no atlas manager is used, create a new canvas\n var context = createCanvasContext2D(size, size);\n this.canvas_ = context.canvas;\n\n // canvas.width and height are rounded to the closest integer\n size = this.canvas_.width;\n imageSize = size;\n\n this.draw_(renderOptions, context, 0, 0);\n\n this.createHitDetectionCanvas_(renderOptions);\n } else {\n // an atlas manager is used, add the symbol to an atlas\n size = Math.round(size);\n\n var hasCustomHitDetectionImage = !this.fill_;\n var renderHitDetectionCallback;\n if (hasCustomHitDetectionImage) {\n // render the hit-detection image into a separate atlas image\n renderHitDetectionCallback =\n this.drawHitDetectionCanvas_.bind(this, renderOptions);\n }\n\n var id = this.getChecksum();\n var info = atlasManager.add(\n id, size, size, this.draw_.bind(this, renderOptions),\n renderHitDetectionCallback);\n\n this.canvas_ = info.image;\n this.origin_ = [info.offsetX, info.offsetY];\n imageSize = info.image.width;\n\n if (hasCustomHitDetectionImage) {\n this.hitDetectionCanvas_ = info.hitImage;\n this.hitDetectionImageSize_ =\n [info.hitImage.width, info.hitImage.height];\n } else {\n this.hitDetectionCanvas_ = this.canvas_;\n this.hitDetectionImageSize_ = [imageSize, imageSize];\n }\n }\n\n this.anchor_ = [size / 2, size / 2];\n this.size_ = [size, size];\n this.imageSize_ = [imageSize, imageSize];\n };\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The rendering context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\n RegularShape.prototype.draw_ = function draw_ (renderOptions, context, x, y) {\n var i, angle0, radiusC;\n // reset transform\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n // then move to (x, y)\n context.translate(x, y);\n\n context.beginPath();\n\n var points = this.points_;\n if (points === Infinity) {\n context.arc(\n renderOptions.size / 2, renderOptions.size / 2,\n this.radius_, 0, 2 * Math.PI, true);\n } else {\n var radius2 = (this.radius2_ !== undefined) ? this.radius2_\n : this.radius_;\n if (radius2 !== this.radius_) {\n points = 2 * points;\n }\n for (i = 0; i <= points; i++) {\n angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;\n radiusC = i % 2 === 0 ? this.radius_ : radius2;\n context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n renderOptions.size / 2 + radiusC * Math.sin(angle0));\n }\n }\n\n\n if (this.fill_) {\n var color = this.fill_.getColor();\n if (color === null) {\n color = defaultFillStyle;\n }\n context.fillStyle = asColorLike(color);\n context.fill();\n }\n if (this.stroke_) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.lineCap = /** @type {CanvasLineCap} */ (renderOptions.lineCap);\n context.lineJoin = /** @type {CanvasLineJoin} */ (renderOptions.lineJoin);\n context.miterLimit = renderOptions.miterLimit;\n context.stroke();\n }\n context.closePath();\n };\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n */\n RegularShape.prototype.createHitDetectionCanvas_ = function createHitDetectionCanvas_ (renderOptions) {\n this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];\n if (this.fill_) {\n this.hitDetectionCanvas_ = this.canvas_;\n return;\n }\n\n // if no fill style is set, create an extra hit-detection image with a\n // default fill style\n var context = createCanvasContext2D(renderOptions.size, renderOptions.size);\n this.hitDetectionCanvas_ = context.canvas;\n\n this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);\n };\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The context.\n * @param {number} x The origin for the symbol (x).\n * @param {number} y The origin for the symbol (y).\n */\n RegularShape.prototype.drawHitDetectionCanvas_ = function drawHitDetectionCanvas_ (renderOptions, context, x, y) {\n // reset transform\n context.setTransform(1, 0, 0, 1, 0, 0);\n\n // then move to (x, y)\n context.translate(x, y);\n\n context.beginPath();\n\n var points = this.points_;\n if (points === Infinity) {\n context.arc(\n renderOptions.size / 2, renderOptions.size / 2,\n this.radius_, 0, 2 * Math.PI, true);\n } else {\n var radius2 = (this.radius2_ !== undefined) ? this.radius2_\n : this.radius_;\n if (radius2 !== this.radius_) {\n points = 2 * points;\n }\n var i, radiusC, angle0;\n for (i = 0; i <= points; i++) {\n angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;\n radiusC = i % 2 === 0 ? this.radius_ : radius2;\n context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),\n renderOptions.size / 2 + radiusC * Math.sin(angle0));\n }\n }\n\n context.fillStyle = asString(defaultFillStyle);\n context.fill();\n if (this.stroke_) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.stroke();\n }\n context.closePath();\n };\n\n /**\n * @return {string} The checksum.\n */\n RegularShape.prototype.getChecksum = function getChecksum () {\n var strokeChecksum = this.stroke_ ?\n this.stroke_.getChecksum() : '-';\n var fillChecksum = this.fill_ ?\n this.fill_.getChecksum() : '-';\n\n var recalculate = !this.checksums_ ||\n (strokeChecksum != this.checksums_[1] ||\n fillChecksum != this.checksums_[2] ||\n this.radius_ != this.checksums_[3] ||\n this.radius2_ != this.checksums_[4] ||\n this.angle_ != this.checksums_[5] ||\n this.points_ != this.checksums_[6]);\n\n if (recalculate) {\n var checksum = 'r' + strokeChecksum + fillChecksum +\n (this.radius_ !== undefined ? this.radius_.toString() : '-') +\n (this.radius2_ !== undefined ? this.radius2_.toString() : '-') +\n (this.angle_ !== undefined ? this.angle_.toString() : '-') +\n (this.points_ !== undefined ? this.points_.toString() : '-');\n this.checksums_ = [checksum, strokeChecksum, fillChecksum,\n this.radius_, this.radius2_, this.angle_, this.points_];\n }\n\n return /** @type {string} */ (this.checksums_[0]);\n };\n\n return RegularShape;\n}(ImageStyle));\n\n\nexport default RegularShape;\n\n//# sourceMappingURL=RegularShape.js.map","/**\n * @module ol/style/Fill\n */\nimport {getUid} from '../util.js';\nimport {asString} from '../color.js';\n\n\n/**\n * @typedef {Object} Options\n * @property {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} [color] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n */\n\n\n/**\n * @classdesc\n * Set fill style for vector features.\n * @api\n */\nvar Fill = function Fill(opt_options) {\n\n var options = opt_options || {};\n\n /**\n * @private\n * @type {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n\n /**\n * @private\n * @type {string|undefined}\n */\n this.checksum_ = undefined;\n};\n\n/**\n * Clones the style. The color is not cloned if it is an {@link module:ol/colorlike~ColorLike}.\n * @return {Fill} The cloned style.\n * @api\n */\nFill.prototype.clone = function clone () {\n var color = this.getColor();\n return new Fill({\n color: Array.isArray(color) ? color.slice() : color || undefined\n });\n};\n\n/**\n * Get the fill color.\n * @return {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} Color.\n * @api\n */\nFill.prototype.getColor = function getColor () {\n return this.color_;\n};\n\n/**\n * Set the color.\n *\n * @param {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} color Color.\n * @api\n */\nFill.prototype.setColor = function setColor (color) {\n this.color_ = color;\n this.checksum_ = undefined;\n};\n\n/**\n * @return {string} The checksum.\n */\nFill.prototype.getChecksum = function getChecksum () {\n if (this.checksum_ === undefined) {\n var color = this.color_;\n if (color) {\n if (Array.isArray(color) || typeof color == 'string') {\n this.checksum_ = 'f' + asString(/** @type {import(\"../color.js\").Color|string} */ (color));\n } else {\n this.checksum_ = getUid(this.color_);\n }\n } else {\n this.checksum_ = 'f-';\n }\n }\n\n return this.checksum_;\n};\n\nexport default Fill;\n\n//# sourceMappingURL=Fill.js.map","/**\n * @module ol/style/Style\n */\n\n/**\n * Feature styles.\n *\n * If no style is defined, the following default style is used:\n * ```js\n * import {Fill, Stroke, Circle, Style} from 'ol/style';\n *\n * var fill = new Fill({\n * color: 'rgba(255,255,255,0.4)'\n * });\n * var stroke = new Stroke({\n * color: '#3399CC',\n * width: 1.25\n * });\n * var styles = [\n * new Style({\n * image: new Circle({\n * fill: fill,\n * stroke: stroke,\n * radius: 5\n * }),\n * fill: fill,\n * stroke: stroke\n * })\n * ];\n * ```\n *\n * A separate editing style has the following defaults:\n * ```js\n * import {Fill, Stroke, Circle, Style} from 'ol/style';\n * import GeometryType from 'ol/geom/GeometryType';\n *\n * var white = [255, 255, 255, 1];\n * var blue = [0, 153, 255, 1];\n * var width = 3;\n * styles[GeometryType.POLYGON] = [\n * new Style({\n * fill: new Fill({\n * color: [255, 255, 255, 0.5]\n * })\n * })\n * ];\n * styles[GeometryType.MULTI_POLYGON] =\n * styles[GeometryType.POLYGON];\n * styles[GeometryType.LINE_STRING] = [\n * new Style({\n * stroke: new Stroke({\n * color: white,\n * width: width + 2\n * })\n * }),\n * new Style({\n * stroke: new Stroke({\n * color: blue,\n * width: width\n * })\n * })\n * ];\n * styles[GeometryType.MULTI_LINE_STRING] =\n * styles[GeometryType.LINE_STRING];\n * styles[GeometryType.POINT] = [\n * new Style({\n * image: new Circle({\n * radius: width * 2,\n * fill: new Fill({\n * color: blue\n * }),\n * stroke: new Stroke({\n * color: white,\n * width: width / 2\n * })\n * }),\n * zIndex: Infinity\n * })\n * ];\n * styles[GeometryType.MULTI_POINT] =\n * styles[GeometryType.POINT];\n * styles[GeometryType.GEOMETRY_COLLECTION] =\n * styles[GeometryType.POLYGON].concat(\n * styles[GeometryType.LINE_STRING],\n * styles[GeometryType.POINT]\n * );\n * ```\n */\nimport {assert} from '../asserts.js';\nimport GeometryType from '../geom/GeometryType.js';\nimport CircleStyle from './Circle.js';\nimport Fill from './Fill.js';\nimport Stroke from './Stroke.js';\n\n\n/**\n * A function that takes an {@link module:ol/Feature} and a `{number}`\n * representing the view's resolution. The function should return a\n * {@link module:ol/style/Style} or an array of them. This way e.g. a\n * vector layer can be styled.\n *\n * @typedef {function(import(\"../Feature.js\").FeatureLike, number):(Style|Array