/*!
 * @brief French Geoportal Extension for Leaflet
 *
 * This software is released under the licence CeCILL-B (Free BSD compatible)
 * @see http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
 * @see http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
 * @see http://www.cecill.info/
 *
 * @copyright copyright (c) IGN 
 * @license CeCILL-B
 * @author IGN
 * @version 2.4.1
 * @date 05/06/2024
 *
 */

/*!
 * @overview  Proj4Leaflet - Smooth Proj4js integration with Leaflet
 * @copyright Copyright (c) 2012, Kartena AB
 * @license   BSD 2-Clause "Simplified" License
 *            See https://raw.githubusercontent.com/kartena/Proj4Leaflet/master/LICENSE
 * @version 1.0.2
 */

/*!
 * @overview  leaflet-draw - Vector drawing and editing plugin for Leaflet 
 * @copyright Copyright (c) 2012-2017 Jon West, Jacob Toye, and Leaflet
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/Leaflet/Leaflet.draw/master/MIT-LICENSE.md
 * @version   1.0.4
 */

/*!
 * Sortable -- JavaScript library for reorderable drag-and-drop lists on modern
 * browsers and touch devices. No jQuery required. Supports Meteor, AngularJS,
 * React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.
 *
 * Released under MIT LICENSE
 *
 * Copyright Lebedev Konstantin <ibnRubaXa@gmail.com>
 * https://github.com/SortableJS/Sortable
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @version 1.14.0
 */

/*!
 * @overview  es6-promise - a tiny implementation of Promises/A+.
 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
 * @version   v4.2.4
 */

/*!
 * @overview   Proj4js - Javascript reprojection library.
 *
 * @authors
 * - Mike Adair madairATdmsolutions.ca
 * - Richard Greenwood richATgreenwoodmap.com
 * - Didier Richard didier.richardATign.fr
 * - Stephen Irons stephen.ironsATclear.net.nz
 * - Olivier Terral oterralATgmail.com
 * - Calvin Metcalf cmetcalfATappgeo.com
 *
 * @copyright Copyright (c) 2014, Mike Adair, Richard Greenwood, Didier Richard, Stephen Irons, Olivier Terral and Calvin Metcalf
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/proj4js/proj4js/master/LICENSE.md
 * @version   2.7.5
 */

(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("leaflet"), require("node-fetch"));
	else if(typeof define === 'function' && define.amd)
		define("Gp", ["leaflet", "require"], factory);
	else if(typeof exports === 'object')
		exports["Gp"] = factory(require("leaflet"), require("node-fetch"));
	else
		root["Gp"] = factory(root["L"], root[undefined]);
})(this, function(__WEBPACK_EXTERNAL_MODULE__2__, __WEBPACK_EXTERNAL_MODULE__53__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Services", function() { return Services; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Error", function() { return Error; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Helper", function() { return Helper; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Protocols", function() { return Protocols; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "servicesDate", function() { return servicesDate; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "servicesVersion", function() { return servicesVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "leafletExtVersion", function() { return leafletExtVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "leafletExtDate", function() { return leafletExtDate; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Config", function() { return Config; });
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
var _package_json__WEBPACK_IMPORTED_MODULE_0___namespace = /*#__PURE__*/__webpack_require__.t(1, 1);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony reexport (default from non-harmony) */ __webpack_require__.d(__webpack_exports__, "LExtended", function() { return leaflet__WEBPACK_IMPORTED_MODULE_1___default.a; });
/* harmony import */ var _Common_Styles__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _Styles__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(22);
/* harmony import */ var _Controls_Controls__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(33);
/* harmony import */ var _Controls_ElevationPath__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(131);
/* harmony import */ var _Layers_Layers__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(135);
/* harmony import */ var _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(113);
/* harmony import */ var _Common_Utils_AutoLoadConfig__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(141);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(41);
/* harmony import */ var _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(137);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "LayerUtils", function() { return _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_10__["default"]; });

/* harmony import */ var _Common_Utils_ProxyUtils__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(142);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ProxyUtils", function() { return _Common_Utils_ProxyUtils__WEBPACK_IMPORTED_MODULE_11__["default"]; });

/* harmony import */ var _Common_Utils_ColorUtils__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(143);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ColorUtils", function() { return _Common_Utils_ColorUtils__WEBPACK_IMPORTED_MODULE_12__["default"]; });

/* harmony import */ var _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(111);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MathUtils", function() { return _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_13__["default"]; });

/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(35);
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Logger", function() { return _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_14__["default"]; });

/**
* Global variable Gp.
*
* @module Gp
* @alias Gp
* @desc
*
* This is the global variable that is exposed in the browser environment.
* Content is composed of constructor, functions and properties...
*
* > Config:  (...)
*
* > ColorUtils: (...)
* > LayerUtils: (...)
* > MathUtils: (...)
* > ProxyUtils: (...)
* > Logger: (...)
*
* > LExtended: (...)
*
* > leafletExtDate: "YYYY-MM-DD"
* > leafletExtVersion: "X.X.X"
*
* > Error: (...)
* > Helper: (...)
* > Protocols: (...)
* > Services: (...)
* > servicesDate: "YYYY-MM-DD"
* > servicesVersion: "X.X.X"
*
* The following variables are aslo global :
*   - proj4,
*   - L
*/




// CSS communes aux extensions !





// import WMTS from "./Layers/WMTS";
// import WMS from "./Layers/WMS";



// Autoload...


// export des services


// reconstruction des ns
var Services = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].Services;
var Error = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].Error;
var Helper = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].Helper;
var Protocols = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].Protocols;
var servicesDate = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].servicesDate;
var servicesVersion = geoportal_access_lib__WEBPACK_IMPORTED_MODULE_9__["default"].servicesVersion;


// Rajout des propriétés de l'extension dans le namespace
/** Version */
var leafletExtVersion = _package_json__WEBPACK_IMPORTED_MODULE_0__.leafletExtVersion || _package_json__WEBPACK_IMPORTED_MODULE_0__.version;
/** Publication date */
var leafletExtDate = _package_json__WEBPACK_IMPORTED_MODULE_0__.date;

// Classes utilitaires






// HACK !?
var Config = window.Gp ? window.Gp.Config : {};

// creation du namespace pour les extensions leaflet
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalLayer = _Layers_Layers__WEBPACK_IMPORTED_MODULE_6__["default"]; // WMS et WMTS
// L.geoportalLayers = {};
// L.geoportalLayers.WMTS = WMTS;
// L.geoportalLayers.WMS = WMS;
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalControl = _Controls_Controls__WEBPACK_IMPORTED_MODULE_4__["default"]; // IsoChrone, SearchEngine, ...

leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalControl.ElevationPath.DISPLAY_PROFILE_LIB_D3 = _Controls_ElevationPath__WEBPACK_IMPORTED_MODULE_5__["default"].DISPLAY_PROFILE_LIB_D3;
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalControl.ElevationPath.DISPLAY_PROFILE_LIB_AMCHARTS = _Controls_ElevationPath__WEBPACK_IMPORTED_MODULE_5__["default"].DISPLAY_PROFILE_LIB_AMCHARTS;
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalControl.ElevationPath.DISPLAY_PROFILE_RAW = _Controls_ElevationPath__WEBPACK_IMPORTED_MODULE_5__["default"].DISPLAY_PROFILE_RAW;
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalControl.ElevationPath.DISPLAY_PROFILE_BY_DEFAULT = _Controls_ElevationPath__WEBPACK_IMPORTED_MODULE_5__["default"].DISPLAY_PROFILE_BY_DEFAULT;
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalCRS = _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"]; // lambert 93 et lambert 2 étendu
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalCRS.EPSG2154 = _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"].EPSG2154(); // lambert 93
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalCRS.EPSG27572 = _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"].EPSG27572(); // lambert 2 étendu
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoportalCRS.EPSG4326 = _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"].EPSG4326();


/***/ }),
/* 1 */
/***/ (function(module) {

module.exports = JSON.parse("{\"name\":\"geoportal-extensions\",\"description\":\"French Geoportal Extensions for OpenLayers, Leaflet and iTowns libraries\",\"version\":\"3.0.4\",\"date\":\"05/06/2024\",\"leafletExtName\":\"French Geoportal Extension for Leaflet\",\"leafletExtVersion\":\"2.4.1\",\"olExtName\":\"French Geoportal Extension for OpenLayers\",\"olExtVersion\":\"3.4.4\",\"itownsExtName\":\"French Geoportal Extension for Itowns\",\"itownsExtVersion\":\"2.5.1\",\"main\":\"dist/leaflet/GpPluginLeaflet.js, dist/openlayers/GpPluginOpenLayers.js, dist/itowns/GpPluginItowns.js\",\"types\":\"dist/leaflet/index.d.ts, dist/openlayers/index.d.ts, dist/itowns/index.d.ts\",\"module\":\"src/Leaflet/index.js, src/OpenLayers/index.js, src/Itowns/index.js\",\"directories\":{},\"scripts\":{\"setup\":\"npm install\",\"clean\":\"echo \\\"Warning: target not yet implemented!\\\" && exit 0\",\"eslint\":\"eslint src/\",\"test\":\"npm run test:serve\",\"test:serve\":\"cd test && webpack-dev-server --hot --config webpack.test.serve.js\",\"sample\":\"npm run sample:serve\",\"sample:serve\":\"npm run sample:ol:serve\",\"sample:itowns:serve\":\"webpack-dev-server --config build/webpack/webpack.config.itowns --mode=development --https --open-page samples/index-itowns-map.html --content-base . --output-public-path '/dist/itowns/' --port 9001 --open\",\"sample:leaflet:serve\":\"webpack-dev-server --config build/webpack/webpack.config.leaflet --mode=development --https --open-page samples/index-leaflet-map.html --content-base . --output-public-path '/dist/leaflet/' --port 9001 --open\",\"sample:ol:serve\":\"webpack-dev-server --config build/webpack/webpack.config.openlayers --mode=development --https --open-page samples/index-openlayers-map.html --content-base . --output-public-path '/dist/openlayers/' --port 9001 --open\",\"generate-types:ol\":\"npx tsc -p build/types/tsconfig-openlayers.json\",\"generate-types:leaflet\":\"npx tsc -p build/types/tsconfig-leaflet.json\",\"generate-types:itowns\":\"npx tsc -p build/types/tsconfig-itowns.json\",\"generate-jsdoc:ol\":\"jsdoc -c build/jsdoc/jsdoc-openlayers.json\",\"generate-jsdoc:leaflet\":\"jsdoc -c build/jsdoc/jsdoc-leaflet.json\",\"generate-jsdoc:itowns\":\"jsdoc -c build/jsdoc/jsdoc-itowns.json\",\"doc\":\"npm run doc:serve\",\"doc:serve\":\"npm run doc:ol:serve\",\"doc:itowns:serve\":\"webpack-dev-server --hot  --config build/webpack/webpack.config.itowns --content-base jsdoc/itowns --port 9001 --open\",\"doc:leaflet:serve\":\"webpack-dev-server --hot  --config build/webpack/webpack.config.leaflet --content-base jsdoc/leaflet --port 9001 --open\",\"doc:ol:serve\":\"webpack-dev-server --hot  --config build/webpack/webpack.config.openlayers --content-base jsdoc/openlayers --port 9001 --open\",\"build:dev\":\"npm-run-all --print-label --print-name build:*:dev\",\"build:prod\":\"npm-run-all --print-label --print-name build:*:prod\",\"build:src\":\"npm-run-all --print-label --print-name build:*:src\",\"build\":\"npm-run-all --print-label --print-name build:*:*\",\"build:itowns\":\"npm-run-all --print-label --print-name build:itowns:*\",\"build:itowns:dev\":\"webpack --config build/webpack/webpack.config.itowns --mode=development\",\"build:itowns:prod\":\"webpack --config build/webpack/webpack.config.itowns --mode=production\",\"build:itowns:src\":\"webpack --config build/webpack/webpack.config.itowns --mode=none\",\"build:ol\":\"npm-run-all --print-label --print-name build:ol:*\",\"build:ol:dev\":\"webpack --config build/webpack/webpack.config.openlayers --mode=development\",\"build:ol:prod\":\"webpack --config build/webpack/webpack.config.openlayers --mode=production\",\"build:ol:src\":\"webpack --config build/webpack/webpack.config.openlayers --mode=none\",\"build:leaflet\":\"npm-run-all --print-label --print-name build:leaflet:*\",\"build:leaflet:dev\":\"webpack --config build/webpack/webpack.config.leaflet --mode=development\",\"build:leaflet:prod\":\"webpack --config build/webpack/webpack.config.leaflet --mode=production\",\"build:leaflet:src\":\"webpack --config build/webpack/webpack.config.leaflet --mode=none\"},\"repository\":{\"type\":\"git\",\"url\":\"https://github.com/IGNF/geoportal-extensions.git\"},\"author\":\"IGNF\",\"keywords\":[\"geoportail\",\"geoplateforme\",\"javascript\",\"OpenLayers\",\"Leaflet\",\"Itowns\",\"3D\"],\"license\":\"CECILL-B\",\"bugs\":{\"url\":\"https://github.com/IGNF/geoportal-extensions/issues\"},\"homepage\":\"https://github.com/IGNF/geoportal-extensions#readme\",\"dependencies\":{\"@mapbox/mapbox-gl-style-spec\":\"13.20.1\",\"eventbusjs\":\"0.2.0\",\"geoportal-access-lib\":\"3.4.2\",\"itowns\":\"2.38.2\",\"leaflet\":\"1.7.1\",\"leaflet-draw\":\"1.0.4\",\"loglevel\":\"^1.6.7\",\"markdown-toc\":\"^1.2.0\",\"ol\":\"6.9.0\",\"ol-mapbox-style\":\"6.7.0\",\"proj4\":\"2.7.5\",\"proj4leaflet\":\"1.0.2\",\"sortablejs\":\"1.14.0\",\"three\":\"0.137.5\",\"typescript\":\"^4.5.5\",\"whatwg-fetch\":\"3.0.0\"},\"devDependencies\":{\"@babel/core\":\"^7.4.4\",\"@babel/plugin-transform-template-literals\":\"^7.7.4\",\"@babel/preset-env\":\"^7.4.4\",\"babel-loader\":\"^8.0.5\",\"chai\":\"^4.2.0\",\"chalk\":\"^4.0.0\",\"clean-webpack-plugin\":\"^3.0.0\",\"copy-webpack-plugin\":\"^5.0.3\",\"core-js\":\"^3.6.4\",\"css-loader\":\"^3.4.2\",\"eslint\":\"^6.8.0\",\"eslint-config-standard\":\"^14.1.1\",\"eslint-loader\":\"^4.0.0\",\"eslint-plugin-import\":\"^2.17.2\",\"eslint-plugin-node\":\"^11.1.0\",\"eslint-plugin-promise\":\"^4.1.1\",\"eslint-plugin-standard\":\"^4.0.0\",\"exports-loader\":\"^0.7.0\",\"expose-loader\":\"^0.7.5\",\"fs-extra\":\"^9.0.0\",\"handlebars\":\"^4.7.5\",\"handlebars-layouts\":\"^3.1.4\",\"html-webpack-plugin\":\"^4.0.4\",\"jsdoc-webpack-plugin\":\"^0.3.0\",\"mini-css-extract-plugin\":\"^0.9.0\",\"mocha\":\"^7.1.1\",\"mocha-loader\":\"^5.0.0\",\"npm-run-all\":\"^4.1.5\",\"optimize-css-assets-webpack-plugin\":\"^5.0.1\",\"path\":\"^0.12.7\",\"replace-bundle-webpack-plugin\":\"^1.0.0\",\"requirejs\":\"^2.3.6\",\"responsive-loader\":\"^1.2.0\",\"speed-measure-webpack-plugin\":\"^1.3.0\",\"string-template\":\"^1.0.0\",\"style-loader\":\"^1.1.3\",\"terser-webpack-plugin\":\"^2.0.0\",\"url-loader\":\"^4.0.0\",\"webpack\":\"^4.30.0\",\"webpack-cli\":\"^3.3.1\",\"webpack-dev-server\":\"^3.3.1\",\"webpack-node-externals\":\"^1.7.2\"}}");

/***/ }),
/* 2 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE__2__;

/***/ }),
/* 3 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _CSS_GPboostRelief_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
/* harmony import */ var _CSS_GPboostRelief_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPboostRelief_css__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _CSS_GPbuildings_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
/* harmony import */ var _CSS_GPbuildings_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPbuildings_css__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _CSS_GPdrawing_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _CSS_GPdrawing_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPdrawing_css__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _CSS_GPelevationPath_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(7);
/* harmony import */ var _CSS_GPelevationPath_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPelevationPath_css__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _CSS_GPgeneralWidget_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8);
/* harmony import */ var _CSS_GPgeneralWidget_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPgeneralWidget_css__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _CSS_GPgetFeatureInfo_css__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
/* harmony import */ var _CSS_GPgetFeatureInfo_css__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPgetFeatureInfo_css__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _CSS_GPisochron_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(10);
/* harmony import */ var _CSS_GPisochron_css__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPisochron_css__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _CSS_GPlayerSwitcher_css__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(11);
/* harmony import */ var _CSS_GPlayerSwitcher_css__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPlayerSwitcher_css__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _CSS_GPlocation_css__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(12);
/* harmony import */ var _CSS_GPlocation_css__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPlocation_css__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var _CSS_GPmeasureArea_css__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(13);
/* harmony import */ var _CSS_GPmeasureArea_css__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPmeasureArea_css__WEBPACK_IMPORTED_MODULE_9__);
/* harmony import */ var _CSS_GPmeasureAzimuth_css__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(14);
/* harmony import */ var _CSS_GPmeasureAzimuth_css__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPmeasureAzimuth_css__WEBPACK_IMPORTED_MODULE_10__);
/* harmony import */ var _CSS_GPmeasureLength_css__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(15);
/* harmony import */ var _CSS_GPmeasureLength_css__WEBPACK_IMPORTED_MODULE_11___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPmeasureLength_css__WEBPACK_IMPORTED_MODULE_11__);
/* harmony import */ var _CSS_GPmeasureToolTip_css__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(16);
/* harmony import */ var _CSS_GPmeasureToolTip_css__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPmeasureToolTip_css__WEBPACK_IMPORTED_MODULE_12__);
/* harmony import */ var _CSS_GPmousePosition_css__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(17);
/* harmony import */ var _CSS_GPmousePosition_css__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPmousePosition_css__WEBPACK_IMPORTED_MODULE_13__);
/* harmony import */ var _CSS_GPreverseGeocoding_css__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(18);
/* harmony import */ var _CSS_GPreverseGeocoding_css__WEBPACK_IMPORTED_MODULE_14___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPreverseGeocoding_css__WEBPACK_IMPORTED_MODULE_14__);
/* harmony import */ var _CSS_GProute_css__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(19);
/* harmony import */ var _CSS_GProute_css__WEBPACK_IMPORTED_MODULE_15___default = /*#__PURE__*/__webpack_require__.n(_CSS_GProute_css__WEBPACK_IMPORTED_MODULE_15__);
/* harmony import */ var _CSS_GPsearchEngine_css__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(20);
/* harmony import */ var _CSS_GPsearchEngine_css__WEBPACK_IMPORTED_MODULE_16___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPsearchEngine_css__WEBPACK_IMPORTED_MODULE_16__);
/* harmony import */ var _CSS_GPwaiting_css__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(21);
/* harmony import */ var _CSS_GPwaiting_css__WEBPACK_IMPORTED_MODULE_17___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPwaiting_css__WEBPACK_IMPORTED_MODULE_17__);



















/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 20 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 21 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 22 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _CSS_GPgeneralWidgetLeaflet_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23);
/* harmony import */ var _CSS_GPgeneralWidgetLeaflet_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_CSS_GPgeneralWidgetLeaflet_css__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _CSS_Controls_ElevationPath_GPelevationPathLeaflet_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(24);
/* harmony import */ var _CSS_Controls_ElevationPath_GPelevationPathLeaflet_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_ElevationPath_GPelevationPathLeaflet_css__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _CSS_Controls_Isochrone_GPisochronLeaflet_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(25);
/* harmony import */ var _CSS_Controls_Isochrone_GPisochronLeaflet_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_Isochrone_GPisochronLeaflet_css__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _CSS_Controls_LayerSwitcher_GPlayerSwitcherLeaflet_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(26);
/* harmony import */ var _CSS_Controls_LayerSwitcher_GPlayerSwitcherLeaflet_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_LayerSwitcher_GPlayerSwitcherLeaflet_css__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _CSS_Controls_LocationSelector_GPlocationLeaflet_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(27);
/* harmony import */ var _CSS_Controls_LocationSelector_GPlocationLeaflet_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_LocationSelector_GPlocationLeaflet_css__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _CSS_Controls_MousePosition_GPmousePositionLeaflet_css__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28);
/* harmony import */ var _CSS_Controls_MousePosition_GPmousePositionLeaflet_css__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_MousePosition_GPmousePositionLeaflet_css__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _CSS_Controls_ReverseGeocoding_GPreverseGeocodingLeaflet_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(29);
/* harmony import */ var _CSS_Controls_ReverseGeocoding_GPreverseGeocodingLeaflet_css__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_ReverseGeocoding_GPreverseGeocodingLeaflet_css__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _CSS_Controls_Route_GProuteLeaflet_css__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(30);
/* harmony import */ var _CSS_Controls_Route_GProuteLeaflet_css__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_Route_GProuteLeaflet_css__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _CSS_Controls_SearchEngine_GPsearchEngineLeaflet_css__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(31);
/* harmony import */ var _CSS_Controls_SearchEngine_GPsearchEngineLeaflet_css__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_CSS_Controls_SearchEngine_GPsearchEngineLeaflet_css__WEBPACK_IMPORTED_MODULE_8__);
/* global true */

// En module ES6, on n'a pas besoin de ces CSS, car on utile le CSS géneré avec WebPack.
// L'utilisation de ces imports est utile lors de la creation du bundle...










// ce flag est substitué via le script de publication des sources du package...
if (true) {
  // plugin leaflet-draw !
  __webpack_require__(32);
}

/***/ }),
/* 23 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 24 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 25 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 26 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 27 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 28 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 29 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 30 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 31 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 32 */
/***/ (function(module, exports, __webpack_require__) {

// extracted by mini-css-extract-plugin

/***/ }),
/* 33 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _LayerSwitcher__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(34);
/* harmony import */ var _Isocurve__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(40);
/* harmony import */ var _MousePosition__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(110);
/* harmony import */ var _ReverseGeocoding__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(122);
/* harmony import */ var _Route__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(125);
/* harmony import */ var _SearchEngine__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(127);
/* harmony import */ var _ElevationPath__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(131);
/* harmony import */ var _Logo__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(134);









/**
 * Geoportal Controls Factory to be used together with Leaflet Maps.
 *
 * @module Controls
 * @alias L.geoportalControl
 * @example
 * var layerSwitcher = L.geoportalControl.LayerSwitcher(options);
 */
var Controls = {
  /**
   * Factory function for LayerSwitcher Control creation.
   *
   * @method LayerSwitcher
   * @static
   * @alias L.geoportalControl.LayerSwitcher
   * @param {Object} options - options for function call.
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.collapsed = true] - collapse mode, false by default
   * @param {Array}   [options.layers] - list of layers to be configured. Each array element is an object, with following properties :
   * @param {Object}  [options.layers.layer] - layer object
   * @param {Boolean} [options.layers.display] - display layer in widget layer list
   * @param {Object}  [options.layers.config] - layer display config
   * @param {String}  [options.layers.config.visibility] - layer visibility on map
   * @param {String}  [options.layers.config.title] - layer alias, to be displayed in widget layer list. E.g. : "Cartes IGN"
   * @param {String}  [options.layers.config.description] - layer description, to be displayed on title hover, or in layer information panel.
   * @param {String}  [options.layers.config.quicklookUrl] - link to a quick look image for this layer.
   * @param {Array}   [options.layers.config.legends] - array of layer legends. Each array element is an object, with following properties :
   *      - url (String, mandatory) : link to a legend
   *      - minScaleDenominator (Number, optional) : min scale denominator for legend validity.
   * @param {Array} [options.layers.config.metadata] - array of layer metadata. Each array element is an object, with property url (String, mandatory) : link to a metadata
   * @returns {L.geoportalControl.LayerSwitcher} - LayerSwitcher Object
   * @example
   *  layers = [
   *      {
   *          layer : wms1,
   *          display : false,
   *          config : {
   *              title : "test layer name 1",
   *              description : "test layer desc 1",
   *          }
   *      }
   *  ];
   *
   *  options = {
   *      position : "topright",
   *      collapsed : true,
   *      layers : layers
   *  };
   *
   *  var layerSwitcher = L.geoportalControl.LayerSwitcher(options);
   */
  LayerSwitcher: function LayerSwitcher(options) {
    return new _LayerSwitcher__WEBPACK_IMPORTED_MODULE_0__["default"](options);
  },
  /**
   * Factory function for Isocurve Control creation.
   *
   * @method Isocurve
   * @static
   * @alias L.geoportalControl.Isocurve
   * @param {Object} options - Isocurve control options
   * @param {String}   [options.apiKey] - API key for services call (isocurve and autocomplete services). The key "calcul" is used by default.
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.collapsed = true] - Specify if widget has to be collapsed (true) or not (false) on map loading. Default is true.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Object}  [options.exclusions = {"toll" : false, "tunnel" : false, "bridge" : false}] - list of exclusions with status (true = checked), by default : ["toll":false, "tunnel":false, "bridge":false].
   * @param {Array}   [options.graphs = ["Voiture", "Pieton"]] - list of graph resources to be used for isocurve calculation, by default : ["Voiture", "Pieton"]. The first element is selected.
   * @param {Array}   [options.methods = ["time", "distance"]] - list of methods, by default : ["time", "distance"]. The first element is selected by default.
   * @param {Array}   [options.directions = ["departure", "arrival"]] - list of directions to be displayed, by default : ["departure", "arrival"]. The first element is selected by default.
   *      Directions enable to specify if input location point will be used as a departure point ("departure") or as an arrival point ("arrival")
   * @param {Boolean} [options.disableReverse = false] - whether to enable/disable the reverse geocoding
   * @param {Object} [options.isocurveOptions = {}] - isocurve service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~isoCurve Gp.Services.isoCurve}
   * @param {Object} [options.autocompleteOptions = {}] - autocomplete service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~autoComplete Gp.Services.autoComplete}
   * @returns {L.geoportalControl.Isocurve} - Isocurve Object
   * @example
   *  var iso = L.geoportalControl.Isocurve({
   *      collapsed : false
   *      methods : ["time", "distance"],
   *      exclusions : {
   *         toll : true,
   *         bridge : false,
   *         tunnel : true
   *      },
   *      graphs : ["Pieton", "Voiture"],
   *      isocurveOptions : {},
   *      autocompleteOptions : {}
   *  });
   */
  Isocurve: function Isocurve(options) {
    return new _Isocurve__WEBPACK_IMPORTED_MODULE_1__["default"](options);
  },
  /**
   * Factory function for Geoportal MousePosition Control creation.
   *
   * @method MousePosition
   * @static
   * @alias L.geoportalControl.MousePosition
   * @param {Object} options - options for function call.
   * @param {String}   [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {String}  [options.position] - position of component into the map, 'bottomleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.collapsed = true] - collapse mode, false by default
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Array}   [options.systems] - list of projection systems, GEOGRAPHIC, MERCATOR, LAMB93 and LAMB2E by default
   *      Each array element (=system) is an object with following properties :
   * @param {String}  options.systems.crs - Proj4 crs alias (from proj4 defs). e.g. : "EPSG:4326". Required
   * @param {String}  [options.systems.label] - CRS label to be displayed in control. Default is crs code (e.g. "EPSG:4326")
   * @param {String}  [options.systems.type] - CRS units type for coordinates conversion : "Geographical" or "Metric". Default: "Metric"
   * @param {Object}  [options.systems.geoBBox] - Aera covered by the system (WGS84 coordinates).
   * @param {Number}  options.systems.geoBBox.right - Right bound.
   * @param {Number}  options.systems.geoBBox.left - Left bound.
   * @param {Number}  options.systems.geoBBox.top - Top bound.
   * @param {Number}  options.systems.geoBBox.bottom - Bottom bound.
   * @param {Array}   [options.units] - list of units by system, Geographical and Metric by default
   *      Values may be "DEC" (decimal degrees), "DMS" (sexagecimal), "RAD" (radians) and "GON" (grades) for geographical coordinates,
   *      and "M" or "KM" for metric coordinates
   * @param {Boolean} [options.displayAltitude = true] - active/desactivate the altitude panel, if desactivate, have just the coordinate panel, true by default
   * @param {Boolean} [options.displayCoordinates = true] - active/desactivate the coordinate panel, if desactivate, have just the altitude panel, true by default
   * @param {Boolean} [options.editCoordinates = false] - If true, coordinates from the MousePosition control can be edited by users to re-center the view. False by default.
   * @param {Object}  [options.altitude] - elevation configuration
   * @param {Object}  [options.altitude.serviceOptions] - options of elevation service. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~getAltitude Gp.Services.getAltitude}
   * @param {Number}  [options.altitude.responseDelay] - latency for altitude request, 500 ms by default
   * @param {Number}  [options.altitude.triggerDelay] - immobilisation time of movement on the map to trigger the elevation calculation, 200 ms by default
   * @param {Number}  [options.altitude.noDataValue] - value used for altitude service no data (default is -99999). In this case, "---m" will be displayed instead of "-99999m"
   * @param {Number}  [options.altitude.noDataValueTolerance] - tolerance for no data value :
   *                  values in [noDataValue - noDataValueTolerance ; noDataValue + noDataValueTolerance] interval will not be displayed, but "---m" will be displayed instead.
   *                  Default is 90000
   * @returns {L.geoportalControl.MousePosition} - MousePosition Object
   * @example
   *  var MousePosition = L.geoportalControl.MousePosition({
   *      position : 'bottomleft',
   *      collapsed : false,
   *      displayAltitude : true,
   *      editCoordinates : false,
   *      altitude : {
   *           triggerDelay : 100,
   *           responseDelay : 500,
   *           noDataValue : -99999,
   *           noDataValueTolerance : 90000,
   *           serviceOptions : {}
   *      },
   *      systems : [
   *       {
   *          crs : L.CRS.EPSG4326,
   *          label : "Lon,Lat",
   *          type : "Geographical"
   *        },
   *       {
   *          crs : L.geoportalCRS.EPSG2154,
   *          label : "Lambert 93",
   *          type : "Metric"
   *        }
   *      ],
   *      units : ["DEC", "DMS"]
   *  });
   */
  MousePosition: function MousePosition(options) {
    return new _MousePosition__WEBPACK_IMPORTED_MODULE_2__["default"](options);
  },
  /**
   * Factory function for Geoportal ReverseGeocode Control creation.
   *
   * @method ReverseGeocode
   * @static
   * @alias L.geoportalControl.ReverseGeocode
   * @extends {L.Control}
   * @param {Object} options - ReverseGeocoding control options
   * @param {String}  [options.apiKey] - API key for services call (reverse geocode service). The "calcul" key is used by default.
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.collapsed = true] - Specify if widget has to be collapsed (true) or not (false) on map loading. Default is true.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Array}  [options.resources =  ["StreetAddress", "PositionOfInterest", "CadastralParcel"]] - resources for geocoding, by default : ["StreetAddress", "PositionOfInterest"]
   * @param {Array}  [options.delimitations = ["Point", "Circle", "Extent"]] - delimitations for reverse geocoding, by default : ["Point", "Circle", "Extent"]
   * @param {Object}  [options.ReverseGeocodeOptions = {}] - reverse geocode service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~reverseGeocode Gp.Services.reverseGeocode} to know all reverse geocode options.
   * @returns {L.geoportalControl.ReverseGeocode} - ReverseGeocode Object
   * @fires reverse:onclickresult
   * @example
   *  var reverse = L.geoportalControl.ReverseGeocode({
   *      collapsed : false,
   *      position : "topright",
   *      resources : ["StreetAddress", "PositionOfInterest"],
   *      delimitations : ["Point", "Circle"],
   *      reverseGeocodeOptions : {}
   *  });
   * reverse.on("reverse:onclickresult", function (e) {
   *   console.log(e.data):
   * });
   */
  ReverseGeocode: function ReverseGeocode(options) {
    return new _ReverseGeocoding__WEBPACK_IMPORTED_MODULE_3__["default"](options);
  },
  /**
   * Factory function for Geoportal Route Control creation.
   *
   * @method Route
   * @static
   * @alias L.geoportalControl.Route
   * @extends {L.Control}
   * @param {Object} options - options for function call.
   * @param {String}   [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {String}  [options.position = "topleft"] - position of component into the map, 'topleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.collapsed = false] - collapse mode, false by default
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Boolean} [options.disableReverse = false] - whether to enable/disable the reverse geocoding when entering points.
   *   Active by default. But, you can disable it when entering with the "ctrl" key on the keyboard
   * @param {Object}  [options.exclusions = {"toll" : false, "tunnel" : false, "bridge" : false}] - list of exclusions with status
   * @param {Array}   [options.graphs = ["Voiture", "Pieton"]] - list of resources, by default : ["Voiture", "Pieton"], and the first element is selected.
   * @param {Object}  [options.autocompleteOptions = {}] - options of autocomplete service. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~autoComplete Gp.Services.autoComplete}
   * @param {Object}  [options.routeOptions = {}] - options of route service. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~route Gp.Services.route}
   * @returns {L.geoportalControl.Route} - Route Object
   * @example
   *  var route = L.geoportalControl.Route({
   *      position : "topright",
   *      collapsed : true,
   *      exclusions : {
   *         "toll" : true,
   *         "bridge" : false,
   *         "tunnel" : true
   *      },
   *      graphs : ['Pieton', 'Voiture'],
   *      autocompleteOptions : {},
   *      routeOptions : {}
   *  });
   */
  Route: function Route(options) {
    return new _Route__WEBPACK_IMPORTED_MODULE_4__["default"](options);
  },
  /**
   * Factory function for Geoportal SearchEngine Control creation.
   *
   * @method SearchEngine
   * @static
   * @alias L.geoportalControl.SearchEngine
   * @extends {L.Control}
   * @param {Object}  options - control options
   * @param {String}  [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {Boolean} [options.collapsed = false] - collapse mode
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {String}  [options.position = "topleft"] - position of component into the map. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {String}  [options.placeholder = "Rechercher un lieu, une adresse"] - set placeholder in search bar
   * @param {Boolean} [options.displayMarker = true] - set a marker on search result
   * @param {String|Object}  [options.markerStyle = "blue"] - set a marker style. Currently possible values are "blue" (default value), "orange", "red" and "green". But you can use an L.Icon object (see {@link http://leafletjs.com/reference-1.2.0.html#icon L.Icon })
   * @param {Boolean} [options.displayInfo = true] - get informations on popup marker
   * @param {String|Numeric|Function} [options.zoomTo] - zoom to results, by default, current zoom.
   *       possible values : "auto", any fixed zoom level or a function retruning a zoom :
   *
   *       ```
   *       zoomTo : function (info) {
   *           // do some stuff...
   *           return zoom; // required : return the zoom level !
   *       }
   *
   *       With parameter 'info' : {
   *           type : "PositionOfInterest" | "StreetAddress" | ...
   *           service : "SuggestedLocation" | "GeocodedLocation"
   *           fields : { // fields of service response }
   *       }
   *       ```
   * @param {String}   [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {Object}  [options.resources] - resources to be used by geocode and autocompletion services, by default : ["StreetAddress", "PositionOfInterest"]
   * @param {Boolean} [options.displayAdvancedSearch] - False to disable advanced search tools (it will not be displayed). Default is true (displayed)
   * @param {Object}  [options.advancedSearch] - advanced search for geocoding (filters)
   * @param {Object}  [options.geocodeOptions] - options of geocode service. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~geocode Gp.Services.geocode}
   * @param {Object}  [options.autocompleteOptions] - options of autocomplete service. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~autoComplete Gp.Services.autoComplete}
   * @param {Object}  [options.autocompleteOptions.serviceOptions] - options of autocomplete service
   * @param {Boolean} [options.autocompleteOptions.triggerGeocode = false] - trigger a geocoding request if the autocompletion does not return any suggestions, false by default
   * @param {Number}  [options.autocompleteOptions.triggerDelay = 1000] - waiting time before sending the geocoding request, 1000ms by default
   * @returns {L.geoportalControl.SearchEngine} - SearchEngine Object
   * @fires searchengine:autocomplete:click
   * @fires searchengine:geocode:click
   * @example
   *  var SearchEngine = L.geoportalControl.SearchEngine({
   *      position : "topright",
   *      collapsed : true,
   *      zoomTo : "auto",
   *      displayInfo : true,
   *      displayAdvancedSearch : true,
   *      resources : ["PositionOfInterest", "StreetAddress"],
   *      advancedSearch : {
   *          PositionOfInterest : [{name : "municipality", title : "Ville"}],
   *          StreetAddress : [{...}],
   *          CadastralParcel : null,
   *      },
   *      apiKey : "zfgzrgffg57rfg8ar7gr4g5r4",
   *      geocodeOptions : {},
   *      autocompleteOptions : {}
   *  });
   *  SearchEngine.on("searchengine:autocomplete:click", function (e) {
   *   console.log(e.data):
   *  });
   *  SearchEngine.on("searchengine:geocode:click", function (e) {
   *   console.log(e.data):
   *  });
   */
  SearchEngine: function SearchEngine(options) {
    return new _SearchEngine__WEBPACK_IMPORTED_MODULE_5__["default"](options);
  },
  /**
   * Factory function for ElevationPath Control creation.
   *
   * @method ElevationPath
   * @static
   * @alias L.geoportalControl.ElevationPath
   * @param {Object} options - options for function call.
   * @param {String}   [options.apiKey] - API key for elevation service call, mandatory if configuration service has not been loaded in advance. See {@link https://github.com/IGNF/geoportal-extensions/blob/master/README-leaflet.md#user-content-config "Configuration de l'accès à la plateforme Géoportail" documentation chapter} for more information.
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Boolean} [options.active = false] - specify if control should be actived at startup. Default is false.
   * @param {Object} [options.stylesOptions = DEFAULT_STYLES] - Styles to use when drawing. see [leaflet options](http://leafletjs.com/reference.html#path-options) for available properties.
   * @param {Object} [options.elevationPathOptions = {}] - elevation path service options. See {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~getAltitude options} for available options
   * @param {Object} [options.displayProfileOptions = {}] - profile options.
   * @param {Function} [options.displayProfileOptions.apply] - function to display profile if you want to cutomise it. By default, [DISPLAY_PROFILE_BY_DEFAULT()](./L.geoportalControl.ElevationPath.html#.DISPLAY_PROFILE_BY_DEFAULT) is used. Helper functions to use with D3 [DISPLAY_PROFILE_LIB_D3()](./L.geoportalControl.ElevationPath.html#.DISPLAY_PROFILE_LIB_D3) or AmCharts [DISPLAY_PROFILE_LIB_AMCHARTS()](./L.geoportalControl.ElevationPath.html#.DISPLAY_PROFILE_LIB_AMCHARTS) frameworks are also provided. You may also provide your own function.
   * @param {Object} [options.displayProfileOptions.target] - DOM container to use to display the profile.
   * @param {Boolean} [options.displayProfileOptions.greaterSlope = true] - display the greater slope into the graph
   * @param {Boolean} [options.displayProfileOptions.meanSlope = true] -  display the mean slope into the graph
   * @param {Boolean} [options.displayProfileOptions.ascendingElevation = true] -  display the ascending elevation into the graph
   * @param {Boolean} [options.displayProfileOptions.descendingElevation = true] -  display the descending elevation into the graph
   * @param {Boolean} [options.displayProfileOptions.currentSlope = true] -  display current slope value on profile mouseover
   *
   * @returns {L.geoportalControl.ElevationPath} - ElevationPath Object
   * @example
   *  var e = L.geoportalControl.ElevationPath({
   *      active : false
   *      position : "topleft"
   *      stylesOptions : {},
   *      elevationPathOptions : {},
   *      displayProfileOptions  : {
   *          apply : L.geoportalControl.DISPLAY_PROFILE_LIB_AMCHARTS
   *          target : null, // by default
   *          meanSlope : true, // by default
   *          greaterSlope : true, // by default
   *          ascendingElevation : false,
   *          descendingElevation : false,
   *          currentSlope : false
   *      }
   *  });
   */
  ElevationPath: function ElevationPath(options) {
    return new _ElevationPath__WEBPACK_IMPORTED_MODULE_6__["default"](options);
  },
  /**
   * Control Logo
   *
   * @private
   * @method Logo
   * @extends {L.Control}
   * @alias L.geoportalControl.Logo
   * @param {Object} options - options for function call.
   * @param {String} options.position - 'topright' by default. See {@link http://leafletjs.com/reference-1.0.2.html#control-option L.Control options} for available values.
   * @param {String} options.url - URL
   * @param {String} options.text - text
   * @param {String} options.picto - picto
   * @param {String|Object} options.size - picto size
   * @returns {Logo} - Logo Object
   * @example
   * var map  = L.map('map').setView([48, 2], 4);
   * var logo = L.geoportalControl.Logo({
   *   position : "topright",
   *   picto : "http://www.ign.fr/logo-ign.jpg",
   *   url : "http://www.ign.fr",
   *   text : "© IGN"
   *   size : {width : '50px', height : '30px'}
   * });
   * logo.addTo(map);
   */
  Logo: function Logo(options) {
    return new _Logo__WEBPACK_IMPORTED_MODULE_7__["default"](options);
  }
};
/* harmony default export */ __webpack_exports__["default"] = (Controls);

/***/ }),
/* 34 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(37);
/* harmony import */ var _Common_Controls_LayerSwitcherDOM__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(38);




var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("layerswitcher");

/**
 * @classdesc
 *
 * Leaflet Control Class to manage map layers : their order, visibility and opacity, and display their informations (title, description, legends, metadata...)
 *
 * Use {@link module:Controls.LayerSwitcher L.geoportalControl.LayerSwitcher()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control-layers" target="_blank">L.Control.Layers</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.LayerSwitcher
 */
var LayerSwitcher = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Control.Layers.extend( /** @lends L.geoportalControl.LayerSwitcher.prototype */{
  includes: _Common_Controls_LayerSwitcherDOM__WEBPACK_IMPORTED_MODULE_3__["default"],
  /**
   * options by default
   * (extend to L.Control.Layers)
   *
   * @private
   */
  options: {
    collapsed: true,
    position: "topright",
    autoZIndex: true,
    layers: []
  },
  // ################################################################### //
  // ##################### Methodes surchargées ######################## //
  // ################################################################### //

  /**
   * @constructor LayerSwitcher
   *
   * @private
   * @alias LayerSwitcher
   * @extends {L.Control}
   * @param {Object} options - options of component
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default
   * @param {Boolean} [options.collapsed = true] - collapse mode, false by default
   * @param {Array} [options.layers] - list of layers to be configured. Each array element is an object, with following properties :
   * @param {Object} [options.layers.layer] - layer object
   * @param {Boolean} [options.layers.display] - display layer in widget layer list
   * @param {String} [options.layers.config.visibility] - layer visibility on map
   * @param {String} [options.layers.config.title] - layer alias, to be displayed in widget layer list. E.g. : "Cartes IGN"
   * @param {String} [options.layers.config.description] - layer description, to be displayed on title hover, or in layer information panel.
   * @param {String} [options.layers.config.quicklookUrl] - link to a quick look image for this layer.
   * @param {Array} [options.layers.config.legends] - array of layer legends. Each array element is an object, with following properties :
   *      - url (String, mandatory) : link to a legend
   *      - minScaleDenominator (Number, optional) : min scale denominator for legend validity.
   * @param {Array} [options.layers.config.metadata] - array of layer metadata. Each array element is an object, with property url (String, mandatory) : link to a metadata
   *
   * @example
   *  layers = [
   *      {
   *          layer : wms1,
   *          display : false,
   *          config : {
   *              title : "test layer name 1",
   *              description : "test layer desc 1",
   *          }
   *      }
   *  ]
   *  options = {
   *      position : "topright",
   *      collapsed : true,
   *      layers : layers
   *  }
   *
   *  var layerSwitcher = L.geoportalControl.LayerSwitcher(options);
   */
  initialize: function initialize(options) {
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.setOptions(this, options);

    // uuid
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].generate();

    // il faut recuperer tous les layers de la carte (cf. onAdd).
    // si une configuration de layers est renseignée, on exploite cette
    // information pour les layers renseignés.
    // Par contre, pour ceux qui n'ont pas de configuration, on exploite
    // les informations issues de la configuration (geoportal-configuration) pour les layers IGN,
    // et, pour les layers non IGN, on gère avec l'ID pours les valeurs
    // de titre ou description  ...

    // a ton une configuration des layers ?
    this._hasLayersConfig = !(!this.options.layers || Object.keys(this.options.layers).length === 0);

    // configuration des layers
    this._layersConfig = this._hasLayersConfig ? this.options.layers : [];

    // liste des layers (c'est l'interface avec le dom !)
    this._layers = {};

    // indice : ordre des layers sur la carte
    // plus c'est haut, plus c'est au dessus de la pile
    this._lastZIndex = 0;

    // si on a une configuration de layers, on l'exploite tout de suite...
    if (this._hasLayersConfig) {
      for (var i = 0; i < this._layersConfig.length; i++) {
        var obj = this._layersConfig[i];
        // signature de la fonction pour une compatibilité avec leaflet...
        this._addLayer(obj.layer, null, true);
      }
    }
  },
  /**
   * Method 'onAdd'
   * (extend to L.Control.Layers)
   * Method to add the control on the map.
   *
   * @param {Object} map - L.Map
   * @returns {HTMLElement} container
   *
   * @private
   */
  onAdd: function onAdd(map) {
    // on charge tous les layers dans le controle avec une
    // configuration automatique des layers pour ceux qui ne sont pas
    // renseignés.
    var layersMap = map._layers;

    // on est dans le cas où nous avons des layers ajoutés à la carte
    if (Object.keys(layersMap).length !== 0) {
      // pour gerer l'ordre d'affichage des layers sur la map
      // ainsi que dans le controle, on veut le fonctionnement suivant :
      // layers ID   : [21  , 23  , 25  , 27]
      // layers Map  : [21:1, 23:2, 25:3, 27:4]
      // mais l'ordre dans le controle doit être inversé
      // layers Ctrl : [27, 25, 23, 21], et ceci sera realisé lors de
      // la creation du DOM pour chaque layer (cf. _update())

      var layersKeys = Object.keys(layersMap); // trie
      this._lastZIndex = 0;
      for (var i = 0; i < layersKeys.length; i++) {
        var layerId = layersKeys[i];

        // gestion des ordres d'affichage des layers
        if (this.options.autoZIndex && layersMap[layerId].setZIndex) {
          this._lastZIndex++;
          layersMap[layerId].setZIndex(this._lastZIndex);
        }

        // y'a t il une configuration des layers ?
        // si oui, le layer renseigné a déjà été pris en compte dans
        // le constructeur..., on passe à la suite...
        if (this._hasLayersConfig) {
          if (this._layers[layerId]) {
            continue;
          }
        }

        // sans configuration, on gére en mode auto le layer.
        // on utilise cette methode
        // this.addOverlay() -> this._addLayer()...
        this.addOverlay(layersMap[layerId]);
      }
    }

    // FIXME au cas où les layers n'ont pas été renseignés sur la carte
    // (via addTo ou options.layers), on decide de prendre ceux qui
    // sont renseignés dans la configuration ?
    if (Object.keys(layersMap).length === 0) {
      var config = this._layersConfig;
      this._lastZIndex = 0;
      for (var j = 0; j < config.length; j++) {
        var layer = config[j].layer;
        if (!map.hasLayer(layer)) {
          // on ajoute le layer à la carte
          map.addLayer(layer);

          // on met en place la structure
          this.addOverlay(layer, null);

          // on gère l'ordres d'affichage des layers
          if (this.options.autoZIndex && layer.setZIndex) {
            this._lastZIndex++;
            layer.setZIndex(this._lastZIndex);
          }
        }
      }
    }

    // mise à jour des visibilités (au niveau du DOM, oeil coché ou non...)
    for (var k in this._layers) {
      if (this._layers.hasOwnProperty(k)) {
        var obj = this._layers[k];
        var _layer = obj.layer;
        var _visibility = obj.visibility;
        // par defaut, la visibilité de la couche est active, donc avec un oeil non coché !
        if (!_visibility) {
          // on met à jour la liste des layers à afficher !
          this._updateVisibilityLayer(_layer);
        }
      }
    }

    // le constructeur retourne this._container !
    // on appelle la methode hérité car elle va realisée le boulot :
    // - _initLayout
    // - _update
    // - evenements sur la carte : layeradd + layerremove
    // this._container = L.Control.Layers.prototype.onAdd.call(this, map);

    this._initLayout();
    this._update();
    map.on("layeradd", this._onLayerChange, this);
    map.on("layerremove", this._onLayerChange, this);

    // expiremental !
    map.eachLayer(function (layer) {
      // ecouteur sur la visibilité des attributions d'un layer IGN
      layer.on("visibilitychange", function () {
        logger.trace("visibilitychange", layer);
      }, this);
      // ecouteur sur la liste des attributions d'un layer IGN
      layer.on("attributionchange", function () {
        logger.trace("attributionchange", layer);
      }, this);
    });
    return this._container;
  },
  /**
   * this method is called when the control is removed from the map
   * and removes events on map.
   * @param {Object} map - the map
   *
   * @private
   */
  onRemove: function onRemove(map) {
    map.off("layeradd", this._onLayerChange, this);
    map.off("layerremove", this._onLayerChange, this);
  },
  /**
   * Method '_addLayer'
   * (overwritten : L.Control.Layers)
   * Methode creation of a useful structure for the interface with the DOM
   * Method private call by this.initialize() or this.addOverlay()
   *
   * @example
   * {
   *    layer : objectlayer,
   *    id : id,
   *    title : title,
   *    description : description
   *    (...)
   * };
   * @param {Object} layer - object type 'L.TileLayer'
   * @param {String} name - layer name or title
   * @param {Boolean} overlay - overlay or not
   *
   * @private
   */
  _addLayer: function _addLayer(layer, name, overlay) {
    // id du layer (IGN ou non)
    var id = layer._geoportal_id ? layer._geoportal_id : layer._leaflet_id;

    // pas d'ID !?
    // le layer n'est pas chargé dans la carte...
    if (typeof id === "undefined") {
      return;
    }

    // recherche de la config pour un layer donné
    var layerConfig = {};
    for (var i in this._layersConfig) {
      if (this._layersConfig.hasOwnProperty(i)) {
        if (id === leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(this._layersConfig[i].layer)) {
          layerConfig = this._layersConfig[i].config;
          // display
          // ce layer n'est pas pris en compte dans le controle
          // mais il peut être affiché dans la map
          // si au préalable, le client l'a ajouté...
          var display = typeof this._layersConfig[i].display !== "undefined" ? this._layersConfig[i].display : true;
          if (!display) {
            return;
          }
          break;
        }
      }
    }

    // construit un objet simplifié pour le dom,
    // par defaut, on prend en compte les layers de type IGN
    // (info de la configuration).
    this._layers[id] = {
      layer: layer,
      id: id,
      overlay: overlay,
      // not use !
      title: layer._geoportal_id && layer._title ? layer._title : name || id,
      description: layer._geoportal_id && layer._description ? layer._description : name || id,
      visibility: true,
      // par defaut, sauf si surcharge via la config...
      legends: layer._geoportal_id ? layer._legends : null,
      metadata: layer._geoportal_id ? layer._metadata : null,
      quicklookUrl: layer._geoportal_id ? layer._quicklookUrl : null
    };

    // surcharge la config ci dessus avec les options de configuration saisies
    if (layerConfig && Object.keys(layerConfig).length) {
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(this._layers[id], layerConfig);
    }

    // mise à jour de la visibilité
    var _visibility = this._layers[id].visibility;
    if (layer._geoportal_id) {
      // mise à jour de la visibilité des attributions pour un layer IGN
      layer.setVisible(_visibility);
    }
    if (!_visibility) {
      // on met à jour la liste des layers à afficher !
      this._updateVisibilityLayer(layer);
    }
  },
  /**
   * Method 'addTo'
   * (overwritten : L.Control.Layers because of exception with _expandIfNotCollapsed())
   *
   * @param {Object} map - the map
   *
   * @returns {Object} this
   */
  addTo: function addTo(map) {
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Control.prototype.addTo.call(this, map);
    return this;
  },
  /**
   * Creation of layers of container
   * (extend to L.Control.Layers)
   *
   * Method private call by this.onAdd()
   *
   * @private
   */
  _initLayout: function _initLayout() {
    // fonctionnement lors de l'initialisation :
    // onAdd -> this._update     -> this._addItem (on boucle sur layers)
    // onAdd -> this._initLayout

    // creation du container principal
    var container = this._container = this._createMainContainerElement();

    // ajout dans le container principal d'affichage des layers
    var input = this._createMainLayersShowElement();
    container.appendChild(input);

    // gestion du mode "collapsed"
    if (!this.options.collapsed) {
      input.checked = true;
    }

    // ajout dans le container principal de la liste des layers
    var divL = this._overlaysList = this._createMainLayersElement();
    container.appendChild(divL);

    // ajout dans le container principal du picto du controle
    var picto = this._createMainPictoElement();
    container.appendChild(picto);

    // ajout dans le container principal du panneau d'information
    var divI = this._createMainInfoElement();
    container.appendChild(divI);

    // creation du mode draggable
    this._createDraggableElement(this._overlaysList, this);

    // desactivation des evenements qui peuvent interférer avec la carte
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);

    // gestion des evenements en interaction avec la carte
    this._map.on("moveend", this._onOutOfRangeLayerZoom, this);

    // gestion des CSS en fonction du placement du controle
    switch (this.getPosition()) {
      case "topright":
        container.style.position = "relative";
        container.style.top = "0";
        container.style.right = "0";
        break;
      case "topleft":
        container.style.position = "relative";
        container.style.top = "0";
        container.style.right = "initial";
        picto.style["float"] = "left";
        divL.style.borderBottomRightRadius = "5px";
        divL.style.borderBottomLeftRadius = "0";
        divI.style.right = "initial";
        divI.style.left = "190px";
        break;
      case "bottomleft":
        container.style.position = "relative";
        container.style.top = "0";
        container.style.right = "initial";
        picto.style["float"] = "left";
        divL.style.borderBottomRightRadius = "5px";
        divL.style.borderBottomLeftRadius = "0";
        divI.style.right = "initial";
        divI.style.left = "190px";
        // divI.style.top = "initial";
        // divI.style.bottom = "190px";
        break;
      case "bottomright":
        container.style.position = "relative";
        container.style.top = "0";
        container.style.right = "0";
        // divI.style.top = "initial";
        // divI.style.bottom = "190px";
        break;
      default:
        container.style.position = "relative";
        container.style.top = "0";
        container.style.right = "0";
    }
  },
  /**
   * Update the construction of DOM for each layer
   * (extend to L.Control.Layers)
   *
   * Method private call by this.onAdd()
   *
   * @private
   */
  _update: function _update() {
    if (!this._container) {
      return;
    }
    this._overlaysList.innerHTML = "";
    var layersId = [];
    for (var i in this._layers) {
      if (this._layers.hasOwnProperty(i)) {
        layersId.push(i);
      }
    }

    // inversion du sens des layers dans le controle
    // car on veut le même ordre que sur la map, et comme je suis un peu
    // parano, je re-trie la liste...
    var layers = layersId.sort(function (a, b) {
      var ia = parseInt(a, 10);
      var ib = parseInt(b, 10);
      return ia - ib;
    }).reverse();
    for (var j = 0; j < layers.length; j++) {
      var id = layers[j];
      var obj = this._layers[id];
      this._addItem(obj);
    }
  },
  /**
   * Construction of the DOM for each layer
   * (extend to L.Control.Layers)
   *
   * Method private call by this._update()
   *
   * @private
   * @param {Object} obj - layer
   * @returns {HTMLElement} container
   */
  _addItem: function _addItem(obj) {
    logger.log("_addItem", obj);
    obj.opacity = obj.layer.options.opacity; // ajout de cette option !
    var container = this._createContainerLayerElement(obj);

    // gestion outOfRange
    obj.layer.options.minZoom > this._map.getZoom() || obj.layer.options.maxZoom < this._map.getZoom() ? leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(container, "outOfRange") : leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(container, "outOfRange");

    // ajout du container dans la liste des layers (de type overlay uniquement !)
    this._overlaysList.appendChild(container);
    return container;
  },
  /**
   * Event onLayer change
   * (extend to L.Control.Layers because of version 1.0.0)
   *
   * @private
   * @param {Event} e - event
   */
  _onLayerChange: function _onLayerChange(e) {
    var obj = this._layers[leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(e.layer)];
    if (!obj) {
      return;
    }
    if (!this._handlingClick) {
      this._update();
    }
    this._map.fire(e.type === "layeradd" ? "overlayadd" : "overlayremove", obj);
  },
  /**
   * Event onLayer remove
   * (extend to L.Control.Layers because of version 1.0.0)
   *
   * @private
   * @param {Object} layer - event
   * @returns {Object} layer
   */
  removeLayer: function removeLayer(layer) {
    // clean DOM !
    var id = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer);
    delete this._layers[id];
    this._update();

    // clean Layers
    var map = this._map;
    if (map) {
      if (map.hasLayer(layer)) {
        map.removeLayer(layer);
      }
    }
    return this;
  },
  // ################################################################### //
  // ################ Methodes de l'instance (privées) ################# //
  // ################################################################### //

  /**
   * Set visibility of attribution layer
   * (call by this._onVisibilityLayerClick())
   *
   * @private
   * @param {Object} layer - layer
   */
  _updateVisibilityLayer: function _updateVisibilityLayer(layer) {
    if (!this._map) {
      return;
    }
    this._handlingClick = true;
    var visibility = this._layers[leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer)].visibility;
    if (visibility && !this._map.hasLayer(layer)) {
      // input non checked dans le DOM, on ouvre l'oeil
      // et on ajoute la couche !
      this._map.addLayer(layer);
    } else if (!visibility && this._map.hasLayer(layer)) {
      // input checked dans le DOM, on ferme l'oeil
      // et on supprime la couche !
      this._map.removeLayer(layer);
    } else {
      logger.log("Status unknown layer !?");
    }
    this._handlingClick = false;
    this._refocusOnMap();
  },
  /**
   * Set visibility of layer (DOM)
   * (call by this.setVisibility())
   *
   * @private
   * @param {Object} layer - layer
   */
  _updateVisibilityDOMLayer: function _updateVisibilityDOMLayer(layer) {
    var layerIdx = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer);
    var visibilityElement = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPvisibility_ID_" + layerIdx)); // FIXME ID !
    var visibilityValue = this._layers[layerIdx].visibility;
    visibilityElement.checked = visibilityValue;
  },
  /**
   * Set opacity of layer (DOM)
   * (call by this.setOpacity())
   *
   * @private
   * @param {Object} layer - layer
   */
  _updateOpacityDOMLayer: function _updateOpacityDOMLayer(layer) {
    var layerIdx = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer);
    var opacityValue = layer.options.opacity;
    var opacityElement = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPopacityValue_ID_" + layerIdx)); // FIXME ID !
    opacityElement.innerHTML = parseInt(opacityValue * 100, 10) + "%";
    opacityElement.value = parseInt(opacityValue * 100, 10);
  },
  // ################################################################### //
  // ################## GESTIONNAIRES d'evenements ##################### //
  // ################################################################### //

  /**
   * Event 'zoom' on layers visibility
   *
   * FIXME contrainte sur l'emprise du layer ?
   *
   * @private
   */
  _onOutOfRangeLayerZoom: function _onOutOfRangeLayerZoom() {
    var map = this._map;
    var layers = this._layers;
    for (var i in layers) {
      if (layers.hasOwnProperty(i)) {
        var layer = layers[i].layer;
        var id = layers[i].id;
        var div = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPlayerSwitcher_ID_" + id)); // FIXME ID !
        if (layer.options.minZoom > map.getZoom() || layer.options.maxZoom < map.getZoom()) {
          leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(div, "outOfRange");
        } else {
          leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(div, "outOfRange");
        }
      }
    }
  },
  /**
   * Event 'click' on layer visibility
   *
   * @private
   * @param {Event} e - MouseEvent
   */
  _onVisibilityLayerClick: function _onVisibilityLayerClick(e) {
    var visibilityElement = e.target.id; // ex GPvisibilityPicto_ID_26
    var visibilityOrder = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(visibilityElement); // ex. 26

    // on met à jour cette interface...
    this._layers[visibilityOrder].visibility = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(visibilityElement).checked;
    var layer = this._layers[visibilityOrder].layer;
    this._updateVisibilityLayer(layer);
  },
  /**
   * Event 'click' on layer deleted
   *
   * @private
   * @param {Event} e - MouseEvent
   */
  _onDropLayerClick: function _onDropLayerClick(e) {
    var layerElement = e.target.id; // ex GPvisibilityPicto_ID_26
    var layerOrder = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(layerElement); // ex. 26
    var layer = this._layers[layerOrder].layer;
    this.removeLayer(layer);
  },
  /**
   * Event 'onchange' on layer opacity
   *
   * FIXME appel en dur d'un identifiant CSS !
   *
   * @private
   * @param {Event} e - ChangeEvent
   */
  _onChangeLayerOpacity: function _onChangeLayerOpacity(e) {
    var layerElement = e.target.id; // ex GPvisibilityPicto_ID_26
    var layerOrder = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(layerElement); // ex. 26
    var layer = this._layers[layerOrder].layer;
    var opacityValue = e.target.value;
    var opacityId = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPopacityValue_ID_" + layerOrder)); // FIXME ID !
    opacityId.innerHTML = opacityValue + "%";
    if (this._map.hasLayer(layer)) {
      if (typeof layer.setOpacity !== "undefined") {
        layer.setOpacity(opacityValue / 100);
      } else {
        // Particularité du format GeoJSON
        layer.setStyle({
          fillOpacity: opacityValue / 100,
          opacity: opacityValue / 100
        });
      }
    }
  },
  /**
   * Event 'click' on opening the information window
   *
   * FIXME appel en dur d'un identifiant CSS !
   *
   * @private
   * @param {Event} e - MouseEvent
   */
  _onOpenLayerInfoClick: function _onOpenLayerInfoClick(e) {
    var layerElement = e.target.id; // ex GPvisibilityPicto_ID_26
    var layerOrder = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(layerElement); // ex. 26
    var layer = this._layers[layerOrder];

    // Close layer info panel
    var divId = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(e.target.id);
    var panel = null;
    var info = null;
    if (divId.className === "GPlayerInfoOpened") {
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(divId, "GPlayerInfoOpened");
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(divId, "GPlayerInfo");
      panel = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPlayerInfoPanel"));
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(panel, "GPpanel");
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(panel, "GPlayerInfoPanelOpened");
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(panel, "GPlayerInfoPanelClosed");
      info = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPlayerInfoContent"));
      panel.removeChild(info);
      return;
    }
    var layers = document.getElementsByClassName("GPlayerInfoOpened");
    for (var i = 0; i < layers.length; i++) {
      layers[i].className = "GPlayerInfo";
    }

    // Open layer info panel
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(divId, "GPlayerInfo");
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(divId, "GPlayerInfoOpened");
    panel = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPlayerInfoPanel"));
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(panel, "GPpanel");
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.removeClass(panel, "GPlayerInfoPanelClosed");
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.addClass(panel, "GPlayerInfoPanelOpened");
    info = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get(this._addUID("GPlayerInfoContent"));
    if (info) {
      panel.removeChild(info);
    }

    // on récupére les infos associées au layer pour mettre à jour
    // dynamiquement le contenu du panel d"infos
    var infoLayer = this._createContainerLayerInfoElement(layer);
    panel.appendChild(infoLayer);
  },
  /**
   * Event "drag & drop" on move layer
   *
   * FIXME appel en dur d'un identifiant CSS !
   *
   * @private
   * @param {Event} e - MouseEvent
   */
  _onDragAndDropLayerClick: function _onDragAndDropLayerClick(e) {
    var layerElement = e.target.id; // ex GPvisibilityPicto_ID_26
    var layerOrder = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(layerElement); // ex. 26
    var layer = this._layers[layerOrder];
    logger.log(layer);
    var matchesLayers = document.querySelectorAll("div.GPlayerSwitcher_layer");
    this._lastZIndex = matchesLayers.length;
    for (var i = 0; i < matchesLayers.length; i++) {
      var tag = matchesLayers[i].id;
      var order = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_2__["default"].index(tag);
      var _layer = this._layers[order].layer;
      if (this.options.autoZIndex && _layer.setZIndex) {
        this._lastZIndex--;
        _layer.setZIndex(this._lastZIndex);
      }
    }
  },
  // ################################################################### //
  // ###### METHODES PUBLIQUES (INTERFACE AVEC LE CONTROLE) ############ //
  // ################################################################### //

  /**
   * Adding layer configuration to be displayed by the control
   *
   * @param {Object} layer - layer to add to layer switcher
   * @param {Object} config - See {@link module:Controls.LayerSwitcher L.geoportalControl.LayerSwitcher()} for layer display config object definition.
   */
  addLayer: function addLayer(layer, config) {
    var map = this._map;
    var cfg = this._layersConfig;
    if (!layer) {
      logger.log("[ERROR] LayerSwitcher:addLayer - missing layer parameter !");
      return;
    }
    if (!map.hasLayer(layer)) {
      logger.log("[WARN] LayerSwitcher:addLayer - layer has not been added on map !");
      map.addLayer(layer);
    }
    var id = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer);
    for (var i in cfg) {
      if (cfg.hasOwnProperty(i)) {
        // layer already added !
        if (id === leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(cfg[i].layer)) {
          delete cfg[i];
          break;
        }
      }
    }
    var _config = config || {};
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(_config, {
      layer: layer
    });
    cfg.push(_config);

    // layer déjà configuré, il reprend sa place !
    if (!this._layers[id]) {
      layer.setZIndex(this._lastZIndex++);
    }
    this.addOverlay(layer);
    this._update();
  },
  /**
   * Set the opacity of a layer, and opacity must be a number from 0 to 1.
   *
   * @param {Object} layer - layer into layerswitcher
   * @param {Number} opacity - 0-1.
   */
  setOpacity: function setOpacity(layer, opacity) {
    logger.trace(layer, opacity);
    if (opacity > 1 || opacity < 0) {
      return;
    }
    if (this._map.hasLayer(layer)) {
      if (typeof layer.setOpacity !== "undefined") {
        layer.setOpacity(opacity);
      } else {
        // Particularité du format GeoJSON pour l'opacité
        layer.options.opacity = opacity;
        layer.setStyle({
          fillOpacity: opacity,
          opacity: opacity
        });
      }
      this._updateOpacityDOMLayer(layer);
    }
  },
  /**
   * Set the visibility of a layer.
   *
   * @param {Object} layer - layer into layerswitcher
   * @param {Object} visibility - true/false.
   */
  setVisibility: function setVisibility(layer, visibility) {
    logger.trace(layer, visibility);
    this._layers[leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.stamp(layer)].visibility = visibility;
    this._updateVisibilityDOMLayer(layer);
    this._updateVisibilityLayer(layer);
  }
});
/* harmony default export */ __webpack_exports__["default"] = (LayerSwitcher);

/***/ }),
/* 35 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var loglevel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(36);
/* harmony import */ var loglevel__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(loglevel__WEBPACK_IMPORTED_MODULE_0__);


/**
 * @module LoggerByDefault
 * @alias [private] LoggerByDefault
 * @description
 * ...
 *
 * @example
 * getLogger();
 * disableAll();
 * enableAll();
 */
var LoggerByDefault = {
  /**
   * creation d'un logger statique
   *
   * @function getLogger
   * @param {String} [name="default"] - the logger name
   * @returns {Object} logger
   */
  getLogger: function getLogger(name) {
    // > Substitute global constants configured at compile time
    // cf. webpack.config.js
    // on définit process si non défini dans l'environnement
    if (typeof process === "undefined") {
      var process = {};
      process.env = {
        VERBOSE: false
      };
    }
    process.env.VERBOSE ? loglevel__WEBPACK_IMPORTED_MODULE_0__["enableAll"]() : loglevel__WEBPACK_IMPORTED_MODULE_0__["disableAll"]();
    var logname = name || "default";
    return loglevel__WEBPACK_IMPORTED_MODULE_0__["getLogger"](logname);
  },
  /**
   * desactive tous les loggers
   * @function disableAll
   */
  disableAll: function disableAll() {
    var loggers = loglevel__WEBPACK_IMPORTED_MODULE_0__["getLoggers"]();
    for (var key in loggers) {
      if (Object.hasOwnProperty.call(loggers, key)) {
        var logger = loggers[key];
        logger.disableAll();
      }
    }
  },
  /**
   * active tous les loggers
   * @function enableAll
   */
  enableAll: function enableAll() {
    var loggers = loglevel__WEBPACK_IMPORTED_MODULE_0__["getLoggers"]();
    for (var key in loggers) {
      if (Object.hasOwnProperty.call(loggers, key)) {
        var logger = loggers[key];
        logger.enableAll();
      }
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LoggerByDefault);

/***/ }),
/* 36 */
/***/ (function(module, exports, __webpack_require__) {

var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*
* loglevel - https://github.com/pimterry/loglevel
*
* Copyright (c) 2013 Tim Perry
* Licensed under the MIT license.
*/
(function (root, definition) {
    "use strict";
    if (true) {
        !(__WEBPACK_AMD_DEFINE_FACTORY__ = (definition),
				__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
				(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :
				__WEBPACK_AMD_DEFINE_FACTORY__),
				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
    } else {}
}(this, function () {
    "use strict";

    // Slightly dubious tricks to cut down minimized file size
    var noop = function() {};
    var undefinedType = "undefined";
    var isIE = (typeof window !== undefinedType) && (typeof window.navigator !== undefinedType) && (
        /Trident\/|MSIE /.test(window.navigator.userAgent)
    );

    var logMethods = [
        "trace",
        "debug",
        "info",
        "warn",
        "error"
    ];

    var _loggersByName = {};
    var defaultLogger = null;

    // Cross-browser bind equivalent that works at least back to IE6
    function bindMethod(obj, methodName) {
        var method = obj[methodName];
        if (typeof method.bind === 'function') {
            return method.bind(obj);
        } else {
            try {
                return Function.prototype.bind.call(method, obj);
            } catch (e) {
                // Missing bind shim or IE8 + Modernizr, fallback to wrapping
                return function() {
                    return Function.prototype.apply.apply(method, [obj, arguments]);
                };
            }
        }
    }

    // Trace() doesn't print the message in IE, so for that case we need to wrap it
    function traceForIE() {
        if (console.log) {
            if (console.log.apply) {
                console.log.apply(console, arguments);
            } else {
                // In old IE, native console methods themselves don't have apply().
                Function.prototype.apply.apply(console.log, [console, arguments]);
            }
        }
        if (console.trace) console.trace();
    }

    // Build the best logging method possible for this env
    // Wherever possible we want to bind, not wrap, to preserve stack traces
    function realMethod(methodName) {
        if (methodName === 'debug') {
            methodName = 'log';
        }

        if (typeof console === undefinedType) {
            return false; // No method possible, for now - fixed later by enableLoggingWhenConsoleArrives
        } else if (methodName === 'trace' && isIE) {
            return traceForIE;
        } else if (console[methodName] !== undefined) {
            return bindMethod(console, methodName);
        } else if (console.log !== undefined) {
            return bindMethod(console, 'log');
        } else {
            return noop;
        }
    }

    // These private functions always need `this` to be set properly

    function replaceLoggingMethods() {
        /*jshint validthis:true */
        var level = this.getLevel();

        // Replace the actual methods.
        for (var i = 0; i < logMethods.length; i++) {
            var methodName = logMethods[i];
            this[methodName] = (i < level) ?
                noop :
                this.methodFactory(methodName, level, this.name);
        }

        // Define log.log as an alias for log.debug
        this.log = this.debug;

        // Return any important warnings.
        if (typeof console === undefinedType && level < this.levels.SILENT) {
            return "No console available for logging";
        }
    }

    // In old IE versions, the console isn't present until you first open it.
    // We build realMethod() replacements here that regenerate logging methods
    function enableLoggingWhenConsoleArrives(methodName) {
        return function () {
            if (typeof console !== undefinedType) {
                replaceLoggingMethods.call(this);
                this[methodName].apply(this, arguments);
            }
        };
    }

    // By default, we use closely bound real methods wherever possible, and
    // otherwise we wait for a console to appear, and then try again.
    function defaultMethodFactory(methodName, _level, _loggerName) {
        /*jshint validthis:true */
        return realMethod(methodName) ||
               enableLoggingWhenConsoleArrives.apply(this, arguments);
    }

    function Logger(name, factory) {
      // Private instance variables.
      var self = this;
      /**
       * The level inherited from a parent logger (or a global default). We
       * cache this here rather than delegating to the parent so that it stays
       * in sync with the actual logging methods that we have installed (the
       * parent could change levels but we might not have rebuilt the loggers
       * in this child yet).
       * @type {number}
       */
      var inheritedLevel;
      /**
       * The default level for this logger, if any. If set, this overrides
       * `inheritedLevel`.
       * @type {number|null}
       */
      var defaultLevel;
      /**
       * A user-specific level for this logger. If set, this overrides
       * `defaultLevel`.
       * @type {number|null}
       */
      var userLevel;

      var storageKey = "loglevel";
      if (typeof name === "string") {
        storageKey += ":" + name;
      } else if (typeof name === "symbol") {
        storageKey = undefined;
      }

      function persistLevelIfPossible(levelNum) {
          var levelName = (logMethods[levelNum] || 'silent').toUpperCase();

          if (typeof window === undefinedType || !storageKey) return;

          // Use localStorage if available
          try {
              window.localStorage[storageKey] = levelName;
              return;
          } catch (ignore) {}

          // Use session cookie as fallback
          try {
              window.document.cookie =
                encodeURIComponent(storageKey) + "=" + levelName + ";";
          } catch (ignore) {}
      }

      function getPersistedLevel() {
          var storedLevel;

          if (typeof window === undefinedType || !storageKey) return;

          try {
              storedLevel = window.localStorage[storageKey];
          } catch (ignore) {}

          // Fallback to cookies if local storage gives us nothing
          if (typeof storedLevel === undefinedType) {
              try {
                  var cookie = window.document.cookie;
                  var cookieName = encodeURIComponent(storageKey);
                  var location = cookie.indexOf(cookieName + "=");
                  if (location !== -1) {
                      storedLevel = /^([^;]+)/.exec(
                          cookie.slice(location + cookieName.length + 1)
                      )[1];
                  }
              } catch (ignore) {}
          }

          // If the stored level is not valid, treat it as if nothing was stored.
          if (self.levels[storedLevel] === undefined) {
              storedLevel = undefined;
          }

          return storedLevel;
      }

      function clearPersistedLevel() {
          if (typeof window === undefinedType || !storageKey) return;

          // Use localStorage if available
          try {
              window.localStorage.removeItem(storageKey);
          } catch (ignore) {}

          // Use session cookie as fallback
          try {
              window.document.cookie =
                encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
          } catch (ignore) {}
      }

      function normalizeLevel(input) {
          var level = input;
          if (typeof level === "string" && self.levels[level.toUpperCase()] !== undefined) {
              level = self.levels[level.toUpperCase()];
          }
          if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
              return level;
          } else {
              throw new TypeError("log.setLevel() called with invalid level: " + input);
          }
      }

      /*
       *
       * Public logger API - see https://github.com/pimterry/loglevel for details
       *
       */

      self.name = name;

      self.levels = { "TRACE": 0, "DEBUG": 1, "INFO": 2, "WARN": 3,
          "ERROR": 4, "SILENT": 5};

      self.methodFactory = factory || defaultMethodFactory;

      self.getLevel = function () {
          if (userLevel != null) {
            return userLevel;
          } else if (defaultLevel != null) {
            return defaultLevel;
          } else {
            return inheritedLevel;
          }
      };

      self.setLevel = function (level, persist) {
          userLevel = normalizeLevel(level);
          if (persist !== false) {  // defaults to true
              persistLevelIfPossible(userLevel);
          }

          // NOTE: in v2, this should call rebuild(), which updates children.
          return replaceLoggingMethods.call(self);
      };

      self.setDefaultLevel = function (level) {
          defaultLevel = normalizeLevel(level);
          if (!getPersistedLevel()) {
              self.setLevel(level, false);
          }
      };

      self.resetLevel = function () {
          userLevel = null;
          clearPersistedLevel();
          replaceLoggingMethods.call(self);
      };

      self.enableAll = function(persist) {
          self.setLevel(self.levels.TRACE, persist);
      };

      self.disableAll = function(persist) {
          self.setLevel(self.levels.SILENT, persist);
      };

      self.rebuild = function () {
          if (defaultLogger !== self) {
              inheritedLevel = normalizeLevel(defaultLogger.getLevel());
          }
          replaceLoggingMethods.call(self);

          if (defaultLogger === self) {
              for (var childName in _loggersByName) {
                _loggersByName[childName].rebuild();
              }
          }
      };

      // Initialize all the internal levels.
      inheritedLevel = normalizeLevel(
          defaultLogger ? defaultLogger.getLevel() : "WARN"
      );
      var initialLevel = getPersistedLevel();
      if (initialLevel != null) {
          userLevel = normalizeLevel(initialLevel);
      }
      replaceLoggingMethods.call(self);
    }

    /*
     *
     * Top-level API
     *
     */

    defaultLogger = new Logger();

    defaultLogger.getLogger = function getLogger(name) {
        if ((typeof name !== "symbol" && typeof name !== "string") || name === "") {
            throw new TypeError("You must supply a name when creating a logger.");
        }

        var logger = _loggersByName[name];
        if (!logger) {
            logger = _loggersByName[name] = new Logger(
                name,
                defaultLogger.methodFactory
            );
        }
        return logger;
    };

    // Grab the current global log variable in case of overwrite
    var _log = (typeof window !== undefinedType) ? window.log : undefined;
    defaultLogger.noConflict = function() {
        if (typeof window !== undefinedType &&
               window.log === defaultLogger) {
            window.log = _log;
        }

        return defaultLogger;
    };

    defaultLogger.getLoggers = function getLoggers() {
        return _loggersByName;
    };

    // ES6 default export, for compatibility
    defaultLogger['default'] = defaultLogger;

    return defaultLogger;
}));


/***/ }),
/* 37 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * @module SelectorID
 * @alias [private] SelectorID
 * @description
 * formalisme d'un tag ID :
 * -> NAME(_ORDER)-1460636385836
 *
 * @example
 * Ex.
 *   GProutePoints-1460636385836
 *   GProutePoint_10-1460636385836
 */
var SelectorID = {
  /**
   * Construction d'un identifiant statique basé sur le timestamp,
   * et qui s'incremente de +1 à chaque appel
   * @function generate
   */
  generate: function () {
    var timestamp = Math.floor(Date.now());
    return function () {
      return timestamp++;
    };
  }(),
  /**
   * nom du tag
   * @function name
   * @param {String} id - the id
   * @returns {String} index
   */
  name: function name(id) {
    var name = null;
    var i = id.lastIndexOf("-");
    if (i === -1) {
      name = id;
    } else {
      name = id.substring(0, i);
    }
    return name;
  },
  /**
   * numero d'identifiant du tag
   *
   * @function index
   * @param {String} id - the id
   * @returns {String} index
   */
  index: function index(id) {
    var index = null;
    var name = this.name(id);
    // if (name !== id) {
    var i = name.lastIndexOf("_");
    if (i !== -1) {
      index = name.substring(i + 1);
    }
    // }

    return index;
  },
  /**
   * uuid du tag
   *
   * @function uuid
   * @param {String} id - the id
   * @returns {String} uuid
   */
  uuid: function uuid(id) {
    var uuid = null;
    var i = id.lastIndexOf("-");
    if (i !== -1) {
      uuid = parseInt(id.substring(i + 1), 10);
    }
    return uuid;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (SelectorID);

/***/ }),
/* 38 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var sortablejs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(39);

var LayerSwitcherDOM = {
  /**
   * Creation du drag and drop
   *
   * @param {Object} elementDraggable - Element HTML (DOM) Container
   * @param {Object} context - this
   */
  _createDraggableElement: function _createDraggableElement(elementDraggable, context) {
    // FIXME retirer cette détection user-agent pour solution propre
    // option forcefallback pour réparer sortable sous Chrome 97
    // option forcefallback casse le layerswitcher du portail sous firefox
    if (navigator.userAgent.match(/chrome|chromium|crios/i)) {
      sortablejs__WEBPACK_IMPORTED_MODULE_0__["default"].create(elementDraggable, {
        handle: ".GPlayerName",
        draggable: ".draggable-layer",
        ghostClass: "GPghostLayer",
        animation: 200,
        forceFallback: true,
        // Call event function on drag and drop
        onEnd: function onEnd(e) {
          // FIXME pas terrrible, mais il faut bien passer ce contexte...
          context._onDragAndDropLayerClick(e);
        }
      });
    } else {
      sortablejs__WEBPACK_IMPORTED_MODULE_0__["default"].create(elementDraggable, {
        handle: ".GPlayerName",
        draggable: ".draggable-layer",
        ghostClass: "GPghostLayer",
        animation: 200,
        // Call event function on drag and drop
        onEnd: function onEnd(e) {
          // FIXME pas terrrible, mais il faut bien passer ce contexte...
          context._onDragAndDropLayerClick(e);
        }
      });
    }
  },
  // ################################################################### //
  // ######################### Main container ########################## //
  // ################################################################### //

  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Creation du container principal (DOM)
   *
   * @returns {DOMElement} container - layer switcher DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPlayerSwitcher");
    container.className = "GPwidget";
    return container;
  },
  /**
   * Creation du container principal d"affichage des layers (DOM)
   *
   * @returns {DOMElement} input - element for minimizing/maximizing the layer switcher
   */
  _createMainLayersShowElement: function _createMainLayersShowElement() {
    // <!-- Hidden checkbox for minimizing/maximizing -->
    var input = document.createElement("input");
    input.id = this._addUID("GPshowLayersList");
    input.type = "checkbox";
    return input;
  },
  /**
   * Creation du container principal des layers (DOM)
   *
   * @returns {DOMElement} container - layers list container
   */
  _createMainLayersElement: function _createMainLayersElement() {
    // ajout de la liste des layers dans le container principal
    // <div id="GPlayersList" class="GPpanel">
    //   (...)
    // </div>
    var div = document.createElement("div");
    div.id = this._addUID("GPlayersList");
    div.className = "GPpanel";
    return div;
  },
  /**
   * Creation du container du picto du controle (DOM)
   *
   * @returns {DOMElement} label
   */
  _createMainPictoElement: function _createMainPictoElement() {
    var self = this;

    // exemple :
    // <!-- Label for minimizing/maximizing -->
    // <label id="GPshowLayersListPicto" class="GPshowAdvancedToolPicto" for="GPshowLayersList" title="Afficher/masquer le gestionnaire de couches">
    //    <span id="GPshowLayersListOpen" class="GPshowAdvancedToolOpen"></span><span id="GPshowLayersListClose"></span>
    // </label>

    var label = document.createElement("label");
    label.id = this._addUID("GPshowLayersListPicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowLayersList");
    label.title = "Afficher/masquer le gestionnaire de couches";
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowLayersListOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    spanOpen.addEventListener("click", function () {
      if (document.getElementById(self._addUID("GPshowLayersList")).checked) {
        var layers = document.getElementsByClassName("GPlayerInfoOpened");
        for (var i = 0; i < layers.length; i++) {
          layers[i].className = "GPlayerInfo";
        }
        document.getElementById(self._addUID("GPlayerInfoPanel")).className = "GPlayerInfoPanelClosed";
      }
    });
    label.appendChild(spanOpen);
    var spanClose = document.createElement("span");
    spanClose.addEventListener("click", function () {
      if (document.getElementById(self._addUID("GPshowLayersList")).checked) {
        var layers = document.getElementsByClassName("GPlayerInfoOpened");
        for (var i = 0; i < layers.length; i++) {
          layers[i].className = "GPlayerInfo";
        }
        document.getElementById(self._addUID("GPlayerInfoPanel")).className = "GPlayerInfoPanelClosed";
      }
    });
    spanClose.id = self._addUID("GPshowLayersListClose");
    label.appendChild(spanClose);
    return label;
  },
  /**
   * Creation du container du panneau d"information (DOM)
   *
   * @returns {DOMElement} container
   */
  _createMainInfoElement: function _createMainInfoElement() {
    // gestion du panneau d"information dans le container principal
    // <div id="GPlayerInfoPanel" class="GPlayerInfoPanelClosed">...</div>
    var div = document.createElement("div");
    div.id = this._addUID("GPlayerInfoPanel");
    div.className = "GPpanel GPlayerInfoPanelClosed";
    return div;
  },
  // ################################################################### //
  // ######################### Layer container ######################### //
  // ################################################################### //

  /**
   * Creation du container du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   * @param {Object} obj.layer - couche (ol ou leaflet)
   * @param {String} obj.id - identifiant de la couche (pour ol ou leaflet)
   * @param {String} obj.title - nom de la couche à afficher dans le controle
   * @param {String} obj.description - description de la couche à afficher
   * @param {Boolean} obj.visibility - visibilité de la couche dans la carte (true or false)
   * @param {Float} obj.opacity - opacité de la couche
   *
   * @returns {DOMElement} container
   */
  _createContainerLayerElement: function _createContainerLayerElement(obj) {
    // exemple :
    // <div id="GPlayerSwitcher_ID_Layer1" class="GPlayerSwitcher_layer outOfRange">
    //     <!-- Basic toolbar : visibility / layer name
    //     _createBasicToolElement
    //           _createBasicToolVisibilityElement
    //           _createBasicToolNameElement
    //     -->
    //     <!-- Hidden checkbox + label for showing advanced toolbar
    //     _createAdvancedToolShowElement
    //     -->
    //     <!-- Advanced toolbar : layer info / opacity slider / opacity value / removal
    //     _createAdvancedToolElement
    //           _createAdvancedToolDeleteElement
    //           _createAdvancedToolInformationElement
    //           _createAdvancedToolOpacityElement
    //     -->
    // </div>

    // <!-- Layer entry in layer list -->
    // <!-- Every item is marked with layerID, which is defined at layer import -->
    var container = document.createElement("div");
    container.id = this._addUID("GPlayerSwitcher_ID_" + obj.id);
    container.className = "GPlayerSwitcher_layer draggable-layer";

    // ajout des outils basiques (visibility / layer name)
    container.appendChild(this._createBasicToolElement(obj));

    // liste des outils avancés (layer info / opacity slider / opacity value / removal)
    var array = this._createAdvancedToolShowElement(obj);
    for (var i = 0; i < array.length; i++) {
      container.appendChild(array[i]);
    }

    // ajout des outils avancés
    container.appendChild(this._createAdvancedToolElement(obj));
    return container;
  },
  // ################################################################### //
  // ############################ Layer tool ########################### //
  // ################################################################### //

  /**
   * Creation du container des outils basiques du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createBasicToolElement: function _createBasicToolElement(obj) {
    // exemple :
    // <div id="GPbasicTools_ID_1" class="GPlayerBasicTools">
    //      <!-- _createBasicToolVisibilityElement -->
    //      <!-- _createBasicToolNameElement -->
    // </div>

    var div = document.createElement("div");
    div.id = this._addUID("GPbasicTools_ID_" + obj.id);
    div.className = "GPlayerBasicTools";
    div.appendChild(this._createBasicToolNameElement(obj));
    var array = this._createBasicToolVisibilityElement(obj);
    for (var i = 0; i < array.length; i++) {
      div.appendChild(array[i]);
    }
    return div;
  },
  /**
   * Creation du nom du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createBasicToolNameElement: function _createBasicToolNameElement(obj) {
    // exemple :
    // <span id="GPname_ID_Layer1" class="GPlayerName" title="Quartiers prioritaires de la ville">Quartiers prioritaires de la ville</span>
    var span = document.createElement("span");
    span.id = this._addUID("GPname_ID_" + obj.id);
    span.className = "GPlayerName";
    span.title = obj.description || obj.title;
    span.innerHTML = obj.title;
    return span;
  },
  /**
   * Creation de l'icone de visibilité du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
    * @returns {DOMElement[]} array containing input and label elements
   */
  _createBasicToolVisibilityElement: function _createBasicToolVisibilityElement(obj) {
    // exemple :
    // <input type="checkbox" id="GPvisibility_ID_Layer1" checked="">
    // <label for="GPvisibility_ID_Layer1" id="GPvisibilityPicto_ID_Layer1" class="GPlayerVisibility" title="Afficher/masquer la couche"></label>

    var list = [];
    var checked = typeof obj.visibility !== "undefined" ? obj.visibility : true;
    var id = this._addUID("GPvisibility_ID_" + obj.id);
    var input = document.createElement("input");
    input.id = id;
    input.type = "checkbox";
    input.checked = checked;
    var label = document.createElement("label");
    label.htmlFor = id;
    label.id = this._addUID("GPvisibilityPicto_ID_" + obj.id);
    label.className = "GPlayerVisibility";
    label.title = "Afficher/masquer la couche";

    // add event for visibility change
    var context = this;
    if (input.addEventListener) {
      input.addEventListener("click", function (e) {
        context._onVisibilityLayerClick(e);
      });
    } else if (input.attachEvent) {
      // internet explorer
      input.attachEvent("onclick", function (e) {
        context._onVisibilityLayerClick(e);
      });
    }
    list.push(input);
    list.push(label);
    return list;
  },
  /**
   * Creation de l'affichage du menu des outils avancés du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement[]} array containing input and label elements
   */
  _createAdvancedToolShowElement: function _createAdvancedToolShowElement(obj) {
    // <input type="checkbox" id="GPshowAdvancedTools_ID_Layer1">
    // <label for="GPshowAdvancedTools_ID_Layer1" id="GPshowAdvancedToolsPicto_ID_Layer1" class="GPshowMoreOptions GPshowLayerAdvancedTools" title="Plus d'outils"></label>

    var list = [];
    var label = document.createElement("label");
    label.id = this._addUID("GPshowAdvancedToolsPicto_ID_" + obj.id);
    label.htmlFor = this._addUID("GPshowAdvancedTools_ID_" + obj.id);
    label.title = "Plus d'outils";
    label.className = "GPshowMoreOptions GPshowLayerAdvancedTools";
    var input = document.createElement("input");
    input.type = "checkbox";
    input.id = this._addUID("GPshowAdvancedTools_ID_" + obj.id);
    list.push(input);
    list.push(label);
    return list;
  },
  /**
   * Creation du container des outils avancés du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createAdvancedToolElement: function _createAdvancedToolElement(obj) {
    // exemple :
    // <div id="GPadvancedTools_ID_Layer1" class="GPlayerAdvancedTools">
    //     <!-- _createAdvancedToolDeleteElement -->
    //     <!-- _createAdvancedToolInformationElement -->
    //     <!-- _createAdvancedToolOpacityElement -->
    // </div>

    var container = document.createElement("div");
    container.id = this._addUID("GPadvancedTools_ID_" + obj.id);
    container.className = "GPlayerAdvancedTools";
    container.appendChild(this._createAdvancedToolDeleteElement(obj));

    // si on n'a de l'informations à afficher, on met en place ce composant
    if (obj.title && obj.description) {
      container.appendChild(this._createAdvancedToolInformationElement(obj));
    }
    if (obj.type !== "feature") {
      var array = this._createAdvancedToolOpacityElement(obj);
      for (var i = 0; i < array.length; i++) {
        container.appendChild(array[i]);
      }
    }
    return container;
  },
  /**
   * Creation de l'icone de suppression du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createAdvancedToolDeleteElement: function _createAdvancedToolDeleteElement(obj) {
    // exemple :
    // <div id="GPremove_ID_Layer1" class="GPlayerRemove" title="Supprimer la couche" onclick="GPdropLayer(this);"></div>

    var div = document.createElement("div");
    div.id = this._addUID("GPremove_ID_" + obj.id);
    div.className = "GPlayerRemove";
    div.title = "Supprimer la couche";
    div.layerId = obj.id;
    var context = this;
    if (div.addEventListener) {
      div.addEventListener("click", function (e) {
        context._onDropLayerClick(e);
      });
    } else if (div.attachEvent) {
      // internet explorer
      div.attachEvent("onclick", function (e) {
        context._onDropLayerClick(e);
      });
    }
    return div;
  },
  /**
   * Creation de l'icone d'information du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createAdvancedToolInformationElement: function _createAdvancedToolInformationElement(obj) {
    // exemple :
    // <div id="GPinfo_ID_Layer1" class="GPlayerInfo" title="Informations/légende" onclick="GPopenLayerInfo(this);"></div>

    var div = document.createElement("div");
    div.id = this._addUID("GPinfo_ID_" + obj.id);
    div.className = "GPlayerInfo";
    div.title = "Informations/légende";
    div.layerId = obj.id;
    // add event on click
    var context = this;
    if (div.addEventListener) {
      div.addEventListener("click", function (e) {
        context._onOpenLayerInfoClick(e);
      });
    } else if (div.attachEvent) {
      // internet explorer
      div.attachEvent("onclick", function (e) {
        context._onOpenLayerInfoClick(e);
      });
    }
    return div;
  },
  /**
   * Creation de l'icone de gestion de l'opacité du layer (DOM)
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement[]} array of two containers
   */
  _createAdvancedToolOpacityElement: function _createAdvancedToolOpacityElement(obj) {
    // exemple :
    // <div id="GPopacity_ID_Layer1" class="GPlayerOpacity" title="Opacité">
    //   <input id="GPopacityRange_ID_Layer1" type="range" value="100" oninput="GPchangeLayerOpacity(this);" onchange="GPchangeLayerOpacity(this);">
    // </div>
    // <div class="GPlayerOpacityValue" id="GPopacityValueDiv_ID_Layer1">
    //   <span id="GPopacityValue_ID_Layer1">100</span>
    //   %
    // </div>

    var list = [];

    // curseur pour changer l'opacité
    var divO = document.createElement("div");
    divO.id = this._addUID("GPopacity_ID_" + obj.id);
    divO.className = "GPlayerOpacity";
    divO.title = "Opacité";
    var opacity = typeof obj.opacity !== "undefined" ? obj.opacity : 1;
    opacity = Math.round(opacity * 100);
    var input = document.createElement("input");
    input.id = this._addUID("GPopacityValueDiv_ID_" + obj.id);
    input.type = "range";
    input.value = opacity;

    // add event for opacity change
    var context = this;
    if (input.addEventListener) {
      input.addEventListener("change", function (e) {
        context._onChangeLayerOpacity(e);
      });
    } else if (input.attachEvent) {
      // internet explorer
      input.attachEvent("onchange", function (e) {
        context._onChangeLayerOpacity(e);
      });
    }
    if (input.addEventListener) {
      input.addEventListener("input", function (e) {
        context._onChangeLayerOpacity(e);
      });
    } else if (input.attachEvent) {
      // internet explorer
      input.attachEvent("oninput", function (e) {
        context._onChangeLayerOpacity(e);
      });
    }
    divO.appendChild(input);

    // Valeur d'opacité
    var divC = document.createElement("div");
    divC.id = this._addUID("GPopacityValueDiv_ID_" + obj.id);
    divC.className = "GPlayerOpacityValue";
    var span = document.createElement("span");
    span.id = this._addUID("GPopacityValue_ID_" + obj.id);
    span.innerHTML = opacity + "%";
    divC.appendChild(span);
    list.push(divO);
    list.push(divC);
    return list;
  },
  // ################################################################### //
  // ############################ Layer info ########################### //
  // ################################################################### //

  /**
   * Creation du container du layer info (DOM)
   *
   * TODO GPlayerInfoPopup : ???
   * TODO GPlayerInfoLink  : mettre en forme les échelles !
   *
   * @param {Object} obj - options de la couche à ajouter dans le layer switcher
   *
   * @returns {DOMElement} container
   */
  _createContainerLayerInfoElement: function _createContainerLayerInfoElement(obj) {
    var container = document.createElement("div");
    container.id = this._addUID("GPlayerInfoContent");
    var title = document.createElement("div");
    title.id = this._addUID("GPlayerInfoTitle");
    title.innerHTML = obj.title;
    container.appendChild(title);
    if (obj.quicklookUrl) {
      var quick = document.createElement("div");
      quick.id = this._addUID("GPlayerInfoQuicklook");
      quick.title = "Afficher un aperçu de la couche";
      var refquick = document.createElement("a");
      refquick.href = obj.quicklookUrl;
      refquick.appendChild(quick);
      container.appendChild(refquick);
    }
    var close = document.createElement("div");
    close.id = this._addUID("GPlayerInfoClose");
    close.title = "Fermer la fenêtre";
    var self = this;
    /** Call event function on close click */
    var onCloseClick = function onCloseClick() {
      document.getElementById(self._addUID("GPlayerInfoPanel")).className = "GPlayerInfoPanelClosed";
      var layers = document.getElementsByClassName("GPlayerInfoOpened");
      for (var i = 0; i < layers.length; i++) {
        layers[i].className = "GPlayerInfo";
      }
    };
    if (close.addEventListener) {
      close.addEventListener("click", onCloseClick);
    } else if (close.attachEvent) {
      // internet explorer
      close.attachEvent("onclick", onCloseClick);
    }
    container.appendChild(close);
    var desc = document.createElement("div");
    desc.id = this._addUID("GPlayerInfoDescription");
    desc.innerHTML = obj.description;
    container.appendChild(desc);
    if (obj.metadata) {
      var mtd = document.createElement("div");
      mtd.id = this._addUID("GPlayerInfoMetadata");
      var mtdtitle = document.createElement("div");
      mtdtitle.className = "GPlayerInfoSubtitle";
      mtdtitle.innerHTML = "Métadonnées";
      mtd.appendChild(mtdtitle);
      for (var i = 0; i < obj.metadata.length; i++) {
        var urlmtd = obj.metadata[i].url;
        var mtdlink = document.createElement("div");
        mtdlink.className = "GPlayerInfoLink";
        var refmtd = document.createElement("a");
        refmtd.href = urlmtd;
        refmtd.innerHTML = urlmtd;
        mtdlink.appendChild(refmtd);
        mtd.appendChild(mtdlink);
      }
      if (obj.metadata.length !== 0) {
        container.appendChild(mtd);
      }
    }
    if (obj.legends) {
      var lgd = document.createElement("div");
      lgd.id = this._addUID("GPlayerInfoLegend");
      var lgdtitle = document.createElement("div");
      lgdtitle.className = "GPlayerInfoSubtitle";
      lgdtitle.innerHTML = "Légende";
      lgd.appendChild(lgdtitle);
      var legends = {};
      var maxScale = obj.maxScaleDenominator || 560000000;

      // on crée un tableau temporaire pour ordonner les légendes selon le dénominateur d'échelle
      for (var k = 0; k < obj.legends.length; k++) {
        var minScale = obj.legends[k].minScaleDenominator;
        if (minScale) {
          var s = minScale.toString();
          minScale = Math.round(parseInt(s.substring(0, 3), 10) / 10) * Math.pow(10, s.length - 2);
        } else {
          minScale = 270;
        }
        legends[minScale] = obj.legends[k];
      }
      for (var scale in legends) {
        if (legends.hasOwnProperty(scale)) {
          var urllgd = legends[scale].url;
          // on n'affiche pas les légendes pointant vers "nolegend.jpg"
          if (typeof urllgd === "string" && urllgd.toLowerCase().indexOf("nolegend.jpg") === -1) {
            // TODO GPlayerInfoPopup
            var lgdlink = document.createElement("div");
            lgdlink.className = "GPlayerInfoLink";
            maxScale = legends[scale].maxScaleDenominator || maxScale;
            var reflgd = document.createElement("a");
            reflgd.href = urllgd;
            reflgd.innerHTML = "Du 1/" + scale + " au 1/" + maxScale;
            lgdlink.appendChild(reflgd);
            lgd.appendChild(lgdlink);
          } else {
            delete legends[scale];
          }
        }
      }
      if (Object.keys(legends).length !== 0) {
        container.appendChild(lgd);
      }
    }
    return container;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LayerSwitcherDOM);

/***/ }),
/* 39 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiDrag", function() { return MultiDragPlugin; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sortable", function() { return Sortable; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Swap", function() { return SwapPlugin; });
/**!
 * Sortable 1.14.0
 * @author	RubaXa   <trash@rubaxa.org>
 * @author	owenm    <owen23355@gmail.com>
 * @license MIT
 */
function ownKeys(object, enumerableOnly) {
  var keys = Object.keys(object);

  if (Object.getOwnPropertySymbols) {
    var symbols = Object.getOwnPropertySymbols(object);

    if (enumerableOnly) {
      symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
    }

    keys.push.apply(keys, symbols);
  }

  return keys;
}

function _objectSpread2(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i] != null ? arguments[i] : {};

    if (i % 2) {
      ownKeys(Object(source), true).forEach(function (key) {
        _defineProperty(target, key, source[key]);
      });
    } else if (Object.getOwnPropertyDescriptors) {
      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
    } else {
      ownKeys(Object(source)).forEach(function (key) {
        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
      });
    }
  }

  return target;
}

function _typeof(obj) {
  "@babel/helpers - typeof";

  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
    _typeof = function (obj) {
      return typeof obj;
    };
  } else {
    _typeof = function (obj) {
      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };
  }

  return _typeof(obj);
}

function _defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true
    });
  } else {
    obj[key] = value;
  }

  return obj;
}

function _extends() {
  _extends = Object.assign || function (target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];

      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }

    return target;
  };

  return _extends.apply(this, arguments);
}

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null) return {};
  var target = {};
  var sourceKeys = Object.keys(source);
  var key, i;

  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i];
    if (excluded.indexOf(key) >= 0) continue;
    target[key] = source[key];
  }

  return target;
}

function _objectWithoutProperties(source, excluded) {
  if (source == null) return {};

  var target = _objectWithoutPropertiesLoose(source, excluded);

  var key, i;

  if (Object.getOwnPropertySymbols) {
    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);

    for (i = 0; i < sourceSymbolKeys.length; i++) {
      key = sourceSymbolKeys[i];
      if (excluded.indexOf(key) >= 0) continue;
      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
      target[key] = source[key];
    }
  }

  return target;
}

function _toConsumableArray(arr) {
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}

function _arrayWithoutHoles(arr) {
  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}

function _iterableToArray(iter) {
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}

function _unsupportedIterableToArray(o, minLen) {
  if (!o) return;
  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
  var n = Object.prototype.toString.call(o).slice(8, -1);
  if (n === "Object" && o.constructor) n = o.constructor.name;
  if (n === "Map" || n === "Set") return Array.from(o);
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}

function _arrayLikeToArray(arr, len) {
  if (len == null || len > arr.length) len = arr.length;

  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];

  return arr2;
}

function _nonIterableSpread() {
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}

var version = "1.14.0";

function userAgent(pattern) {
  if (typeof window !== 'undefined' && window.navigator) {
    return !! /*@__PURE__*/navigator.userAgent.match(pattern);
  }
}

var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
var Edge = userAgent(/Edge/i);
var FireFox = userAgent(/firefox/i);
var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
var IOS = userAgent(/iP(ad|od|hone)/i);
var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);

var captureMode = {
  capture: false,
  passive: false
};

function on(el, event, fn) {
  el.addEventListener(event, fn, !IE11OrLess && captureMode);
}

function off(el, event, fn) {
  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
}

function matches(
/**HTMLElement*/
el,
/**String*/
selector) {
  if (!selector) return;
  selector[0] === '>' && (selector = selector.substring(1));

  if (el) {
    try {
      if (el.matches) {
        return el.matches(selector);
      } else if (el.msMatchesSelector) {
        return el.msMatchesSelector(selector);
      } else if (el.webkitMatchesSelector) {
        return el.webkitMatchesSelector(selector);
      }
    } catch (_) {
      return false;
    }
  }

  return false;
}

function getParentOrHost(el) {
  return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
}

function closest(
/**HTMLElement*/
el,
/**String*/
selector,
/**HTMLElement*/
ctx, includeCTX) {
  if (el) {
    ctx = ctx || document;

    do {
      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
        return el;
      }

      if (el === ctx) break;
      /* jshint boss:true */
    } while (el = getParentOrHost(el));
  }

  return null;
}

var R_SPACE = /\s+/g;

function toggleClass(el, name, state) {
  if (el && name) {
    if (el.classList) {
      el.classList[state ? 'add' : 'remove'](name);
    } else {
      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
    }
  }
}

function css(el, prop, val) {
  var style = el && el.style;

  if (style) {
    if (val === void 0) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        val = document.defaultView.getComputedStyle(el, '');
      } else if (el.currentStyle) {
        val = el.currentStyle;
      }

      return prop === void 0 ? val : val[prop];
    } else {
      if (!(prop in style) && prop.indexOf('webkit') === -1) {
        prop = '-webkit-' + prop;
      }

      style[prop] = val + (typeof val === 'string' ? '' : 'px');
    }
  }
}

function matrix(el, selfOnly) {
  var appliedTransforms = '';

  if (typeof el === 'string') {
    appliedTransforms = el;
  } else {
    do {
      var transform = css(el, 'transform');

      if (transform && transform !== 'none') {
        appliedTransforms = transform + ' ' + appliedTransforms;
      }
      /* jshint boss:true */

    } while (!selfOnly && (el = el.parentNode));
  }

  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
  /*jshint -W056 */

  return matrixFn && new matrixFn(appliedTransforms);
}

function find(ctx, tagName, iterator) {
  if (ctx) {
    var list = ctx.getElementsByTagName(tagName),
        i = 0,
        n = list.length;

    if (iterator) {
      for (; i < n; i++) {
        iterator(list[i], i);
      }
    }

    return list;
  }

  return [];
}

function getWindowScrollingElement() {
  var scrollingElement = document.scrollingElement;

  if (scrollingElement) {
    return scrollingElement;
  } else {
    return document.documentElement;
  }
}
/**
 * Returns the "bounding client rect" of given element
 * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
 * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
 * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
 * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
 * @param  {[HTMLElement]} container              The parent the element will be placed in
 * @return {Object}                               The boundingClientRect of el, with specified adjustments
 */


function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
  if (!el.getBoundingClientRect && el !== window) return;
  var elRect, top, left, bottom, right, height, width;

  if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {
    elRect = el.getBoundingClientRect();
    top = elRect.top;
    left = elRect.left;
    bottom = elRect.bottom;
    right = elRect.right;
    height = elRect.height;
    width = elRect.width;
  } else {
    top = 0;
    left = 0;
    bottom = window.innerHeight;
    right = window.innerWidth;
    height = window.innerHeight;
    width = window.innerWidth;
  }

  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
    // Adjust for translate()
    container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
    // Not needed on <= IE11

    if (!IE11OrLess) {
      do {
        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
          var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container

          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
          bottom = top + elRect.height;
          right = left + elRect.width;
          break;
        }
        /* jshint boss:true */

      } while (container = container.parentNode);
    }
  }

  if (undoScale && el !== window) {
    // Adjust for scale()
    var elMatrix = matrix(container || el),
        scaleX = elMatrix && elMatrix.a,
        scaleY = elMatrix && elMatrix.d;

    if (elMatrix) {
      top /= scaleY;
      left /= scaleX;
      width /= scaleX;
      height /= scaleY;
      bottom = top + height;
      right = left + width;
    }
  }

  return {
    top: top,
    left: left,
    bottom: bottom,
    right: right,
    width: width,
    height: height
  };
}
/**
 * Checks if a side of an element is scrolled past a side of its parents
 * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
 * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
 * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
 * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
 */


function isScrolledPast(el, elSide, parentSide) {
  var parent = getParentAutoScrollElement(el, true),
      elSideVal = getRect(el)[elSide];
  /* jshint boss:true */

  while (parent) {
    var parentSideVal = getRect(parent)[parentSide],
        visible = void 0;

    if (parentSide === 'top' || parentSide === 'left') {
      visible = elSideVal >= parentSideVal;
    } else {
      visible = elSideVal <= parentSideVal;
    }

    if (!visible) return parent;
    if (parent === getWindowScrollingElement()) break;
    parent = getParentAutoScrollElement(parent, false);
  }

  return false;
}
/**
 * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
 * and non-draggable elements
 * @param  {HTMLElement} el       The parent element
 * @param  {Number} childNum      The index of the child
 * @param  {Object} options       Parent Sortable's options
 * @return {HTMLElement}          The child at index childNum, or null if not found
 */


function getChild(el, childNum, options, includeDragEl) {
  var currentChild = 0,
      i = 0,
      children = el.children;

  while (i < children.length) {
    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {
      if (currentChild === childNum) {
        return children[i];
      }

      currentChild++;
    }

    i++;
  }

  return null;
}
/**
 * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
 * @param  {HTMLElement} el       Parent element
 * @param  {selector} selector    Any other elements that should be ignored
 * @return {HTMLElement}          The last child, ignoring ghostEl
 */


function lastChild(el, selector) {
  var last = el.lastElementChild;

  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
    last = last.previousElementSibling;
  }

  return last || null;
}
/**
 * Returns the index of an element within its parent for a selected set of
 * elements
 * @param  {HTMLElement} el
 * @param  {selector} selector
 * @return {number}
 */


function index(el, selector) {
  var index = 0;

  if (!el || !el.parentNode) {
    return -1;
  }
  /* jshint boss:true */


  while (el = el.previousElementSibling) {
    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
      index++;
    }
  }

  return index;
}
/**
 * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
 * The value is returned in real pixels.
 * @param  {HTMLElement} el
 * @return {Array}             Offsets in the format of [left, top]
 */


function getRelativeScrollOffset(el) {
  var offsetLeft = 0,
      offsetTop = 0,
      winScroller = getWindowScrollingElement();

  if (el) {
    do {
      var elMatrix = matrix(el),
          scaleX = elMatrix.a,
          scaleY = elMatrix.d;
      offsetLeft += el.scrollLeft * scaleX;
      offsetTop += el.scrollTop * scaleY;
    } while (el !== winScroller && (el = el.parentNode));
  }

  return [offsetLeft, offsetTop];
}
/**
 * Returns the index of the object within the given array
 * @param  {Array} arr   Array that may or may not hold the object
 * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
 * @return {Number}      The index of the object in the array, or -1
 */


function indexOfObject(arr, obj) {
  for (var i in arr) {
    if (!arr.hasOwnProperty(i)) continue;

    for (var key in obj) {
      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
    }
  }

  return -1;
}

function getParentAutoScrollElement(el, includeSelf) {
  // skip to window
  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
  var elem = el;
  var gotSelf = false;

  do {
    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
      var elemCSS = css(elem);

      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
        if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
        if (gotSelf || includeSelf) return elem;
        gotSelf = true;
      }
    }
    /* jshint boss:true */

  } while (elem = elem.parentNode);

  return getWindowScrollingElement();
}

function extend(dst, src) {
  if (dst && src) {
    for (var key in src) {
      if (src.hasOwnProperty(key)) {
        dst[key] = src[key];
      }
    }
  }

  return dst;
}

function isRectEqual(rect1, rect2) {
  return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
}

var _throttleTimeout;

function throttle(callback, ms) {
  return function () {
    if (!_throttleTimeout) {
      var args = arguments,
          _this = this;

      if (args.length === 1) {
        callback.call(_this, args[0]);
      } else {
        callback.apply(_this, args);
      }

      _throttleTimeout = setTimeout(function () {
        _throttleTimeout = void 0;
      }, ms);
    }
  };
}

function cancelThrottle() {
  clearTimeout(_throttleTimeout);
  _throttleTimeout = void 0;
}

function scrollBy(el, x, y) {
  el.scrollLeft += x;
  el.scrollTop += y;
}

function clone(el) {
  var Polymer = window.Polymer;
  var $ = window.jQuery || window.Zepto;

  if (Polymer && Polymer.dom) {
    return Polymer.dom(el).cloneNode(true);
  } else if ($) {
    return $(el).clone(true)[0];
  } else {
    return el.cloneNode(true);
  }
}

function setRect(el, rect) {
  css(el, 'position', 'absolute');
  css(el, 'top', rect.top);
  css(el, 'left', rect.left);
  css(el, 'width', rect.width);
  css(el, 'height', rect.height);
}

function unsetRect(el) {
  css(el, 'position', '');
  css(el, 'top', '');
  css(el, 'left', '');
  css(el, 'width', '');
  css(el, 'height', '');
}

var expando = 'Sortable' + new Date().getTime();

function AnimationStateManager() {
  var animationStates = [],
      animationCallbackId;
  return {
    captureAnimationState: function captureAnimationState() {
      animationStates = [];
      if (!this.options.animation) return;
      var children = [].slice.call(this.el.children);
      children.forEach(function (child) {
        if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
        animationStates.push({
          target: child,
          rect: getRect(child)
        });

        var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation


        if (child.thisAnimationDuration) {
          var childMatrix = matrix(child, true);

          if (childMatrix) {
            fromRect.top -= childMatrix.f;
            fromRect.left -= childMatrix.e;
          }
        }

        child.fromRect = fromRect;
      });
    },
    addAnimationState: function addAnimationState(state) {
      animationStates.push(state);
    },
    removeAnimationState: function removeAnimationState(target) {
      animationStates.splice(indexOfObject(animationStates, {
        target: target
      }), 1);
    },
    animateAll: function animateAll(callback) {
      var _this = this;

      if (!this.options.animation) {
        clearTimeout(animationCallbackId);
        if (typeof callback === 'function') callback();
        return;
      }

      var animating = false,
          animationTime = 0;
      animationStates.forEach(function (state) {
        var time = 0,
            target = state.target,
            fromRect = target.fromRect,
            toRect = getRect(target),
            prevFromRect = target.prevFromRect,
            prevToRect = target.prevToRect,
            animatingRect = state.rect,
            targetMatrix = matrix(target, true);

        if (targetMatrix) {
          // Compensate for current animation
          toRect.top -= targetMatrix.f;
          toRect.left -= targetMatrix.e;
        }

        target.toRect = toRect;

        if (target.thisAnimationDuration) {
          // Could also check if animatingRect is between fromRect and toRect
          if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
          (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
            // If returning to same place as started from animation and on same axis
            time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
          }
        } // if fromRect != toRect: animate


        if (!isRectEqual(toRect, fromRect)) {
          target.prevFromRect = fromRect;
          target.prevToRect = toRect;

          if (!time) {
            time = _this.options.animation;
          }

          _this.animate(target, animatingRect, toRect, time);
        }

        if (time) {
          animating = true;
          animationTime = Math.max(animationTime, time);
          clearTimeout(target.animationResetTimer);
          target.animationResetTimer = setTimeout(function () {
            target.animationTime = 0;
            target.prevFromRect = null;
            target.fromRect = null;
            target.prevToRect = null;
            target.thisAnimationDuration = null;
          }, time);
          target.thisAnimationDuration = time;
        }
      });
      clearTimeout(animationCallbackId);

      if (!animating) {
        if (typeof callback === 'function') callback();
      } else {
        animationCallbackId = setTimeout(function () {
          if (typeof callback === 'function') callback();
        }, animationTime);
      }

      animationStates = [];
    },
    animate: function animate(target, currentRect, toRect, duration) {
      if (duration) {
        css(target, 'transition', '');
        css(target, 'transform', '');
        var elMatrix = matrix(this.el),
            scaleX = elMatrix && elMatrix.a,
            scaleY = elMatrix && elMatrix.d,
            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
        target.animatingX = !!translateX;
        target.animatingY = !!translateY;
        css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
        this.forRepaintDummy = repaint(target); // repaint

        css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
        css(target, 'transform', 'translate3d(0,0,0)');
        typeof target.animated === 'number' && clearTimeout(target.animated);
        target.animated = setTimeout(function () {
          css(target, 'transition', '');
          css(target, 'transform', '');
          target.animated = false;
          target.animatingX = false;
          target.animatingY = false;
        }, duration);
      }
    }
  };
}

function repaint(target) {
  return target.offsetWidth;
}

function calculateRealTime(animatingRect, fromRect, toRect, options) {
  return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
}

var plugins = [];
var defaults = {
  initializeByDefault: true
};
var PluginManager = {
  mount: function mount(plugin) {
    // Set default static properties
    for (var option in defaults) {
      if (defaults.hasOwnProperty(option) && !(option in plugin)) {
        plugin[option] = defaults[option];
      }
    }

    plugins.forEach(function (p) {
      if (p.pluginName === plugin.pluginName) {
        throw "Sortable: Cannot mount plugin ".concat(plugin.pluginName, " more than once");
      }
    });
    plugins.push(plugin);
  },
  pluginEvent: function pluginEvent(eventName, sortable, evt) {
    var _this = this;

    this.eventCanceled = false;

    evt.cancel = function () {
      _this.eventCanceled = true;
    };

    var eventNameGlobal = eventName + 'Global';
    plugins.forEach(function (plugin) {
      if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable

      if (sortable[plugin.pluginName][eventNameGlobal]) {
        sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({
          sortable: sortable
        }, evt));
      } // Only fire plugin event if plugin is enabled in this sortable,
      // and plugin has event defined


      if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
        sortable[plugin.pluginName][eventName](_objectSpread2({
          sortable: sortable
        }, evt));
      }
    });
  },
  initializePlugins: function initializePlugins(sortable, el, defaults, options) {
    plugins.forEach(function (plugin) {
      var pluginName = plugin.pluginName;
      if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
      var initialized = new plugin(sortable, el, sortable.options);
      initialized.sortable = sortable;
      initialized.options = sortable.options;
      sortable[pluginName] = initialized; // Add default options from plugin

      _extends(defaults, initialized.defaults);
    });

    for (var option in sortable.options) {
      if (!sortable.options.hasOwnProperty(option)) continue;
      var modified = this.modifyOption(sortable, option, sortable.options[option]);

      if (typeof modified !== 'undefined') {
        sortable.options[option] = modified;
      }
    }
  },
  getEventProperties: function getEventProperties(name, sortable) {
    var eventProperties = {};
    plugins.forEach(function (plugin) {
      if (typeof plugin.eventProperties !== 'function') return;

      _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
    });
    return eventProperties;
  },
  modifyOption: function modifyOption(sortable, name, value) {
    var modifiedValue;
    plugins.forEach(function (plugin) {
      // Plugin must exist on the Sortable
      if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin

      if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
        modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
      }
    });
    return modifiedValue;
  }
};

function dispatchEvent(_ref) {
  var sortable = _ref.sortable,
      rootEl = _ref.rootEl,
      name = _ref.name,
      targetEl = _ref.targetEl,
      cloneEl = _ref.cloneEl,
      toEl = _ref.toEl,
      fromEl = _ref.fromEl,
      oldIndex = _ref.oldIndex,
      newIndex = _ref.newIndex,
      oldDraggableIndex = _ref.oldDraggableIndex,
      newDraggableIndex = _ref.newDraggableIndex,
      originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      extraEventProperties = _ref.extraEventProperties;
  sortable = sortable || rootEl && rootEl[expando];
  if (!sortable) return;
  var evt,
      options = sortable.options,
      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature

  if (window.CustomEvent && !IE11OrLess && !Edge) {
    evt = new CustomEvent(name, {
      bubbles: true,
      cancelable: true
    });
  } else {
    evt = document.createEvent('Event');
    evt.initEvent(name, true, true);
  }

  evt.to = toEl || rootEl;
  evt.from = fromEl || rootEl;
  evt.item = targetEl || rootEl;
  evt.clone = cloneEl;
  evt.oldIndex = oldIndex;
  evt.newIndex = newIndex;
  evt.oldDraggableIndex = oldDraggableIndex;
  evt.newDraggableIndex = newDraggableIndex;
  evt.originalEvent = originalEvent;
  evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;

  var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));

  for (var option in allEventProperties) {
    evt[option] = allEventProperties[option];
  }

  if (rootEl) {
    rootEl.dispatchEvent(evt);
  }

  if (options[onName]) {
    options[onName].call(sortable, evt);
  }
}

var _excluded = ["evt"];

var pluginEvent = function pluginEvent(eventName, sortable) {
  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
      originalEvent = _ref.evt,
      data = _objectWithoutProperties(_ref, _excluded);

  PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({
    dragEl: dragEl,
    parentEl: parentEl,
    ghostEl: ghostEl,
    rootEl: rootEl,
    nextEl: nextEl,
    lastDownEl: lastDownEl,
    cloneEl: cloneEl,
    cloneHidden: cloneHidden,
    dragStarted: moved,
    putSortable: putSortable,
    activeSortable: Sortable.active,
    originalEvent: originalEvent,
    oldIndex: oldIndex,
    oldDraggableIndex: oldDraggableIndex,
    newIndex: newIndex,
    newDraggableIndex: newDraggableIndex,
    hideGhostForTarget: _hideGhostForTarget,
    unhideGhostForTarget: _unhideGhostForTarget,
    cloneNowHidden: function cloneNowHidden() {
      cloneHidden = true;
    },
    cloneNowShown: function cloneNowShown() {
      cloneHidden = false;
    },
    dispatchSortableEvent: function dispatchSortableEvent(name) {
      _dispatchEvent({
        sortable: sortable,
        name: name,
        originalEvent: originalEvent
      });
    }
  }, data));
};

function _dispatchEvent(info) {
  dispatchEvent(_objectSpread2({
    putSortable: putSortable,
    cloneEl: cloneEl,
    targetEl: dragEl,
    rootEl: rootEl,
    oldIndex: oldIndex,
    oldDraggableIndex: oldDraggableIndex,
    newIndex: newIndex,
    newDraggableIndex: newDraggableIndex
  }, info));
}

var dragEl,
    parentEl,
    ghostEl,
    rootEl,
    nextEl,
    lastDownEl,
    cloneEl,
    cloneHidden,
    oldIndex,
    newIndex,
    oldDraggableIndex,
    newDraggableIndex,
    activeGroup,
    putSortable,
    awaitingDragStarted = false,
    ignoreNextClick = false,
    sortables = [],
    tapEvt,
    touchEvt,
    lastDx,
    lastDy,
    tapDistanceLeft,
    tapDistanceTop,
    moved,
    lastTarget,
    lastDirection,
    pastFirstInvertThresh = false,
    isCircumstantialInvert = false,
    targetMoveDistance,
    // For positioning ghost absolutely
ghostRelativeParent,
    ghostRelativeParentInitialScroll = [],
    // (left, top)
_silent = false,
    savedInputChecked = [];
/** @const */

var documentExists = typeof document !== 'undefined',
    PositionGhostAbsolutely = IOS,
    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
    // This will not pass for IE9, because IE9 DnD only works on anchors
supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
    supportCssPointerEvents = function () {
  if (!documentExists) return; // false when <= IE11

  if (IE11OrLess) {
    return false;
  }

  var el = document.createElement('x');
  el.style.cssText = 'pointer-events:auto';
  return el.style.pointerEvents === 'auto';
}(),
    _detectDirection = function _detectDirection(el, options) {
  var elCSS = css(el),
      elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
      child1 = getChild(el, 0, options),
      child2 = getChild(el, 1, options),
      firstChildCSS = child1 && css(child1),
      secondChildCSS = child2 && css(child2),
      firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
      secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;

  if (elCSS.display === 'flex') {
    return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
  }

  if (elCSS.display === 'grid') {
    return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
  }

  if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
    var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
    return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
  }

  return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
},
    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
  var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
      dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
      dragElOppLength = vertical ? dragRect.width : dragRect.height,
      targetS1Opp = vertical ? targetRect.left : targetRect.top,
      targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
      targetOppLength = vertical ? targetRect.width : targetRect.height;
  return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
},

/**
 * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
 * @param  {Number} x      X position
 * @param  {Number} y      Y position
 * @return {HTMLElement}   Element of the first found nearest Sortable
 */
_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
  var ret;
  sortables.some(function (sortable) {
    var threshold = sortable[expando].options.emptyInsertThreshold;
    if (!threshold || lastChild(sortable)) return;
    var rect = getRect(sortable),
        insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
        insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;

    if (insideHorizontally && insideVertically) {
      return ret = sortable;
    }
  });
  return ret;
},
    _prepareGroup = function _prepareGroup(options) {
  function toFn(value, pull) {
    return function (to, from, dragEl, evt) {
      var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;

      if (value == null && (pull || sameGroup)) {
        // Default pull value
        // Default pull and put value if same group
        return true;
      } else if (value == null || value === false) {
        return false;
      } else if (pull && value === 'clone') {
        return value;
      } else if (typeof value === 'function') {
        return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
      } else {
        var otherGroup = (pull ? to : from).options.group.name;
        return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
      }
    };
  }

  var group = {};
  var originalGroup = options.group;

  if (!originalGroup || _typeof(originalGroup) != 'object') {
    originalGroup = {
      name: originalGroup
    };
  }

  group.name = originalGroup.name;
  group.checkPull = toFn(originalGroup.pull, true);
  group.checkPut = toFn(originalGroup.put);
  group.revertClone = originalGroup.revertClone;
  options.group = group;
},
    _hideGhostForTarget = function _hideGhostForTarget() {
  if (!supportCssPointerEvents && ghostEl) {
    css(ghostEl, 'display', 'none');
  }
},
    _unhideGhostForTarget = function _unhideGhostForTarget() {
  if (!supportCssPointerEvents && ghostEl) {
    css(ghostEl, 'display', '');
  }
}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position


if (documentExists) {
  document.addEventListener('click', function (evt) {
    if (ignoreNextClick) {
      evt.preventDefault();
      evt.stopPropagation && evt.stopPropagation();
      evt.stopImmediatePropagation && evt.stopImmediatePropagation();
      ignoreNextClick = false;
      return false;
    }
  }, true);
}

var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
  if (dragEl) {
    evt = evt.touches ? evt.touches[0] : evt;

    var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);

    if (nearest) {
      // Create imitation event
      var event = {};

      for (var i in evt) {
        if (evt.hasOwnProperty(i)) {
          event[i] = evt[i];
        }
      }

      event.target = event.rootEl = nearest;
      event.preventDefault = void 0;
      event.stopPropagation = void 0;

      nearest[expando]._onDragOver(event);
    }
  }
};

var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
  if (dragEl) {
    dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
  }
};
/**
 * @class  Sortable
 * @param  {HTMLElement}  el
 * @param  {Object}       [options]
 */


function Sortable(el, options) {
  if (!(el && el.nodeType && el.nodeType === 1)) {
    throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
  }

  this.el = el; // root element

  this.options = options = _extends({}, options); // Export instance

  el[expando] = this;
  var defaults = {
    group: null,
    sort: true,
    disabled: false,
    store: null,
    handle: null,
    draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
    swapThreshold: 1,
    // percentage; 0 <= x <= 1
    invertSwap: false,
    // invert always
    invertedSwapThreshold: null,
    // will be set to same as swapThreshold if default
    removeCloneOnHide: true,
    direction: function direction() {
      return _detectDirection(el, this.options);
    },
    ghostClass: 'sortable-ghost',
    chosenClass: 'sortable-chosen',
    dragClass: 'sortable-drag',
    ignore: 'a, img',
    filter: null,
    preventOnFilter: true,
    animation: 0,
    easing: null,
    setData: function setData(dataTransfer, dragEl) {
      dataTransfer.setData('Text', dragEl.textContent);
    },
    dropBubble: false,
    dragoverBubble: false,
    dataIdAttr: 'data-id',
    delay: 0,
    delayOnTouchOnly: false,
    touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
    forceFallback: false,
    fallbackClass: 'sortable-fallback',
    fallbackOnBody: false,
    fallbackTolerance: 0,
    fallbackOffset: {
      x: 0,
      y: 0
    },
    supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && !Safari,
    emptyInsertThreshold: 5
  };
  PluginManager.initializePlugins(this, el, defaults); // Set default options

  for (var name in defaults) {
    !(name in options) && (options[name] = defaults[name]);
  }

  _prepareGroup(options); // Bind all private methods


  for (var fn in this) {
    if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
      this[fn] = this[fn].bind(this);
    }
  } // Setup drag mode


  this.nativeDraggable = options.forceFallback ? false : supportDraggable;

  if (this.nativeDraggable) {
    // Touch start threshold cannot be greater than the native dragstart threshold
    this.options.touchStartThreshold = 1;
  } // Bind events


  if (options.supportPointer) {
    on(el, 'pointerdown', this._onTapStart);
  } else {
    on(el, 'mousedown', this._onTapStart);
    on(el, 'touchstart', this._onTapStart);
  }

  if (this.nativeDraggable) {
    on(el, 'dragover', this);
    on(el, 'dragenter', this);
  }

  sortables.push(this.el); // Restore sorting

  options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager

  _extends(this, AnimationStateManager());
}

Sortable.prototype =
/** @lends Sortable.prototype */
{
  constructor: Sortable,
  _isOutsideThisEl: function _isOutsideThisEl(target) {
    if (!this.el.contains(target) && target !== this.el) {
      lastTarget = null;
    }
  },
  _getDirection: function _getDirection(evt, target) {
    return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
  },
  _onTapStart: function _onTapStart(
  /** Event|TouchEvent */
  evt) {
    if (!evt.cancelable) return;

    var _this = this,
        el = this.el,
        options = this.options,
        preventOnFilter = options.preventOnFilter,
        type = evt.type,
        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
        target = (touch || evt).target,
        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
        filter = options.filter;

    _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.


    if (dragEl) {
      return;
    }

    if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
      return; // only left button and enabled
    } // cancel dnd if original target is content editable


    if (originalTarget.isContentEditable) {
      return;
    } // Safari ignores further event handling after mousedown


    if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {
      return;
    }

    target = closest(target, options.draggable, el, false);

    if (target && target.animated) {
      return;
    }

    if (lastDownEl === target) {
      // Ignoring duplicate `down`
      return;
    } // Get the index of the dragged element within its parent


    oldIndex = index(target);
    oldDraggableIndex = index(target, options.draggable); // Check filter

    if (typeof filter === 'function') {
      if (filter.call(this, evt, target, this)) {
        _dispatchEvent({
          sortable: _this,
          rootEl: originalTarget,
          name: 'filter',
          targetEl: target,
          toEl: el,
          fromEl: el
        });

        pluginEvent('filter', _this, {
          evt: evt
        });
        preventOnFilter && evt.cancelable && evt.preventDefault();
        return; // cancel dnd
      }
    } else if (filter) {
      filter = filter.split(',').some(function (criteria) {
        criteria = closest(originalTarget, criteria.trim(), el, false);

        if (criteria) {
          _dispatchEvent({
            sortable: _this,
            rootEl: criteria,
            name: 'filter',
            targetEl: target,
            fromEl: el,
            toEl: el
          });

          pluginEvent('filter', _this, {
            evt: evt
          });
          return true;
        }
      });

      if (filter) {
        preventOnFilter && evt.cancelable && evt.preventDefault();
        return; // cancel dnd
      }
    }

    if (options.handle && !closest(originalTarget, options.handle, el, false)) {
      return;
    } // Prepare `dragstart`


    this._prepareDragStart(evt, touch, target);
  },
  _prepareDragStart: function _prepareDragStart(
  /** Event */
  evt,
  /** Touch */
  touch,
  /** HTMLElement */
  target) {
    var _this = this,
        el = _this.el,
        options = _this.options,
        ownerDocument = el.ownerDocument,
        dragStartFn;

    if (target && !dragEl && target.parentNode === el) {
      var dragRect = getRect(target);
      rootEl = el;
      dragEl = target;
      parentEl = dragEl.parentNode;
      nextEl = dragEl.nextSibling;
      lastDownEl = target;
      activeGroup = options.group;
      Sortable.dragged = dragEl;
      tapEvt = {
        target: dragEl,
        clientX: (touch || evt).clientX,
        clientY: (touch || evt).clientY
      };
      tapDistanceLeft = tapEvt.clientX - dragRect.left;
      tapDistanceTop = tapEvt.clientY - dragRect.top;
      this._lastX = (touch || evt).clientX;
      this._lastY = (touch || evt).clientY;
      dragEl.style['will-change'] = 'all';

      dragStartFn = function dragStartFn() {
        pluginEvent('delayEnded', _this, {
          evt: evt
        });

        if (Sortable.eventCanceled) {
          _this._onDrop();

          return;
        } // Delayed drag has been triggered
        // we can re-enable the events: touchmove/mousemove


        _this._disableDelayedDragEvents();

        if (!FireFox && _this.nativeDraggable) {
          dragEl.draggable = true;
        } // Bind the events: dragstart/dragend


        _this._triggerDragStart(evt, touch); // Drag start event


        _dispatchEvent({
          sortable: _this,
          name: 'choose',
          originalEvent: evt
        }); // Chosen item


        toggleClass(dragEl, options.chosenClass, true);
      }; // Disable "draggable"


      options.ignore.split(',').forEach(function (criteria) {
        find(dragEl, criteria.trim(), _disableDraggable);
      });
      on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
      on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
      on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
      on(ownerDocument, 'mouseup', _this._onDrop);
      on(ownerDocument, 'touchend', _this._onDrop);
      on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)

      if (FireFox && this.nativeDraggable) {
        this.options.touchStartThreshold = 4;
        dragEl.draggable = true;
      }

      pluginEvent('delayStart', this, {
        evt: evt
      }); // Delay is impossible for native DnD in Edge or IE

      if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
        if (Sortable.eventCanceled) {
          this._onDrop();

          return;
        } // If the user moves the pointer or let go the click or touch
        // before the delay has been reached:
        // disable the delayed drag


        on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
        on(ownerDocument, 'touchend', _this._disableDelayedDrag);
        on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
        on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
        on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
        options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
        _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
      } else {
        dragStartFn();
      }
    }
  },
  _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
  /** TouchEvent|PointerEvent **/
  e) {
    var touch = e.touches ? e.touches[0] : e;

    if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
      this._disableDelayedDrag();
    }
  },
  _disableDelayedDrag: function _disableDelayedDrag() {
    dragEl && _disableDraggable(dragEl);
    clearTimeout(this._dragStartTimer);

    this._disableDelayedDragEvents();
  },
  _disableDelayedDragEvents: function _disableDelayedDragEvents() {
    var ownerDocument = this.el.ownerDocument;
    off(ownerDocument, 'mouseup', this._disableDelayedDrag);
    off(ownerDocument, 'touchend', this._disableDelayedDrag);
    off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
    off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
    off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
    off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
  },
  _triggerDragStart: function _triggerDragStart(
  /** Event */
  evt,
  /** Touch */
  touch) {
    touch = touch || evt.pointerType == 'touch' && evt;

    if (!this.nativeDraggable || touch) {
      if (this.options.supportPointer) {
        on(document, 'pointermove', this._onTouchMove);
      } else if (touch) {
        on(document, 'touchmove', this._onTouchMove);
      } else {
        on(document, 'mousemove', this._onTouchMove);
      }
    } else {
      on(dragEl, 'dragend', this);
      on(rootEl, 'dragstart', this._onDragStart);
    }

    try {
      if (document.selection) {
        // Timeout neccessary for IE9
        _nextTick(function () {
          document.selection.empty();
        });
      } else {
        window.getSelection().removeAllRanges();
      }
    } catch (err) {}
  },
  _dragStarted: function _dragStarted(fallback, evt) {

    awaitingDragStarted = false;

    if (rootEl && dragEl) {
      pluginEvent('dragStarted', this, {
        evt: evt
      });

      if (this.nativeDraggable) {
        on(document, 'dragover', _checkOutsideTargetEl);
      }

      var options = this.options; // Apply effect

      !fallback && toggleClass(dragEl, options.dragClass, false);
      toggleClass(dragEl, options.ghostClass, true);
      Sortable.active = this;
      fallback && this._appendGhost(); // Drag start event

      _dispatchEvent({
        sortable: this,
        name: 'start',
        originalEvent: evt
      });
    } else {
      this._nulling();
    }
  },
  _emulateDragOver: function _emulateDragOver() {
    if (touchEvt) {
      this._lastX = touchEvt.clientX;
      this._lastY = touchEvt.clientY;

      _hideGhostForTarget();

      var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
      var parent = target;

      while (target && target.shadowRoot) {
        target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
        if (target === parent) break;
        parent = target;
      }

      dragEl.parentNode[expando]._isOutsideThisEl(target);

      if (parent) {
        do {
          if (parent[expando]) {
            var inserted = void 0;
            inserted = parent[expando]._onDragOver({
              clientX: touchEvt.clientX,
              clientY: touchEvt.clientY,
              target: target,
              rootEl: parent
            });

            if (inserted && !this.options.dragoverBubble) {
              break;
            }
          }

          target = parent; // store last element
        }
        /* jshint boss:true */
        while (parent = parent.parentNode);
      }

      _unhideGhostForTarget();
    }
  },
  _onTouchMove: function _onTouchMove(
  /**TouchEvent*/
  evt) {
    if (tapEvt) {
      var options = this.options,
          fallbackTolerance = options.fallbackTolerance,
          fallbackOffset = options.fallbackOffset,
          touch = evt.touches ? evt.touches[0] : evt,
          ghostMatrix = ghostEl && matrix(ghostEl, true),
          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging

      if (!Sortable.active && !awaitingDragStarted) {
        if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
          return;
        }

        this._onDragStart(evt, true);
      }

      if (ghostEl) {
        if (ghostMatrix) {
          ghostMatrix.e += dx - (lastDx || 0);
          ghostMatrix.f += dy - (lastDy || 0);
        } else {
          ghostMatrix = {
            a: 1,
            b: 0,
            c: 0,
            d: 1,
            e: dx,
            f: dy
          };
        }

        var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
        css(ghostEl, 'webkitTransform', cssMatrix);
        css(ghostEl, 'mozTransform', cssMatrix);
        css(ghostEl, 'msTransform', cssMatrix);
        css(ghostEl, 'transform', cssMatrix);
        lastDx = dx;
        lastDy = dy;
        touchEvt = touch;
      }

      evt.cancelable && evt.preventDefault();
    }
  },
  _appendGhost: function _appendGhost() {
    // Bug if using scale(): https://stackoverflow.com/questions/2637058
    // Not being adjusted for
    if (!ghostEl) {
      var container = this.options.fallbackOnBody ? document.body : rootEl,
          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
          options = this.options; // Position absolutely

      if (PositionGhostAbsolutely) {
        // Get relatively positioned parent
        ghostRelativeParent = container;

        while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
          ghostRelativeParent = ghostRelativeParent.parentNode;
        }

        if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
          if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
          rect.top += ghostRelativeParent.scrollTop;
          rect.left += ghostRelativeParent.scrollLeft;
        } else {
          ghostRelativeParent = getWindowScrollingElement();
        }

        ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
      }

      ghostEl = dragEl.cloneNode(true);
      toggleClass(ghostEl, options.ghostClass, false);
      toggleClass(ghostEl, options.fallbackClass, true);
      toggleClass(ghostEl, options.dragClass, true);
      css(ghostEl, 'transition', '');
      css(ghostEl, 'transform', '');
      css(ghostEl, 'box-sizing', 'border-box');
      css(ghostEl, 'margin', 0);
      css(ghostEl, 'top', rect.top);
      css(ghostEl, 'left', rect.left);
      css(ghostEl, 'width', rect.width);
      css(ghostEl, 'height', rect.height);
      css(ghostEl, 'opacity', '0.8');
      css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
      css(ghostEl, 'zIndex', '100000');
      css(ghostEl, 'pointerEvents', 'none');
      Sortable.ghost = ghostEl;
      container.appendChild(ghostEl); // Set transform-origin

      css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
    }
  },
  _onDragStart: function _onDragStart(
  /**Event*/
  evt,
  /**boolean*/
  fallback) {
    var _this = this;

    var dataTransfer = evt.dataTransfer;
    var options = _this.options;
    pluginEvent('dragStart', this, {
      evt: evt
    });

    if (Sortable.eventCanceled) {
      this._onDrop();

      return;
    }

    pluginEvent('setupClone', this);

    if (!Sortable.eventCanceled) {
      cloneEl = clone(dragEl);
      cloneEl.draggable = false;
      cloneEl.style['will-change'] = '';

      this._hideClone();

      toggleClass(cloneEl, this.options.chosenClass, false);
      Sortable.clone = cloneEl;
    } // #1143: IFrame support workaround


    _this.cloneId = _nextTick(function () {
      pluginEvent('clone', _this);
      if (Sortable.eventCanceled) return;

      if (!_this.options.removeCloneOnHide) {
        rootEl.insertBefore(cloneEl, dragEl);
      }

      _this._hideClone();

      _dispatchEvent({
        sortable: _this,
        name: 'clone'
      });
    });
    !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events

    if (fallback) {
      ignoreNextClick = true;
      _this._loopId = setInterval(_this._emulateDragOver, 50);
    } else {
      // Undo what was set in _prepareDragStart before drag started
      off(document, 'mouseup', _this._onDrop);
      off(document, 'touchend', _this._onDrop);
      off(document, 'touchcancel', _this._onDrop);

      if (dataTransfer) {
        dataTransfer.effectAllowed = 'move';
        options.setData && options.setData.call(_this, dataTransfer, dragEl);
      }

      on(document, 'drop', _this); // #1276 fix:

      css(dragEl, 'transform', 'translateZ(0)');
    }

    awaitingDragStarted = true;
    _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
    on(document, 'selectstart', _this);
    moved = true;

    if (Safari) {
      css(document.body, 'user-select', 'none');
    }
  },
  // Returns true - if no further action is needed (either inserted or another condition)
  _onDragOver: function _onDragOver(
  /**Event*/
  evt) {
    var el = this.el,
        target = evt.target,
        dragRect,
        targetRect,
        revert,
        options = this.options,
        group = options.group,
        activeSortable = Sortable.active,
        isOwner = activeGroup === group,
        canSort = options.sort,
        fromSortable = putSortable || activeSortable,
        vertical,
        _this = this,
        completedFired = false;

    if (_silent) return;

    function dragOverEvent(name, extra) {
      pluginEvent(name, _this, _objectSpread2({
        evt: evt,
        isOwner: isOwner,
        axis: vertical ? 'vertical' : 'horizontal',
        revert: revert,
        dragRect: dragRect,
        targetRect: targetRect,
        canSort: canSort,
        fromSortable: fromSortable,
        target: target,
        completed: completed,
        onMove: function onMove(target, after) {
          return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
        },
        changed: changed
      }, extra));
    } // Capture animation state


    function capture() {
      dragOverEvent('dragOverAnimationCapture');

      _this.captureAnimationState();

      if (_this !== fromSortable) {
        fromSortable.captureAnimationState();
      }
    } // Return invocation when dragEl is inserted (or completed)


    function completed(insertion) {
      dragOverEvent('dragOverCompleted', {
        insertion: insertion
      });

      if (insertion) {
        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
        if (isOwner) {
          activeSortable._hideClone();
        } else {
          activeSortable._showClone(_this);
        }

        if (_this !== fromSortable) {
          // Set ghost class to new sortable's ghost class
          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
          toggleClass(dragEl, options.ghostClass, true);
        }

        if (putSortable !== _this && _this !== Sortable.active) {
          putSortable = _this;
        } else if (_this === Sortable.active && putSortable) {
          putSortable = null;
        } // Animation


        if (fromSortable === _this) {
          _this._ignoreWhileAnimating = target;
        }

        _this.animateAll(function () {
          dragOverEvent('dragOverAnimationComplete');
          _this._ignoreWhileAnimating = null;
        });

        if (_this !== fromSortable) {
          fromSortable.animateAll();
          fromSortable._ignoreWhileAnimating = null;
        }
      } // Null lastTarget if it is not inside a previously swapped element


      if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
        lastTarget = null;
      } // no bubbling and not fallback


      if (!options.dragoverBubble && !evt.rootEl && target !== document) {
        dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted


        !insertion && nearestEmptyInsertDetectEvent(evt);
      }

      !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
      return completedFired = true;
    } // Call when dragEl has been inserted


    function changed() {
      newIndex = index(dragEl);
      newDraggableIndex = index(dragEl, options.draggable);

      _dispatchEvent({
        sortable: _this,
        name: 'change',
        toEl: el,
        newIndex: newIndex,
        newDraggableIndex: newDraggableIndex,
        originalEvent: evt
      });
    }

    if (evt.preventDefault !== void 0) {
      evt.cancelable && evt.preventDefault();
    }

    target = closest(target, options.draggable, el, true);
    dragOverEvent('dragOver');
    if (Sortable.eventCanceled) return completedFired;

    if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
      return completed(false);
    }

    ignoreNextClick = false;

    if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list
    : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
      vertical = this._getDirection(evt, target) === 'vertical';
      dragRect = getRect(dragEl);
      dragOverEvent('dragOverValid');
      if (Sortable.eventCanceled) return completedFired;

      if (revert) {
        parentEl = rootEl; // actualization

        capture();

        this._hideClone();

        dragOverEvent('revert');

        if (!Sortable.eventCanceled) {
          if (nextEl) {
            rootEl.insertBefore(dragEl, nextEl);
          } else {
            rootEl.appendChild(dragEl);
          }
        }

        return completed(true);
      }

      var elLastChild = lastChild(el, options.draggable);

      if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
        // Insert to end of list
        // If already at end of list: Do not insert
        if (elLastChild === dragEl) {
          return completed(false);
        } // if there is a last element, it is the target


        if (elLastChild && el === evt.target) {
          target = elLastChild;
        }

        if (target) {
          targetRect = getRect(target);
        }

        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
          capture();
          el.appendChild(dragEl);
          parentEl = el; // actualization

          changed();
          return completed(true);
        }
      } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {
        // Insert to start of list
        var firstChild = getChild(el, 0, options, true);

        if (firstChild === dragEl) {
          return completed(false);
        }

        target = firstChild;
        targetRect = getRect(target);

        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {
          capture();
          el.insertBefore(dragEl, firstChild);
          parentEl = el; // actualization

          changed();
          return completed(true);
        }
      } else if (target.parentNode === el) {
        targetRect = getRect(target);
        var direction = 0,
            targetBeforeFirstSwap,
            differentLevel = dragEl.parentNode !== el,
            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
            side1 = vertical ? 'top' : 'left',
            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;

        if (lastTarget !== target) {
          targetBeforeFirstSwap = targetRect[side1];
          pastFirstInvertThresh = false;
          isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
        }

        direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
        var sibling;

        if (direction !== 0) {
          // Check if target is beside dragEl in respective direction (ignoring hidden elements)
          var dragIndex = index(dragEl);

          do {
            dragIndex -= direction;
            sibling = parentEl.children[dragIndex];
          } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
        } // If dragEl is already beside target: Do not insert


        if (direction === 0 || sibling === target) {
          return completed(false);
        }

        lastTarget = target;
        lastDirection = direction;
        var nextSibling = target.nextElementSibling,
            after = false;
        after = direction === 1;

        var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);

        if (moveVector !== false) {
          if (moveVector === 1 || moveVector === -1) {
            after = moveVector === 1;
          }

          _silent = true;
          setTimeout(_unsilent, 30);
          capture();

          if (after && !nextSibling) {
            el.appendChild(dragEl);
          } else {
            target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
          } // Undo chrome's scroll adjustment (has no effect on other browsers)


          if (scrolledPastTop) {
            scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
          }

          parentEl = dragEl.parentNode; // actualization
          // must be done before animation

          if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
            targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
          }

          changed();
          return completed(true);
        }
      }

      if (el.contains(dragEl)) {
        return completed(false);
      }
    }

    return false;
  },
  _ignoreWhileAnimating: null,
  _offMoveEvents: function _offMoveEvents() {
    off(document, 'mousemove', this._onTouchMove);
    off(document, 'touchmove', this._onTouchMove);
    off(document, 'pointermove', this._onTouchMove);
    off(document, 'dragover', nearestEmptyInsertDetectEvent);
    off(document, 'mousemove', nearestEmptyInsertDetectEvent);
    off(document, 'touchmove', nearestEmptyInsertDetectEvent);
  },
  _offUpEvents: function _offUpEvents() {
    var ownerDocument = this.el.ownerDocument;
    off(ownerDocument, 'mouseup', this._onDrop);
    off(ownerDocument, 'touchend', this._onDrop);
    off(ownerDocument, 'pointerup', this._onDrop);
    off(ownerDocument, 'touchcancel', this._onDrop);
    off(document, 'selectstart', this);
  },
  _onDrop: function _onDrop(
  /**Event*/
  evt) {
    var el = this.el,
        options = this.options; // Get the index of the dragged element within its parent

    newIndex = index(dragEl);
    newDraggableIndex = index(dragEl, options.draggable);
    pluginEvent('drop', this, {
      evt: evt
    });
    parentEl = dragEl && dragEl.parentNode; // Get again after plugin event

    newIndex = index(dragEl);
    newDraggableIndex = index(dragEl, options.draggable);

    if (Sortable.eventCanceled) {
      this._nulling();

      return;
    }

    awaitingDragStarted = false;
    isCircumstantialInvert = false;
    pastFirstInvertThresh = false;
    clearInterval(this._loopId);
    clearTimeout(this._dragStartTimer);

    _cancelNextTick(this.cloneId);

    _cancelNextTick(this._dragStartId); // Unbind events


    if (this.nativeDraggable) {
      off(document, 'drop', this);
      off(el, 'dragstart', this._onDragStart);
    }

    this._offMoveEvents();

    this._offUpEvents();

    if (Safari) {
      css(document.body, 'user-select', '');
    }

    css(dragEl, 'transform', '');

    if (evt) {
      if (moved) {
        evt.cancelable && evt.preventDefault();
        !options.dropBubble && evt.stopPropagation();
      }

      ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);

      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
        // Remove clone(s)
        cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
      }

      if (dragEl) {
        if (this.nativeDraggable) {
          off(dragEl, 'dragend', this);
        }

        _disableDraggable(dragEl);

        dragEl.style['will-change'] = ''; // Remove classes
        // ghostClass is added in dragStarted

        if (moved && !awaitingDragStarted) {
          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
        }

        toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event

        _dispatchEvent({
          sortable: this,
          name: 'unchoose',
          toEl: parentEl,
          newIndex: null,
          newDraggableIndex: null,
          originalEvent: evt
        });

        if (rootEl !== parentEl) {
          if (newIndex >= 0) {
            // Add event
            _dispatchEvent({
              rootEl: parentEl,
              name: 'add',
              toEl: parentEl,
              fromEl: rootEl,
              originalEvent: evt
            }); // Remove event


            _dispatchEvent({
              sortable: this,
              name: 'remove',
              toEl: parentEl,
              originalEvent: evt
            }); // drag from one list and drop into another


            _dispatchEvent({
              rootEl: parentEl,
              name: 'sort',
              toEl: parentEl,
              fromEl: rootEl,
              originalEvent: evt
            });

            _dispatchEvent({
              sortable: this,
              name: 'sort',
              toEl: parentEl,
              originalEvent: evt
            });
          }

          putSortable && putSortable.save();
        } else {
          if (newIndex !== oldIndex) {
            if (newIndex >= 0) {
              // drag & drop within the same list
              _dispatchEvent({
                sortable: this,
                name: 'update',
                toEl: parentEl,
                originalEvent: evt
              });

              _dispatchEvent({
                sortable: this,
                name: 'sort',
                toEl: parentEl,
                originalEvent: evt
              });
            }
          }
        }

        if (Sortable.active) {
          /* jshint eqnull:true */
          if (newIndex == null || newIndex === -1) {
            newIndex = oldIndex;
            newDraggableIndex = oldDraggableIndex;
          }

          _dispatchEvent({
            sortable: this,
            name: 'end',
            toEl: parentEl,
            originalEvent: evt
          }); // Save sorting


          this.save();
        }
      }
    }

    this._nulling();
  },
  _nulling: function _nulling() {
    pluginEvent('nulling', this);
    rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
    savedInputChecked.forEach(function (el) {
      el.checked = true;
    });
    savedInputChecked.length = lastDx = lastDy = 0;
  },
  handleEvent: function handleEvent(
  /**Event*/
  evt) {
    switch (evt.type) {
      case 'drop':
      case 'dragend':
        this._onDrop(evt);

        break;

      case 'dragenter':
      case 'dragover':
        if (dragEl) {
          this._onDragOver(evt);

          _globalDragOver(evt);
        }

        break;

      case 'selectstart':
        evt.preventDefault();
        break;
    }
  },

  /**
   * Serializes the item into an array of string.
   * @returns {String[]}
   */
  toArray: function toArray() {
    var order = [],
        el,
        children = this.el.children,
        i = 0,
        n = children.length,
        options = this.options;

    for (; i < n; i++) {
      el = children[i];

      if (closest(el, options.draggable, this.el, false)) {
        order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
      }
    }

    return order;
  },

  /**
   * Sorts the elements according to the array.
   * @param  {String[]}  order  order of the items
   */
  sort: function sort(order, useAnimation) {
    var items = {},
        rootEl = this.el;
    this.toArray().forEach(function (id, i) {
      var el = rootEl.children[i];

      if (closest(el, this.options.draggable, rootEl, false)) {
        items[id] = el;
      }
    }, this);
    useAnimation && this.captureAnimationState();
    order.forEach(function (id) {
      if (items[id]) {
        rootEl.removeChild(items[id]);
        rootEl.appendChild(items[id]);
      }
    });
    useAnimation && this.animateAll();
  },

  /**
   * Save the current sorting
   */
  save: function save() {
    var store = this.options.store;
    store && store.set && store.set(this);
  },

  /**
   * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
   * @param   {HTMLElement}  el
   * @param   {String}       [selector]  default: `options.draggable`
   * @returns {HTMLElement|null}
   */
  closest: function closest$1(el, selector) {
    return closest(el, selector || this.options.draggable, this.el, false);
  },

  /**
   * Set/get option
   * @param   {string} name
   * @param   {*}      [value]
   * @returns {*}
   */
  option: function option(name, value) {
    var options = this.options;

    if (value === void 0) {
      return options[name];
    } else {
      var modifiedValue = PluginManager.modifyOption(this, name, value);

      if (typeof modifiedValue !== 'undefined') {
        options[name] = modifiedValue;
      } else {
        options[name] = value;
      }

      if (name === 'group') {
        _prepareGroup(options);
      }
    }
  },

  /**
   * Destroy
   */
  destroy: function destroy() {
    pluginEvent('destroy', this);
    var el = this.el;
    el[expando] = null;
    off(el, 'mousedown', this._onTapStart);
    off(el, 'touchstart', this._onTapStart);
    off(el, 'pointerdown', this._onTapStart);

    if (this.nativeDraggable) {
      off(el, 'dragover', this);
      off(el, 'dragenter', this);
    } // Remove draggable attributes


    Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
      el.removeAttribute('draggable');
    });

    this._onDrop();

    this._disableDelayedDragEvents();

    sortables.splice(sortables.indexOf(this.el), 1);
    this.el = el = null;
  },
  _hideClone: function _hideClone() {
    if (!cloneHidden) {
      pluginEvent('hideClone', this);
      if (Sortable.eventCanceled) return;
      css(cloneEl, 'display', 'none');

      if (this.options.removeCloneOnHide && cloneEl.parentNode) {
        cloneEl.parentNode.removeChild(cloneEl);
      }

      cloneHidden = true;
    }
  },
  _showClone: function _showClone(putSortable) {
    if (putSortable.lastPutMode !== 'clone') {
      this._hideClone();

      return;
    }

    if (cloneHidden) {
      pluginEvent('showClone', this);
      if (Sortable.eventCanceled) return; // show clone at dragEl or original position

      if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {
        rootEl.insertBefore(cloneEl, dragEl);
      } else if (nextEl) {
        rootEl.insertBefore(cloneEl, nextEl);
      } else {
        rootEl.appendChild(cloneEl);
      }

      if (this.options.group.revertClone) {
        this.animate(dragEl, cloneEl);
      }

      css(cloneEl, 'display', '');
      cloneHidden = false;
    }
  }
};

function _globalDragOver(
/**Event*/
evt) {
  if (evt.dataTransfer) {
    evt.dataTransfer.dropEffect = 'move';
  }

  evt.cancelable && evt.preventDefault();
}

function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
  var evt,
      sortable = fromEl[expando],
      onMoveFn = sortable.options.onMove,
      retVal; // Support for new CustomEvent feature

  if (window.CustomEvent && !IE11OrLess && !Edge) {
    evt = new CustomEvent('move', {
      bubbles: true,
      cancelable: true
    });
  } else {
    evt = document.createEvent('Event');
    evt.initEvent('move', true, true);
  }

  evt.to = toEl;
  evt.from = fromEl;
  evt.dragged = dragEl;
  evt.draggedRect = dragRect;
  evt.related = targetEl || toEl;
  evt.relatedRect = targetRect || getRect(toEl);
  evt.willInsertAfter = willInsertAfter;
  evt.originalEvent = originalEvent;
  fromEl.dispatchEvent(evt);

  if (onMoveFn) {
    retVal = onMoveFn.call(sortable, evt, originalEvent);
  }

  return retVal;
}

function _disableDraggable(el) {
  el.draggable = false;
}

function _unsilent() {
  _silent = false;
}

function _ghostIsFirst(evt, vertical, sortable) {
  var rect = getRect(getChild(sortable.el, 0, sortable.options, true));
  var spacer = 10;
  return vertical ? evt.clientX < rect.left - spacer || evt.clientY < rect.top && evt.clientX < rect.right : evt.clientY < rect.top - spacer || evt.clientY < rect.bottom && evt.clientX < rect.left;
}

function _ghostIsLast(evt, vertical, sortable) {
  var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
  var spacer = 10;
  return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
}

function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
  var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
      targetLength = vertical ? targetRect.height : targetRect.width,
      targetS1 = vertical ? targetRect.top : targetRect.left,
      targetS2 = vertical ? targetRect.bottom : targetRect.right,
      invert = false;

  if (!invertSwap) {
    // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
    if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
      // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
      // check if past first invert threshold on side opposite of lastDirection
      if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
        // past first invert threshold, do not restrict inverted threshold to dragEl shadow
        pastFirstInvertThresh = true;
      }

      if (!pastFirstInvertThresh) {
        // dragEl shadow (target move distance shadow)
        if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
        : mouseOnAxis > targetS2 - targetMoveDistance) {
          return -lastDirection;
        }
      } else {
        invert = true;
      }
    } else {
      // Regular
      if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
        return _getInsertDirection(target);
      }
    }
  }

  invert = invert || invertSwap;

  if (invert) {
    // Invert of regular
    if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
      return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
    }
  }

  return 0;
}
/**
 * Gets the direction dragEl must be swapped relative to target in order to make it
 * seem that dragEl has been "inserted" into that element's position
 * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
 * @return {Number}                   Direction dragEl must be swapped
 */


function _getInsertDirection(target) {
  if (index(dragEl) < index(target)) {
    return 1;
  } else {
    return -1;
  }
}
/**
 * Generate id
 * @param   {HTMLElement} el
 * @returns {String}
 * @private
 */


function _generateId(el) {
  var str = el.tagName + el.className + el.src + el.href + el.textContent,
      i = str.length,
      sum = 0;

  while (i--) {
    sum += str.charCodeAt(i);
  }

  return sum.toString(36);
}

function _saveInputCheckedState(root) {
  savedInputChecked.length = 0;
  var inputs = root.getElementsByTagName('input');
  var idx = inputs.length;

  while (idx--) {
    var el = inputs[idx];
    el.checked && savedInputChecked.push(el);
  }
}

function _nextTick(fn) {
  return setTimeout(fn, 0);
}

function _cancelNextTick(id) {
  return clearTimeout(id);
} // Fixed #973:


if (documentExists) {
  on(document, 'touchmove', function (evt) {
    if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
      evt.preventDefault();
    }
  });
} // Export utils


Sortable.utils = {
  on: on,
  off: off,
  css: css,
  find: find,
  is: function is(el, selector) {
    return !!closest(el, selector, el, false);
  },
  extend: extend,
  throttle: throttle,
  closest: closest,
  toggleClass: toggleClass,
  clone: clone,
  index: index,
  nextTick: _nextTick,
  cancelNextTick: _cancelNextTick,
  detectDirection: _detectDirection,
  getChild: getChild
};
/**
 * Get the Sortable instance of an element
 * @param  {HTMLElement} element The element
 * @return {Sortable|undefined}         The instance of Sortable
 */

Sortable.get = function (element) {
  return element[expando];
};
/**
 * Mount a plugin to Sortable
 * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
 */


Sortable.mount = function () {
  for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
    plugins[_key] = arguments[_key];
  }

  if (plugins[0].constructor === Array) plugins = plugins[0];
  plugins.forEach(function (plugin) {
    if (!plugin.prototype || !plugin.prototype.constructor) {
      throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
    }

    if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);
    PluginManager.mount(plugin);
  });
};
/**
 * Create sortable instance
 * @param {HTMLElement}  el
 * @param {Object}      [options]
 */


Sortable.create = function (el, options) {
  return new Sortable(el, options);
}; // Export


Sortable.version = version;

var autoScrolls = [],
    scrollEl,
    scrollRootEl,
    scrolling = false,
    lastAutoScrollX,
    lastAutoScrollY,
    touchEvt$1,
    pointerElemChangedInterval;

function AutoScrollPlugin() {
  function AutoScroll() {
    this.defaults = {
      scroll: true,
      forceAutoScrollFallback: false,
      scrollSensitivity: 30,
      scrollSpeed: 10,
      bubbleScroll: true
    }; // Bind all private methods

    for (var fn in this) {
      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
        this[fn] = this[fn].bind(this);
      }
    }
  }

  AutoScroll.prototype = {
    dragStarted: function dragStarted(_ref) {
      var originalEvent = _ref.originalEvent;

      if (this.sortable.nativeDraggable) {
        on(document, 'dragover', this._handleAutoScroll);
      } else {
        if (this.options.supportPointer) {
          on(document, 'pointermove', this._handleFallbackAutoScroll);
        } else if (originalEvent.touches) {
          on(document, 'touchmove', this._handleFallbackAutoScroll);
        } else {
          on(document, 'mousemove', this._handleFallbackAutoScroll);
        }
      }
    },
    dragOverCompleted: function dragOverCompleted(_ref2) {
      var originalEvent = _ref2.originalEvent;

      // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
      if (!this.options.dragOverBubble && !originalEvent.rootEl) {
        this._handleAutoScroll(originalEvent);
      }
    },
    drop: function drop() {
      if (this.sortable.nativeDraggable) {
        off(document, 'dragover', this._handleAutoScroll);
      } else {
        off(document, 'pointermove', this._handleFallbackAutoScroll);
        off(document, 'touchmove', this._handleFallbackAutoScroll);
        off(document, 'mousemove', this._handleFallbackAutoScroll);
      }

      clearPointerElemChangedInterval();
      clearAutoScrolls();
      cancelThrottle();
    },
    nulling: function nulling() {
      touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
      autoScrolls.length = 0;
    },
    _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
      this._handleAutoScroll(evt, true);
    },
    _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
      var _this = this;

      var x = (evt.touches ? evt.touches[0] : evt).clientX,
          y = (evt.touches ? evt.touches[0] : evt).clientY,
          elem = document.elementFromPoint(x, y);
      touchEvt$1 = evt; // IE does not seem to have native autoscroll,
      // Edge's autoscroll seems too conditional,
      // MACOS Safari does not have autoscroll,
      // Firefox and Chrome are good

      if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {
        autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change

        var ogElemScroller = getParentAutoScrollElement(elem, true);

        if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
          pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour

          pointerElemChangedInterval = setInterval(function () {
            var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);

            if (newElem !== ogElemScroller) {
              ogElemScroller = newElem;
              clearAutoScrolls();
            }

            autoScroll(evt, _this.options, newElem, fallback);
          }, 10);
          lastAutoScrollX = x;
          lastAutoScrollY = y;
        }
      } else {
        // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
        if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
          clearAutoScrolls();
          return;
        }

        autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
      }
    }
  };
  return _extends(AutoScroll, {
    pluginName: 'scroll',
    initializeByDefault: true
  });
}

function clearAutoScrolls() {
  autoScrolls.forEach(function (autoScroll) {
    clearInterval(autoScroll.pid);
  });
  autoScrolls = [];
}

function clearPointerElemChangedInterval() {
  clearInterval(pointerElemChangedInterval);
}

var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
  if (!options.scroll) return;
  var x = (evt.touches ? evt.touches[0] : evt).clientX,
      y = (evt.touches ? evt.touches[0] : evt).clientY,
      sens = options.scrollSensitivity,
      speed = options.scrollSpeed,
      winScroller = getWindowScrollingElement();
  var scrollThisInstance = false,
      scrollCustomFn; // New scroll root, set scrollEl

  if (scrollRootEl !== rootEl) {
    scrollRootEl = rootEl;
    clearAutoScrolls();
    scrollEl = options.scroll;
    scrollCustomFn = options.scrollFn;

    if (scrollEl === true) {
      scrollEl = getParentAutoScrollElement(rootEl, true);
    }
  }

  var layersOut = 0;
  var currentParent = scrollEl;

  do {
    var el = currentParent,
        rect = getRect(el),
        top = rect.top,
        bottom = rect.bottom,
        left = rect.left,
        right = rect.right,
        width = rect.width,
        height = rect.height,
        canScrollX = void 0,
        canScrollY = void 0,
        scrollWidth = el.scrollWidth,
        scrollHeight = el.scrollHeight,
        elCSS = css(el),
        scrollPosX = el.scrollLeft,
        scrollPosY = el.scrollTop;

    if (el === winScroller) {
      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
    } else {
      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
    }

    var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
    var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);

    if (!autoScrolls[layersOut]) {
      for (var i = 0; i <= layersOut; i++) {
        if (!autoScrolls[i]) {
          autoScrolls[i] = {};
        }
      }
    }

    if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
      autoScrolls[layersOut].el = el;
      autoScrolls[layersOut].vx = vx;
      autoScrolls[layersOut].vy = vy;
      clearInterval(autoScrolls[layersOut].pid);

      if (vx != 0 || vy != 0) {
        scrollThisInstance = true;
        /* jshint loopfunc:true */

        autoScrolls[layersOut].pid = setInterval(function () {
          // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
          if (isFallback && this.layer === 0) {
            Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely

          }

          var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
          var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;

          if (typeof scrollCustomFn === 'function') {
            if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
              return;
            }
          }

          scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
        }.bind({
          layer: layersOut
        }), 24);
      }
    }

    layersOut++;
  } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));

  scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
}, 30);

var drop = function drop(_ref) {
  var originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      dragEl = _ref.dragEl,
      activeSortable = _ref.activeSortable,
      dispatchSortableEvent = _ref.dispatchSortableEvent,
      hideGhostForTarget = _ref.hideGhostForTarget,
      unhideGhostForTarget = _ref.unhideGhostForTarget;
  if (!originalEvent) return;
  var toSortable = putSortable || activeSortable;
  hideGhostForTarget();
  var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
  var target = document.elementFromPoint(touch.clientX, touch.clientY);
  unhideGhostForTarget();

  if (toSortable && !toSortable.el.contains(target)) {
    dispatchSortableEvent('spill');
    this.onSpill({
      dragEl: dragEl,
      putSortable: putSortable
    });
  }
};

function Revert() {}

Revert.prototype = {
  startIndex: null,
  dragStart: function dragStart(_ref2) {
    var oldDraggableIndex = _ref2.oldDraggableIndex;
    this.startIndex = oldDraggableIndex;
  },
  onSpill: function onSpill(_ref3) {
    var dragEl = _ref3.dragEl,
        putSortable = _ref3.putSortable;
    this.sortable.captureAnimationState();

    if (putSortable) {
      putSortable.captureAnimationState();
    }

    var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);

    if (nextSibling) {
      this.sortable.el.insertBefore(dragEl, nextSibling);
    } else {
      this.sortable.el.appendChild(dragEl);
    }

    this.sortable.animateAll();

    if (putSortable) {
      putSortable.animateAll();
    }
  },
  drop: drop
};

_extends(Revert, {
  pluginName: 'revertOnSpill'
});

function Remove() {}

Remove.prototype = {
  onSpill: function onSpill(_ref4) {
    var dragEl = _ref4.dragEl,
        putSortable = _ref4.putSortable;
    var parentSortable = putSortable || this.sortable;
    parentSortable.captureAnimationState();
    dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
    parentSortable.animateAll();
  },
  drop: drop
};

_extends(Remove, {
  pluginName: 'removeOnSpill'
});

var lastSwapEl;

function SwapPlugin() {
  function Swap() {
    this.defaults = {
      swapClass: 'sortable-swap-highlight'
    };
  }

  Swap.prototype = {
    dragStart: function dragStart(_ref) {
      var dragEl = _ref.dragEl;
      lastSwapEl = dragEl;
    },
    dragOverValid: function dragOverValid(_ref2) {
      var completed = _ref2.completed,
          target = _ref2.target,
          onMove = _ref2.onMove,
          activeSortable = _ref2.activeSortable,
          changed = _ref2.changed,
          cancel = _ref2.cancel;
      if (!activeSortable.options.swap) return;
      var el = this.sortable.el,
          options = this.options;

      if (target && target !== el) {
        var prevSwapEl = lastSwapEl;

        if (onMove(target) !== false) {
          toggleClass(target, options.swapClass, true);
          lastSwapEl = target;
        } else {
          lastSwapEl = null;
        }

        if (prevSwapEl && prevSwapEl !== lastSwapEl) {
          toggleClass(prevSwapEl, options.swapClass, false);
        }
      }

      changed();
      completed(true);
      cancel();
    },
    drop: function drop(_ref3) {
      var activeSortable = _ref3.activeSortable,
          putSortable = _ref3.putSortable,
          dragEl = _ref3.dragEl;
      var toSortable = putSortable || this.sortable;
      var options = this.options;
      lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);

      if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
        if (dragEl !== lastSwapEl) {
          toSortable.captureAnimationState();
          if (toSortable !== activeSortable) activeSortable.captureAnimationState();
          swapNodes(dragEl, lastSwapEl);
          toSortable.animateAll();
          if (toSortable !== activeSortable) activeSortable.animateAll();
        }
      }
    },
    nulling: function nulling() {
      lastSwapEl = null;
    }
  };
  return _extends(Swap, {
    pluginName: 'swap',
    eventProperties: function eventProperties() {
      return {
        swapItem: lastSwapEl
      };
    }
  });
}

function swapNodes(n1, n2) {
  var p1 = n1.parentNode,
      p2 = n2.parentNode,
      i1,
      i2;
  if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
  i1 = index(n1);
  i2 = index(n2);

  if (p1.isEqualNode(p2) && i1 < i2) {
    i2++;
  }

  p1.insertBefore(n2, p1.children[i1]);
  p2.insertBefore(n1, p2.children[i2]);
}

var multiDragElements = [],
    multiDragClones = [],
    lastMultiDragSelect,
    // for selection with modifier key down (SHIFT)
multiDragSortable,
    initialFolding = false,
    // Initial multi-drag fold when drag started
folding = false,
    // Folding any other time
dragStarted = false,
    dragEl$1,
    clonesFromRect,
    clonesHidden;

function MultiDragPlugin() {
  function MultiDrag(sortable) {
    // Bind all private methods
    for (var fn in this) {
      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
        this[fn] = this[fn].bind(this);
      }
    }

    if (sortable.options.supportPointer) {
      on(document, 'pointerup', this._deselectMultiDrag);
    } else {
      on(document, 'mouseup', this._deselectMultiDrag);
      on(document, 'touchend', this._deselectMultiDrag);
    }

    on(document, 'keydown', this._checkKeyDown);
    on(document, 'keyup', this._checkKeyUp);
    this.defaults = {
      selectedClass: 'sortable-selected',
      multiDragKey: null,
      setData: function setData(dataTransfer, dragEl) {
        var data = '';

        if (multiDragElements.length && multiDragSortable === sortable) {
          multiDragElements.forEach(function (multiDragElement, i) {
            data += (!i ? '' : ', ') + multiDragElement.textContent;
          });
        } else {
          data = dragEl.textContent;
        }

        dataTransfer.setData('Text', data);
      }
    };
  }

  MultiDrag.prototype = {
    multiDragKeyDown: false,
    isMultiDrag: false,
    delayStartGlobal: function delayStartGlobal(_ref) {
      var dragged = _ref.dragEl;
      dragEl$1 = dragged;
    },
    delayEnded: function delayEnded() {
      this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
    },
    setupClone: function setupClone(_ref2) {
      var sortable = _ref2.sortable,
          cancel = _ref2.cancel;
      if (!this.isMultiDrag) return;

      for (var i = 0; i < multiDragElements.length; i++) {
        multiDragClones.push(clone(multiDragElements[i]));
        multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
        multiDragClones[i].draggable = false;
        multiDragClones[i].style['will-change'] = '';
        toggleClass(multiDragClones[i], this.options.selectedClass, false);
        multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
      }

      sortable._hideClone();

      cancel();
    },
    clone: function clone(_ref3) {
      var sortable = _ref3.sortable,
          rootEl = _ref3.rootEl,
          dispatchSortableEvent = _ref3.dispatchSortableEvent,
          cancel = _ref3.cancel;
      if (!this.isMultiDrag) return;

      if (!this.options.removeCloneOnHide) {
        if (multiDragElements.length && multiDragSortable === sortable) {
          insertMultiDragClones(true, rootEl);
          dispatchSortableEvent('clone');
          cancel();
        }
      }
    },
    showClone: function showClone(_ref4) {
      var cloneNowShown = _ref4.cloneNowShown,
          rootEl = _ref4.rootEl,
          cancel = _ref4.cancel;
      if (!this.isMultiDrag) return;
      insertMultiDragClones(false, rootEl);
      multiDragClones.forEach(function (clone) {
        css(clone, 'display', '');
      });
      cloneNowShown();
      clonesHidden = false;
      cancel();
    },
    hideClone: function hideClone(_ref5) {
      var _this = this;

      var sortable = _ref5.sortable,
          cloneNowHidden = _ref5.cloneNowHidden,
          cancel = _ref5.cancel;
      if (!this.isMultiDrag) return;
      multiDragClones.forEach(function (clone) {
        css(clone, 'display', 'none');

        if (_this.options.removeCloneOnHide && clone.parentNode) {
          clone.parentNode.removeChild(clone);
        }
      });
      cloneNowHidden();
      clonesHidden = true;
      cancel();
    },
    dragStartGlobal: function dragStartGlobal(_ref6) {
      var sortable = _ref6.sortable;

      if (!this.isMultiDrag && multiDragSortable) {
        multiDragSortable.multiDrag._deselectMultiDrag();
      }

      multiDragElements.forEach(function (multiDragElement) {
        multiDragElement.sortableIndex = index(multiDragElement);
      }); // Sort multi-drag elements

      multiDragElements = multiDragElements.sort(function (a, b) {
        return a.sortableIndex - b.sortableIndex;
      });
      dragStarted = true;
    },
    dragStarted: function dragStarted(_ref7) {
      var _this2 = this;

      var sortable = _ref7.sortable;
      if (!this.isMultiDrag) return;

      if (this.options.sort) {
        // Capture rects,
        // hide multi drag elements (by positioning them absolute),
        // set multi drag elements rects to dragRect,
        // show multi drag elements,
        // animate to rects,
        // unset rects & remove from DOM
        sortable.captureAnimationState();

        if (this.options.animation) {
          multiDragElements.forEach(function (multiDragElement) {
            if (multiDragElement === dragEl$1) return;
            css(multiDragElement, 'position', 'absolute');
          });
          var dragRect = getRect(dragEl$1, false, true, true);
          multiDragElements.forEach(function (multiDragElement) {
            if (multiDragElement === dragEl$1) return;
            setRect(multiDragElement, dragRect);
          });
          folding = true;
          initialFolding = true;
        }
      }

      sortable.animateAll(function () {
        folding = false;
        initialFolding = false;

        if (_this2.options.animation) {
          multiDragElements.forEach(function (multiDragElement) {
            unsetRect(multiDragElement);
          });
        } // Remove all auxiliary multidrag items from el, if sorting enabled


        if (_this2.options.sort) {
          removeMultiDragElements();
        }
      });
    },
    dragOver: function dragOver(_ref8) {
      var target = _ref8.target,
          completed = _ref8.completed,
          cancel = _ref8.cancel;

      if (folding && ~multiDragElements.indexOf(target)) {
        completed(false);
        cancel();
      }
    },
    revert: function revert(_ref9) {
      var fromSortable = _ref9.fromSortable,
          rootEl = _ref9.rootEl,
          sortable = _ref9.sortable,
          dragRect = _ref9.dragRect;

      if (multiDragElements.length > 1) {
        // Setup unfold animation
        multiDragElements.forEach(function (multiDragElement) {
          sortable.addAnimationState({
            target: multiDragElement,
            rect: folding ? getRect(multiDragElement) : dragRect
          });
          unsetRect(multiDragElement);
          multiDragElement.fromRect = dragRect;
          fromSortable.removeAnimationState(multiDragElement);
        });
        folding = false;
        insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
      }
    },
    dragOverCompleted: function dragOverCompleted(_ref10) {
      var sortable = _ref10.sortable,
          isOwner = _ref10.isOwner,
          insertion = _ref10.insertion,
          activeSortable = _ref10.activeSortable,
          parentEl = _ref10.parentEl,
          putSortable = _ref10.putSortable;
      var options = this.options;

      if (insertion) {
        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
        if (isOwner) {
          activeSortable._hideClone();
        }

        initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location

        if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
          // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
          var dragRectAbsolute = getRect(dragEl$1, false, true, true);
          multiDragElements.forEach(function (multiDragElement) {
            if (multiDragElement === dragEl$1) return;
            setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
            // while folding, and so that we can capture them again because old sortable will no longer be fromSortable

            parentEl.appendChild(multiDragElement);
          });
          folding = true;
        } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out


        if (!isOwner) {
          // Only remove if not folding (folding will remove them anyways)
          if (!folding) {
            removeMultiDragElements();
          }

          if (multiDragElements.length > 1) {
            var clonesHiddenBefore = clonesHidden;

            activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden


            if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
              multiDragClones.forEach(function (clone) {
                activeSortable.addAnimationState({
                  target: clone,
                  rect: clonesFromRect
                });
                clone.fromRect = clonesFromRect;
                clone.thisAnimationDuration = null;
              });
            }
          } else {
            activeSortable._showClone(sortable);
          }
        }
      }
    },
    dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
      var dragRect = _ref11.dragRect,
          isOwner = _ref11.isOwner,
          activeSortable = _ref11.activeSortable;
      multiDragElements.forEach(function (multiDragElement) {
        multiDragElement.thisAnimationDuration = null;
      });

      if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
        clonesFromRect = _extends({}, dragRect);
        var dragMatrix = matrix(dragEl$1, true);
        clonesFromRect.top -= dragMatrix.f;
        clonesFromRect.left -= dragMatrix.e;
      }
    },
    dragOverAnimationComplete: function dragOverAnimationComplete() {
      if (folding) {
        folding = false;
        removeMultiDragElements();
      }
    },
    drop: function drop(_ref12) {
      var evt = _ref12.originalEvent,
          rootEl = _ref12.rootEl,
          parentEl = _ref12.parentEl,
          sortable = _ref12.sortable,
          dispatchSortableEvent = _ref12.dispatchSortableEvent,
          oldIndex = _ref12.oldIndex,
          putSortable = _ref12.putSortable;
      var toSortable = putSortable || this.sortable;
      if (!evt) return;
      var options = this.options,
          children = parentEl.children; // Multi-drag selection

      if (!dragStarted) {
        if (options.multiDragKey && !this.multiDragKeyDown) {
          this._deselectMultiDrag();
        }

        toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));

        if (!~multiDragElements.indexOf(dragEl$1)) {
          multiDragElements.push(dragEl$1);
          dispatchEvent({
            sortable: sortable,
            rootEl: rootEl,
            name: 'select',
            targetEl: dragEl$1,
            originalEvt: evt
          }); // Modifier activated, select from last to dragEl

          if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
            var lastIndex = index(lastMultiDragSelect),
                currentIndex = index(dragEl$1);

            if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
              // Must include lastMultiDragSelect (select it), in case modified selection from no selection
              // (but previous selection existed)
              var n, i;

              if (currentIndex > lastIndex) {
                i = lastIndex;
                n = currentIndex;
              } else {
                i = currentIndex;
                n = lastIndex + 1;
              }

              for (; i < n; i++) {
                if (~multiDragElements.indexOf(children[i])) continue;
                toggleClass(children[i], options.selectedClass, true);
                multiDragElements.push(children[i]);
                dispatchEvent({
                  sortable: sortable,
                  rootEl: rootEl,
                  name: 'select',
                  targetEl: children[i],
                  originalEvt: evt
                });
              }
            }
          } else {
            lastMultiDragSelect = dragEl$1;
          }

          multiDragSortable = toSortable;
        } else {
          multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
          lastMultiDragSelect = null;
          dispatchEvent({
            sortable: sortable,
            rootEl: rootEl,
            name: 'deselect',
            targetEl: dragEl$1,
            originalEvt: evt
          });
        }
      } // Multi-drag drop


      if (dragStarted && this.isMultiDrag) {
        folding = false; // Do not "unfold" after around dragEl if reverted

        if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
          var dragRect = getRect(dragEl$1),
              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
          if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
          toSortable.captureAnimationState();

          if (!initialFolding) {
            if (options.animation) {
              dragEl$1.fromRect = dragRect;
              multiDragElements.forEach(function (multiDragElement) {
                multiDragElement.thisAnimationDuration = null;

                if (multiDragElement !== dragEl$1) {
                  var rect = folding ? getRect(multiDragElement) : dragRect;
                  multiDragElement.fromRect = rect; // Prepare unfold animation

                  toSortable.addAnimationState({
                    target: multiDragElement,
                    rect: rect
                  });
                }
              });
            } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
            // properly they must all be removed


            removeMultiDragElements();
            multiDragElements.forEach(function (multiDragElement) {
              if (children[multiDragIndex]) {
                parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
              } else {
                parentEl.appendChild(multiDragElement);
              }

              multiDragIndex++;
            }); // If initial folding is done, the elements may have changed position because they are now
            // unfolding around dragEl, even though dragEl may not have his index changed, so update event
            // must be fired here as Sortable will not.

            if (oldIndex === index(dragEl$1)) {
              var update = false;
              multiDragElements.forEach(function (multiDragElement) {
                if (multiDragElement.sortableIndex !== index(multiDragElement)) {
                  update = true;
                  return;
                }
              });

              if (update) {
                dispatchSortableEvent('update');
              }
            }
          } // Must be done after capturing individual rects (scroll bar)


          multiDragElements.forEach(function (multiDragElement) {
            unsetRect(multiDragElement);
          });
          toSortable.animateAll();
        }

        multiDragSortable = toSortable;
      } // Remove clones if necessary


      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
        multiDragClones.forEach(function (clone) {
          clone.parentNode && clone.parentNode.removeChild(clone);
        });
      }
    },
    nullingGlobal: function nullingGlobal() {
      this.isMultiDrag = dragStarted = false;
      multiDragClones.length = 0;
    },
    destroyGlobal: function destroyGlobal() {
      this._deselectMultiDrag();

      off(document, 'pointerup', this._deselectMultiDrag);
      off(document, 'mouseup', this._deselectMultiDrag);
      off(document, 'touchend', this._deselectMultiDrag);
      off(document, 'keydown', this._checkKeyDown);
      off(document, 'keyup', this._checkKeyUp);
    },
    _deselectMultiDrag: function _deselectMultiDrag(evt) {
      if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable

      if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable

      if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click

      if (evt && evt.button !== 0) return;

      while (multiDragElements.length) {
        var el = multiDragElements[0];
        toggleClass(el, this.options.selectedClass, false);
        multiDragElements.shift();
        dispatchEvent({
          sortable: this.sortable,
          rootEl: this.sortable.el,
          name: 'deselect',
          targetEl: el,
          originalEvt: evt
        });
      }
    },
    _checkKeyDown: function _checkKeyDown(evt) {
      if (evt.key === this.options.multiDragKey) {
        this.multiDragKeyDown = true;
      }
    },
    _checkKeyUp: function _checkKeyUp(evt) {
      if (evt.key === this.options.multiDragKey) {
        this.multiDragKeyDown = false;
      }
    }
  };
  return _extends(MultiDrag, {
    // Static methods & properties
    pluginName: 'multiDrag',
    utils: {
      /**
       * Selects the provided multi-drag item
       * @param  {HTMLElement} el    The element to be selected
       */
      select: function select(el) {
        var sortable = el.parentNode[expando];
        if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;

        if (multiDragSortable && multiDragSortable !== sortable) {
          multiDragSortable.multiDrag._deselectMultiDrag();

          multiDragSortable = sortable;
        }

        toggleClass(el, sortable.options.selectedClass, true);
        multiDragElements.push(el);
      },

      /**
       * Deselects the provided multi-drag item
       * @param  {HTMLElement} el    The element to be deselected
       */
      deselect: function deselect(el) {
        var sortable = el.parentNode[expando],
            index = multiDragElements.indexOf(el);
        if (!sortable || !sortable.options.multiDrag || !~index) return;
        toggleClass(el, sortable.options.selectedClass, false);
        multiDragElements.splice(index, 1);
      }
    },
    eventProperties: function eventProperties() {
      var _this3 = this;

      var oldIndicies = [],
          newIndicies = [];
      multiDragElements.forEach(function (multiDragElement) {
        oldIndicies.push({
          multiDragElement: multiDragElement,
          index: multiDragElement.sortableIndex
        }); // multiDragElements will already be sorted if folding

        var newIndex;

        if (folding && multiDragElement !== dragEl$1) {
          newIndex = -1;
        } else if (folding) {
          newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
        } else {
          newIndex = index(multiDragElement);
        }

        newIndicies.push({
          multiDragElement: multiDragElement,
          index: newIndex
        });
      });
      return {
        items: _toConsumableArray(multiDragElements),
        clones: [].concat(multiDragClones),
        oldIndicies: oldIndicies,
        newIndicies: newIndicies
      };
    },
    optionListeners: {
      multiDragKey: function multiDragKey(key) {
        key = key.toLowerCase();

        if (key === 'ctrl') {
          key = 'Control';
        } else if (key.length > 1) {
          key = key.charAt(0).toUpperCase() + key.substr(1);
        }

        return key;
      }
    }
  });
}

function insertMultiDragElements(clonesInserted, rootEl) {
  multiDragElements.forEach(function (multiDragElement, i) {
    var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];

    if (target) {
      rootEl.insertBefore(multiDragElement, target);
    } else {
      rootEl.appendChild(multiDragElement);
    }
  });
}
/**
 * Insert multi-drag clones
 * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
 * @param  {HTMLElement} rootEl
 */


function insertMultiDragClones(elementsInserted, rootEl) {
  multiDragClones.forEach(function (clone, i) {
    var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];

    if (target) {
      rootEl.insertBefore(clone, target);
    } else {
      rootEl.appendChild(clone);
    }
  });
}

function removeMultiDragElements() {
  multiDragElements.forEach(function (multiDragElement) {
    if (multiDragElement === dragEl$1) return;
    multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
  });
}

Sortable.mount(new AutoScrollPlugin());
Sortable.mount(Remove, Revert);

/* harmony default export */ __webpack_exports__["default"] = (Sortable);



/***/ }),
/* 40 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(41);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37);
/* harmony import */ var _LocationSelector__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(104);
/* harmony import */ var _Common_Controls_IsoDOM__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(109);
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }






var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("Isocurve");

/**
 * @classdesc
 *
 * Leaflet Control Class to compute and display Isochrone or isodistances curves.
 *
 * Use {@link module:Controls.Isocurve L.geoportalControl.Isocurve()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.Isocurve
 */
var Isocurve = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Control.extend( /** @lends L.geoportalControl.Isocurve.prototype */{
  includes: _Common_Controls_IsoDOM__WEBPACK_IMPORTED_MODULE_5__["default"],
  /**
   * Options du service
   *
   * @private
   */
  options: {
    position: "topleft",
    collapsed: true,
    // plier !
    methods: ["time", "distance"],
    graphs: ["Voiture", "Pieton"],
    exclusions: {
      toll: false,
      tunnel: false,
      bridge: false
    },
    directions: ["departure", "arrival"],
    disableReverse: false,
    isocurveOptions: {},
    autocompleteOptions: {}
  },
  /**
   * @constructor Isocurve
   *
   * @private
   * @param {Object} options - Isocurve control options
   * @param {String}   [options.apiKey] - API key for services call (isocurve and autocomplete services). The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Boolean} [options.collapsed = true] - Specify if widget has to be collapsed (true) or not (false) on map loading. Default is true.
   * @param {Object}  [options.exclusions = {"toll" : false, "tunnel" : false, "bridge" : false}] - list of exclusions with status (true = checked), by default : ["toll":false, "tunnel":false, "bridge":false].
   * @param {Array}   [options.graphs = ["Voiture", "Pieton"]] - list of graph resources to be used for isocurve calculation, by default : ["Voiture", "Pieton"]. The first element is selected.
   * @param {Array}   [options.methods = ["time", "distance"]] - list of methods, by default : ["time", "distance"]. The first element is selected by default.
   * @param {Array}   [options.directions = ["departure", "arrival"]] - list of directions to be displayed, by default : ["departure", "arrival"]. The first element is selected by default.
   *      Directions enable to specify if input location point will be used as a departure point ("departure") or as an arrival point ("arrival")
   * @param {Boolean} [options.disableReverse = false] - whether to enable/disable the reverse geocoding
   * @param {Object} [options.isocurveOptions = {}] - isocurve service options.
   * @param {Object} [options.autocompleteOptions = {}] - autocomplete service options.
   * @example
   *  var iso = L.geoportalControl.Isocurve({
   *      collapsed : false
   *      methods : ["time", "distance"],
   *      exclusions : {
   *         toll : true,
   *         bridge : false,
   *         tunnel : true
   *      },
   *      graphs : ["Pieton", "Voiture"],
   *      isocurveOptions : {},
   *      autocompleteOptions : {}
   *  });
   */
  initialize: function initialize(options) {
    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.setOptions(this, options);

    /** uuid */
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].generate();

    /** detection du support : desktop ou tactile */
    this._isDesktop = this._detectSupport();

    /** detection si le panneau est reduit */
    // on desactive l'impl. reduction de la fenetre
    // this._reducePanel = false;

    /** container principaux */
    this._waitingContainer = null;
    this._showContainer = null;
    this._pictoContainer = null;
    this._formContainer = null;
    this._submitContainer = null;

    /** Mode de transport selectionné : 'Voiture' ou 'Pieton' */
    this._currentTransport = null;

    /** Sens du parcours selectionné : 'Départ' ou 'Arrivée' */
    this._currentDirection = null;

    /** Type d'isochrone et valeur selectionné : 'isochrone' ou 'distance' */
    this._currentComputation = null;
    this._currentTimeHour = 0;
    this._currentTimeMinute = 0;
    this._currentDistance = 0;

    /** Exclusions selectionnées : Tunnel, Toll et Bridge */
    this._currentExclusions = [];

    // initialisation
    this._initTransport();
    this._initComputation();
    this._initDirection();
    this._initExclusions();

    /** le point */
    this._currentPoint = null;

    /** la geometrie de l'isochrone */
    this._geojsonIso = null;

    /** si un calcul est en cours ou non */
    this._waiting = false;
    /** timer pour cacher la patience après un certain temps */
    this._timer = null;

    /**
     * reponse du service
     * Ex. {
     *   totalTime, totalDistance, bbox, routeGeometry,
     *   routeInstructions : [{duration, distance, code, instruction, bbox, geometry}]
     * }
     */
    this._currentIsoResults = null;

    /**
     * liste des ressources avec droits par service
     * Ex. {
     *   "IsoChrone" : {
     *       key : "ger4g456re45er456t4er5ge5",
     *       resources : ["Pieton", "Voiture"]
     *   }
     * }
     */
    this._resources = {};
  },
  /**
   * this method is called by this.addTo(map) when the control is added on the map
   * and fills variable 'this._container = this.onAdd(map)',
   * and create or disable events on map.
   * @param {L.Map} map - object map
   * @returns {DOMElement} container
   * @private
   */
  onAdd: function onAdd(map) {
    // initialisation du DOM du composant
    var container = this._container = this._initLayout(map);

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    return container;
  },
  /**
   * TODO this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @private
   */
  onRemove: function onRemove( /* map */) {},
  // ################################################################### //
  // ####################### init application ########################## //
  // ################################################################### //

  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initTransport: function _initTransport() {
    // Mode de transport selectionné
    this._currentTransport = "Voiture"; // par defaut

    // par defaut
    var transport = this.options.graphs;
    if (!transport || transport.length === 0) {
      this.options.graphs = ["Voiture", "Pieton"];
    }

    // option
    if (leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.isArray(transport) && transport.length) {
      // FIXME pb si le 1er graphe n'est pas une ressource connue !
      if (transport[0] === "Voiture" || transport[0] === "Pieton") {
        this._currentTransport = transport[0];
      }
    }

    // option sur le service
    var serviceOptions = this.options.isocurveOptions;
    if (serviceOptions.graph) {
      this._currentTransport = serviceOptions.graph;
    }
  },
  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initDirection: function _initDirection() {
    this._currentDirection = "departure"; // par defaut

    // par defaut
    var directions = this.options.directions;
    if (!directions || directions.length === 0) {
      this.options.directions = ["departure", "arrival"];
    }

    // option
    if (leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.isArray(directions) && directions.length) {
      // FIXME pb si le 1er graphe n'est pas une ressource connue !
      if (directions[0] === "departure" || directions[0] === "arrival") {
        this._currentDirection = directions[0];
      }
    }

    // si l'utilisateur a spécifié une méthode dans le service, on surcharge les options du widget
    var serviceOptions = this.options.isocurveOptions;
    if (!serviceOptions.reverse) {
      this._currentDirection = "departure";
    }
    if (serviceOptions.reverse === true) {
      this._currentDirection = "arrival";
      this.options.directions = ["arrival", "departure"];
    }
  },
  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initComputation: function _initComputation() {
    // Mode de calcul selectionné
    this._currentComputation = "time"; // par defaut

    // par defaut
    var methods = this.options.methods;
    if (!methods || methods.length === 0) {
      this.options.methods = ["time", "distance"];
    }

    // option
    if (leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.isArray(methods) && methods.length) {
      // FIXME pb si le 1er graphe n'est pas une ressource connue !
      if (methods[0] === "time" || methods[0] === "distance") {
        this._currentComputation = methods[0];
      }
    }

    // si l'utilisateur a spécifié une méthode dans le service, on surcharge les options du widget
    var serviceOptions = this.options.isocurveOptions;
    if (serviceOptions.method) {
      this._currentComputation = serviceOptions.method;
    }
    if (serviceOptions.time) {
      this._currentComputation = "time";
    }
    if (serviceOptions.distance) {
      this._currentComputation = "distance";
    }
  },
  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initExclusions: function _initExclusions() {
    // Exclusions selectionnées : Tunnel, Toll et Bridge
    this._currentExclusions = []; // par defaut

    // par defaut
    var exclusion = this.options.exclusions;
    if (!exclusion || _typeof(exclusion) === "object" && Object.keys(exclusion).length === 0) {
      this.options.exclusions = {
        toll: false,
        tunnel: false,
        bridge: false
      };
    }

    // option
    if (exclusion && _typeof(exclusion) === "object" && Object.keys(exclusion).length) {
      for (var k in exclusion) {
        if (exclusion.hasOwnProperty(k)) {
          if (exclusion.k) {
            this._currentExclusions.push(k);
          }
        }
      }
    }

    // si l'utilisateur a spécifié des exclusions dans le service, on surcharge les options du widget
    var serviceOptions = this.options.isocurveOptions;
    if (Array.isArray(serviceOptions.exclusions)) {
      this._currentExclusions = serviceOptions.exclusions;
    }
  },
  // ################################################################### //
  // ############################## other init ######################### //
  // ################################################################### //

  /**
   * this method is called by the constructor.
   * this information is useful to switch to touch mode.
   * Detection : test for desktop or tactile
   * @returns {Boolean} desktop or tactile
   * @private
   */
  _detectSupport: function _detectSupport() {
    // TODO
    // Choix de gérer la détection dans le code du composant au lieu du DOM car :
    // Utilisation de l'implémentation Leaflet
    // http://leafletjs.com/reference.html#browser

    var isDesktop = true;
    var userAgent = window.navigator.userAgent.toLowerCase();
    if (userAgent.indexOf("iphone") !== -1 || userAgent.indexOf("ipod") !== -1 || userAgent.indexOf("ipad") !== -1 || userAgent.indexOf("android") !== -1 || userAgent.indexOf("mobile") !== -1 || userAgent.indexOf("blackberry") !== -1 || userAgent.indexOf("tablet") !== -1 || userAgent.indexOf("phone") !== -1 || userAgent.indexOf("touch") !== -1) {
      isDesktop = false;
    }
    if (userAgent.indexOf("msie") !== -1 || userAgent.indexOf("trident") !== -1) {
      isDesktop = true;
    }
    return isDesktop;
  },
  // ################################################################### //
  // ########################### init dom ############################## //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   * @param {L.Map} map - object map
   * @returns {DOMElement} container
   * @private
   */
  _initLayout: function _initLayout(map) {
    // create main container
    var container = this._createMainContainerElement();
    var inputShow = this._showContainer = this._createShowIsoElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (!this.options.collapsed) {
      inputShow.checked = true;
    }
    var picto = this._pictoContainer = this._createShowIsoPictoElement();
    container.appendChild(picto);

    // panneau
    var panel = this._createIsoPanelElement();

    // header
    var header = this._createIsoPanelHeaderElement();
    panel.appendChild(header);

    // form
    var form = this._formContainer = this._createIsoPanelFormElement();

    // form: menu des points
    var point = this._createIsoPanelFormPointElement(map);
    form.appendChild(point);

    // form: menu du choix de la méthode de calcul (time ou distance)
    var isoChronChecked = false;
    var isoDistChecked = false;
    var typeChoice = this._createIsoPanelFormTypeChoiceElement();
    for (var i = 0; i < this.options.methods.length; i++) {
      if (this.options.methods[i] === "time") {
        isoChronChecked = i === 0;
        typeChoice.appendChild(this._createIsoPanelFormTypeChoiceChronElement(isoChronChecked));
      }
      if (this.options.methods[i] === "distance") {
        isoDistChecked = i === 0;
        typeChoice.appendChild(this._createIsoPanelFormTypeChoiceDistElement(isoDistChecked));
      }
    }
    form.appendChild(typeChoice);

    // form: menu du choix des valeurs
    form.appendChild(this._createIsoPanelFormValueIsochronElement(isoChronChecked));
    form.appendChild(this._createIsoPanelFormValueIsodistanceElement(isoDistChecked));

    // form: menu du choix du transport et du sens du parcours
    var modeChoice = this._createIsoPanelFormModeChoiceElement();
    modeChoice.appendChild(this._createIsoPanelFormModeChoiceTransportElement(this.options.graphs));
    modeChoice.appendChild(this._createIsoPanelFormModeChoiceDirectionElement(this.options.directions));
    form.appendChild(modeChoice);

    // form: menu des exclusions
    if (this.options.exclusions && _typeof(this.options.exclusions) === "object" && Object.keys(this.options.exclusions).length !== 0) {
      form.appendChild(this._createShowIsoExclusionsElement());
      form.appendChild(this._createShowIsoExclusionsPictoElement());
      var exclusion = this._createIsoPanelFormExclusionsElement();
      exclusion.appendChild(this._createIsoPanelFormExclusionOptionsElement(this.options.exclusions));
      form.appendChild(exclusion);
    }
    var divReset = this._createIsoFormResetElement();
    form.appendChild(divReset);

    // form: bouton du calcul
    var submit = this._submitContainer = this._createIsoSubmitFormElement();
    form.appendChild(submit);
    panel.appendChild(form);

    // waiting
    var waiting = this._waitingContainer = this._createIsoWaitingElement();
    panel.appendChild(waiting);
    container.appendChild(panel);
    return container;
  },
  // ################################################################### //
  // ############################## DOM ################################ //
  // ################################################################### //

  /**
   * Create a Point
   * OVERWRITTEN
   * @param {L.Map} map - object map
   * @returns {Object} DOM element
   * @private
   */
  _createIsoPanelFormPointElement: function _createIsoPanelFormPointElement(map) {
    // point de depart
    this._currentPoint = new _LocationSelector__WEBPACK_IMPORTED_MODULE_4__["default"]({
      apiKey: this.options.apiKey || null,
      tag: {
        id: 0,
        unique: this._uid,
        label: "Départ",
        color: "red",
        display: true
      },
      displayInfo: true,
      disableReverse: this.options.disableReverse,
      autocompleteOptions: this.options.autocompleteOptions || null
    });
    this._currentPoint.setMap(map);
    return this._currentPoint.getContainer();
  },
  // ################################################################### //
  // ####################### handlers events to dom #################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on 'GPshowIsochronPicto' picto
   * (cf. this._createShowIsoPictoElement),
   * and clear inputs and previous isochrone drawings
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowIsoPanelClick: function onShowIsoPanelClick(e) {
    logger.log("onShowIsoPanelClick", e);
    // on desactive l'impl. reduction de la fenetre
    // if (this._geojsonIso && !this._reducePanel) {
    //     this._clear();
    // }
    // this._reducePanel = false;
  },
  /**
   * this method is called by event 'click' on '' arrow button
   * (cf. this.),
   * and clear inputs and previous isochrone drawings
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoResetClick: function onIsoResetClick(e) {
    logger.log("onIsoResetClick", e);
    this._clear();
  },
  // // on desactive l'impl. reduction de la fenetre
  // /**
  // * this method is called by event 'click' on 'GPisochronPanelReduce' picto
  // * (cf. this.),
  // * and reduce the panel
  // *
  // * @private
  // */
  // onReduceIsoPanelClick : function () {
  //     logger.log("onReduceIsoPanelClick");
  //     this._reducePanel = true;
  // },

  /**
   * this method is called by event 'change' on 'GPisochronChoiceAltDist' or 'GPisochronChoiceAltChron'
   * input (cf. this._createIsoPanelFormTypeChoiceElement),
   * and updates current computation mode
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoTypeChoiceChange: function onIsoTypeChoiceChange(e) {
    var value = e.target.value;
    if (!value) {
      return;
    }
    if (value === "isodistance") {
      this._currentComputation = "distance";
    }
    if (value === "isochron") {
      this._currentComputation = "time";
    }
  },
  /**
   * this method is called by event 'click' on 'GPisochronTransportPedestrian' or 'GPisochronTransportCar'
   * input (cf. this._createIsoPanelFormModeChoiceTransportElement),
   * and updates current transport mode
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoModeTransportChange: function onIsoModeTransportChange(e) {
    var value = e.target.value;
    if (!value) {
      return;
    }
    this._currentTransport = value;
  },
  /**
   * this method is called by event 'change' on 'GPisochronDirectionSelect' select
   * (cf. this._createIsoPanelFormModeChoiceDirectionElement),
   * and updates current direction mode
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoModeDirectionChange: function onIsoModeDirectionChange(e) {
    var value = e.target.value;
    if (!value) {
      return;
    }
    this._currentDirection = value;
  },
  /**
   * this method is called by event 'change' on ''
   * input (cf. this.),
   * and updates current time value
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoValueChronTimeHourChange: function onIsoValueChronTimeHourChange(e) {
    var value = e.target.value;

    // pointer to...
    this._timeHourContainer = e.target;
    if (!value) {
      return;
    }
    this._currentTimeHour = value;
  },
  /**
   * this method is called by event 'change' on ''
   * input (cf. this.),
   * and updates current time value
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoValueChronTimeMinuteChange: function onIsoValueChronTimeMinuteChange(e) {
    var value = e.target.value;

    // pointer to...
    this._timeMinuteContainer = e.target;
    if (!value) {
      return;
    }
    this._currentTimeMinute = value;
  },
  /**
   * this method is called by event 'change' on ''
   * input (cf. this.),
   * and updates current distance value
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoValueDistChange: function onIsoValueDistChange(e) {
    var value = e.target.value;

    // pointer to...
    this._distanceContainer = e.target;
    if (!value) {
      return;
    }
    this._currentDistance = value;
  },
  /**
   * this method is called by event 'change' on 'GPIsoExclusionsToll'
   * or 'GPIsoeExclusionsTunnel' or 'GPIsoExclusionsBridge' tag input
   * (cf. this._createIsoPanelFormExclusionOptionsElement).
   * this value is saved as a parameter for the service isocurve.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onIsoExclusionsChange: function onIsoExclusionsChange(e) {
    var value = e.target.value;
    var checked = e.target.checked;
    if (!value) {
      return;
    }
    var bFound = false;
    var iFound = null;
    for (var i = 0; i < this._currentExclusions.length; i++) {
      if (deepEqual(this._currentExclusions[i], value.toLowerCase())) {
        iFound = i;
        bFound = true;
      }
    }
    // on l'ajoute si la valeur n'existe pas et est selectionnée
    if (!bFound && !checked) {
      this._currentExclusions.push(value.toLowerCase());
    }
    // on la retire si la valeur existe et est deselectionnée
    if (bFound && checked) {
      this._currentExclusions.splice(iFound, 1);
    }
  },
  /**
   * this method is called by event 'submit' on 'GPisochronForm' tag form
   * (cf. this._createIsoPanelFormElement),
   * and call isocurve service to display results
   *
   * @private
   */
  onIsoComputationSubmit: function onIsoComputationSubmit() {
    if (!this._currentPoint || !this._currentPoint.getCoordinate || !this._currentPoint.getCoordinate()) {
      return;
    }

    // récupération du temps
    var time;
    if (this._currentComputation.toLowerCase() === "time") {
      // durée exprimée en secondes
      time = this._currentTimeHour * 3600 + this._currentTimeMinute * 60;
      logger.log("time : ", time);
    }

    // récupération de la distance
    var distance;
    if (this._currentComputation.toLowerCase() === "distance") {
      // distance exprimée en mètres
      distance = this._currentDistance * 1000;
      logger.log("distance : ", distance);
    }

    // si on n'a pas de valeur de calcul renseignée, on ne lance pas la requête.
    if (!time && !distance) {
      logger.log("Missing time or distance parameter");
      return;
    }

    // mise en place de la patience
    this._displayWaitingContainer();
    var self = this;
    var pointCoordinate = self._currentPoint.getCoordinate();
    var position = {
      x: pointCoordinate.lon || pointCoordinate.lng,
      y: pointCoordinate.lat
    };
    this._requestIsoCurve({
      position: position,
      graph: self._currentTransport,
      exclusions: self._currentExclusions,
      method: self._currentComputation,
      reverse: self._currentDirection.toLowerCase() === "arrival",
      time: time,
      distance: distance,
      smoothing: true,
      timeout: 7000,
      protocol: "XHR",
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results) {
          self._drawIsoResults(results);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME mise à jour du controle mais le service ne repond pas en 200 !?
        self._hideWaitingContainer();
        self._clearIsoResultsGeometry();
        logger.log(error.message);
      }
    });
  },
  // ################################################################### //
  // ######################## isocurve calculation ##################### //
  // ################################################################### //

  /**
   * this method is called by this.onIsoComputationSubmit
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   *
   * @private
   */
  _requestIsoCurve: function _requestIsoCurve(settings) {
    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || _typeof(settings) === "object" && Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si on n'a pas de point d'origine
    if (!settings.position) {
      return;
    }
    var options = {};
    // on recupere les parametres de saisie et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(options, settings);
    // ainsi que les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(options, this.options.isocurveOptions);
    options.apiKey = this.options.isocurveOptions.apiKey || this.options.apiKey;

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    options.ssl = this.options.ssl;
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_2__["default"].Services.isoCurve(options);
  },
  /**
   * this method is called by this.onIsoComputationSubmit (in case of success)
   * and draw isocurve results geometry on map
   *
   * @param {Object} results - isocurve response results
   *
   * @private
   */
  _drawIsoResults: function _drawIsoResults(results) {
    this._clearIsoResultsGeometry();

    // sauvegarde de l'etat des resultats
    this._currentIsoResults = results;
    if (!results.geometry) {
      // cache la patience
      this._hideWaitingContainer();
      return;
    }
    var map = this._map;
    var _geometry = results.geometry;
    var _style = {
      color: "#ff7800",
      weight: 5,
      opacity: 0.65
    };
    this._geojsonIso = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.geoJson(_geometry, {
      style: _style
    }).addTo(map);

    // cache la patience
    this._hideWaitingContainer();
    this._formContainer.className = "GPisochroComponentHidden";
  },
  // ################################################################### //
  // ############################# Clean ############################### //
  // ################################################################### //

  /**
   * this method is called by this.onShowIsoPanelClick()
   * and it clears all elements (reinit).
   *
   * @private
   */
  _clear: function _clear() {
    this._initTransport();
    this._initExclusions();
    this._initComputation();
    this._initDirection();

    // resultats du service
    this._currentIsoResults = null;

    // la geometrie
    this._clearIsoResultsGeometry();

    // les points
    this._currentPoint.clear();

    // nettoyer les valeurs dans le DOM !
    if (this._timeHourContainer) {
      this._timeHourContainer.value = 0;
    }
    if (this._timeMinuteContainer) {
      this._timeMinuteContainer.value = 0;
    }
    if (this._distanceContainer) {
      this._distanceContainer.value = 0;
    }
  },
  /**
   * this method is called by this.onIsoComputationSubmit()
   * and it clears all route geometries.
   *
   * @private
   */
  _clearIsoResultsGeometry: function _clearIsoResultsGeometry() {
    var map = this._map;
    if (this._geojsonIso != null) {
      map.removeLayer(this._geojsonIso);
      this._geojsonIso = null;
    }
  },
  // ################################################################### //
  // ############################ Patience ############################# //
  // ################################################################### //

  /**
   * this method displays waiting container and sets a timeout
   *
   * @private
   */
  _displayWaitingContainer: function _displayWaitingContainer() {
    this._waitingContainer.className = "GPisochronCalcWaitingContainerVisible";
    this._waiting = true;

    // mise en place d'un timeout pour réinitialiser le panel (cacher la patience)
    // si on est toujours en attente (si la requête est bloquée par exemple)
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
    var context = this;
    this._timer = setTimeout(function () {
      if (context._waiting === true) {
        context._hideWaitingContainer();
      } else {
        if (context._timer) {
          clearTimeout(context._timer);
        }
      }
    }, 16000);
  },
  /**
   * this method hides waiting container and clears timeout
   *
   * @private
   */
  _hideWaitingContainer: function _hideWaitingContainer() {
    if (this._waiting) {
      this._waitingContainer.className = "GPisochronCalcWaitingContainerHidden";
      this._waiting = false;
      clearTimeout(this._timer);
      this._timer = null;
    }
  },
  // ################################################################### //
  // ###### METHODES PUBLIQUES (INTERFACE AVEC LE CONTROLE) ############ //
  // ################################################################### //

  /**
   * This method is public.
   * It allows to control the execution of a traitment.
   *
   * @param {Object} position - position = {lon: , lat: }
   * @param {Object} value - distance en km ou heures-minutes
   * @param {Object} options - options = {...}
   */
  compute: function compute(position, value, options) {
    if (!this._showContainer.checked) {
      this._pictoContainer.click();
    }
    var map = this._map;
    if (!map) {
      return;
    }

    // Les options par defauts
    var settings = {
      direction: "departure",
      method: "time",
      transport: "Voiture",
      exclusions: []
    };

    // On recupere les options
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(settings, options);
    this._currentPoint.setCoordinate(position);
    var input = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPlocationOrigin_" + 0 + "-" + this._uid);
    input.value = position.lng + " , " + position.lat;
    this._currentTransport = settings.transport;
    if (settings.transport === "Voiture") {
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronTransportCar-" + this._uid).checked = true;
    } else {
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronTransportPedestrian-" + this._uid).checked = true;
    }
    this._currentExclusions = settings.exclusions;
    this._currentComputation = settings.method;
    if (settings.method === "time") {
      var time = value.split(".");
      this._currentTimeHour = time[0] || 0;
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronValueChronInput1-" + this._uid).value = this._currentTimeHour;
      this._currentTimeMinute = time[1] || 0;
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronValueChronInput2-" + this._uid).value = this._currentTimeMinute;
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronChoiceAltChron-" + this._uid).click();
    } else {
      this._currentDistance = value;
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronValueDistInput-" + this._uid).value = this._currentDistance;
      leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronChoiceAltDist-" + this._uid).click();
    }
    this._currentDirection = settings.direction;
    settings.direction === "departure" ? leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronDirectionSelect-" + this._uid).selectedIndex = 0 : leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.get("GPisochronDirectionSelect-" + this._uid).selectedIndex = 1;
    this.onIsoComputationSubmit();
    map.flyTo(position);
  }
});
/* harmony default export */ __webpack_exports__["default"] = (Isocurve);
var deepEqual = function deepEqual(x, y) {
  if (x === y) {
    return true;
  } else if (_typeof(x) === "object" && x != null && _typeof(y) === "object" && y != null) {
    if (Object.keys(x).length !== Object.keys(y).length) {
      return false;
    }
    for (var prop in x) {
      if (y.hasOwnProperty(prop)) {
        if (!deepEqual(x[prop], y[prop])) {
          return false;
        }
      } else {
        return false;
      }
    }
    return true;
  } else {
    return false;
  }
};

/***/ }),
/* 41 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "servicesVersion", function() { return servicesVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "servicesDate", function() { return servicesDate; });
/* harmony import */ var _Services_Services__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(42);
/* harmony import */ var _Services_DefaultUrlService__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63);
/* harmony import */ var _Services_Alti_Response_model_AltiResponse__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(76);
/* harmony import */ var _Services_Alti_Response_model_Elevation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(77);
/* harmony import */ var _Services_AutoComplete_Response_model_AutoCompleteResponse__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(90);
/* harmony import */ var _Services_AutoComplete_Response_model_SuggestedLocation__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91);
/* harmony import */ var _Services_ProcessIsoCurve_Response_model_ProcessIsoCurveResponse__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(103);
/* harmony import */ var _Services_Route_Response_model_RouteResponse__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(97);
/* harmony import */ var _Services_Route_Response_model_RouteInstruction__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(98);
/* harmony import */ var _Services_Config_Config__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(43);
/* harmony import */ var _Protocols_XHR__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(49);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(61);
/* harmony import */ var _Utils_Helper__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(47);
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(62);
var _package_json__WEBPACK_IMPORTED_MODULE_13___namespace = /*#__PURE__*/__webpack_require__.t(62, 1);
/**
* Global variable Gp.
*
* @module Gp
* @alias Gp
* @description
*
* This is the global variable that is exposed in the browser environment.
* Content is composed of constructor, functions and properties...
*
* > {@link Gp.Error Error()}
*     - .TYPE_SRVERR : "SERVICE_ERROR"
*     - .TYPE_UNKERR : "UNKNOWN_ERROR"
*     - .TYPE_USEERR : "USAGE_ERROR"
*
* > {@link module:Helper Helper}
*     - .indent()
*     - .normalyzeParameters()
*     - .normalyzeUrl()
*
* > {@link module:XHR Protocols.XHR}
*     - .call()
*
* > {@link module:Services Services (objects)}
*     - .Alti
*         - {@link Gp.Services.Alti.Elevation .Elevation()}
*     - {@link Gp.Services.AltiResponse .AltiResponse()}
*     - .AutoComplete
*         - {@link Gp.Services.AutoComplete.SuggestedLocation .SuggestedLocation()}
*     - {@link Gp.Services.AutoCompleteResponse .AutoCompleteResponse()}
*     - {@link Gp.Services.Config .Config()}
*     - {@link Gp.Services.DefaultUrl .DefaultUrl()}
*     - {@link Gp.Services.GeocodeResponse .GeocodeResponse()}
*     - {@link Gp.Services.GetConfigResponse .GetConfigResponse()}
*     - {@link Gp.Services.IsoCurveResponse .IsoCurveResponse()}
*     - .Route
*         - {@link Gp.Services.Route.RouteInstruction .RouteInstruction()}
*     - {@link Gp.Services.RouteResponse .RouteResponse()}
*
* > Services (factory)
*     - {@link module:Services~autoComplete .autoComplete()}
*     - {@link module:Services~geocode .geocode()}
*     - {@link module:Services~getAltitude .getAltitude()}
*     - {@link module:Services~getConfig .getConfig()}
*     - {@link module:Services~isoCurve .isoCurve()}
*     - {@link module:Services~reverseGeocode .reverseGeocode()}
*     - {@link module:Services~route .route()}
*
* > servicesDate : "YYYY-MM-DD"
*
* > servicesVersion : "X.X.X"
*
*/

















/** Version */
const servicesVersion = _package_json__WEBPACK_IMPORTED_MODULE_13__.version;
/** Publication date */
const servicesDate = _package_json__WEBPACK_IMPORTED_MODULE_13__.date;

// on declare les ns dans root global
var Gp = {};

Gp.servicesVersion = servicesVersion;
Gp.servicesDate = servicesDate;

// Export Protocols
Gp.Protocols = {};
Gp.Protocols.XHR = _Protocols_XHR__WEBPACK_IMPORTED_MODULE_10__["default"];
// Export services
Gp.Services = _Services_Services__WEBPACK_IMPORTED_MODULE_0__["default"];
// Export DefaultUrls
Gp.Services.DefaultUrl = _Services_DefaultUrlService__WEBPACK_IMPORTED_MODULE_1__["default"];
// Export Alti
Gp.Services.AltiResponse = _Services_Alti_Response_model_AltiResponse__WEBPACK_IMPORTED_MODULE_2__["default"];
Gp.Services.Alti = {};
Gp.Services.Alti.Elevation = _Services_Alti_Response_model_Elevation__WEBPACK_IMPORTED_MODULE_3__["default"];
// Export Autocomplete
Gp.Services.AutoCompleteResponse = _Services_AutoComplete_Response_model_AutoCompleteResponse__WEBPACK_IMPORTED_MODULE_4__["default"];
Gp.Services.AutoComplete = {};
Gp.Services.AutoComplete.SuggestedLocation = _Services_AutoComplete_Response_model_SuggestedLocation__WEBPACK_IMPORTED_MODULE_5__["default"];
// Export Config
Gp.Services.Config = _Services_Config_Config__WEBPACK_IMPORTED_MODULE_9__["default"];
// Export IsoCurve
Gp.Services.IsoCurveResponse = _Services_ProcessIsoCurve_Response_model_ProcessIsoCurveResponse__WEBPACK_IMPORTED_MODULE_6__["default"];
// Export Route
Gp.Services.RouteResponse = _Services_Route_Response_model_RouteResponse__WEBPACK_IMPORTED_MODULE_7__["default"];
Gp.Services.Route = {};
Gp.Services.Route.RouteInstruction = _Services_Route_Response_model_RouteInstruction__WEBPACK_IMPORTED_MODULE_8__["default"];
// Export Erreurs et Outils
Gp.Error = _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_11__["default"];
Gp.Helper = _Utils_Helper__WEBPACK_IMPORTED_MODULE_12__["default"];

/* harmony default export */ __webpack_exports__["default"] = (Gp);


/***/ }),
/* 42 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(43);
/* harmony import */ var _Alti_Alti__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(65);
/* harmony import */ var _Geocode_Geocode__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(79);
/* harmony import */ var _Geocode_ReverseGeocode__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(87);
/* harmony import */ var _AutoComplete_AutoComplete__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(88);
/* harmony import */ var _Route_Route__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(92);
/* harmony import */ var _ProcessIsoCurve_ProcessIsoCurve__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(99);
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "point|circle|bbox" }] */

/**
* Geoportal web services invocation namespace.
*
* @module Services
* @alias Gp.Services
*/








var Services = {
    /**
     * Access to Geoportal resources metadata availables with one ore several keys
     *
     * @method getConfig
     * @param {Object} options - Options for function call.
     * @param {String} [options.apiKey] - Access key(s) ("," as separator, no spaces) to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}
     * @param {String} [options.customConfigFile] - path to a local config file. Overload the apiKey parameter
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.GetConfigResponse} object as a parameter except if "rawResponse" parameter is set to true : a String will be returned.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     */
    getConfig : function (options) {
        var configService = new _Config_Config__WEBPACK_IMPORTED_MODULE_0__["default"](options);
        configService.call();
    },
    /**
     * Getting elevations in or along of one or several points on french territories using the [elevation services of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/alti.html}.<br/>
     * Two use cases are availables :<br/>
     * 1. getting elevations of the given points : don't use the options.sampling parameter ;<br/>
     * 2. getting a regular set of elevations along the given points : use the options.sampling parameter.
     *
     * @method getAltitude
     * @param {Object} options - Options for function call.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {Array.<Object>} options.positions - Array of positions ({lon:float, lat:float}) expressed in CRS:84 coordinates system, where to get elevations. 50 positions maximum may be given. 2 positions minimum are required if you use the options.sampling parameter.
     * @param {Number} [options.sampling] - Number of points to use (between 2 and 5000) in order to compute an elevation path. The points given with the options.positions parameter are used to fix the planimetric path along which the elevations will be computed.<br/>
     * If not used, only elevations of these positions will be returned.
     * @param {Boolean} [options.zonly=false] - Set this parameter to true if you only want to have elevations returned without corresponding coordinates.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.AltiResponse} object as a parameter, except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.serverUrl=https://data.geopf.fr/altimetrie/1.0/calcul/alti/rest/elevation.json] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.protocol=XHR] - Protocol used to handle dialog with web service. Possible values are 'JSONP' ({@link https://en.wikipedia.org/wiki/JSONP}) and 'XHR' ({@link https://en.wikipedia.org/wiki/XMLHttpRequest}). Only XHR protocol is supported in a NodeJS environment. Only use if you know what you're doing.
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {String} [options.httpMethod=GET] - HTTP method to use when requesting underlying web service in case of a XHR protocol use (see above). Possible values are 'GET' and 'POST'. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {String} [options.contentType="application/xml"] - Content-Type to use when requesting underlying web service in case of a XHR protocol use (see above) and if method HTTP is POST. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     * @param {String} [options.api='REST'] - What API to use for interacting with underlying web service : 'REST'. Only use if you know what you are doing.
     * @param {String} [options.outputFormat='xml'] - Output format for underlying web service response : 'xml' or 'json'. Only use if you know what you are doing.
     */
    getAltitude : function (options) {
        var altiService = new _Alti_Alti__WEBPACK_IMPORTED_MODULE_1__["default"](options);
        altiService.call();
    },
    /**
     * Getting positon of a geographic identifier (places names, address, cadastral parcel, other...) using the [geocoding web service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/geocodage.html}.
     *
     * @example
     * Gp.Services.geocode ({
     *     apiKey : "carte",
     *     location : "73 avenue de Paris, Saint-Mandé",
     *     // traitement des resultats
     *     onSuccess  : function (result) {
     *         console.log("found (x:"+result.position.x+", y:"+result.position.y+")") ;
     *     }
     * }) ;
     *
     *
     * @method geocode
     * @param {Object} options - Options for function call.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {String} [options.index="StreetAddress"] - Geographical identifier type to search. Values currently availables are : "PositionOfInterest" for place names, "StreetAddress" for address search, "CadastralParcel" for Cadastral parcels search, "location" for a multi-index search on "StreetAddress" and "PositionOfInterest". Default is "StreetAddress".
     * @param {String} options.query - Geographic identifier to locate.
     * @param {Object} [options.filters] - Additional filters to apply to search. The following properties may be given.
     *      @param {String} [options.filters.[prop]] - Additionnal properties to filter search. Properties depends on options.index, and values type should be "String".
     *      <br/><br/>
     *      Properties availables for address search :<br/>
     *      "postalCode", "inseeCode" and "city".
     *      <br/><br/>
     *      Properties availables for place names search :<br/>
     *      "postalCode", "inseeCode" and "type".
     *      <br/><br/>
     *      Properties availables for cadastral parcels search :<br/>
     *      "codeDepartement", "codeCommune", "nomCommune", "codeCommuneAbs", "codeArrondissement", "section", "numero", "feuille".
     * @param {Number} [options.maximumResponses=20] - Maximum number of responses. Default underlying service value applies (20) if not provided.
     * @param {Boolean} [options.returnTrueGeometry=false] - Set this parameter to true if you wish to have the true geometrie returned.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.GeocodeResponse} object as a parameter except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.serverUrl=http (s)://data.geopf.fr/geocodage/search] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     */
    geocode : function (options) {
        var geocodeService = new _Geocode_Geocode__WEBPACK_IMPORTED_MODULE_2__["default"](options);
        geocodeService.call();
    },
    /**
     * Retrieving geographical identifiers (place names, address, cadastral parcels, ...) near a given position, using the [reverse geocoding web service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/geocodage-inverse.html}.
     *
     * @method reverseGeocode
     * @param {Object} options - Options for function call.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {String} [options.index="StreetAddress"] - Geographical identifier type to search. Values currently availables are : "PositionOfInterest" for place names, "StreetAddress" for address search, "CadastralParcel" for Cadastral parcels search, "location" for a multi-index search on "StreetAddress" and "PositionOfInterest". Default is "StreetAddress".
     * @param {Object} options.position - Reference position where to search geographical identifiers.
     *      @param {Float} options.position.lon - Longitude
     *      @param {Float} options.position.lat - Latitude
     * @param {Object} [options.filters] - Additional filters to apply to search. The following properties may be given.
     *      @param {String} [options.filters.[prop]] - Additionnal properties to filter search. Properties depends on options.index, and values type should be "String".
     *      <br/><br/>
     *      Properties availables for address search :<br/>
     *      "postalCode", "inseeCode" and "city".
     *      <br/><br/>
     *      Properties availables for place names search :<br/>
     *      "postalCode", "inseeCode" and "type".
     *      <br/><br/>
     *      Properties availables for cadastral parcels search :<br/>
     *      "codeDepartement", "codeCommune", "nomCommune", "codeCommuneAbs", "codeArrondissement", "section", "numero", "feuille".
     * @param {Object} [options.searchGeometry] - Location where to perform the search.
     *      @param {String} options.searchGeometry.type - Geometry type (Point|Circle|Linestring|Polygon)
     *      @param {Array.<Float>|Array.Array.<Float>} options.searchGeometry.coordinates - Coordinates
     *      @param {Float} [options.searchGeometry.radius] - Radius (only for type 'Circle')
     * @param {Number} [options.maximumResponses=20] - Maximum number of responses. Default underlying service value applies (20) if not provided.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.GeocodeResponse} object as a parameter except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.serverUrl=https://data.geopf.fr/geocodage/reverse] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     */
    reverseGeocode : function (options) {
        var reverseGeocodeService = new _Geocode_ReverseGeocode__WEBPACK_IMPORTED_MODULE_3__["default"](options);
        reverseGeocodeService.call();
    },
    /**
     * Getting suggestions of probable places names or address based on uncomplete texts, using the [autocompletion service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/autocompletion.html}
     *
     * @method autoComplete
     * @param {Object} options - Options for function call.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {String} options.text - Text input to complete.
     * @param {Array.<String>} [options.filterOptions.type = "StreetAddress"] - Suggestion types to provide : address ("StreetAddress") and/or place name ("PositionOfInterest").
     * @param {Array.<String>} [options.filterOptions.territory] - Places where to limit the search of suggestions : "METROPOLE" (Corsica and metropolitan France), "DOMTOM" (French overseas departments and territories), or an INSEE code of a department. No limitation by default. For instance : ['METROPOLE', '31']
     * @param {Number} [options.maximumResponses = 10] - Maximum number of responses.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.AutoCompleteResponse} object as a parameter except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.serverUrl=https://data.geopf.fr/geocodage/completion] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.protocol=XHR] - Protocol used to handle dialog with web service. Possible values are 'JSONP' ({@link https://en.wikipedia.org/wiki/JSONP}) and 'XHR' ({@link https://en.wikipedia.org/wiki/XMLHttpRequest}). Only XHR protocol is supported in a NodeJS environment. Only use if you know what you're doing.
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {String} [options.httpMethod=GET] - HTTP method to use when requesting underlying web service in case of a XHR protocol use (see above). Possible values are 'GET' and 'POST'. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {String} [options.contentType="application/xml"] - Content-Type to use when requesting underlying web service in case of a XHR protocol use (see above) and if method HTTP is POST. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     */
    autoComplete : function (options) {
        var autoCompleteService = new _AutoComplete_AutoComplete__WEBPACK_IMPORTED_MODULE_4__["default"](options);
        autoCompleteService.call();
    },
    /**
     * Getting a route from one point to another using the [route service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/itineraires.html}.
     *
     * @method route
     * @param {Object} options - Options for function call.
     * @param {String} options.resource - Resource used to compute the route. Available values are in the GetCapabilities.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {String} [options.routePreference = "fastest"] - Indicates the way to compute the route : "fastest" (time optimisation) or "shortest" (distance optimisation). Available values are in the GetCapabilities.
     * @param {Gp.Point} options.startPoint - Start point of the route. Expressed in CRS:84 coordinates system (startPoint.x corresponds to longitude, startPoint.y corresponds to latitude). Available bbox are in the GetCapabilities.
     * @param {Gp.Point} options.endPoint - End point of the route. Expressed in CRS:84 coordinates system (endPoint.x corresponds to longitude, endPoint.y corresponds to latitude). Available bbox are in the GetCapabilities.
     * @param {Array.<Gp.Point>} [options.viaPoints] - Ordered via Points of the route. Expressed in CRS:84 coordinates system (viaPoints[i].x corresponds to longitude, viaPoints[i].y corresponds to latitude). Available bbox are in the GetCapabilities.
     * @param {String} [options.graph = "Voiture"] - User profile to use to compute the route : "Voiture" (using a vehicule) or "Pieton" (pedestrian). Has an influence on the kind of roads the route may use and the average speed. Available bbox are in the GetCapabilities.
     * @param {Array.<String>} [options.exclusions] - DEPRECATED: use options.constraints. Indicates if route has to avoid some features ("toll", "bridge" or "tunnel").
     * @param {Boolean} [options.geometryInInstructions = false] - Indicates if route geometry has to be also returned with route instructions.
     * @param {Boolean} [options.provideBoundingBox = true] - Indicates if route instructions has to be localised with a BBOX in the response.
     * @param {String} [options.distanceUnit = "m"] - The unit used to provide distances in the response ("meter" or "kilometer").
     * @param {String} [options.timeUnit = "second"] - The unit used to provide duration in the response ("standard", "second", "minute", "hour").
     * @param {Array.<String>} [options.waysAttributes] - Way Attributes to add in the response. Available values are in the GetCapabilities.
     * @param {Array.<Object>} [options.constraints] - Constraints used ({'constraintType':'banned','key':'ways_type','operator':'=','value':'autoroute'}). Available values are in the GetCapabilities.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.RouteResponse} object as a parameter except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.outputFormat='json'] - Output format ("json" or "xml") to use for underlying webService. Only use if you know what you are doing.
     * @param {String} [options.serverUrl=https://data.geopf.fr/navigation/itineraire] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.protocol=XHR] - Protocol used to handle dialog with web service. Possible values are 'JSONP' ({@link https://en.wikipedia.org/wiki/JSONP}) and 'XHR' ({@link https://en.wikipedia.org/wiki/XMLHttpRequest}). Only XHR protocol is supported in a NodeJS environment. Only use if you know what you're doing.
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {String} [options.httpMethod=GET] - HTTP method to use when requesting underlying web service in case of a XHR protocol use (see above). Possible values are 'GET' and 'POST'. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {String} [options.contentType="application/xml"] - Content-Type to use when requesting underlying web service in case of a XHR protocol use (see above) and if method HTTP is POST. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     */
    route : function (options) {
        var routeService = new _Route_Route__WEBPACK_IMPORTED_MODULE_5__["default"](options);
        routeService.call();
    },
    /**
     * Computing a set of places (curve) reachable from a given point (or from where to start to reach a given point) within a time or distance constraint using the [isochrone service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/isochrones.html}.
     *
     * @method isoCurve
     * @param {Object} options - Options for function call.
     * @param {String} options.apiKey - Access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
     * @param {String} options.resource - Resource used to compute the route. Available values are in the GetCapabilities.
     * @param {Gp.Point} options.position - Start or Arrival (options.reverse===true) Point for the computing. Expressed in CRS:84 coordinates system (position.x corresponds to longitude, position.y corresponds to latitude).
     * @param {String} [options.graph = "Voiture"] - User profile to use to compute the isoCurve : "Voiture" (using a vehicule) or "Pieton" (pedestrian). Has an influence on the kind of roads to use and the average speed. Available values are in the GetCapabilities.
     * @param {Array.<String>} [options.exclusions] - DEPRECATED: use options.constraints. Indicates if route has to avoid some features ("toll", "bridge" or "tunnel").
     * @param {Array.<Object>} [options.constraints] - Constraints used ({'constraintType':'banned','key':'ways_type','operator':'=','value':'autoroute'}). Available values are in the GetCapabilities.
     * @param {String} [options.method = "time"] - Computing method to use : "time" (using a duration as a constraint) or "distance" (using a distance as a constraint). Available values are in the GetCapabilities.
     * @param {Float} options.time - Maximum duration (expressed in seconds) to use when options.method is set to "time".
     * @param {Float} options.distance - Maximum distance (expressed in meters) to use when options.method is set to "distance".
     * @param {Boolean} [options.reverse = false] - Set this parameter to true if you want options.position to be the destination (instead of departure) for the computing.
     * @param {String} [options.distanceUnit = "km"] - The unit used to provide distances in the response ("m" or "km").
     * @param {String} [options.timeUnit = "second"] - The unit used to provide duration in the response ("standard", "second", "minute", "hour").
     * @param {Boolean} [options.smoothing = false] - DEPRECATED: Set this parameter to true if you want the resulting geometry to be smoothed.
     * @param {Boolean} [options.holes = false] - DEPRECATED: Set this parameter to true if you want the resulting geometry (polygon) to have holes if pertinent.
     * @param {Function} options.onSuccess - Callback function for getting successful service response. Takes a {@link Gp.Services.IsoCurveResponse} object as a parameter except if "rawResponse" is set to true.
     * @param {Function} [options.onFailure] - Callback function for handling unsuccessful service responses (timeOut, missing rights, ...). Takes a {@link Gp.Error} object as parameter.
     * @param {Number} [options.timeOut=0] - Number of milliseconds above which a timeOut response will be returned with onFailure callback (see above). Default value is 0 which means timeOut will not be handled.
     * @param {String} [options.outputFormat='json'] - Output format ("json") to use for underlying webService. Only use if you know what you are doing.
     * @param {String} [options.serverUrl=https://data.geopf.fr/navigation/isochrone] - Web service URL. If used, options.apiKey parameter is ignored. Only use if you know what you're doing.
     * @param {Boolean} [options.ssl = true] - Use of HTTPS or HTTP protocol to request the services. HTTPS by default (ssl=true).
     * @param {String} [options.protocol=XHR] - Protocol used to handle dialog with web service. Possible values are 'JSONP' ({@link https://en.wikipedia.org/wiki/JSONP}) and 'XHR' ({@link https://en.wikipedia.org/wiki/XMLHttpRequest}). Only XHR protocol is supported in a NodeJS environment. Only use if you know what you're doing.
     * @param {String} [options.proxyURL] - Proxy URL to use when requesting underlying web service. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you're doing.
     * @param {String} [options.callbackSuffix] - Callback function name suffix to use in case of a JSONP protocol use (see above), to set your own suffix instead of auto-increment. Ignored when options.protocol is set to 'XHR' value. Only use if you know what you're doing.
     * @param {String} [options.httpMethod=GET] - HTTP method to use when requesting underlying web service in case of a XHR protocol use (see above). Possible values are 'GET' and 'POST'. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {String} [options.contentType="application/xml"] - Content-Type to use when requesting underlying web service in case of a XHR protocol use (see above) and if method HTTP is POST. Ignored when options.protocol is set to 'JSONP' value. Only use if you know what you are doing.
     * @param {Boolean} [options.rawResponse=false] - Setting this parameter to true implies you want to handle the service response by yourself : it will be returned as an unparsed String in onSuccess callback parameter. Only use if you know what you are doing.
     * @param {Function} [options.onBeforeParse] - Callback function for handling service response before parsing (as an unparsed String). Takes a String as a parameter (the raw service response). Returns a String that will be parsed as the service response. Only use if you know what you are doing.
     */
    isoCurve : function (options) {
        var processIsoCurveService = new _ProcessIsoCurve_ProcessIsoCurve__WEBPACK_IMPORTED_MODULE_6__["default"](options);
        processIsoCurveService.call();
    }
};

/**
 * Point object.
 *
 * @namespace
 * @alias Gp.Point
 *
 * @property {Float} x - Point abscissa
 * @property {Float} y - Point ordinate
 */
var point = {};

/**
 * Circle object.
 *
 * @namespace
 * @alias Gp.Circle
 *
 * @property {Float} x - Circle center abscissa.
 * @property {Float} y - Circle center ordinate.
 * @property {Float} radius - Circle radius.
 */
var circle = {};

/**
 * Bounding box object, expressed with four coordinates.
 *
 * @namespace
 * @alias Gp.BBox
 *
 * @property {Float} left - minimum abscissa
 * @property {Float} right - maximum abscissa
 * @property {Float} bottom - minimum ordinate
 * @property {Float} top - maximum ordinate
 */
var bbox = {};

/* harmony default export */ __webpack_exports__["default"] = (Services);


/***/ }),
/* 43 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(63);
/* harmony import */ var _ConfigInterface__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(64);






/**
 * @classdesc
 *
 * Recupération de la configuration de clés Géoportail sous forme de JSON
 *
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.Config
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 * @param {Sting} options.apiKey - clé(s) dont on veut obtenir la configuration. Si plusieurs clés, séparer chacune par une virgule
 * @param {Boolean} [options.sync=false] - force le mode synchrone
 * @param {String} options.customConfigFile - chemin vers un fichier de configuration personnalisé. Surcharge le paramètre apiKey.
 *
 * @example
 *   var options = {
 *      apiKey : "cartes,ortho",
 *      sync : false,
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *   };
 *
 */
function Config (options) {
    if (!(this instanceof Config)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "Config"));
    }

    /**
     * Nom de la classe (heritage)
     */
    this.CLASSNAME = "Config";

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Config");
    this.logger.trace("[Constructeur Config (options)]");

    // #####################
    // analyse des options
    // #####################

    // gestion du callback onSuccess
    var bOnSuccess = !!(options.onSuccess !== null && typeof options.onSuccess === "function");
    if (!bOnSuccess) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "onSuccess()"));
    }
    if (!options.apiKey && !options.customConfigFile) {
        // si pas de thème spécifié, on récupère toutes les ressources possibles dans l'objet Config
        options.apiKey = "full";
    }
    this.options = {};
    this.options.onSuccess = options.onSuccess;
    this.options.onFailure = options.onFailure;

    // mode sync
    this.options.sync = options.sync || false;

    // gestion d'un tableau d'url des fichiers de configuration
    this.options.listConfigUrls = (options.customConfigFile)
        ? [options.customConfigFile]
        : !Array.isArray(options.apiKey)
            ? _DefaultUrlService__WEBPACK_IMPORTED_MODULE_3__["default"].Config.url(options.apiKey.split(","))
            : _DefaultUrlService__WEBPACK_IMPORTED_MODULE_3__["default"].Config.url(options.apiKey);
}

/**
 * @lends module:Config#
 */
Config.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_2__["default"].prototype, {
    // todo
    // getter/setter
});

/**
 * Constructeur (alias)
 */
Config.prototype.constructor = Config;

/**
 * Création de la requête
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 * @overload
 */
Config.prototype.buildRequest = function (error, success) {
    // liste des urls des fichiers de configuration en JSON
    this.listConfigUrls = this.options.listConfigUrls;

    if (!this.listConfigUrls) {
        error.call(this, new Error("url by default not found !"));
        return;
    }

    // INFO :
    // il n'y a pas de construction de requête,
    // on passe directement à l'appel des requêtes
    success.call(this, this.listConfigUrls);
};

/**
 * Récupération des configuration
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 * @overload
 */
Config.prototype.callService = function (error, success) {
    if (this.options.sync) {
        __callServiceSync.call(this, error, success);
    } else {
        __callService.call(this, error, success);
    }
};

/**
 * Requêtes en mode asynchrone
 *
 * @param {*} error
 * @param {*} success
 * @private
 */
var __callService = function (error, success) {
    // liste des resultats au format JSON
    this.listConfigResults = [];

    // test on env. nodejs or browser
    let Fetch = null;
    if (typeof window === "undefined") {
        var nodefetch = __webpack_require__(53);
        Fetch = nodefetch;
    } else {
        Fetch = window.fetch;
    }

    // the factory of fetch !
    var fetchFactory = (url) => {
        return Fetch(url, { credentials : "same-origin" })
            .then((response) => {
                if (response.ok) {
                    return response.json()
                        .then((json) => {
                            // TODO :
                            // tester le contenu !
                            return json;
                        })
                        .catch((error) => {
                            throw new Error("Exception Json : " + error);
                        });
                } else {
                    throw new Error("Exception HTTP : " + response.status + " (status code) !");
                }
            })
            .catch((error) => {
                return new Promise((resolve, reject) => {
                    // eslint-disable-line no-unused-vars
                    reject(error);
                });
            });
    };

    // construction des promises fetch
    var promises = [];
    for (let index = 0; index < this.listConfigUrls.length; index++) {
        const url = this.listConfigUrls[index];
        promises.push(fetchFactory(url));
    }

    Promise.all(promises)
        .then((results) => {
            if (!results) {
                throw new Error("results config empty !?");
            }
            results.forEach((result) => {
                // TODO :
                // verification des resultats
                this.listConfigResults.push(result);
            });
        })
        .then(() => {
            success.call(this, this.listConfigResults);
        })
        .catch((e) => {
            // TODO :
            // construction d'un message
            error.call(this, e);
        });
};

/**
 * Requêtes en mode synchrone
 *
 * @param {*} error
 * @param {*} success
 * @private
 */
var __callServiceSync = function (error, success) {
    // liste des resultats au format JSON
    this.listConfigResults = [];

    // FIXME :
    // boucle synchrone !
    for (var i = 0; i < this.listConfigUrls.length; i++) {
        const url = this.listConfigUrls[i];
        // TODO :
        // prévoir le CORS, headers, ...
        const request = new XMLHttpRequest();
        request.open("GET", url, false);
        request.send(null);
        if (request.status === 200) {
            // TODO :
            // tester la reponse !
            var response = JSON.parse(request.responseText);
            this.listConfigResults.push(response);
        }
    }
    // callback
    if (this.listConfigResults.length !== 0) {
        success.call(this, this.listConfigResults);
    } else {
        error.call(this, new Error("..."));
    }
};

/**
 * Analyse et mise en forme de la réponse en fusionnant les configurations
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 * @overload
 */
Config.prototype.analyzeResponse = function (error, success) {
    // fonction de merge des objects JSON
    var mergeConfig = function (objects) {
        // objet fusion des couches
        var allLayersConfig = {};
        // objet fusion des clés
        var allKeysConfig = {};
        // objet fusion des TMS
        var allTMSConfig = {};

        // on fusionne les résultat
        for (var i = 0; i < objects.length; i++) {
            if (!objects[i].generalOptions || !objects[i].layers) {
                return;
            }
            allKeysConfig = {
                ...allKeysConfig,
                ...objects[i].generalOptions.apiKeys
            };
            allLayersConfig = {
                ...allLayersConfig,
                ...objects[i].layers
            };
            allTMSConfig = {
                ...allTMSConfig,
                ...objects[i].tileMatrixSets
            };
        }

        var mergedConfig = {
            generalOptions : {
                apiKeys : allKeysConfig
            },
            layers : allLayersConfig,
            tileMatrixSets : allTMSConfig
        };
        return mergedConfig;
    };

    // fusion des configurations JSON
    var ConfigJSON = mergeConfig(this.listConfigResults);
    if (!ConfigJSON) {
        error.call(this, new Error("configuration structure not conforme !"));
        return;
    }

    // creation des interfaces
    var IConfig = new _ConfigInterface__WEBPACK_IMPORTED_MODULE_4__["default"]();
    // ajout des interfaces avec la configuration JSON
    Object.assign(IConfig, ConfigJSON);

    // définition de la variable globale Gp.Config
    var scope = typeof window !== "undefined" ? window : {};
    if (!scope.Gp) {
        scope.Gp = {};
    }

    // enregistrement
    if (scope.Gp.Config) {
        Object.assign(scope.Gp.Config, IConfig);
        // dans le doute..., ceinture et bretelles !
        for (var property in IConfig) {
            scope.Gp.Config[property] = IConfig[property];
        }
    } else {
        scope.Gp.Config = IConfig;
    }

    // INFO :
    // il n'y a pas d'analyse des résultats,
    // on passe directement à l'appel de la callback utilisateur
    success.call(this, scope.Gp.Config);
};

/* harmony default export */ __webpack_exports__["default"] = (Config);


/***/ }),
/* 44 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var loglevel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(36);
/* harmony import */ var loglevel__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(loglevel__WEBPACK_IMPORTED_MODULE_0__);


var LoggerByDefault = {
    /**
     * logger statique
     *
     * @static
     * @param {String} name - nom du logger
     * @returns {Object} retourne un logger
     */
    getLogger : function (name) {
        // Substitute global constants configured at compile time
        // cf. webpack.config.js
        // on définit process si non défini dans l'environnement
        // eslint-disable-next-line no-use-before-define
        if (typeof process === "undefined") {
            var process = {};
            process.env = {
                VERBOSE : false
            };
        }
        (process.env.VERBOSE) ? loglevel__WEBPACK_IMPORTED_MODULE_0__["enableAll"]() : loglevel__WEBPACK_IMPORTED_MODULE_0__["disableAll"]();
        var logname = name || "default";
        return loglevel__WEBPACK_IMPORTED_MODULE_0__["getLogger"](logname);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (LoggerByDefault);


/***/ }),
/* 45 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Classe de gestion des erreurs qui permer d'associer un message d'erreur à l'exception lancée.
 *
 * @example
 * MessagesResources.getMessage("ERROR_PARAM_MISSING", "x", "y", "z")));
 * // --> output : Parameter(s) 'x - y - z' missing
 *
 * @module MessagesResources
 * @alias Gp.Utils.MessagesResources
 * @private
 */
var MessagesResources = {

    // Paramètres
    PARAM_MISSING : "Parameter(s) '%var%' missing",
    PARAM_EMPTY : "Parameter(s) '%var%' empty",
    PARAM_TYPE : "Wrong type(s) for parameter(s) '%var%'",
    PARAM_FORMAT : "Parameter(s) '%var%' not correctly formatted",
    PARAM_NOT_SUPPORT : "Value(s) for parameter(s) '%var%' not supported",
    PARAM_NOT_SUPPORT_NODEJS : "Value(s) for parameter(s) '%var%' not supported to NodeJS",
    PARAM_UNKNOWN : "Value(s) for parameter(s) '%var%' unknown",

    // Services
    // Requête
    SERVICE_REQUEST_BUILD : "An error occurred during the request building of the service",
    SERVICE_REQUEST_EMPTY : "The request sent to the service is empty",

    // Réponse
    SERVICE_RESPONSE_EXCEPTION : "The service returned an exception : '%var%'",
    SERVICE_RESPONSE_EXCEPTION_2 : "The service returned an exception",
    SERVICE_RESPONSE_ANALYSE : "An error occurred while parsing the response '%var%' of the service",
    SERVICE_RESPONSE_ANALYSE_2 : "An unknown error occurred while parsing the response",
    SERVICE_RESPONSE_EMPTY : "The response of the service is empty",
    SERVICE_RESPONSE_EMPTY_2 : "The response from the service could not be analyzed or is empty",
    SERVICE_RESPONSE_FORMAT : "The format of the service response is not supported (handled format(s) : '%var%')",
    SERVICE_RESPONSE_FORMAT_2 : "The format of the service response is not supported",
    SERVICE_RESPONSE_FORMAT_3 : "No suggestion matching the search",

    // Classes
    CLASS_CONSTRUCTOR : "'%var%' constructor cannot be called as a function.",

    /**
     * Fonction qui va retourner le message d'erreur associé à la clé donnée
     *
     * @method getMessage
     * @param {String} clef - Clef de l'erreur (ex : ERROR_PARAM)
     * @param {String[]} parametres - Paramètres/variables concernés par le message d'erreur associé à la clef donnée
     * @return {String} message - String contenant le message de l'exception
     */
    getMessage : function (clef, parametres) {
        // param de la fonction uniquement pour la documentation...

        if (Object.keys(arguments).length === 0) {
            return "Message indefined !";
        }

        var params = Array.prototype.slice.call(arguments);
        var key = params.shift();
        var args = params;

        var message = this[key];

        try {
            if (Array.isArray(args) && args.length > 0) {
                message = message.replace("%var%", args.join(" - "));
            } else {
                message = message.replace("%var%", "%var% (not specified)");
            }
        } catch (e) {
            // error de string.replace()

        }

        return message;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (MessagesResources);


/***/ }),
/* 46 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(47);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(45);
/* harmony import */ var _Protocols_Protocol__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(48);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(61);
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(62);
var _package_json__WEBPACK_IMPORTED_MODULE_5___namespace = /*#__PURE__*/__webpack_require__.t(62, 1);





// import DefaultUrlService from "./DefaultUrlService";
// package.json (extract version)


/**
 * @classdesc
 * Composant Service
 *
 * @constructor
 * @alias Gp.Services.CommonService
 * @param {Object} options - options communes à tous les services
 *
 * @param {String} [options.serverUrl] - URL d'accès au service. Par défaut "https://data.geopf.fr/SERVICE/".
 *      Permet de forcer l'utilisation d'un service équivalent déployé derrière une éventuelle autre URL d'accès.
 *      Si ce paramètre est renseigné alors, le paramètre par défaut est ignoré.
 *
 * @param {String} [options.protocol] - Le protocole à utiliser pour récupérer les informations du service :
 *      peut valoir 'JSONP' ou 'XHR'.
 *      Par défaut, c'est le protocole XHR qui sera utilisé.
 *      Attention, le protocole JSONP n'est pas valide dans un environnement NodeJS (Utilisation du mode XHR).
 *
 * @param {Boolean} [options.ssl] - Indique si l'on souhaite intérroger les services en https.
 *      Ce paramètre ne fonctionne que pour une utilisation hors navigateur (ex. NodeJS).
 *      Sur un navigateur, le protocole est automatiquement extrait de l'url du site...
 *      Par défaut, on utilise le protocole http (ssl=false).
 *
 * @param {String} [options.proxyURL] - Le proxy à utiliser pour pallier au problème de cross-domain dans le cas d'une requête XHR.
 *      Utile si le paramètre 'protocol' vaut 'XHR', il ne sera pas pris en compte si protocol vaut JSONP.
 *
 * @param {String} [options.callbackSuffix] - Suffixe de la fonction de callback à utiliser, dans le cas du protocole JSONP.
 *      Par défaut, la fonction de callback portera un nom du type "callback"+ID, où ID est soit un identifiant unique généré à chaque requête,
 *      soit le paramètre callbackSuffix s'il est spécifié. Par exemple, si callbackSuffix="_2", la fonction sera "callback_2 ()".
 *      Utile pour utiliser une réponse déjà encapsulée dans une fonction de callback, dont le nom est connu
 *      Utile seulement si le paramètre 'protocol' vaut 'JSONP', il ne sera pas pris en compte si protocol vaut 'XHR'.
 *
 * @param {String} [options.httpMethod] - La méthode HTTP
 *      à utiliser dans le cas d'une requête XHR : peut valoir 'GET' ou 'POST'.
 *      Non pris en compte si 'protocol' vaut JSONP qui fonctionne obligatoirement en GET.
 *      Par défaut, c'est la méthode GET qui est utilisée.
 *
 * @param {String} [options.contentType] - Content-Type de la requete
 *      à utiliser dans le cas d'une requête XHR en mode POST.
 *      Non pris en compte si 'protocol' vaut JSONP et/ou la méthode HTTP vaut GET.
 *      Par défaut, c'est la méthode GET qui est utilisée donc on n'utilise pas de Content-Type.
 *
 * @param {Number} [options.timeOut] - Délai d'attente maximal (en ms) de la réponse du service (à partir de l'envoi de la requête).
 *      Par défaut, aucun timeOut n'est pris en compte (timeoutDelay= 0).
 *
 * @param {Boolean} [options.rawResponse] - Indique si l'on souhaite que la réponse du service ne soit pas parsée par l'API avant d'être restituée.
 *      (Cf. paramètre « onSuccess » pour plus de détails).
 *
 * @param {Function} [options.onSuccess] - Fonction appelée lorsque le service répond correctement à la requête
 *      (code HTTP 200, sans message d'erreur).
 *      Cette fonction prend en paramètre la réponse du service,
 *      soit sous la forme d'un Object Javascript formaté par le parseur dédié à la syntaxe du service (comportement par défaut) ;
 *      soit brute au format String non prétraité si le paramètre « rawResponse » a été précisé avec la valeur « true ».
 *
 * @param {Function} [options.onFailure] - Fonction appelée lorsque le service ne répond pas correctement
 *      (code HTTP de retour différent de 200 ou pas de réponse).
 *
 * @param {Function} [options.onBeforeParse] - Fonction appelée avant le parsing de la réponse
 *      Permet de modifier la réponse avant parsing et la fonction doit retourner une String.
 *      Cette fonction prend en paramètre la réponse telle que renvoyée par le service
 *      (cad au format json ou xml).
 *      Pour le JSONP, si le paramètre "rawResponse" a été précisé avec la valeur "true",
 *      la fonction prend en paramètre un Object JavaScript contenant la réponse XML.
 *
 * @example
 *   var options = {
 *      serverUrl : 'http://localhost/service/',
 *      protocol : 'JSONP', // JSONP|XHR
 *      ssl : false,
 *      proxyURL : null,
 *      callbackName : null,
 *      httpMethod : 'GET', // GET|POST
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      onBeforeParse : function (rawResponse) {}
 *   };
 */
function CommonService (options) {
    if (!(this instanceof CommonService)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("CLASS_CONSTRUCTOR"));
    }

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("CommonService");
    this.logger.trace("[Constructeur CommonService (options)]");

    // #####################
    // récupération des options par défaut pour les paramètres optionnels
    // #####################

    /**
     * Options du service
     * @type {Object}
     */
    this.options = {
        // protocol : "JSONP",
        protocol : "XHR",
        ssl : true,
        proxyURL : "",
        // callbackName : "",
        callbackSuffix : null,
        httpMethod : "GET",
        timeOut : 0,
        rawResponse : false,
        scope : this,
        /**
        * callback par defaut pour la reponse
        * @param {Object} response - response
        * @private
        */
        onSuccess : function (response) {
            console.log("onSuccess - la reponse est la suivante : ", response);
        },
        /**
        * callback par defaut pour les erreurs
        * @param {Object} error - error
        * @private
        */
        onFailure : function (error) {
            if (error.status === 200 || !error.status) {
                console.log("onFailure : ", error.message);
            } else {
                console.log("onFailure - Erreur (", error.status, ") : ", error.message);
            }
        }
    };

    // et on ajoute les options en paramètre aux options par défaut
    for (var opt in options) {
        if (options.hasOwnProperty(opt)) {
            this.options[opt] = options[opt];
        }
    }

    // #####################
    // analyse des options
    // #####################

    // modification de la fonction de callback onSuccess dans le cas où la réponse brute est demandée
    if (this.options.rawResponse && !this.options.onSuccess) {
        /**
        * callback par defaut pour la reponse
        * @param {Object} response - response
        * @private
        */
        this.options.onSuccess = function (response) {
            console.log("onSuccess - la réponse brute du service est la suivante : ", response);
        };
    }

    // gestion du callback onSuccess
    var bOnSuccess = !!(this.options.onSuccess !== null && typeof this.options.onSuccess === "function");
    if (!bOnSuccess) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("PARAM_MISSING", "onSuccess()"));
    }

    // gestion de la methode HTTP
    this.options.httpMethod = (typeof options.httpMethod === "string") ? options.httpMethod.toUpperCase() : "GET";

    switch (this.options.httpMethod) {
        case "POST":
        case "GET":
            break;
        case "PUT":
        case "DELETE":
        case "HEAD":
        case "OPTIONS":
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("PARAM_NOT_SUPPORT", "httpMethod"));
        default:
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("PARAM_UNKNOWN", "httpMethod"));
    }

    // gestion du protocole
    // this.options.protocol = (typeof options.protocol === "string" ) ? options.protocol.toUpperCase() : "JSONP";
    this.options.protocol = (typeof options.protocol === "string") ? options.protocol.toUpperCase() : "XHR";

    switch (this.options.protocol) {
        case "JSONP":
        case "XHR":
            break;
        default:
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("PARAM_UNKNOWN", "protocol"));
    }

    // on determine l'environnement d'execution : browser ou non ?
    // et on lance une exception sur l'utilisation du protocole JSONP pour nodeJS...
    if (typeof window === "undefined" && this.options.protocol === "JSONP") {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_2__["default"].getMessage("PARAM_NOT_SUPPORT_NODEJS", "protocol=JSONP (instead use XHR)"));
    }

    // le protocole JSONP ne fonctionne qu'en GET.
    if (this.options.protocol === "JSONP") {
        this.options.httpMethod = "GET";
    }

    // gestion du cache
    this.options.nocache = options.nocache || false;

    // #####################
    // attributs d'instances
    // #####################

    /**
     * Format de réponse du service
     */
    this.options.outputFormat = null;
    /**
     * Requête envoyée au service
     */
    this.request = null;
    /**
     * Reponse du service
     */
    this.response = null;
}

/**
 * @lends module:CommonService
 */
CommonService.prototype = {

    /*
     * Constructeur (alias)
     */
    constructor : CommonService,

    /**
     * Appel du service Géoportail
     */
    call : function () {
        /* jshint validthis : true */
        this.logger.trace("CommonService::call ()");

        var context = this;
        /** fonction d'execution */
        function run () {
            this.logger.trace("CommonService::run ()");
            this.buildRequest.call(context, onError, onBuildRequest);
        }

        run.call(context);

        // callback de fin de construction de la requête
        function onBuildRequest (result) {
            this.logger.trace("CommonService::onBuildRequest : ", result);
            this.callService.call(context, onError, onCallService);
        }

        // callback de fin d'appel au service
        function onCallService (result) {
            this.logger.trace("CommonService::onCallService : ", result);
            this.analyzeResponse.call(context, onError, onAnalyzeResponse);
        }

        // callback de fin de lecture de la reponse
        function onAnalyzeResponse (result) {
            this.logger.trace("CommonService::onAnalyzeResponse : ", result);
            if (result) {
                this.options.onSuccess.call(this, result);
            } else {
                return onError.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"]("Analyse de la reponse en échec !?"));
            }
        }

        // callback de gestion des erreurs : renvoit un objet de type ErrorService
        function onError (error) {
            this.logger.trace("CommonService::onError()");
            // error : l'objet est du type ErrorService ou Error
            var e = error;
            if (!(e instanceof _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"])) {
                e = new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"](error.message);
            }
            this.options.onFailure.call(this, e);
        }
    },

    /**
     * Création de la requête
     * @param {Function} error - callback
     * @param {Function} success - callback
     */
    buildRequest : function (error, success) {
        // INFO
        this.logger.error("overwritten method !");
        // retourne l'objet 'this.request'
        if (error) {
            error.call(this, "This method must be overwritten !");
        }
        success.call(this, "This method must be overwritten !");
    },

    /**
     * Appel du service
     * @param {Function} error - callback
     * @param {Function} success - callback
     */
    callService : function (error, success) {
        // INFO
        // retourne l'objet 'this.response'

        // NOTES
        //  Pour le mode XHR, on recupère une reponse sous forme d'un json ou xml (#document).
        //  Pour le mode JSONP, on a toujours un objet JSON mais sous 2 formes :
        //      - natif
        //      - XML encapsulé :
        //          {http : {status:200, error:null},xml :'réponse du service'}
        //          {http : {status:400, error:'reponse du service'},xml :null}
        //  En XHR, la reponse est directement sauvegardée dans 'this.response'.
        //  Par contre, en JSONP, on doit analyser la reponse (status ou non vide),
        //  et ne renvoyer que le contenu (xml ou l'objet)

        // gestion de la proxification du service
        var strUrlProxified = null;
        var strData = this.request;

        // a t on mis en place un proxy ?
        // la proxyfication est valable uniquement en mode XHR !
        var bUrlProxified = !!(this.options.proxyURL && this.options.protocol === "XHR");

        // rajout de l'option gpbibaccess
        // INFO : acces au numero de version de package.conf aprés compilation !
        var requestMetaOptions = {
            "gp-access-lib" : _package_json__WEBPACK_IMPORTED_MODULE_5__.version
        };

        if (this.options.apiKey) {
            requestMetaOptions.apiKey = this.options.apiKey;
        }

        this.options.serverUrl = _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__["default"].normalyzeUrl(this.options.serverUrl, requestMetaOptions, false);

        // si le proxy est renseigné, on proxifie l'url du service
        if (bUrlProxified) {
            if (this.options.httpMethod === "GET") {
                strUrlProxified = this.options.proxyURL + _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__["default"].normalyzeUrl(this.options.serverUrl, this.request, true);
                strData = null;
            }

            if (this.options.httpMethod === "POST") {
                strUrlProxified = this.options.proxyURL + _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__["default"].normalyzeUrl(this.options.serverUrl, null, true);
                strData = this.request;
            }
        }

        // contexte du composant spécifique !
        var self = this;

        var options = {
            url : strUrlProxified || this.options.serverUrl,
            method : this.options.httpMethod,
            protocol : this.options.protocol,
            timeOut : this.options.timeOut || 0,
            format : this.options.outputFormat, // ceci declenche le parsing de la reponse du service, mais on souhaite toujours une reponse brute (string) !
            nocache : this.options.nocache || false, // ceci permet d'ajouter un timestamp dans la requête
            wrap : this.options.protocol !== "XHR", // ceci declenche l'encapsulation de la reponse XML du service dans du JSON, mais pas en mode XHR !
            callbackSuffix : this.options.callbackSuffix,
            // callbackName : this.options.callbackName || null,
            data : strData,
            headers : null, // TODO...
            content : this.options.contentType || "application/xml",
            scope : this.options.scope || this,
            // callback de reponse
            onResponse : function (response) {
                self.logger.trace("callService::onResponse()");

                // le contenu de la reponse à renvoyer !
                var content = null;

                // XHR : on renvoie toujours la reponse brute du service (json ou xml)
                // au parser du composant...
                if (self.options.protocol === "XHR") {
                    self.logger.trace("Response XHR", response);
                    content = response; // par defaut, la reponse du service  !
                }

                // JSONP : on pre-analyse la reponse brute du service (encapsuler ou pas)
                // avant de l'envoyer au parser du composant...
                if (self.options.protocol === "JSONP") {
                    self.logger.trace("Response JSON", response);
                    if (response) {
                        if (response.http) {
                            // reponse encapsulée :
                            // ex. reponse du service en xml
                            // > {http : {status:200, error:null},xml :'réponse du service'}
                            if (response.http.status !== 200) {
                                error.call(self, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"]({
                                    status : response.http.status,
                                    message : response.http.error,
                                    type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"].TYPE_SRVERR
                                }));
                                return;
                            } else {
                                content = response.xml; // par defaut !
                                if (self.options.rawResponse) {
                                    content = response;
                                }
                            }
                        } else {
                            // reponse non encapsulée :
                            // ex. reponse du service en json ou xml
                            content = response;
                        }
                    } else {
                        error.call(self, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"]("Le contenu de la reponse est vide !?"));
                        return;
                    }
                }

                // si on souhaite parser la reponse du service
                if (typeof self.options.onBeforeParse === "function") {
                    var newResponse = self.options.onBeforeParse(content);
                    if (typeof newResponse === "string") {
                        // la reponse parsée par l'utilisateur est retournée sous
                        // forme de string !
                        content = newResponse;
                    }
                }
                // sauvegarde de la reponse dans l'objet parent (CommonService)
                self.response = content;
                // on renvoie la reponse...
                success.call(self, content);
            },
            // callback des erreurs
            onFailure : function (e) {
                self.logger.trace("callService::onFailure()");
                // on est forcement sur une erreur levée par un service !
                e.type = _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"].TYPE_SRVERR;
                error.call(self, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"](e));
            },
            // callback de timeOut
            onTimeOut : function () {
                self.logger.trace("callService::onTimeOut()");
                error.call(self, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_4__["default"]("TimeOut!"));
            }
        };

        _Protocols_Protocol__WEBPACK_IMPORTED_MODULE_3__["default"].send(options);
    },

    /**
     * Analyse de la réponse
     * @param {Function} error - callback
     * @param {Function} success - callback
     */
    analyzeResponse : function (error, success) {
        // INFO
        this.logger.error("overwritten method !");
        // retourne l'objet spécifique au type de composant (json)
        if (error) {
            error.call(this, "This method must be overwritten !");
        }
        success.call(this, "This method must be overwritten !");
    }

};

/* harmony default export */ __webpack_exports__["default"] = (CommonService);


/***/ }),
/* 47 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Classe utilitaire
 *
 * @module Helper
 * @alias Gp.Helper
 */
var Helper = {

    /**
     * concatenation des parametres key/value dans les urls
     *
     * @method normalyzeParameters
     * @static
     * @param {Object} params - tableau de clef/valeur
     *
     * @example
     *  Gp.Utils.Helper.normalyzeParameters ({
     *         key1:value1,
     *         key2:value2,
     *         key3:value3
     *  });
     *  // out : "key1=value1&key2=value2&key3=value3"
     *
     * @returns {String} retourne les paramètres concaténés
     */
    normalyzeParameters : function (params) {
        var myParams = null;

        if (params) {
            var tabParams = [];
            for (var key in params) {
                if (params.hasOwnProperty(key)) {
                    var value = params[key];
                    if (!value) {
                        value = "";
                    }
                    tabParams.push(key + "=" + value);
                }
            }

            myParams = tabParams.join("&");
        }

        return myParams;
    },

    /**
     * Concaténation et encodage des urls.
     *
     * @method normalyzeUrl
     * @static
     * @param {String} url - url
     * @param {Object|String} params - tableau de clef/valeur ou string
     * @param {Boolean} encode - true|false, false par defaut
     *
     * @example
     *  Gp.Utils.Helper.normalyzeUrl (url, {
     *         key1:value1,
     *         key2=:value2,
     *         key3:value3
     *  });
     *  // out : "url?key1=value1&key2=value2&key3=value3"
     *
     * @returns {String} retourne une url normalisée
     */
    normalyzeUrl : function (url, params, encode) {
        var myUrl = url;

        if (url) {
            if (url.split("?").length - 1 >= 2) {
                // S'il y a plusieurs "?" dans l'URL, on garde le premier et on remplace les autres par des &
                var firstOccuranceIndex = url.search(/\?/) + 1;
                myUrl = url.substring(0, firstOccuranceIndex) + url.slice(firstOccuranceIndex).replace(/\?/g, "&");
            }

            var k = url.indexOf("?");
            if (k === -1) { // pas de ? et KVP
                myUrl += "?";
            }

            if (k !== -1 && k !== url.length - 1) { // KVP
                myUrl += "&";
            }
        }

        if (params) {
            if (typeof params === "string") {
                params = params.replace("?", "");
                myUrl += params;
            } else {
                myUrl += this.normalyzeParameters(params);
            }
        }

        if (encode) {
            // FIXME bonne idée ?
            myUrl = encodeURIComponent(myUrl);
        }

        return myUrl;
    },

    /**
     * Indentation d'une chaine
     *
     * @method indent
     * @static
     * @param {Number} n - nombre de tabulation
     * @param {String} msg - chaine
     *
     * @example
     * Gp.Utils.Helper.indent (2, "message à indenter")
     * // out
     * // ........message à indenter
     *
     * @returns {String} retourne une chaine indentée
     */
    indent : function (n, msg) {
        var num = n || 0;
        return new Array(num + 1).join("\t") + msg;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (Helper);


/***/ }),
/* 48 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_Helper__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(47);
/* harmony import */ var _XHR__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(49);
/* harmony import */ var _JSONP__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(60);
/**
 * Interface de dialogue avec les webservices
 *
 * @module Protocols
 * @private
 * @alias Gp.Protocols
 */




var Protocol = {

    /**
     * Interface unique d"envoi d"une requête.
     *
     * @method send
     * @static
     * @param {Object} options - options generales
     * @param {String} options.url      - url du service
     * @param {String} options.method   - GET, POST, PUT, DELETE
     * @param {String} options.protocol - XHR | JSONP
     * @param {String} options.format   - format de la reponse du service : json, xml ou null (brute)...
     * @param {String} options.wrap     - encapsuler la reponse du service dans du JSON : true|false (true par defaut sur le protocole JSONP)
     * @param {String} options.callbackSuffix - suffixe de la fonction de callback (JSONP uniquement) (ex: si callbackSuffix="", la fonction s'appellera "callback")
     * @param {String} options.timeOut  - 0 ms
     * @param {Boolean} options.nocache  - true|false
     * @param {Object|String} options.data        - content (post) ou param (get)
     * @param {Object|String} options.headers     - (post) ex. referer
     * @param {Object|String} options.content - (post) ex. "application/json"
     * @param {String} options.scope       - this (TODO)
     * @param {Function} options.onResponse - callback
     * @param {Function} options.onFailure - callback
     * @param {Function} options.onTimeOut - callback
     * @param {String} options.proxyUrl -  (TODO)
     */
    send : function (options) {
        // INFO
        // "output" - param est interne à la classe "Protocol" (parametrable via "wrap"), et à ajouter à l"url
        //      ce param est independant du service car il est géré par le filtre LUA :
        //          ex. json|xml (json par defaut).
        //          Ce param. permet d"encapsuler du XML dans du JSON :
        //              {http : {status:200, error:null},xml :"réponse du service"}
        //          Utile pour les services qui ne repondent que du XML (ex. Geocodage)
        //
        // |-------------------------------------------------|
        // |      \service |      |     |                    |
        // | output\ format| json | xml |     remarques      |
        // |--------\------|------|-----|--------------------|
        // |    json       | json | json| json/xml encapsulé |
        // |    xml        | json | xml | param inactif      |
        // |-------------------------------------------------|
        // ex. le service demande une reponse native au "format" json et avec un "output" json.
        // on a donc une reponse json encapsulé dans un json : ce qu'on ne souhaite pas !
        // dans ce cas on ne renseigne pas output=json

        // INFO
        // "wrap" - choix d"encapsuler ou non les reponses dans du JSON.
        //      Par defaut, on encapsule uniquement les reponses sur le protocole JSONP (et qui sont en xml) !

        // INFO
        // "callback" - param est interne à la classe "Protocol" (non parametrable), et à ajouter à l"url
        //      ce param est independant du service car il est géré aussi par le filtre LUA :
        //          ex. callback|null
        //          Ce param. permet de renvoyer une reponse javascript :
        //              callback ({http : {status:200, error:null},xml :"réponse du service"})
        //          Ce param. est non renseigné par defaut car pour du JSONP, on utilise le
        //          le protocol JSONP, et ce dernier implemente déjà le callback !

        // settings par defaut
        var settings = options || {
            method : "GET",
            // protocol : "JSONP",
            protocol : "XHR",
            timeOut : 0,
            format : null,
            wrap : true,
            nocache : true,
            output : "json",
            callback : null,
            callbackSuffix : null
        };

        // on determine l'environnement d'execution : browser ou non ?
        // et on stoppe pour nodeJS... sur un protocole JSONP !
        if (typeof window === "undefined" && options.protocol === "JSONP") {
            console.log("Value (s) for parameter (s) 'protocol=JSONP (instead use XHR)' not supported to NodeJS");
            return;
        }

        if (options.protocol === "XHR" || options.format === "json") {
            settings.wrap = false;
        } else if (options.protocol === "JSONP" && options.format === "xml") {
            settings.wrap = true;
        }

        settings.callback = null; // FIXME non géré !?
        settings.output = settings.wrap ? "json" : null;

        // on encapsule les reponses dans un objet JSON
        if (settings.wrap) {
            var params = {};
            params.output = settings.output;
            params.callback = settings.callback;
            delete params.callback; // FIXME non géré !?
            settings.url = _Utils_Helper__WEBPACK_IMPORTED_MODULE_0__["default"].normalyzeUrl(options.url, params);
        }

        // choix de l"implementation :
        // XHR ou JSONP
        switch (settings.protocol) {
            case "XHR":
                // on normalise l'url (gestion du cache)
                if (options.method === "GET" && options.nocache) {
                    settings.url = _Utils_Helper__WEBPACK_IMPORTED_MODULE_0__["default"].normalyzeUrl(settings.url, {
                        t : new Date().getTime()
                    });
                }
                // appel du service en XHR
                _XHR__WEBPACK_IMPORTED_MODULE_1__["default"].call(settings);
                break;
            case "JSONP":

                // on normalise l'url si les params. sont renseignés dans la string|object "data"
                if (settings.data) {
                    settings.url = _Utils_Helper__WEBPACK_IMPORTED_MODULE_0__["default"].normalyzeUrl(settings.url, settings.data);
                }

                // appel du service en JSONP
                _JSONP__WEBPACK_IMPORTED_MODULE_2__["default"].call(settings);
                break;
            default:
                throw new Error("protocol not supported (XHR|JSONP) !");
        }
    }

};

/* harmony default export */ __webpack_exports__["default"] = (Protocol);


/***/ }),
/* 49 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(47);
/* harmony import */ var es6_promise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(50);
/* harmony import */ var es6_promise__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(es6_promise__WEBPACK_IMPORTED_MODULE_2__);
/* global Promise, require, XDomainRequest */




// import __request from "request";
// import __xmldom from "xmldom";

/**
 * Ajax Request (use of Promises)
 *
 * @module XHR
 * @alias Gp.Protocols.XHR
 * @see dependance 'es6-promise'
 */

// cf. https://xhr.spec.whatwg.org/
// cf. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

var XHR = {

    /**
     * Interface unique d'envoi d'une requête.
     *
     * @method call
     * @static
     * @param {Object} settings - options generales
     * @param {String} settings.url    - url du service
     * @param {String} settings.method - GET, POST, PUT, DELETE
     * @param {String} settings.format - format de la reponse du service : json, xml ou null (brute)
     * @param {String} settings.data   - content (post) ou param (get)
     * @param {String} settings.proxy  - proxy url
     * @param {Object|String} settings.headers - (post) ex. referer
     * @param {Object|String} settings.content - (post) ex. 'application/json'
     * @param {String} settings.timeOut - timeout = 0 par defaut
     * @param {String} settings.scope - this
     * @param {Function} settings.onResponse - callback
     * @param {Function} settings.onFailure  - callback
     */
    call : function (settings) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("XHR");
        logger.trace("[XHR::call()]");

        // FIXME
        // To polyfill the global environment
        es6_promise__WEBPACK_IMPORTED_MODULE_2___default.a.polyfill();

        // test sur les settings obligatoires
        if (!settings.url) {
            throw new Error("missing parameter : url is not defined !");
        }

        if (!settings.method) {
            throw new Error("missing parameter : method is not defined !");
        }

        if (!settings.format) {
            settings.format = "text"; // reponse brute !
        }

        var options = {};
        options.url = settings.url;
        options.data = settings.data ? settings.data : null;
        options.method = settings.method;
        options.timeOut = settings.timeOut || 0;
        options.scope = settings.scope || this;
        options.proxy = settings.proxy || null;
        options.content = settings.content || null;
        options.headers = settings.headers || {
            referer : "http://localhost"
        };

        // test sur les valeurs de 'settings.method'
        switch (settings.method) {
            case "DELETE":
            case "GET":
                break;
            case "PUT":
            case "POST":
                // on force sur ces params spécifiques au mode POST
                options.content = settings.content ? settings.content : "application/x-www-form-urlencoded"; // FIXME en attente des services : bascule en "application/xml" ou "application/json"
                options.headers = settings.headers ? settings.headers : { referer : "http://localhost" }; // FIXME parametrable...
                break;
            case "HEAD":
            case "OPTIONS":
                throw new Error("HTTP method not yet supported !");
            default:
                throw new Error("HTTP method unknown !");
        }

        // test sur les valeurs de 'settings.format'
        switch (settings.format) {
            case "text":
                this.__call(options)
                    .then(function (response) {
                        logger.trace(response);
                        settings.onResponse.call(this, response);
                    })
                    .catch(function (error) {
                        settings.onFailure.call(this, error);
                    });
                break;
            case "json":
                this.__callJSON(options)
                    .then(function (response) {
                        logger.trace(response);
                        settings.onResponse.call(this, response);
                    })
                    .catch(function (error) {
                        settings.onFailure.call(this, error);
                    });
                break;
            case "xml":
                this.__callXML(options)
                    .then(function (response) {
                        logger.trace(response);
                        settings.onResponse.call(this, response);
                    })
                    .catch(function (error) {
                        settings.onFailure.call(this, error);
                    });
                break;
            default:
                throw new Error("This output Format is not yet supported !");
        }
    },

    /**
     * Requete
     *
     * @method __call
     * @private
     * @param  {Object} options - options
     * @return {Object} promise
     */
    __call : function (options) {
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("XHR");
        logger.trace("[XHR::__call()]");

        var promise = new Promise(
            function (resolve, reject) {
                // traitement du corps de la requête
                var corps = (options.method === "POST" || options.method === "PUT") ? 1 : 0;

                // seulement si options.data n'est pas vide (peut être un objet ou une chaine de caractères)
                if (options.data && ((typeof options.data === "object" && Object.keys(options.data).length) || (typeof options.data === "string" && options.data.length)) && !corps) {
                    options.url = _Utils_Helper__WEBPACK_IMPORTED_MODULE_1__["default"].normalyzeUrl(options.url, options.data);
                }

                logger.trace("URL = ", options.url);

                var hXHR = null;

                // test on env. nodejs or browser
                if (typeof window === "undefined") {
                    var nodefetch = __webpack_require__(53);

                    var opts = {
                        headers : {
                            Referer : "https://localhost"
                        }
                    };

                    if (options.data && typeof options.data === "string" && corps) {
                        opts = {
                            method : options.method,
                            body : options.data,
                            headers : {
                                "Content-Type" : options.content,
                                Referer : "https://localhost"
                            }
                        };
                    }

                    return nodefetch(options.url, opts)
                        .then(function (response) {
                            if (response.ok) { // res.status >= 200 && res.status < 300
                                resolve(response.text());
                            } else {
                                var message = "Errors Occured on Http Request (status : '" + response.statusText + "' | url : '" + response.url + "')";
                                var status = response.status;
                                reject({
                                    message : message,
                                    status : status
                                });
                            }
                        })
                        .catch(function (e) {
                            reject({
                                message : e,
                                status : -1
                            });
                        });
                } else {
                    if (window.XMLHttpRequest) {
                        logger.trace("XMLHttpRequest");

                        hXHR = new XMLHttpRequest();
                        hXHR.open(options.method, options.url, true); // async
                        hXHR.overrideMimeType = options.content;

                        // gestion du timeout
                        var onTimeOutTrigger = null;
                        if (options.timeOut > 0) {
                            // FIXME le timeout interne ne me permet pas de declencher le bon message...
                            // hXHR.timeout = options.timeOut;
                            logger.trace("XHR - TimeOut actif !");
                            /**
                             * Description
                             *
                             * @method onTimeOutTrigger
                             * @private
                             */
                            onTimeOutTrigger = window.setTimeout(
                                function () {
                                    var message = "TimeOut Occured on Http Request with XMLHttpRequest !";
                                    reject({
                                        message : message,
                                        status : -1
                                    });
                                }, options.timeOut);
                        }

                        if (corps) {
                            // headers, data, content of data
                            // cf. https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
                            logger.trace("data = ", options.data);
                            hXHR.setRequestHeader("Content-type", options.content);
                            // FIXME refused to set unsafe header content-length javascript
                            // hXHR.setRequestHeader ("Content-length", options.data.length);
                            // hXHR.setRequestHeader ("Referer", options.headers.referer);
                        }

                        /**
                         * On Error
                         * FIXME ne se declenche pas !?
                         *
                         * @param {Object} e - Event
                         * @method onerror
                         * @private
                         */
                        hXHR.onerror = function (e) {
                            console.log(e);
                            reject(new Error("Errors Occured on Http Request with XMLHttpRequest !"));
                        };

                        /**
                         * On Timeout
                         * FIXME ne se declenche pas !?
                         *
                         * @param {Object} e - Event
                         * @method ontimeout
                         * @private
                         */
                        hXHR.ontimeout = function (e) {
                            console.log(e);
                            reject(new Error("TimeOut Occured on Http Request with XMLHttpRequest !"));
                        };

                        /**
                         * Description
                         *
                         * @method onreadystatechange
                         * @private
                         */
                        hXHR.onreadystatechange = function (e) {
                            if (hXHR.readyState === 4) { // DONE
                                if (hXHR.status === 200) {
                                    window.clearTimeout(onTimeOutTrigger);
                                    resolve(hXHR.response);
                                } else {
                                    var message = "Errors Occured on Http Request (status : '" + e.target.statusText + "' | url : '" + e.target.responseURL + "' | response : '" + e.target.response + "')";
                                    var status = e.target.status;
                                    reject({
                                        message : message,
                                        status : status
                                    });
                                }
                            }
                        };

                        // gestion du content data
                        var data4xhr = (options.data && corps) ? options.data : null;

                        hXHR.send(data4xhr);
                    } else if (window.XDomainRequest) {
                        // worked in Internet Explorer 8–10 only !
                        logger.trace("XDomainRequest");

                        hXHR = new XDomainRequest();
                        hXHR.open(options.method, options.url);

                        hXHR.overrideMimeType = options.content;

                        if (options.timeOut > 0) {
                            hXHR.timeout = options.timeout;
                            logger.trace("XHR - TimeOut actif !");
                        }

                        if (corps) {
                            // headers, data, content of data
                            // cf. https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
                            hXHR.setRequestHeader("Content-type", options.content);
                            // FIXME refused to set unsafe header content-length javascript
                            // hXHR.setRequestHeader ("Content-length", options.data.length);
                            // hXHR.setRequestHeader ("Referer", options.headers.referer);
                        }

                        /**
                         * Description
                         *
                         * @method onerror
                         * @private
                         */
                        hXHR.onerror = function () {
                            reject(new Error("Errors Occured on Http Request with XMLHttpRequest !"));
                        };

                        /**
                         * Description
                         *
                         * @method ontimeout
                         * @private
                         */
                        hXHR.ontimeout = function () {
                            reject(new Error("TimeOut Occured on Http Request with XMLHttpRequest !"));
                        };

                        /**
                         * On Load
                         *
                         * @method onload
                         * @private
                         */
                        hXHR.onload = function (e) {
                            if (hXHR.status === 200) {
                                resolve(hXHR.responseText);
                            } else {
                                var message = "Errors Occured on Http Request (status : '" + e.target.statusText + "' | url : '" + e.target.responseURL + "')";
                                var status = e.target.status;
                                reject({
                                    message : message,
                                    status : status
                                });
                            }
                        };

                        var data4xdr = (options.data && corps) ? options.data : null;

                        hXHR.send(data4xdr);
                    } else {
                        throw new Error("CORS not supported");
                    }
                }
            }
        );

        return promise;
    },

    /**
     * Requete avec parser JSON
     *
     * @method __callJSON
     * @private
     * @param  {Object} options - options
     * @return {Object} promise
     */
    __callJSON : function (options) {
        return this.__call(options)
            .then(JSON.parse)
            .catch(function (error) {
                console.log("_callJSON failed on : ", options.url, error);
                // FIXME pas d'exception, laissons le fil se derouler...
                // throw error;
            });
    },

    /**
     * Requete avec parser XML
     *
     * @method __callXML
     * @private
     * @param  {Object} options - options
     * @return {Object} promise
     */
    __callXML : function (options) {
        return this.__call(options)
            .then(function (response) {
                var xmlDoc;

                // test on env. nodejs or browser
                if (typeof window === "undefined") {
                    var DOMParser = __webpack_require__(54).DOMParser; // __xmldom.DOMParser
                    xmlDoc = new DOMParser().parseFromString(response, "text/xml");
                } else {
                    if (window.DOMParser) {
                        var parser = new window.DOMParser();
                        xmlDoc = parser.parseFromString(response, "text/xml");
                    } else { // IE
                        xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
                        xmlDoc.async = false;
                        xmlDoc.loadXML(response);
                    }
                }

                return xmlDoc;
            })
            .catch(function (error) {
                console.log("__callXML failed on : ", options.url, error);
                // FIXME pas d'exception, laissons le fil se derouler...
                // throw error;
            });
    }

};

/* harmony default export */ __webpack_exports__["default"] = (XHR);


/***/ }),
/* 50 */
/***/ (function(module, exports, __webpack_require__) {

/* WEBPACK VAR INJECTION */(function(process, global) {/*!
 * @overview es6-promise - a tiny implementation of Promises/A+.
 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
 * @license   Licensed under MIT license
 *            See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
 * @version   v4.2.8+1e68dce6
 */

(function (global, factory) {
	 true ? module.exports = factory() :
	undefined;
}(this, (function () { 'use strict';

function objectOrFunction(x) {
  var type = typeof x;
  return x !== null && (type === 'object' || type === 'function');
}

function isFunction(x) {
  return typeof x === 'function';
}



var _isArray = void 0;
if (Array.isArray) {
  _isArray = Array.isArray;
} else {
  _isArray = function (x) {
    return Object.prototype.toString.call(x) === '[object Array]';
  };
}

var isArray = _isArray;

var len = 0;
var vertxNext = void 0;
var customSchedulerFn = void 0;

var asap = function asap(callback, arg) {
  queue[len] = callback;
  queue[len + 1] = arg;
  len += 2;
  if (len === 2) {
    // If len is 2, that means that we need to schedule an async flush.
    // If additional callbacks are queued before the queue is flushed, they
    // will be processed by this flush that we are scheduling.
    if (customSchedulerFn) {
      customSchedulerFn(flush);
    } else {
      scheduleFlush();
    }
  }
};

function setScheduler(scheduleFn) {
  customSchedulerFn = scheduleFn;
}

function setAsap(asapFn) {
  asap = asapFn;
}

var browserWindow = typeof window !== 'undefined' ? window : undefined;
var browserGlobal = browserWindow || {};
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';

// test for web worker but not in IE10
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';

// node
function useNextTick() {
  // node version 0.10.x displays a deprecation warning when nextTick is used recursively
  // see https://github.com/cujojs/when/issues/410 for details
  return function () {
    return process.nextTick(flush);
  };
}

// vertx
function useVertxTimer() {
  if (typeof vertxNext !== 'undefined') {
    return function () {
      vertxNext(flush);
    };
  }

  return useSetTimeout();
}

function useMutationObserver() {
  var iterations = 0;
  var observer = new BrowserMutationObserver(flush);
  var node = document.createTextNode('');
  observer.observe(node, { characterData: true });

  return function () {
    node.data = iterations = ++iterations % 2;
  };
}

// web worker
function useMessageChannel() {
  var channel = new MessageChannel();
  channel.port1.onmessage = flush;
  return function () {
    return channel.port2.postMessage(0);
  };
}

function useSetTimeout() {
  // Store setTimeout reference so es6-promise will be unaffected by
  // other code modifying setTimeout (like sinon.useFakeTimers())
  var globalSetTimeout = setTimeout;
  return function () {
    return globalSetTimeout(flush, 1);
  };
}

var queue = new Array(1000);
function flush() {
  for (var i = 0; i < len; i += 2) {
    var callback = queue[i];
    var arg = queue[i + 1];

    callback(arg);

    queue[i] = undefined;
    queue[i + 1] = undefined;
  }

  len = 0;
}

function attemptVertx() {
  try {
    var vertx = Function('return this')().require('vertx');
    vertxNext = vertx.runOnLoop || vertx.runOnContext;
    return useVertxTimer();
  } catch (e) {
    return useSetTimeout();
  }
}

var scheduleFlush = void 0;
// Decide what async method to use to triggering processing of queued callbacks:
if (isNode) {
  scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
  scheduleFlush = useMutationObserver();
} else if (isWorker) {
  scheduleFlush = useMessageChannel();
} else if (browserWindow === undefined && "function" === 'function') {
  scheduleFlush = attemptVertx();
} else {
  scheduleFlush = useSetTimeout();
}

function then(onFulfillment, onRejection) {
  var parent = this;

  var child = new this.constructor(noop);

  if (child[PROMISE_ID] === undefined) {
    makePromise(child);
  }

  var _state = parent._state;


  if (_state) {
    var callback = arguments[_state - 1];
    asap(function () {
      return invokeCallback(_state, child, callback, parent._result);
    });
  } else {
    subscribe(parent, child, onFulfillment, onRejection);
  }

  return child;
}

/**
  `Promise.resolve` returns a promise that will become resolved with the
  passed `value`. It is shorthand for the following:

  ```javascript
  let promise = new Promise(function(resolve, reject){
    resolve(1);
  });

  promise.then(function(value){
    // value === 1
  });
  ```

  Instead of writing the above, your code now simply becomes the following:

  ```javascript
  let promise = Promise.resolve(1);

  promise.then(function(value){
    // value === 1
  });
  ```

  @method resolve
  @static
  @param {Any} value value that the returned promise will be resolved with
  Useful for tooling.
  @return {Promise} a promise that will become fulfilled with the given
  `value`
*/
function resolve$1(object) {
  /*jshint validthis:true */
  var Constructor = this;

  if (object && typeof object === 'object' && object.constructor === Constructor) {
    return object;
  }

  var promise = new Constructor(noop);
  resolve(promise, object);
  return promise;
}

var PROMISE_ID = Math.random().toString(36).substring(2);

function noop() {}

var PENDING = void 0;
var FULFILLED = 1;
var REJECTED = 2;

function selfFulfillment() {
  return new TypeError("You cannot resolve a promise with itself");
}

function cannotReturnOwn() {
  return new TypeError('A promises callback cannot return that same promise.');
}

function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
  try {
    then$$1.call(value, fulfillmentHandler, rejectionHandler);
  } catch (e) {
    return e;
  }
}

function handleForeignThenable(promise, thenable, then$$1) {
  asap(function (promise) {
    var sealed = false;
    var error = tryThen(then$$1, thenable, function (value) {
      if (sealed) {
        return;
      }
      sealed = true;
      if (thenable !== value) {
        resolve(promise, value);
      } else {
        fulfill(promise, value);
      }
    }, function (reason) {
      if (sealed) {
        return;
      }
      sealed = true;

      reject(promise, reason);
    }, 'Settle: ' + (promise._label || ' unknown promise'));

    if (!sealed && error) {
      sealed = true;
      reject(promise, error);
    }
  }, promise);
}

function handleOwnThenable(promise, thenable) {
  if (thenable._state === FULFILLED) {
    fulfill(promise, thenable._result);
  } else if (thenable._state === REJECTED) {
    reject(promise, thenable._result);
  } else {
    subscribe(thenable, undefined, function (value) {
      return resolve(promise, value);
    }, function (reason) {
      return reject(promise, reason);
    });
  }
}

function handleMaybeThenable(promise, maybeThenable, then$$1) {
  if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
    handleOwnThenable(promise, maybeThenable);
  } else {
    if (then$$1 === undefined) {
      fulfill(promise, maybeThenable);
    } else if (isFunction(then$$1)) {
      handleForeignThenable(promise, maybeThenable, then$$1);
    } else {
      fulfill(promise, maybeThenable);
    }
  }
}

function resolve(promise, value) {
  if (promise === value) {
    reject(promise, selfFulfillment());
  } else if (objectOrFunction(value)) {
    var then$$1 = void 0;
    try {
      then$$1 = value.then;
    } catch (error) {
      reject(promise, error);
      return;
    }
    handleMaybeThenable(promise, value, then$$1);
  } else {
    fulfill(promise, value);
  }
}

function publishRejection(promise) {
  if (promise._onerror) {
    promise._onerror(promise._result);
  }

  publish(promise);
}

function fulfill(promise, value) {
  if (promise._state !== PENDING) {
    return;
  }

  promise._result = value;
  promise._state = FULFILLED;

  if (promise._subscribers.length !== 0) {
    asap(publish, promise);
  }
}

function reject(promise, reason) {
  if (promise._state !== PENDING) {
    return;
  }
  promise._state = REJECTED;
  promise._result = reason;

  asap(publishRejection, promise);
}

function subscribe(parent, child, onFulfillment, onRejection) {
  var _subscribers = parent._subscribers;
  var length = _subscribers.length;


  parent._onerror = null;

  _subscribers[length] = child;
  _subscribers[length + FULFILLED] = onFulfillment;
  _subscribers[length + REJECTED] = onRejection;

  if (length === 0 && parent._state) {
    asap(publish, parent);
  }
}

function publish(promise) {
  var subscribers = promise._subscribers;
  var settled = promise._state;

  if (subscribers.length === 0) {
    return;
  }

  var child = void 0,
      callback = void 0,
      detail = promise._result;

  for (var i = 0; i < subscribers.length; i += 3) {
    child = subscribers[i];
    callback = subscribers[i + settled];

    if (child) {
      invokeCallback(settled, child, callback, detail);
    } else {
      callback(detail);
    }
  }

  promise._subscribers.length = 0;
}

function invokeCallback(settled, promise, callback, detail) {
  var hasCallback = isFunction(callback),
      value = void 0,
      error = void 0,
      succeeded = true;

  if (hasCallback) {
    try {
      value = callback(detail);
    } catch (e) {
      succeeded = false;
      error = e;
    }

    if (promise === value) {
      reject(promise, cannotReturnOwn());
      return;
    }
  } else {
    value = detail;
  }

  if (promise._state !== PENDING) {
    // noop
  } else if (hasCallback && succeeded) {
    resolve(promise, value);
  } else if (succeeded === false) {
    reject(promise, error);
  } else if (settled === FULFILLED) {
    fulfill(promise, value);
  } else if (settled === REJECTED) {
    reject(promise, value);
  }
}

function initializePromise(promise, resolver) {
  try {
    resolver(function resolvePromise(value) {
      resolve(promise, value);
    }, function rejectPromise(reason) {
      reject(promise, reason);
    });
  } catch (e) {
    reject(promise, e);
  }
}

var id = 0;
function nextId() {
  return id++;
}

function makePromise(promise) {
  promise[PROMISE_ID] = id++;
  promise._state = undefined;
  promise._result = undefined;
  promise._subscribers = [];
}

function validationError() {
  return new Error('Array Methods must be provided an Array');
}

var Enumerator = function () {
  function Enumerator(Constructor, input) {
    this._instanceConstructor = Constructor;
    this.promise = new Constructor(noop);

    if (!this.promise[PROMISE_ID]) {
      makePromise(this.promise);
    }

    if (isArray(input)) {
      this.length = input.length;
      this._remaining = input.length;

      this._result = new Array(this.length);

      if (this.length === 0) {
        fulfill(this.promise, this._result);
      } else {
        this.length = this.length || 0;
        this._enumerate(input);
        if (this._remaining === 0) {
          fulfill(this.promise, this._result);
        }
      }
    } else {
      reject(this.promise, validationError());
    }
  }

  Enumerator.prototype._enumerate = function _enumerate(input) {
    for (var i = 0; this._state === PENDING && i < input.length; i++) {
      this._eachEntry(input[i], i);
    }
  };

  Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
    var c = this._instanceConstructor;
    var resolve$$1 = c.resolve;


    if (resolve$$1 === resolve$1) {
      var _then = void 0;
      var error = void 0;
      var didError = false;
      try {
        _then = entry.then;
      } catch (e) {
        didError = true;
        error = e;
      }

      if (_then === then && entry._state !== PENDING) {
        this._settledAt(entry._state, i, entry._result);
      } else if (typeof _then !== 'function') {
        this._remaining--;
        this._result[i] = entry;
      } else if (c === Promise$1) {
        var promise = new c(noop);
        if (didError) {
          reject(promise, error);
        } else {
          handleMaybeThenable(promise, entry, _then);
        }
        this._willSettleAt(promise, i);
      } else {
        this._willSettleAt(new c(function (resolve$$1) {
          return resolve$$1(entry);
        }), i);
      }
    } else {
      this._willSettleAt(resolve$$1(entry), i);
    }
  };

  Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
    var promise = this.promise;


    if (promise._state === PENDING) {
      this._remaining--;

      if (state === REJECTED) {
        reject(promise, value);
      } else {
        this._result[i] = value;
      }
    }

    if (this._remaining === 0) {
      fulfill(promise, this._result);
    }
  };

  Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
    var enumerator = this;

    subscribe(promise, undefined, function (value) {
      return enumerator._settledAt(FULFILLED, i, value);
    }, function (reason) {
      return enumerator._settledAt(REJECTED, i, reason);
    });
  };

  return Enumerator;
}();

/**
  `Promise.all` accepts an array of promises, and returns a new promise which
  is fulfilled with an array of fulfillment values for the passed promises, or
  rejected with the reason of the first passed promise to be rejected. It casts all
  elements of the passed iterable to promises as it runs this algorithm.

  Example:

  ```javascript
  let promise1 = resolve(1);
  let promise2 = resolve(2);
  let promise3 = resolve(3);
  let promises = [ promise1, promise2, promise3 ];

  Promise.all(promises).then(function(array){
    // The array here would be [ 1, 2, 3 ];
  });
  ```

  If any of the `promises` given to `all` are rejected, the first promise
  that is rejected will be given as an argument to the returned promises's
  rejection handler. For example:

  Example:

  ```javascript
  let promise1 = resolve(1);
  let promise2 = reject(new Error("2"));
  let promise3 = reject(new Error("3"));
  let promises = [ promise1, promise2, promise3 ];

  Promise.all(promises).then(function(array){
    // Code here never runs because there are rejected promises!
  }, function(error) {
    // error.message === "2"
  });
  ```

  @method all
  @static
  @param {Array} entries array of promises
  @param {String} label optional string for labeling the promise.
  Useful for tooling.
  @return {Promise} promise that is fulfilled when all `promises` have been
  fulfilled, or rejected if any of them become rejected.
  @static
*/
function all(entries) {
  return new Enumerator(this, entries).promise;
}

/**
  `Promise.race` returns a new promise which is settled in the same way as the
  first passed promise to settle.

  Example:

  ```javascript
  let promise1 = new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve('promise 1');
    }, 200);
  });

  let promise2 = new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve('promise 2');
    }, 100);
  });

  Promise.race([promise1, promise2]).then(function(result){
    // result === 'promise 2' because it was resolved before promise1
    // was resolved.
  });
  ```

  `Promise.race` is deterministic in that only the state of the first
  settled promise matters. For example, even if other promises given to the
  `promises` array argument are resolved, but the first settled promise has
  become rejected before the other promises became fulfilled, the returned
  promise will become rejected:

  ```javascript
  let promise1 = new Promise(function(resolve, reject){
    setTimeout(function(){
      resolve('promise 1');
    }, 200);
  });

  let promise2 = new Promise(function(resolve, reject){
    setTimeout(function(){
      reject(new Error('promise 2'));
    }, 100);
  });

  Promise.race([promise1, promise2]).then(function(result){
    // Code here never runs
  }, function(reason){
    // reason.message === 'promise 2' because promise 2 became rejected before
    // promise 1 became fulfilled
  });
  ```

  An example real-world use case is implementing timeouts:

  ```javascript
  Promise.race([ajax('foo.json'), timeout(5000)])
  ```

  @method race
  @static
  @param {Array} promises array of promises to observe
  Useful for tooling.
  @return {Promise} a promise which settles in the same way as the first passed
  promise to settle.
*/
function race(entries) {
  /*jshint validthis:true */
  var Constructor = this;

  if (!isArray(entries)) {
    return new Constructor(function (_, reject) {
      return reject(new TypeError('You must pass an array to race.'));
    });
  } else {
    return new Constructor(function (resolve, reject) {
      var length = entries.length;
      for (var i = 0; i < length; i++) {
        Constructor.resolve(entries[i]).then(resolve, reject);
      }
    });
  }
}

/**
  `Promise.reject` returns a promise rejected with the passed `reason`.
  It is shorthand for the following:

  ```javascript
  let promise = new Promise(function(resolve, reject){
    reject(new Error('WHOOPS'));
  });

  promise.then(function(value){
    // Code here doesn't run because the promise is rejected!
  }, function(reason){
    // reason.message === 'WHOOPS'
  });
  ```

  Instead of writing the above, your code now simply becomes the following:

  ```javascript
  let promise = Promise.reject(new Error('WHOOPS'));

  promise.then(function(value){
    // Code here doesn't run because the promise is rejected!
  }, function(reason){
    // reason.message === 'WHOOPS'
  });
  ```

  @method reject
  @static
  @param {Any} reason value that the returned promise will be rejected with.
  Useful for tooling.
  @return {Promise} a promise rejected with the given `reason`.
*/
function reject$1(reason) {
  /*jshint validthis:true */
  var Constructor = this;
  var promise = new Constructor(noop);
  reject(promise, reason);
  return promise;
}

function needsResolver() {
  throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
}

function needsNew() {
  throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
}

/**
  Promise objects represent the eventual result of an asynchronous operation. The
  primary way of interacting with a promise is through its `then` method, which
  registers callbacks to receive either a promise's eventual value or the reason
  why the promise cannot be fulfilled.

  Terminology
  -----------

  - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
  - `thenable` is an object or function that defines a `then` method.
  - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
  - `exception` is a value that is thrown using the throw statement.
  - `reason` is a value that indicates why a promise was rejected.
  - `settled` the final resting state of a promise, fulfilled or rejected.

  A promise can be in one of three states: pending, fulfilled, or rejected.

  Promises that are fulfilled have a fulfillment value and are in the fulfilled
  state.  Promises that are rejected have a rejection reason and are in the
  rejected state.  A fulfillment value is never a thenable.

  Promises can also be said to *resolve* a value.  If this value is also a
  promise, then the original promise's settled state will match the value's
  settled state.  So a promise that *resolves* a promise that rejects will
  itself reject, and a promise that *resolves* a promise that fulfills will
  itself fulfill.


  Basic Usage:
  ------------

  ```js
  let promise = new Promise(function(resolve, reject) {
    // on success
    resolve(value);

    // on failure
    reject(reason);
  });

  promise.then(function(value) {
    // on fulfillment
  }, function(reason) {
    // on rejection
  });
  ```

  Advanced Usage:
  ---------------

  Promises shine when abstracting away asynchronous interactions such as
  `XMLHttpRequest`s.

  ```js
  function getJSON(url) {
    return new Promise(function(resolve, reject){
      let xhr = new XMLHttpRequest();

      xhr.open('GET', url);
      xhr.onreadystatechange = handler;
      xhr.responseType = 'json';
      xhr.setRequestHeader('Accept', 'application/json');
      xhr.send();

      function handler() {
        if (this.readyState === this.DONE) {
          if (this.status === 200) {
            resolve(this.response);
          } else {
            reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
          }
        }
      };
    });
  }

  getJSON('/posts.json').then(function(json) {
    // on fulfillment
  }, function(reason) {
    // on rejection
  });
  ```

  Unlike callbacks, promises are great composable primitives.

  ```js
  Promise.all([
    getJSON('/posts'),
    getJSON('/comments')
  ]).then(function(values){
    values[0] // => postsJSON
    values[1] // => commentsJSON

    return values;
  });
  ```

  @class Promise
  @param {Function} resolver
  Useful for tooling.
  @constructor
*/

var Promise$1 = function () {
  function Promise(resolver) {
    this[PROMISE_ID] = nextId();
    this._result = this._state = undefined;
    this._subscribers = [];

    if (noop !== resolver) {
      typeof resolver !== 'function' && needsResolver();
      this instanceof Promise ? initializePromise(this, resolver) : needsNew();
    }
  }

  /**
  The primary way of interacting with a promise is through its `then` method,
  which registers callbacks to receive either a promise's eventual value or the
  reason why the promise cannot be fulfilled.
   ```js
  findUser().then(function(user){
    // user is available
  }, function(reason){
    // user is unavailable, and you are given the reason why
  });
  ```
   Chaining
  --------
   The return value of `then` is itself a promise.  This second, 'downstream'
  promise is resolved with the return value of the first promise's fulfillment
  or rejection handler, or rejected if the handler throws an exception.
   ```js
  findUser().then(function (user) {
    return user.name;
  }, function (reason) {
    return 'default name';
  }).then(function (userName) {
    // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
    // will be `'default name'`
  });
   findUser().then(function (user) {
    throw new Error('Found user, but still unhappy');
  }, function (reason) {
    throw new Error('`findUser` rejected and we're unhappy');
  }).then(function (value) {
    // never reached
  }, function (reason) {
    // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
    // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
  });
  ```
  If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
   ```js
  findUser().then(function (user) {
    throw new PedagogicalException('Upstream error');
  }).then(function (value) {
    // never reached
  }).then(function (value) {
    // never reached
  }, function (reason) {
    // The `PedgagocialException` is propagated all the way down to here
  });
  ```
   Assimilation
  ------------
   Sometimes the value you want to propagate to a downstream promise can only be
  retrieved asynchronously. This can be achieved by returning a promise in the
  fulfillment or rejection handler. The downstream promise will then be pending
  until the returned promise is settled. This is called *assimilation*.
   ```js
  findUser().then(function (user) {
    return findCommentsByAuthor(user);
  }).then(function (comments) {
    // The user's comments are now available
  });
  ```
   If the assimliated promise rejects, then the downstream promise will also reject.
   ```js
  findUser().then(function (user) {
    return findCommentsByAuthor(user);
  }).then(function (comments) {
    // If `findCommentsByAuthor` fulfills, we'll have the value here
  }, function (reason) {
    // If `findCommentsByAuthor` rejects, we'll have the reason here
  });
  ```
   Simple Example
  --------------
   Synchronous Example
   ```javascript
  let result;
   try {
    result = findResult();
    // success
  } catch(reason) {
    // failure
  }
  ```
   Errback Example
   ```js
  findResult(function(result, err){
    if (err) {
      // failure
    } else {
      // success
    }
  });
  ```
   Promise Example;
   ```javascript
  findResult().then(function(result){
    // success
  }, function(reason){
    // failure
  });
  ```
   Advanced Example
  --------------
   Synchronous Example
   ```javascript
  let author, books;
   try {
    author = findAuthor();
    books  = findBooksByAuthor(author);
    // success
  } catch(reason) {
    // failure
  }
  ```
   Errback Example
   ```js
   function foundBooks(books) {
   }
   function failure(reason) {
   }
   findAuthor(function(author, err){
    if (err) {
      failure(err);
      // failure
    } else {
      try {
        findBoooksByAuthor(author, function(books, err) {
          if (err) {
            failure(err);
          } else {
            try {
              foundBooks(books);
            } catch(reason) {
              failure(reason);
            }
          }
        });
      } catch(error) {
        failure(err);
      }
      // success
    }
  });
  ```
   Promise Example;
   ```javascript
  findAuthor().
    then(findBooksByAuthor).
    then(function(books){
      // found books
  }).catch(function(reason){
    // something went wrong
  });
  ```
   @method then
  @param {Function} onFulfilled
  @param {Function} onRejected
  Useful for tooling.
  @return {Promise}
  */

  /**
  `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
  as the catch block of a try/catch statement.
  ```js
  function findAuthor(){
  throw new Error('couldn't find that author');
  }
  // synchronous
  try {
  findAuthor();
  } catch(reason) {
  // something went wrong
  }
  // async with promises
  findAuthor().catch(function(reason){
  // something went wrong
  });
  ```
  @method catch
  @param {Function} onRejection
  Useful for tooling.
  @return {Promise}
  */


  Promise.prototype.catch = function _catch(onRejection) {
    return this.then(null, onRejection);
  };

  /**
    `finally` will be invoked regardless of the promise's fate just as native
    try/catch/finally behaves
  
    Synchronous example:
  
    ```js
    findAuthor() {
      if (Math.random() > 0.5) {
        throw new Error();
      }
      return new Author();
    }
  
    try {
      return findAuthor(); // succeed or fail
    } catch(error) {
      return findOtherAuther();
    } finally {
      // always runs
      // doesn't affect the return value
    }
    ```
  
    Asynchronous example:
  
    ```js
    findAuthor().catch(function(reason){
      return findOtherAuther();
    }).finally(function(){
      // author was either found, or not
    });
    ```
  
    @method finally
    @param {Function} callback
    @return {Promise}
  */


  Promise.prototype.finally = function _finally(callback) {
    var promise = this;
    var constructor = promise.constructor;

    if (isFunction(callback)) {
      return promise.then(function (value) {
        return constructor.resolve(callback()).then(function () {
          return value;
        });
      }, function (reason) {
        return constructor.resolve(callback()).then(function () {
          throw reason;
        });
      });
    }

    return promise.then(callback, callback);
  };

  return Promise;
}();

Promise$1.prototype.then = then;
Promise$1.all = all;
Promise$1.race = race;
Promise$1.resolve = resolve$1;
Promise$1.reject = reject$1;
Promise$1._setScheduler = setScheduler;
Promise$1._setAsap = setAsap;
Promise$1._asap = asap;

/*global self*/
function polyfill() {
  var local = void 0;

  if (typeof global !== 'undefined') {
    local = global;
  } else if (typeof self !== 'undefined') {
    local = self;
  } else {
    try {
      local = Function('return this')();
    } catch (e) {
      throw new Error('polyfill failed because global object is unavailable in this environment');
    }
  }

  var P = local.Promise;

  if (P) {
    var promiseToString = null;
    try {
      promiseToString = Object.prototype.toString.call(P.resolve());
    } catch (e) {
      // silently ignored
    }

    if (promiseToString === '[object Promise]' && !P.cast) {
      return;
    }
  }

  local.Promise = Promise$1;
}

// Strange compat..
Promise$1.polyfill = polyfill;
Promise$1.Promise = Promise$1;

return Promise$1;

})));



//# sourceMappingURL=es6-promise.map

/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(51), __webpack_require__(52)))

/***/ }),
/* 51 */
/***/ (function(module, exports) {

// shim for using process in browser
var process = module.exports = {};

// cached from whatever global is present so that test runners that stub it
// don't break things.  But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals.  It's inside a
// function because try/catches deoptimize in certain engines.

var cachedSetTimeout;
var cachedClearTimeout;

function defaultSetTimout() {
    throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
    throw new Error('clearTimeout has not been defined');
}
(function () {
    try {
        if (typeof setTimeout === 'function') {
            cachedSetTimeout = setTimeout;
        } else {
            cachedSetTimeout = defaultSetTimout;
        }
    } catch (e) {
        cachedSetTimeout = defaultSetTimout;
    }
    try {
        if (typeof clearTimeout === 'function') {
            cachedClearTimeout = clearTimeout;
        } else {
            cachedClearTimeout = defaultClearTimeout;
        }
    } catch (e) {
        cachedClearTimeout = defaultClearTimeout;
    }
} ())
function runTimeout(fun) {
    if (cachedSetTimeout === setTimeout) {
        //normal enviroments in sane situations
        return setTimeout(fun, 0);
    }
    // if setTimeout wasn't available but was latter defined
    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
        cachedSetTimeout = setTimeout;
        return setTimeout(fun, 0);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedSetTimeout(fun, 0);
    } catch(e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
            return cachedSetTimeout.call(null, fun, 0);
        } catch(e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
            return cachedSetTimeout.call(this, fun, 0);
        }
    }


}
function runClearTimeout(marker) {
    if (cachedClearTimeout === clearTimeout) {
        //normal enviroments in sane situations
        return clearTimeout(marker);
    }
    // if clearTimeout wasn't available but was latter defined
    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
        cachedClearTimeout = clearTimeout;
        return clearTimeout(marker);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedClearTimeout(marker);
    } catch (e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
            return cachedClearTimeout.call(null, marker);
        } catch (e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
            return cachedClearTimeout.call(this, marker);
        }
    }



}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

function cleanUpNextTick() {
    if (!draining || !currentQueue) {
        return;
    }
    draining = false;
    if (currentQueue.length) {
        queue = currentQueue.concat(queue);
    } else {
        queueIndex = -1;
    }
    if (queue.length) {
        drainQueue();
    }
}

function drainQueue() {
    if (draining) {
        return;
    }
    var timeout = runTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    runClearTimeout(timeout);
}

process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        runTimeout(drainQueue);
    }
};

// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;

process.listeners = function (name) { return [] }

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };


/***/ }),
/* 52 */
/***/ (function(module, exports) {

var g;

// This works in non-strict mode
g = (function() {
	return this;
})();

try {
	// This works if eval is allowed (see CSP)
	g = g || new Function("return this")();
} catch (e) {
	// This works if the window reference is available
	if (typeof window === "object") g = window;
}

// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}

module.exports = g;


/***/ }),
/* 53 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE__53__;

/***/ }),
/* 54 */
/***/ (function(module, exports, __webpack_require__) {

var dom = __webpack_require__(55)
exports.DOMImplementation = dom.DOMImplementation
exports.XMLSerializer = dom.XMLSerializer
exports.DOMParser = __webpack_require__(57).DOMParser


/***/ }),
/* 55 */
/***/ (function(module, exports, __webpack_require__) {

var conventions = __webpack_require__(56);

var find = conventions.find;
var NAMESPACE = conventions.NAMESPACE;

/**
 * A prerequisite for `[].filter`, to drop elements that are empty
 * @param {string} input
 * @returns {boolean}
 */
function notEmptyString (input) {
	return input !== ''
}
/**
 * @see https://infra.spec.whatwg.org/#split-on-ascii-whitespace
 * @see https://infra.spec.whatwg.org/#ascii-whitespace
 *
 * @param {string} input
 * @returns {string[]} (can be empty)
 */
function splitOnASCIIWhitespace(input) {
	// U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, U+0020 SPACE
	return input ? input.split(/[\t\n\f\r ]+/).filter(notEmptyString) : []
}

/**
 * Adds element as a key to current if it is not already present.
 *
 * @param {Record<string, boolean | undefined>} current
 * @param {string} element
 * @returns {Record<string, boolean | undefined>}
 */
function orderedSetReducer (current, element) {
	if (!current.hasOwnProperty(element)) {
		current[element] = true;
	}
	return current;
}

/**
 * @see https://infra.spec.whatwg.org/#ordered-set
 * @param {string} input
 * @returns {string[]}
 */
function toOrderedSet(input) {
	if (!input) return [];
	var list = splitOnASCIIWhitespace(input);
	return Object.keys(list.reduce(orderedSetReducer, {}))
}

/**
 * Uses `list.indexOf` to implement something like `Array.prototype.includes`,
 * which we can not rely on being available.
 *
 * @param {any[]} list
 * @returns {function(any): boolean}
 */
function arrayIncludes (list) {
	return function(element) {
		return list && list.indexOf(element) !== -1;
	}
}

function copy(src,dest){
	for(var p in src){
		if (Object.prototype.hasOwnProperty.call(src, p)) {
			dest[p] = src[p];
		}
	}
}

/**
^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
 */
function _extends(Class,Super){
	var pt = Class.prototype;
	if(!(pt instanceof Super)){
		function t(){};
		t.prototype = Super.prototype;
		t = new t();
		copy(pt,t);
		Class.prototype = pt = t;
	}
	if(pt.constructor != Class){
		if(typeof Class != 'function'){
			console.error("unknown Class:"+Class)
		}
		pt.constructor = Class
	}
}

// Node Types
var NodeType = {}
var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;

// ExceptionCode
var ExceptionCode = {}
var ExceptionMessage = {};
var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
//level2
var INVALID_STATE_ERR        	= ExceptionCode.INVALID_STATE_ERR        	= ((ExceptionMessage[11]="Invalid state"),11);
var SYNTAX_ERR               	= ExceptionCode.SYNTAX_ERR               	= ((ExceptionMessage[12]="Syntax error"),12);
var INVALID_MODIFICATION_ERR 	= ExceptionCode.INVALID_MODIFICATION_ERR 	= ((ExceptionMessage[13]="Invalid modification"),13);
var NAMESPACE_ERR            	= ExceptionCode.NAMESPACE_ERR           	= ((ExceptionMessage[14]="Invalid namespace"),14);
var INVALID_ACCESS_ERR       	= ExceptionCode.INVALID_ACCESS_ERR      	= ((ExceptionMessage[15]="Invalid access"),15);

/**
 * DOM Level 2
 * Object DOMException
 * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
 * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
 */
function DOMException(code, message) {
	if(message instanceof Error){
		var error = message;
	}else{
		error = this;
		Error.call(this, ExceptionMessage[code]);
		this.message = ExceptionMessage[code];
		if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
	}
	error.code = code;
	if(message) this.message = this.message + ": " + message;
	return error;
};
DOMException.prototype = Error.prototype;
copy(ExceptionCode,DOMException)

/**
 * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
 * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.
 * The items in the NodeList are accessible via an integral index, starting from 0.
 */
function NodeList() {
};
NodeList.prototype = {
	/**
	 * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
	 * @standard level1
	 */
	length:0,
	/**
	 * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
	 * @standard level1
	 * @param index  unsigned long
	 *   Index into the collection.
	 * @return Node
	 * 	The node at the indexth position in the NodeList, or null if that is not a valid index.
	 */
	item: function(index) {
		return index >= 0 && index < this.length ? this[index] : null;
	},
	toString:function(isHTML,nodeFilter){
		for(var buf = [], i = 0;i<this.length;i++){
			serializeToString(this[i],buf,isHTML,nodeFilter);
		}
		return buf.join('');
	},
	/**
	 * @private
	 * @param {function (Node):boolean} predicate
	 * @returns {Node[]}
	 */
	filter: function (predicate) {
		return Array.prototype.filter.call(this, predicate);
	},
	/**
	 * @private
	 * @param {Node} item
	 * @returns {number}
	 */
	indexOf: function (item) {
		return Array.prototype.indexOf.call(this, item);
	},
};

function LiveNodeList(node,refresh){
	this._node = node;
	this._refresh = refresh
	_updateLiveList(this);
}
function _updateLiveList(list){
	var inc = list._node._inc || list._node.ownerDocument._inc;
	if (list._inc !== inc) {
		var ls = list._refresh(list._node);
		__set__(list,'length',ls.length);
		if (!list.$$length || ls.length < list.$$length) {
			for (var i = ls.length; i in list; i++) {
				if (Object.prototype.hasOwnProperty.call(list, i)) {
					delete list[i];
				}
			}
		}
		copy(ls,list);
		list._inc = inc;
	}
}
LiveNodeList.prototype.item = function(i){
	_updateLiveList(this);
	return this[i] || null;
}

_extends(LiveNodeList,NodeList);

/**
 * Objects implementing the NamedNodeMap interface are used
 * to represent collections of nodes that can be accessed by name.
 * Note that NamedNodeMap does not inherit from NodeList;
 * NamedNodeMaps are not maintained in any particular order.
 * Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index,
 * but this is simply to allow convenient enumeration of the contents of a NamedNodeMap,
 * and does not imply that the DOM specifies an order to these Nodes.
 * NamedNodeMap objects in the DOM are live.
 * used for attributes or DocumentType entities
 */
function NamedNodeMap() {
};

function _findNodeIndex(list,node){
	var i = list.length;
	while(i--){
		if(list[i] === node){return i}
	}
}

function _addNamedNode(el,list,newAttr,oldAttr){
	if(oldAttr){
		list[_findNodeIndex(list,oldAttr)] = newAttr;
	}else{
		list[list.length++] = newAttr;
	}
	if(el){
		newAttr.ownerElement = el;
		var doc = el.ownerDocument;
		if(doc){
			oldAttr && _onRemoveAttribute(doc,el,oldAttr);
			_onAddAttribute(doc,el,newAttr);
		}
	}
}
function _removeNamedNode(el,list,attr){
	//console.log('remove attr:'+attr)
	var i = _findNodeIndex(list,attr);
	if(i>=0){
		var lastIndex = list.length-1
		while(i<lastIndex){
			list[i] = list[++i]
		}
		list.length = lastIndex;
		if(el){
			var doc = el.ownerDocument;
			if(doc){
				_onRemoveAttribute(doc,el,attr);
				attr.ownerElement = null;
			}
		}
	}else{
		throw new DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
	}
}
NamedNodeMap.prototype = {
	length:0,
	item:NodeList.prototype.item,
	getNamedItem: function(key) {
//		if(key.indexOf(':')>0 || key == 'xmlns'){
//			return null;
//		}
		//console.log()
		var i = this.length;
		while(i--){
			var attr = this[i];
			//console.log(attr.nodeName,key)
			if(attr.nodeName == key){
				return attr;
			}
		}
	},
	setNamedItem: function(attr) {
		var el = attr.ownerElement;
		if(el && el!=this._ownerElement){
			throw new DOMException(INUSE_ATTRIBUTE_ERR);
		}
		var oldAttr = this.getNamedItem(attr.nodeName);
		_addNamedNode(this._ownerElement,this,attr,oldAttr);
		return oldAttr;
	},
	/* returns Node */
	setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
		var el = attr.ownerElement, oldAttr;
		if(el && el!=this._ownerElement){
			throw new DOMException(INUSE_ATTRIBUTE_ERR);
		}
		oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
		_addNamedNode(this._ownerElement,this,attr,oldAttr);
		return oldAttr;
	},

	/* returns Node */
	removeNamedItem: function(key) {
		var attr = this.getNamedItem(key);
		_removeNamedNode(this._ownerElement,this,attr);
		return attr;


	},// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR

	//for level2
	removeNamedItemNS:function(namespaceURI,localName){
		var attr = this.getNamedItemNS(namespaceURI,localName);
		_removeNamedNode(this._ownerElement,this,attr);
		return attr;
	},
	getNamedItemNS: function(namespaceURI, localName) {
		var i = this.length;
		while(i--){
			var node = this[i];
			if(node.localName == localName && node.namespaceURI == namespaceURI){
				return node;
			}
		}
		return null;
	}
};

/**
 * The DOMImplementation interface represents an object providing methods
 * which are not dependent on any particular document.
 * Such an object is returned by the `Document.implementation` property.
 *
 * __The individual methods describe the differences compared to the specs.__
 *
 * @constructor
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation MDN
 * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490 DOM Level 1 Core (Initial)
 * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490 DOM Level 2 Core
 * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-102161490 DOM Level 3 Core
 * @see https://dom.spec.whatwg.org/#domimplementation DOM Living Standard
 */
function DOMImplementation() {
}

DOMImplementation.prototype = {
	/**
	 * The DOMImplementation.hasFeature() method returns a Boolean flag indicating if a given feature is supported.
	 * The different implementations fairly diverged in what kind of features were reported.
	 * The latest version of the spec settled to force this method to always return true, where the functionality was accurate and in use.
	 *
	 * @deprecated It is deprecated and modern browsers return true in all cases.
	 *
	 * @param {string} feature
	 * @param {string} [version]
	 * @returns {boolean} always true
	 *
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/hasFeature MDN
	 * @see https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-5CED94D7 DOM Level 1 Core
	 * @see https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature DOM Living Standard
	 */
	hasFeature: function(feature, version) {
			return true;
	},
	/**
	 * Creates an XML Document object of the specified type with its document element.
	 *
	 * __It behaves slightly different from the description in the living standard__:
	 * - There is no interface/class `XMLDocument`, it returns a `Document` instance.
	 * - `contentType`, `encoding`, `mode`, `origin`, `url` fields are currently not declared.
	 * - this implementation is not validating names or qualified names
	 *   (when parsing XML strings, the SAX parser takes care of that)
	 *
	 * @param {string|null} namespaceURI
	 * @param {string} qualifiedName
	 * @param {DocumentType=null} doctype
	 * @returns {Document}
	 *
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocument MDN
	 * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocument DOM Level 2 Core (initial)
	 * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument  DOM Level 2 Core
	 *
	 * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract
	 * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names
	 * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names
	 */
	createDocument: function(namespaceURI,  qualifiedName, doctype){
		var doc = new Document();
		doc.implementation = this;
		doc.childNodes = new NodeList();
		doc.doctype = doctype || null;
		if (doctype){
			doc.appendChild(doctype);
		}
		if (qualifiedName){
			var root = doc.createElementNS(namespaceURI, qualifiedName);
			doc.appendChild(root);
		}
		return doc;
	},
	/**
	 * Returns a doctype, with the given `qualifiedName`, `publicId`, and `systemId`.
	 *
	 * __This behavior is slightly different from the in the specs__:
	 * - this implementation is not validating names or qualified names
	 *   (when parsing XML strings, the SAX parser takes care of that)
	 *
	 * @param {string} qualifiedName
	 * @param {string} [publicId]
	 * @param {string} [systemId]
	 * @returns {DocumentType} which can either be used with `DOMImplementation.createDocument` upon document creation
	 * 				  or can be put into the document via methods like `Node.insertBefore()` or `Node.replaceChild()`
	 *
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMImplementation/createDocumentType MDN
	 * @see https://www.w3.org/TR/DOM-Level-2-Core/core.html#Level-2-Core-DOM-createDocType DOM Level 2 Core
	 * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype DOM Living Standard
	 *
	 * @see https://dom.spec.whatwg.org/#validate-and-extract DOM: Validate and extract
	 * @see https://www.w3.org/TR/xml/#NT-NameStartChar XML Spec: Names
	 * @see https://www.w3.org/TR/xml-names/#ns-qualnames XML Namespaces: Qualified names
	 */
	createDocumentType: function(qualifiedName, publicId, systemId){
		var node = new DocumentType();
		node.name = qualifiedName;
		node.nodeName = qualifiedName;
		node.publicId = publicId || '';
		node.systemId = systemId || '';

		return node;
	}
};


/**
 * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
 */

function Node() {
};

Node.prototype = {
	firstChild : null,
	lastChild : null,
	previousSibling : null,
	nextSibling : null,
	attributes : null,
	parentNode : null,
	childNodes : null,
	ownerDocument : null,
	nodeValue : null,
	namespaceURI : null,
	prefix : null,
	localName : null,
	// Modified in DOM Level 2:
	insertBefore:function(newChild, refChild){//raises
		return _insertBefore(this,newChild,refChild);
	},
	replaceChild:function(newChild, oldChild){//raises
		_insertBefore(this, newChild,oldChild, assertPreReplacementValidityInDocument);
		if(oldChild){
			this.removeChild(oldChild);
		}
	},
	removeChild:function(oldChild){
		return _removeChild(this,oldChild);
	},
	appendChild:function(newChild){
		return this.insertBefore(newChild,null);
	},
	hasChildNodes:function(){
		return this.firstChild != null;
	},
	cloneNode:function(deep){
		return cloneNode(this.ownerDocument||this,this,deep);
	},
	// Modified in DOM Level 2:
	normalize:function(){
		var child = this.firstChild;
		while(child){
			var next = child.nextSibling;
			if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
				this.removeChild(next);
				child.appendData(next.data);
			}else{
				child.normalize();
				child = next;
			}
		}
	},
  	// Introduced in DOM Level 2:
	isSupported:function(feature, version){
		return this.ownerDocument.implementation.hasFeature(feature,version);
	},
    // Introduced in DOM Level 2:
    hasAttributes:function(){
    	return this.attributes.length>0;
    },
	/**
	 * Look up the prefix associated to the given namespace URI, starting from this node.
	 * **The default namespace declarations are ignored by this method.**
	 * See Namespace Prefix Lookup for details on the algorithm used by this method.
	 *
	 * _Note: The implementation seems to be incomplete when compared to the algorithm described in the specs._
	 *
	 * @param {string | null} namespaceURI
	 * @returns {string | null}
	 * @see https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespacePrefix
	 * @see https://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespacePrefixAlgo
	 * @see https://dom.spec.whatwg.org/#dom-node-lookupprefix
	 * @see https://github.com/xmldom/xmldom/issues/322
	 */
    lookupPrefix:function(namespaceURI){
    	var el = this;
    	while(el){
    		var map = el._nsMap;
    		//console.dir(map)
    		if(map){
    			for(var n in map){
						if (Object.prototype.hasOwnProperty.call(map, n) && map[n] === namespaceURI) {
							return n;
						}
    			}
    		}
    		el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
    	}
    	return null;
    },
    // Introduced in DOM Level 3:
    lookupNamespaceURI:function(prefix){
    	var el = this;
    	while(el){
    		var map = el._nsMap;
    		//console.dir(map)
    		if(map){
    			if(Object.prototype.hasOwnProperty.call(map, prefix)){
    				return map[prefix] ;
    			}
    		}
    		el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
    	}
    	return null;
    },
    // Introduced in DOM Level 3:
    isDefaultNamespace:function(namespaceURI){
    	var prefix = this.lookupPrefix(namespaceURI);
    	return prefix == null;
    }
};


function _xmlEncoder(c){
	return c == '<' && '&lt;' ||
         c == '>' && '&gt;' ||
         c == '&' && '&amp;' ||
         c == '"' && '&quot;' ||
         '&#'+c.charCodeAt()+';'
}


copy(NodeType,Node);
copy(NodeType,Node.prototype);

/**
 * @param callback return true for continue,false for break
 * @return boolean true: break visit;
 */
function _visitNode(node,callback){
	if(callback(node)){
		return true;
	}
	if(node = node.firstChild){
		do{
			if(_visitNode(node,callback)){return true}
        }while(node=node.nextSibling)
    }
}



function Document(){
	this.ownerDocument = this;
}

function _onAddAttribute(doc,el,newAttr){
	doc && doc._inc++;
	var ns = newAttr.namespaceURI ;
	if(ns === NAMESPACE.XMLNS){
		//update namespace
		el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value
	}
}

function _onRemoveAttribute(doc,el,newAttr,remove){
	doc && doc._inc++;
	var ns = newAttr.namespaceURI ;
	if(ns === NAMESPACE.XMLNS){
		//update namespace
		delete el._nsMap[newAttr.prefix?newAttr.localName:'']
	}
}

/**
 * Updates `el.childNodes`, updating the indexed items and it's `length`.
 * Passing `newChild` means it will be appended.
 * Otherwise it's assumed that an item has been removed,
 * and `el.firstNode` and it's `.nextSibling` are used
 * to walk the current list of child nodes.
 *
 * @param {Document} doc
 * @param {Node} el
 * @param {Node} [newChild]
 * @private
 */
function _onUpdateChild (doc, el, newChild) {
	if(doc && doc._inc){
		doc._inc++;
		//update childNodes
		var cs = el.childNodes;
		if (newChild) {
			cs[cs.length++] = newChild;
		} else {
			var child = el.firstChild;
			var i = 0;
			while (child) {
				cs[i++] = child;
				child = child.nextSibling;
			}
			cs.length = i;
			delete cs[cs.length];
		}
	}
}

/**
 * Removes the connections between `parentNode` and `child`
 * and any existing `child.previousSibling` or `child.nextSibling`.
 *
 * @see https://github.com/xmldom/xmldom/issues/135
 * @see https://github.com/xmldom/xmldom/issues/145
 *
 * @param {Node} parentNode
 * @param {Node} child
 * @returns {Node} the child that was removed.
 * @private
 */
function _removeChild (parentNode, child) {
	var previous = child.previousSibling;
	var next = child.nextSibling;
	if (previous) {
		previous.nextSibling = next;
	} else {
		parentNode.firstChild = next;
	}
	if (next) {
		next.previousSibling = previous;
	} else {
		parentNode.lastChild = previous;
	}
	child.parentNode = null;
	child.previousSibling = null;
	child.nextSibling = null;
	_onUpdateChild(parentNode.ownerDocument, parentNode);
	return child;
}

/**
 * Returns `true` if `node` can be a parent for insertion.
 * @param {Node} node
 * @returns {boolean}
 */
function hasValidParentNodeType(node) {
	return (
		node &&
		(node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE || node.nodeType === Node.ELEMENT_NODE)
	);
}

/**
 * Returns `true` if `node` can be inserted according to it's `nodeType`.
 * @param {Node} node
 * @returns {boolean}
 */
function hasInsertableNodeType(node) {
	return (
		node &&
		(isElementNode(node) ||
			isTextNode(node) ||
			isDocTypeNode(node) ||
			node.nodeType === Node.DOCUMENT_FRAGMENT_NODE ||
			node.nodeType === Node.COMMENT_NODE ||
			node.nodeType === Node.PROCESSING_INSTRUCTION_NODE)
	);
}

/**
 * Returns true if `node` is a DOCTYPE node
 * @param {Node} node
 * @returns {boolean}
 */
function isDocTypeNode(node) {
	return node && node.nodeType === Node.DOCUMENT_TYPE_NODE;
}

/**
 * Returns true if the node is an element
 * @param {Node} node
 * @returns {boolean}
 */
function isElementNode(node) {
	return node && node.nodeType === Node.ELEMENT_NODE;
}
/**
 * Returns true if `node` is a text node
 * @param {Node} node
 * @returns {boolean}
 */
function isTextNode(node) {
	return node && node.nodeType === Node.TEXT_NODE;
}

/**
 * Check if en element node can be inserted before `child`, or at the end if child is falsy,
 * according to the presence and position of a doctype node on the same level.
 *
 * @param {Document} doc The document node
 * @param {Node} child the node that would become the nextSibling if the element would be inserted
 * @returns {boolean} `true` if an element can be inserted before child
 * @private
 * https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 */
function isElementInsertionPossible(doc, child) {
	var parentChildNodes = doc.childNodes || [];
	if (find(parentChildNodes, isElementNode) || isDocTypeNode(child)) {
		return false;
	}
	var docTypeNode = find(parentChildNodes, isDocTypeNode);
	return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
}

/**
 * Check if en element node can be inserted before `child`, or at the end if child is falsy,
 * according to the presence and position of a doctype node on the same level.
 *
 * @param {Node} doc The document node
 * @param {Node} child the node that would become the nextSibling if the element would be inserted
 * @returns {boolean} `true` if an element can be inserted before child
 * @private
 * https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 */
function isElementReplacementPossible(doc, child) {
	var parentChildNodes = doc.childNodes || [];

	function hasElementChildThatIsNotChild(node) {
		return isElementNode(node) && node !== child;
	}

	if (find(parentChildNodes, hasElementChildThatIsNotChild)) {
		return false;
	}
	var docTypeNode = find(parentChildNodes, isDocTypeNode);
	return !(child && docTypeNode && parentChildNodes.indexOf(docTypeNode) > parentChildNodes.indexOf(child));
}

/**
 * @private
 * Steps 1-5 of the checks before inserting and before replacing a child are the same.
 *
 * @param {Node} parent the parent node to insert `node` into
 * @param {Node} node the node to insert
 * @param {Node=} child the node that should become the `nextSibling` of `node`
 * @returns {Node}
 * @throws DOMException for several node combinations that would create a DOM that is not well-formed.
 * @throws DOMException if `child` is provided but is not a child of `parent`.
 * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 * @see https://dom.spec.whatwg.org/#concept-node-replace
 */
function assertPreInsertionValidity1to5(parent, node, child) {
	// 1. If `parent` is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
	if (!hasValidParentNodeType(parent)) {
		throw new DOMException(HIERARCHY_REQUEST_ERR, 'Unexpected parent node type ' + parent.nodeType);
	}
	// 2. If `node` is a host-including inclusive ancestor of `parent`, then throw a "HierarchyRequestError" DOMException.
	// not implemented!
	// 3. If `child` is non-null and its parent is not `parent`, then throw a "NotFoundError" DOMException.
	if (child && child.parentNode !== parent) {
		throw new DOMException(NOT_FOUND_ERR, 'child not in parent');
	}
	if (
		// 4. If `node` is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
		!hasInsertableNodeType(node) ||
		// 5. If either `node` is a Text node and `parent` is a document,
		// the sax parser currently adds top level text nodes, this will be fixed in 0.9.0
		// || (node.nodeType === Node.TEXT_NODE && parent.nodeType === Node.DOCUMENT_NODE)
		// or `node` is a doctype and `parent` is not a document, then throw a "HierarchyRequestError" DOMException.
		(isDocTypeNode(node) && parent.nodeType !== Node.DOCUMENT_NODE)
	) {
		throw new DOMException(
			HIERARCHY_REQUEST_ERR,
			'Unexpected node type ' + node.nodeType + ' for parent node type ' + parent.nodeType
		);
	}
}

/**
 * @private
 * Step 6 of the checks before inserting and before replacing a child are different.
 *
 * @param {Document} parent the parent node to insert `node` into
 * @param {Node} node the node to insert
 * @param {Node | undefined} child the node that should become the `nextSibling` of `node`
 * @returns {Node}
 * @throws DOMException for several node combinations that would create a DOM that is not well-formed.
 * @throws DOMException if `child` is provided but is not a child of `parent`.
 * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 * @see https://dom.spec.whatwg.org/#concept-node-replace
 */
function assertPreInsertionValidityInDocument(parent, node, child) {
	var parentChildNodes = parent.childNodes || [];
	var nodeChildNodes = node.childNodes || [];

	// DocumentFragment
	if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
		var nodeChildElements = nodeChildNodes.filter(isElementNode);
		// If node has more than one element child or has a Text node child.
		if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
		}
		// Otherwise, if `node` has one element child and either `parent` has an element child,
		// `child` is a doctype, or `child` is non-null and a doctype is following `child`.
		if (nodeChildElements.length === 1 && !isElementInsertionPossible(parent, child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
		}
	}
	// Element
	if (isElementNode(node)) {
		// `parent` has an element child, `child` is a doctype,
		// or `child` is non-null and a doctype is following `child`.
		if (!isElementInsertionPossible(parent, child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
		}
	}
	// DocumentType
	if (isDocTypeNode(node)) {
		// `parent` has a doctype child,
		if (find(parentChildNodes, isDocTypeNode)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
		}
		var parentElementChild = find(parentChildNodes, isElementNode);
		// `child` is non-null and an element is preceding `child`,
		if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
		}
		// or `child` is null and `parent` has an element child.
		if (!child && parentElementChild) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can not be appended since element is present');
		}
	}
}

/**
 * @private
 * Step 6 of the checks before inserting and before replacing a child are different.
 *
 * @param {Document} parent the parent node to insert `node` into
 * @param {Node} node the node to insert
 * @param {Node | undefined} child the node that should become the `nextSibling` of `node`
 * @returns {Node}
 * @throws DOMException for several node combinations that would create a DOM that is not well-formed.
 * @throws DOMException if `child` is provided but is not a child of `parent`.
 * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 * @see https://dom.spec.whatwg.org/#concept-node-replace
 */
function assertPreReplacementValidityInDocument(parent, node, child) {
	var parentChildNodes = parent.childNodes || [];
	var nodeChildNodes = node.childNodes || [];

	// DocumentFragment
	if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
		var nodeChildElements = nodeChildNodes.filter(isElementNode);
		// If `node` has more than one element child or has a Text node child.
		if (nodeChildElements.length > 1 || find(nodeChildNodes, isTextNode)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'More than one element or text in fragment');
		}
		// Otherwise, if `node` has one element child and either `parent` has an element child that is not `child` or a doctype is following `child`.
		if (nodeChildElements.length === 1 && !isElementReplacementPossible(parent, child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Element in fragment can not be inserted before doctype');
		}
	}
	// Element
	if (isElementNode(node)) {
		// `parent` has an element child that is not `child` or a doctype is following `child`.
		if (!isElementReplacementPossible(parent, child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one element can be added and only after doctype');
		}
	}
	// DocumentType
	if (isDocTypeNode(node)) {
		function hasDoctypeChildThatIsNotChild(node) {
			return isDocTypeNode(node) && node !== child;
		}

		// `parent` has a doctype child that is not `child`,
		if (find(parentChildNodes, hasDoctypeChildThatIsNotChild)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Only one doctype is allowed');
		}
		var parentElementChild = find(parentChildNodes, isElementNode);
		// or an element is preceding `child`.
		if (child && parentChildNodes.indexOf(parentElementChild) < parentChildNodes.indexOf(child)) {
			throw new DOMException(HIERARCHY_REQUEST_ERR, 'Doctype can only be inserted before an element');
		}
	}
}

/**
 * @private
 * @param {Node} parent the parent node to insert `node` into
 * @param {Node} node the node to insert
 * @param {Node=} child the node that should become the `nextSibling` of `node`
 * @returns {Node}
 * @throws DOMException for several node combinations that would create a DOM that is not well-formed.
 * @throws DOMException if `child` is provided but is not a child of `parent`.
 * @see https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
 */
function _insertBefore(parent, node, child, _inDocumentAssertion) {
	// To ensure pre-insertion validity of a node into a parent before a child, run these steps:
	assertPreInsertionValidity1to5(parent, node, child);

	// If parent is a document, and any of the statements below, switched on the interface node implements,
	// are true, then throw a "HierarchyRequestError" DOMException.
	if (parent.nodeType === Node.DOCUMENT_NODE) {
		(_inDocumentAssertion || assertPreInsertionValidityInDocument)(parent, node, child);
	}

	var cp = node.parentNode;
	if(cp){
		cp.removeChild(node);//remove and update
	}
	if(node.nodeType === DOCUMENT_FRAGMENT_NODE){
		var newFirst = node.firstChild;
		if (newFirst == null) {
			return node;
		}
		var newLast = node.lastChild;
	}else{
		newFirst = newLast = node;
	}
	var pre = child ? child.previousSibling : parent.lastChild;

	newFirst.previousSibling = pre;
	newLast.nextSibling = child;


	if(pre){
		pre.nextSibling = newFirst;
	}else{
		parent.firstChild = newFirst;
	}
	if(child == null){
		parent.lastChild = newLast;
	}else{
		child.previousSibling = newLast;
	}
	do{
		newFirst.parentNode = parent;
	}while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
	_onUpdateChild(parent.ownerDocument||parent, parent);
	//console.log(parent.lastChild.nextSibling == null)
	if (node.nodeType == DOCUMENT_FRAGMENT_NODE) {
		node.firstChild = node.lastChild = null;
	}
	return node;
}

/**
 * Appends `newChild` to `parentNode`.
 * If `newChild` is already connected to a `parentNode` it is first removed from it.
 *
 * @see https://github.com/xmldom/xmldom/issues/135
 * @see https://github.com/xmldom/xmldom/issues/145
 * @param {Node} parentNode
 * @param {Node} newChild
 * @returns {Node}
 * @private
 */
function _appendSingleChild (parentNode, newChild) {
	if (newChild.parentNode) {
		newChild.parentNode.removeChild(newChild);
	}
	newChild.parentNode = parentNode;
	newChild.previousSibling = parentNode.lastChild;
	newChild.nextSibling = null;
	if (newChild.previousSibling) {
		newChild.previousSibling.nextSibling = newChild;
	} else {
		parentNode.firstChild = newChild;
	}
	parentNode.lastChild = newChild;
	_onUpdateChild(parentNode.ownerDocument, parentNode, newChild);
	return newChild;
}

Document.prototype = {
	//implementation : null,
	nodeName :  '#document',
	nodeType :  DOCUMENT_NODE,
	/**
	 * The DocumentType node of the document.
	 *
	 * @readonly
	 * @type DocumentType
	 */
	doctype :  null,
	documentElement :  null,
	_inc : 1,

	insertBefore :  function(newChild, refChild){//raises
		if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
			var child = newChild.firstChild;
			while(child){
				var next = child.nextSibling;
				this.insertBefore(child,refChild);
				child = next;
			}
			return newChild;
		}
		_insertBefore(this, newChild, refChild);
		newChild.ownerDocument = this;
		if (this.documentElement === null && newChild.nodeType === ELEMENT_NODE) {
			this.documentElement = newChild;
		}

		return newChild;
	},
	removeChild :  function(oldChild){
		if(this.documentElement == oldChild){
			this.documentElement = null;
		}
		return _removeChild(this,oldChild);
	},
	replaceChild: function (newChild, oldChild) {
		//raises
		_insertBefore(this, newChild, oldChild, assertPreReplacementValidityInDocument);
		newChild.ownerDocument = this;
		if (oldChild) {
			this.removeChild(oldChild);
		}
		if (isElementNode(newChild)) {
			this.documentElement = newChild;
		}
	},
	// Introduced in DOM Level 2:
	importNode : function(importedNode,deep){
		return importNode(this,importedNode,deep);
	},
	// Introduced in DOM Level 2:
	getElementById :	function(id){
		var rtv = null;
		_visitNode(this.documentElement,function(node){
			if(node.nodeType == ELEMENT_NODE){
				if(node.getAttribute('id') == id){
					rtv = node;
					return true;
				}
			}
		})
		return rtv;
	},

	/**
	 * The `getElementsByClassName` method of `Document` interface returns an array-like object
	 * of all child elements which have **all** of the given class name(s).
	 *
	 * Returns an empty list if `classeNames` is an empty string or only contains HTML white space characters.
	 *
	 *
	 * Warning: This is a live LiveNodeList.
	 * Changes in the DOM will reflect in the array as the changes occur.
	 * If an element selected by this array no longer qualifies for the selector,
	 * it will automatically be removed. Be aware of this for iteration purposes.
	 *
	 * @param {string} classNames is a string representing the class name(s) to match; multiple class names are separated by (ASCII-)whitespace
	 *
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
	 * @see https://dom.spec.whatwg.org/#concept-getelementsbyclassname
	 */
	getElementsByClassName: function(classNames) {
		var classNamesSet = toOrderedSet(classNames)
		return new LiveNodeList(this, function(base) {
			var ls = [];
			if (classNamesSet.length > 0) {
				_visitNode(base.documentElement, function(node) {
					if(node !== base && node.nodeType === ELEMENT_NODE) {
						var nodeClassNames = node.getAttribute('class')
						// can be null if the attribute does not exist
						if (nodeClassNames) {
							// before splitting and iterating just compare them for the most common case
							var matches = classNames === nodeClassNames;
							if (!matches) {
								var nodeClassNamesSet = toOrderedSet(nodeClassNames)
								matches = classNamesSet.every(arrayIncludes(nodeClassNamesSet))
							}
							if(matches) {
								ls.push(node);
							}
						}
					}
				});
			}
			return ls;
		});
	},

	//document factory method:
	createElement :	function(tagName){
		var node = new Element();
		node.ownerDocument = this;
		node.nodeName = tagName;
		node.tagName = tagName;
		node.localName = tagName;
		node.childNodes = new NodeList();
		var attrs	= node.attributes = new NamedNodeMap();
		attrs._ownerElement = node;
		return node;
	},
	createDocumentFragment :	function(){
		var node = new DocumentFragment();
		node.ownerDocument = this;
		node.childNodes = new NodeList();
		return node;
	},
	createTextNode :	function(data){
		var node = new Text();
		node.ownerDocument = this;
		node.appendData(data)
		return node;
	},
	createComment :	function(data){
		var node = new Comment();
		node.ownerDocument = this;
		node.appendData(data)
		return node;
	},
	createCDATASection :	function(data){
		var node = new CDATASection();
		node.ownerDocument = this;
		node.appendData(data)
		return node;
	},
	createProcessingInstruction :	function(target,data){
		var node = new ProcessingInstruction();
		node.ownerDocument = this;
		node.tagName = node.nodeName = node.target = target;
		node.nodeValue = node.data = data;
		return node;
	},
	createAttribute :	function(name){
		var node = new Attr();
		node.ownerDocument	= this;
		node.name = name;
		node.nodeName	= name;
		node.localName = name;
		node.specified = true;
		return node;
	},
	createEntityReference :	function(name){
		var node = new EntityReference();
		node.ownerDocument	= this;
		node.nodeName	= name;
		return node;
	},
	// Introduced in DOM Level 2:
	createElementNS :	function(namespaceURI,qualifiedName){
		var node = new Element();
		var pl = qualifiedName.split(':');
		var attrs	= node.attributes = new NamedNodeMap();
		node.childNodes = new NodeList();
		node.ownerDocument = this;
		node.nodeName = qualifiedName;
		node.tagName = qualifiedName;
		node.namespaceURI = namespaceURI;
		if(pl.length == 2){
			node.prefix = pl[0];
			node.localName = pl[1];
		}else{
			//el.prefix = null;
			node.localName = qualifiedName;
		}
		attrs._ownerElement = node;
		return node;
	},
	// Introduced in DOM Level 2:
	createAttributeNS :	function(namespaceURI,qualifiedName){
		var node = new Attr();
		var pl = qualifiedName.split(':');
		node.ownerDocument = this;
		node.nodeName = qualifiedName;
		node.name = qualifiedName;
		node.namespaceURI = namespaceURI;
		node.specified = true;
		if(pl.length == 2){
			node.prefix = pl[0];
			node.localName = pl[1];
		}else{
			//el.prefix = null;
			node.localName = qualifiedName;
		}
		return node;
	}
};
_extends(Document,Node);


function Element() {
	this._nsMap = {};
};
Element.prototype = {
	nodeType : ELEMENT_NODE,
	hasAttribute : function(name){
		return this.getAttributeNode(name)!=null;
	},
	getAttribute : function(name){
		var attr = this.getAttributeNode(name);
		return attr && attr.value || '';
	},
	getAttributeNode : function(name){
		return this.attributes.getNamedItem(name);
	},
	setAttribute : function(name, value){
		var attr = this.ownerDocument.createAttribute(name);
		attr.value = attr.nodeValue = "" + value;
		this.setAttributeNode(attr)
	},
	removeAttribute : function(name){
		var attr = this.getAttributeNode(name)
		attr && this.removeAttributeNode(attr);
	},

	//four real opeartion method
	appendChild:function(newChild){
		if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
			return this.insertBefore(newChild,null);
		}else{
			return _appendSingleChild(this,newChild);
		}
	},
	setAttributeNode : function(newAttr){
		return this.attributes.setNamedItem(newAttr);
	},
	setAttributeNodeNS : function(newAttr){
		return this.attributes.setNamedItemNS(newAttr);
	},
	removeAttributeNode : function(oldAttr){
		//console.log(this == oldAttr.ownerElement)
		return this.attributes.removeNamedItem(oldAttr.nodeName);
	},
	//get real attribute name,and remove it by removeAttributeNode
	removeAttributeNS : function(namespaceURI, localName){
		var old = this.getAttributeNodeNS(namespaceURI, localName);
		old && this.removeAttributeNode(old);
	},

	hasAttributeNS : function(namespaceURI, localName){
		return this.getAttributeNodeNS(namespaceURI, localName)!=null;
	},
	getAttributeNS : function(namespaceURI, localName){
		var attr = this.getAttributeNodeNS(namespaceURI, localName);
		return attr && attr.value || '';
	},
	setAttributeNS : function(namespaceURI, qualifiedName, value){
		var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
		attr.value = attr.nodeValue = "" + value;
		this.setAttributeNode(attr)
	},
	getAttributeNodeNS : function(namespaceURI, localName){
		return this.attributes.getNamedItemNS(namespaceURI, localName);
	},

	getElementsByTagName : function(tagName){
		return new LiveNodeList(this,function(base){
			var ls = [];
			_visitNode(base,function(node){
				if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
					ls.push(node);
				}
			});
			return ls;
		});
	},
	getElementsByTagNameNS : function(namespaceURI, localName){
		return new LiveNodeList(this,function(base){
			var ls = [];
			_visitNode(base,function(node){
				if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
					ls.push(node);
				}
			});
			return ls;

		});
	}
};
Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;


_extends(Element,Node);
function Attr() {
};
Attr.prototype.nodeType = ATTRIBUTE_NODE;
_extends(Attr,Node);


function CharacterData() {
};
CharacterData.prototype = {
	data : '',
	substringData : function(offset, count) {
		return this.data.substring(offset, offset+count);
	},
	appendData: function(text) {
		text = this.data+text;
		this.nodeValue = this.data = text;
		this.length = text.length;
	},
	insertData: function(offset,text) {
		this.replaceData(offset,0,text);

	},
	appendChild:function(newChild){
		throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
	},
	deleteData: function(offset, count) {
		this.replaceData(offset,count,"");
	},
	replaceData: function(offset, count, text) {
		var start = this.data.substring(0,offset);
		var end = this.data.substring(offset+count);
		text = start + text + end;
		this.nodeValue = this.data = text;
		this.length = text.length;
	}
}
_extends(CharacterData,Node);
function Text() {
};
Text.prototype = {
	nodeName : "#text",
	nodeType : TEXT_NODE,
	splitText : function(offset) {
		var text = this.data;
		var newText = text.substring(offset);
		text = text.substring(0, offset);
		this.data = this.nodeValue = text;
		this.length = text.length;
		var newNode = this.ownerDocument.createTextNode(newText);
		if(this.parentNode){
			this.parentNode.insertBefore(newNode, this.nextSibling);
		}
		return newNode;
	}
}
_extends(Text,CharacterData);
function Comment() {
};
Comment.prototype = {
	nodeName : "#comment",
	nodeType : COMMENT_NODE
}
_extends(Comment,CharacterData);

function CDATASection() {
};
CDATASection.prototype = {
	nodeName : "#cdata-section",
	nodeType : CDATA_SECTION_NODE
}
_extends(CDATASection,CharacterData);


function DocumentType() {
};
DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
_extends(DocumentType,Node);

function Notation() {
};
Notation.prototype.nodeType = NOTATION_NODE;
_extends(Notation,Node);

function Entity() {
};
Entity.prototype.nodeType = ENTITY_NODE;
_extends(Entity,Node);

function EntityReference() {
};
EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
_extends(EntityReference,Node);

function DocumentFragment() {
};
DocumentFragment.prototype.nodeName =	"#document-fragment";
DocumentFragment.prototype.nodeType =	DOCUMENT_FRAGMENT_NODE;
_extends(DocumentFragment,Node);


function ProcessingInstruction() {
}
ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
_extends(ProcessingInstruction,Node);
function XMLSerializer(){}
XMLSerializer.prototype.serializeToString = function(node,isHtml,nodeFilter){
	return nodeSerializeToString.call(node,isHtml,nodeFilter);
}
Node.prototype.toString = nodeSerializeToString;
function nodeSerializeToString(isHtml,nodeFilter){
	var buf = [];
	var refNode = this.nodeType == 9 && this.documentElement || this;
	var prefix = refNode.prefix;
	var uri = refNode.namespaceURI;

	if(uri && prefix == null){
		//console.log(prefix)
		var prefix = refNode.lookupPrefix(uri);
		if(prefix == null){
			//isHTML = true;
			var visibleNamespaces=[
			{namespace:uri,prefix:null}
			//{namespace:uri,prefix:''}
			]
		}
	}
	serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);
	//console.log('###',this.nodeType,uri,prefix,buf.join(''))
	return buf.join('');
}

function needNamespaceDefine(node, isHTML, visibleNamespaces) {
	var prefix = node.prefix || '';
	var uri = node.namespaceURI;
	// According to [Namespaces in XML 1.0](https://www.w3.org/TR/REC-xml-names/#ns-using) ,
	// and more specifically https://www.w3.org/TR/REC-xml-names/#nsc-NoPrefixUndecl :
	// > In a namespace declaration for a prefix [...], the attribute value MUST NOT be empty.
	// in a similar manner [Namespaces in XML 1.1](https://www.w3.org/TR/xml-names11/#ns-using)
	// and more specifically https://www.w3.org/TR/xml-names11/#nsc-NSDeclared :
	// > [...] Furthermore, the attribute value [...] must not be an empty string.
	// so serializing empty namespace value like xmlns:ds="" would produce an invalid XML document.
	if (!uri) {
		return false;
	}
	if (prefix === "xml" && uri === NAMESPACE.XML || uri === NAMESPACE.XMLNS) {
		return false;
	}

	var i = visibleNamespaces.length
	while (i--) {
		var ns = visibleNamespaces[i];
		// get namespace prefix
		if (ns.prefix === prefix) {
			return ns.namespace !== uri;
		}
	}
	return true;
}
/**
 * Well-formed constraint: No < in Attribute Values
 * > The replacement text of any entity referred to directly or indirectly
 * > in an attribute value must not contain a <.
 * @see https://www.w3.org/TR/xml11/#CleanAttrVals
 * @see https://www.w3.org/TR/xml11/#NT-AttValue
 *
 * Literal whitespace other than space that appear in attribute values
 * are serialized as their entity references, so they will be preserved.
 * (In contrast to whitespace literals in the input which are normalized to spaces)
 * @see https://www.w3.org/TR/xml11/#AVNormalize
 * @see https://w3c.github.io/DOM-Parsing/#serializing-an-element-s-attributes
 */
function addSerializedAttribute(buf, qualifiedName, value) {
	buf.push(' ', qualifiedName, '="', value.replace(/[<>&"\t\n\r]/g, _xmlEncoder), '"')
}

function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
	if (!visibleNamespaces) {
		visibleNamespaces = [];
	}

	if(nodeFilter){
		node = nodeFilter(node);
		if(node){
			if(typeof node == 'string'){
				buf.push(node);
				return;
			}
		}else{
			return;
		}
		//buf.sort.apply(attrs, attributeSorter);
	}

	switch(node.nodeType){
	case ELEMENT_NODE:
		var attrs = node.attributes;
		var len = attrs.length;
		var child = node.firstChild;
		var nodeName = node.tagName;

		isHTML = NAMESPACE.isHTML(node.namespaceURI) || isHTML

		var prefixedNodeName = nodeName
		if (!isHTML && !node.prefix && node.namespaceURI) {
			var defaultNS
			// lookup current default ns from `xmlns` attribute
			for (var ai = 0; ai < attrs.length; ai++) {
				if (attrs.item(ai).name === 'xmlns') {
					defaultNS = attrs.item(ai).value
					break
				}
			}
			if (!defaultNS) {
				// lookup current default ns in visibleNamespaces
				for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
					var namespace = visibleNamespaces[nsi]
					if (namespace.prefix === '' && namespace.namespace === node.namespaceURI) {
						defaultNS = namespace.namespace
						break
					}
				}
			}
			if (defaultNS !== node.namespaceURI) {
				for (var nsi = visibleNamespaces.length - 1; nsi >= 0; nsi--) {
					var namespace = visibleNamespaces[nsi]
					if (namespace.namespace === node.namespaceURI) {
						if (namespace.prefix) {
							prefixedNodeName = namespace.prefix + ':' + nodeName
						}
						break
					}
				}
			}
		}

		buf.push('<', prefixedNodeName);

		for(var i=0;i<len;i++){
			// add namespaces for attributes
			var attr = attrs.item(i);
			if (attr.prefix == 'xmlns') {
				visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
			}else if(attr.nodeName == 'xmlns'){
				visibleNamespaces.push({ prefix: '', namespace: attr.value });
			}
		}

		for(var i=0;i<len;i++){
			var attr = attrs.item(i);
			if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
				var prefix = attr.prefix||'';
				var uri = attr.namespaceURI;
				addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
				visibleNamespaces.push({ prefix: prefix, namespace:uri });
			}
			serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
		}

		// add namespace for current node
		if (nodeName === prefixedNodeName && needNamespaceDefine(node, isHTML, visibleNamespaces)) {
			var prefix = node.prefix||'';
			var uri = node.namespaceURI;
			addSerializedAttribute(buf, prefix ? 'xmlns:' + prefix : "xmlns", uri);
			visibleNamespaces.push({ prefix: prefix, namespace:uri });
		}

		if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
			buf.push('>');
			//if is cdata child node
			if(isHTML && /^script$/i.test(nodeName)){
				while(child){
					if(child.data){
						buf.push(child.data);
					}else{
						serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					}
					child = child.nextSibling;
				}
			}else
			{
				while(child){
					serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
					child = child.nextSibling;
				}
			}
			buf.push('</',prefixedNodeName,'>');
		}else{
			buf.push('/>');
		}
		// remove added visible namespaces
		//visibleNamespaces.length = startVisibleNamespaces;
		return;
	case DOCUMENT_NODE:
	case DOCUMENT_FRAGMENT_NODE:
		var child = node.firstChild;
		while(child){
			serializeToString(child, buf, isHTML, nodeFilter, visibleNamespaces.slice());
			child = child.nextSibling;
		}
		return;
	case ATTRIBUTE_NODE:
		return addSerializedAttribute(buf, node.name, node.value);
	case TEXT_NODE:
		/**
		 * The ampersand character (&) and the left angle bracket (<) must not appear in their literal form,
		 * except when used as markup delimiters, or within a comment, a processing instruction, or a CDATA section.
		 * If they are needed elsewhere, they must be escaped using either numeric character references or the strings
		 * `&amp;` and `&lt;` respectively.
		 * The right angle bracket (>) may be represented using the string " &gt; ", and must, for compatibility,
		 * be escaped using either `&gt;` or a character reference when it appears in the string `]]>` in content,
		 * when that string is not marking the end of a CDATA section.
		 *
		 * In the content of elements, character data is any string of characters
		 * which does not contain the start-delimiter of any markup
		 * and does not include the CDATA-section-close delimiter, `]]>`.
		 *
		 * @see https://www.w3.org/TR/xml/#NT-CharData
		 * @see https://w3c.github.io/DOM-Parsing/#xml-serializing-a-text-node
		 */
		return buf.push(node.data
			.replace(/[<&>]/g,_xmlEncoder)
		);
	case CDATA_SECTION_NODE:
		return buf.push( '<![CDATA[',node.data,']]>');
	case COMMENT_NODE:
		return buf.push( "<!--",node.data,"-->");
	case DOCUMENT_TYPE_NODE:
		var pubid = node.publicId;
		var sysid = node.systemId;
		buf.push('<!DOCTYPE ',node.name);
		if(pubid){
			buf.push(' PUBLIC ', pubid);
			if (sysid && sysid!='.') {
				buf.push(' ', sysid);
			}
			buf.push('>');
		}else if(sysid && sysid!='.'){
			buf.push(' SYSTEM ', sysid, '>');
		}else{
			var sub = node.internalSubset;
			if(sub){
				buf.push(" [",sub,"]");
			}
			buf.push(">");
		}
		return;
	case PROCESSING_INSTRUCTION_NODE:
		return buf.push( "<?",node.target," ",node.data,"?>");
	case ENTITY_REFERENCE_NODE:
		return buf.push( '&',node.nodeName,';');
	//case ENTITY_NODE:
	//case NOTATION_NODE:
	default:
		buf.push('??',node.nodeName);
	}
}
function importNode(doc,node,deep){
	var node2;
	switch (node.nodeType) {
	case ELEMENT_NODE:
		node2 = node.cloneNode(false);
		node2.ownerDocument = doc;
		//var attrs = node2.attributes;
		//var len = attrs.length;
		//for(var i=0;i<len;i++){
			//node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
		//}
	case DOCUMENT_FRAGMENT_NODE:
		break;
	case ATTRIBUTE_NODE:
		deep = true;
		break;
	//case ENTITY_REFERENCE_NODE:
	//case PROCESSING_INSTRUCTION_NODE:
	////case TEXT_NODE:
	//case CDATA_SECTION_NODE:
	//case COMMENT_NODE:
	//	deep = false;
	//	break;
	//case DOCUMENT_NODE:
	//case DOCUMENT_TYPE_NODE:
	//cannot be imported.
	//case ENTITY_NODE:
	//case NOTATION_NODE：
	//can not hit in level3
	//default:throw e;
	}
	if(!node2){
		node2 = node.cloneNode(false);//false
	}
	node2.ownerDocument = doc;
	node2.parentNode = null;
	if(deep){
		var child = node.firstChild;
		while(child){
			node2.appendChild(importNode(doc,child,deep));
			child = child.nextSibling;
		}
	}
	return node2;
}
//
//var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
//					attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
function cloneNode(doc,node,deep){
	var node2 = new node.constructor();
	for (var n in node) {
		if (Object.prototype.hasOwnProperty.call(node, n)) {
			var v = node[n];
			if (typeof v != "object") {
				if (v != node2[n]) {
					node2[n] = v;
				}
			}
		}
	}
	if(node.childNodes){
		node2.childNodes = new NodeList();
	}
	node2.ownerDocument = doc;
	switch (node2.nodeType) {
	case ELEMENT_NODE:
		var attrs	= node.attributes;
		var attrs2	= node2.attributes = new NamedNodeMap();
		var len = attrs.length
		attrs2._ownerElement = node2;
		for(var i=0;i<len;i++){
			node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
		}
		break;;
	case ATTRIBUTE_NODE:
		deep = true;
	}
	if(deep){
		var child = node.firstChild;
		while(child){
			node2.appendChild(cloneNode(doc,child,deep));
			child = child.nextSibling;
		}
	}
	return node2;
}

function __set__(object,key,value){
	object[key] = value
}
//do dynamic
try{
	if(Object.defineProperty){
		Object.defineProperty(LiveNodeList.prototype,'length',{
			get:function(){
				_updateLiveList(this);
				return this.$$length;
			}
		});

		Object.defineProperty(Node.prototype,'textContent',{
			get:function(){
				return getTextContent(this);
			},

			set:function(data){
				switch(this.nodeType){
				case ELEMENT_NODE:
				case DOCUMENT_FRAGMENT_NODE:
					while(this.firstChild){
						this.removeChild(this.firstChild);
					}
					if(data || String(data)){
						this.appendChild(this.ownerDocument.createTextNode(data));
					}
					break;

				default:
					this.data = data;
					this.value = data;
					this.nodeValue = data;
				}
			}
		})

		function getTextContent(node){
			switch(node.nodeType){
			case ELEMENT_NODE:
			case DOCUMENT_FRAGMENT_NODE:
				var buf = [];
				node = node.firstChild;
				while(node){
					if(node.nodeType!==7 && node.nodeType !==8){
						buf.push(getTextContent(node));
					}
					node = node.nextSibling;
				}
				return buf.join('');
			default:
				return node.nodeValue;
			}
		}

		__set__ = function(object,key,value){
			//console.log(value)
			object['$$'+key] = value
		}
	}
}catch(e){//ie8
}

//if(typeof require == 'function'){
	exports.DocumentType = DocumentType;
	exports.DOMException = DOMException;
	exports.DOMImplementation = DOMImplementation;
	exports.Element = Element;
	exports.Node = Node;
	exports.NodeList = NodeList;
	exports.XMLSerializer = XMLSerializer;
//}


/***/ }),
/* 56 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


/**
 * Ponyfill for `Array.prototype.find` which is only available in ES6 runtimes.
 *
 * Works with anything that has a `length` property and index access properties, including NodeList.
 *
 * @template {unknown} T
 * @param {Array<T> | ({length:number, [number]: T})} list
 * @param {function (item: T, index: number, list:Array<T> | ({length:number, [number]: T})):boolean} predicate
 * @param {Partial<Pick<ArrayConstructor['prototype'], 'find'>>?} ac `Array.prototype` by default,
 * 				allows injecting a custom implementation in tests
 * @returns {T | undefined}
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
 * @see https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find
 */
function find(list, predicate, ac) {
	if (ac === undefined) {
		ac = Array.prototype;
	}
	if (list && typeof ac.find === 'function') {
		return ac.find.call(list, predicate);
	}
	for (var i = 0; i < list.length; i++) {
		if (Object.prototype.hasOwnProperty.call(list, i)) {
			var item = list[i];
			if (predicate.call(undefined, item, i, list)) {
				return item;
			}
		}
	}
}

/**
 * "Shallow freezes" an object to render it immutable.
 * Uses `Object.freeze` if available,
 * otherwise the immutability is only in the type.
 *
 * Is used to create "enum like" objects.
 *
 * @template T
 * @param {T} object the object to freeze
 * @param {Pick<ObjectConstructor, 'freeze'> = Object} oc `Object` by default,
 * 				allows to inject custom object constructor for tests
 * @returns {Readonly<T>}
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
 */
function freeze(object, oc) {
	if (oc === undefined) {
		oc = Object
	}
	return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object
}

/**
 * Since we can not rely on `Object.assign` we provide a simplified version
 * that is sufficient for our needs.
 *
 * @param {Object} target
 * @param {Object | null | undefined} source
 *
 * @returns {Object} target
 * @throws TypeError if target is not an object
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
 * @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign
 */
function assign(target, source) {
	if (target === null || typeof target !== 'object') {
		throw new TypeError('target is not an object')
	}
	for (var key in source) {
		if (Object.prototype.hasOwnProperty.call(source, key)) {
			target[key] = source[key]
		}
	}
	return target
}

/**
 * All mime types that are allowed as input to `DOMParser.parseFromString`
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN
 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec
 * @see DOMParser.prototype.parseFromString
 */
var MIME_TYPE = freeze({
	/**
	 * `text/html`, the only mime type that triggers treating an XML document as HTML.
	 *
	 * @see DOMParser.SupportedType.isHTML
	 * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
	 * @see https://en.wikipedia.org/wiki/HTML Wikipedia
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
	 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec
	 */
	HTML: 'text/html',

	/**
	 * Helper method to check a mime type if it indicates an HTML document
	 *
	 * @param {string} [value]
	 * @returns {boolean}
	 *
	 * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
	 * @see https://en.wikipedia.org/wiki/HTML Wikipedia
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
	 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring 	 */
	isHTML: function (value) {
		return value === MIME_TYPE.HTML
	},

	/**
	 * `application/xml`, the standard mime type for XML documents.
	 *
	 * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration
	 * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303
	 * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
	 */
	XML_APPLICATION: 'application/xml',

	/**
	 * `text/html`, an alias for `application/xml`.
	 *
	 * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303
	 * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration
	 * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
	 */
	XML_TEXT: 'text/xml',

	/**
	 * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,
	 * but is parsed as an XML document.
	 *
	 * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration
	 * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec
	 * @see https://en.wikipedia.org/wiki/XHTML Wikipedia
	 */
	XML_XHTML_APPLICATION: 'application/xhtml+xml',

	/**
	 * `image/svg+xml`,
	 *
	 * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration
	 * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1
	 * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia
	 */
	XML_SVG_IMAGE: 'image/svg+xml',
})

/**
 * Namespaces that are used in this code base.
 *
 * @see http://www.w3.org/TR/REC-xml-names
 */
var NAMESPACE = freeze({
	/**
	 * The XHTML namespace.
	 *
	 * @see http://www.w3.org/1999/xhtml
	 */
	HTML: 'http://www.w3.org/1999/xhtml',

	/**
	 * Checks if `uri` equals `NAMESPACE.HTML`.
	 *
	 * @param {string} [uri]
	 *
	 * @see NAMESPACE.HTML
	 */
	isHTML: function (uri) {
		return uri === NAMESPACE.HTML
	},

	/**
	 * The SVG namespace.
	 *
	 * @see http://www.w3.org/2000/svg
	 */
	SVG: 'http://www.w3.org/2000/svg',

	/**
	 * The `xml:` namespace.
	 *
	 * @see http://www.w3.org/XML/1998/namespace
	 */
	XML: 'http://www.w3.org/XML/1998/namespace',

	/**
	 * The `xmlns:` namespace
	 *
	 * @see https://www.w3.org/2000/xmlns/
	 */
	XMLNS: 'http://www.w3.org/2000/xmlns/',
})

exports.assign = assign;
exports.find = find;
exports.freeze = freeze;
exports.MIME_TYPE = MIME_TYPE;
exports.NAMESPACE = NAMESPACE;


/***/ }),
/* 57 */
/***/ (function(module, exports, __webpack_require__) {

var conventions = __webpack_require__(56);
var dom = __webpack_require__(55)
var entities = __webpack_require__(58);
var sax = __webpack_require__(59);

var DOMImplementation = dom.DOMImplementation;

var NAMESPACE = conventions.NAMESPACE;

var ParseError = sax.ParseError;
var XMLReader = sax.XMLReader;

/**
 * Normalizes line ending according to https://www.w3.org/TR/xml11/#sec-line-ends:
 *
 * > XML parsed entities are often stored in computer files which,
 * > for editing convenience, are organized into lines.
 * > These lines are typically separated by some combination
 * > of the characters CARRIAGE RETURN (#xD) and LINE FEED (#xA).
 * >
 * > To simplify the tasks of applications, the XML processor must behave
 * > as if it normalized all line breaks in external parsed entities (including the document entity)
 * > on input, before parsing, by translating all of the following to a single #xA character:
 * >
 * > 1. the two-character sequence #xD #xA
 * > 2. the two-character sequence #xD #x85
 * > 3. the single character #x85
 * > 4. the single character #x2028
 * > 5. any #xD character that is not immediately followed by #xA or #x85.
 *
 * @param {string} input
 * @returns {string}
 */
function normalizeLineEndings(input) {
	return input
		.replace(/\r[\n\u0085]/g, '\n')
		.replace(/[\r\u0085\u2028]/g, '\n')
}

/**
 * @typedef Locator
 * @property {number} [columnNumber]
 * @property {number} [lineNumber]
 */

/**
 * @typedef DOMParserOptions
 * @property {DOMHandler} [domBuilder]
 * @property {Function} [errorHandler]
 * @property {(string) => string} [normalizeLineEndings] used to replace line endings before parsing
 * 						defaults to `normalizeLineEndings`
 * @property {Locator} [locator]
 * @property {Record<string, string>} [xmlns]
 *
 * @see normalizeLineEndings
 */

/**
 * The DOMParser interface provides the ability to parse XML or HTML source code
 * from a string into a DOM `Document`.
 *
 * _xmldom is different from the spec in that it allows an `options` parameter,
 * to override the default behavior._
 *
 * @param {DOMParserOptions} [options]
 * @constructor
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization
 */
function DOMParser(options){
	this.options = options ||{locator:{}};
}

DOMParser.prototype.parseFromString = function(source,mimeType){
	var options = this.options;
	var sax =  new XMLReader();
	var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
	var errorHandler = options.errorHandler;
	var locator = options.locator;
	var defaultNSMap = options.xmlns||{};
	var isHTML = /\/x?html?$/.test(mimeType);//mimeType.toLowerCase().indexOf('html') > -1;
  	var entityMap = isHTML ? entities.HTML_ENTITIES : entities.XML_ENTITIES;
	if(locator){
		domBuilder.setDocumentLocator(locator)
	}

	sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
	sax.domBuilder = options.domBuilder || domBuilder;
	if(isHTML){
		defaultNSMap[''] = NAMESPACE.HTML;
	}
	defaultNSMap.xml = defaultNSMap.xml || NAMESPACE.XML;
	var normalize = options.normalizeLineEndings || normalizeLineEndings;
	if (source && typeof source === 'string') {
		sax.parse(
			normalize(source),
			defaultNSMap,
			entityMap
		)
	} else {
		sax.errorHandler.error('invalid doc source')
	}
	return domBuilder.doc;
}
function buildErrorHandler(errorImpl,domBuilder,locator){
	if(!errorImpl){
		if(domBuilder instanceof DOMHandler){
			return domBuilder;
		}
		errorImpl = domBuilder ;
	}
	var errorHandler = {}
	var isCallback = errorImpl instanceof Function;
	locator = locator||{}
	function build(key){
		var fn = errorImpl[key];
		if(!fn && isCallback){
			fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl;
		}
		errorHandler[key] = fn && function(msg){
			fn('[xmldom '+key+']\t'+msg+_locator(locator));
		}||function(){};
	}
	build('warning');
	build('error');
	build('fatalError');
	return errorHandler;
}

//console.log('#\n\n\n\n\n\n\n####')
/**
 * +ContentHandler+ErrorHandler
 * +LexicalHandler+EntityResolver2
 * -DeclHandler-DTDHandler
 *
 * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
 * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
 * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
 */
function DOMHandler() {
    this.cdata = false;
}
function position(locator,node){
	node.lineNumber = locator.lineNumber;
	node.columnNumber = locator.columnNumber;
}
/**
 * @see org.xml.sax.ContentHandler#startDocument
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
 */
DOMHandler.prototype = {
	startDocument : function() {
    	this.doc = new DOMImplementation().createDocument(null, null, null);
    	if (this.locator) {
        	this.doc.documentURI = this.locator.systemId;
    	}
	},
	startElement:function(namespaceURI, localName, qName, attrs) {
		var doc = this.doc;
	    var el = doc.createElementNS(namespaceURI, qName||localName);
	    var len = attrs.length;
	    appendElement(this, el);
	    this.currentElement = el;

		this.locator && position(this.locator,el)
	    for (var i = 0 ; i < len; i++) {
	        var namespaceURI = attrs.getURI(i);
	        var value = attrs.getValue(i);
	        var qName = attrs.getQName(i);
			var attr = doc.createAttributeNS(namespaceURI, qName);
			this.locator &&position(attrs.getLocator(i),attr);
			attr.value = attr.nodeValue = value;
			el.setAttributeNode(attr)
	    }
	},
	endElement:function(namespaceURI, localName, qName) {
		var current = this.currentElement
		var tagName = current.tagName;
		this.currentElement = current.parentNode;
	},
	startPrefixMapping:function(prefix, uri) {
	},
	endPrefixMapping:function(prefix) {
	},
	processingInstruction:function(target, data) {
	    var ins = this.doc.createProcessingInstruction(target, data);
	    this.locator && position(this.locator,ins)
	    appendElement(this, ins);
	},
	ignorableWhitespace:function(ch, start, length) {
	},
	characters:function(chars, start, length) {
		chars = _toString.apply(this,arguments)
		//console.log(chars)
		if(chars){
			if (this.cdata) {
				var charNode = this.doc.createCDATASection(chars);
			} else {
				var charNode = this.doc.createTextNode(chars);
			}
			if(this.currentElement){
				this.currentElement.appendChild(charNode);
			}else if(/^\s*$/.test(chars)){
				this.doc.appendChild(charNode);
				//process xml
			}
			this.locator && position(this.locator,charNode)
		}
	},
	skippedEntity:function(name) {
	},
	endDocument:function() {
		this.doc.normalize();
	},
	setDocumentLocator:function (locator) {
	    if(this.locator = locator){// && !('lineNumber' in locator)){
	    	locator.lineNumber = 0;
	    }
	},
	//LexicalHandler
	comment:function(chars, start, length) {
		chars = _toString.apply(this,arguments)
	    var comm = this.doc.createComment(chars);
	    this.locator && position(this.locator,comm)
	    appendElement(this, comm);
	},

	startCDATA:function() {
	    //used in characters() methods
	    this.cdata = true;
	},
	endCDATA:function() {
	    this.cdata = false;
	},

	startDTD:function(name, publicId, systemId) {
		var impl = this.doc.implementation;
	    if (impl && impl.createDocumentType) {
	        var dt = impl.createDocumentType(name, publicId, systemId);
	        this.locator && position(this.locator,dt)
	        appendElement(this, dt);
					this.doc.doctype = dt;
	    }
	},
	/**
	 * @see org.xml.sax.ErrorHandler
	 * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
	 */
	warning:function(error) {
		console.warn('[xmldom warning]\t'+error,_locator(this.locator));
	},
	error:function(error) {
		console.error('[xmldom error]\t'+error,_locator(this.locator));
	},
	fatalError:function(error) {
		throw new ParseError(error, this.locator);
	}
}
function _locator(l){
	if(l){
		return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
	}
}
function _toString(chars,start,length){
	if(typeof chars == 'string'){
		return chars.substr(start,length)
	}else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
		if(chars.length >= start+length || start){
			return new java.lang.String(chars,start,length)+'';
		}
		return chars;
	}
}

/*
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
 * used method of org.xml.sax.ext.LexicalHandler:
 *  #comment(chars, start, length)
 *  #startCDATA()
 *  #endCDATA()
 *  #startDTD(name, publicId, systemId)
 *
 *
 * IGNORED method of org.xml.sax.ext.LexicalHandler:
 *  #endDTD()
 *  #startEntity(name)
 *  #endEntity(name)
 *
 *
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
 * IGNORED method of org.xml.sax.ext.DeclHandler
 * 	#attributeDecl(eName, aName, type, mode, value)
 *  #elementDecl(name, model)
 *  #externalEntityDecl(name, publicId, systemId)
 *  #internalEntityDecl(name, value)
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
 * IGNORED method of org.xml.sax.EntityResolver2
 *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
 *  #resolveEntity(publicId, systemId)
 *  #getExternalSubset(name, baseURI)
 * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
 * IGNORED method of org.xml.sax.DTDHandler
 *  #notationDecl(name, publicId, systemId) {};
 *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
 */
"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
	DOMHandler.prototype[key] = function(){return null}
})

/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
function appendElement (hander,node) {
    if (!hander.currentElement) {
        hander.doc.appendChild(node);
    } else {
        hander.currentElement.appendChild(node);
    }
}//appendChild and setAttributeNS are preformance key

exports.__DOMHandler = DOMHandler;
exports.normalizeLineEndings = normalizeLineEndings;
exports.DOMParser = DOMParser;


/***/ }),
/* 58 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var freeze = __webpack_require__(56).freeze;

/**
 * The entities that are predefined in every XML document.
 *
 * @see https://www.w3.org/TR/2006/REC-xml11-20060816/#sec-predefined-ent W3C XML 1.1
 * @see https://www.w3.org/TR/2008/REC-xml-20081126/#sec-predefined-ent W3C XML 1.0
 * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML Wikipedia
 */
exports.XML_ENTITIES = freeze({
	amp: '&',
	apos: "'",
	gt: '>',
	lt: '<',
	quot: '"',
});

/**
 * A map of all entities that are detected in an HTML document.
 * They contain all entries from `XML_ENTITIES`.
 *
 * @see XML_ENTITIES
 * @see DOMParser.parseFromString
 * @see DOMImplementation.prototype.createHTMLDocument
 * @see https://html.spec.whatwg.org/#named-character-references WHATWG HTML(5) Spec
 * @see https://html.spec.whatwg.org/entities.json JSON
 * @see https://www.w3.org/TR/xml-entity-names/ W3C XML Entity Names
 * @see https://www.w3.org/TR/html4/sgml/entities.html W3C HTML4/SGML
 * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Character_entity_references_in_HTML Wikipedia (HTML)
 * @see https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Entities_representing_special_characters_in_XHTML Wikpedia (XHTML)
 */
exports.HTML_ENTITIES = freeze({
	Aacute: '\u00C1',
	aacute: '\u00E1',
	Abreve: '\u0102',
	abreve: '\u0103',
	ac: '\u223E',
	acd: '\u223F',
	acE: '\u223E\u0333',
	Acirc: '\u00C2',
	acirc: '\u00E2',
	acute: '\u00B4',
	Acy: '\u0410',
	acy: '\u0430',
	AElig: '\u00C6',
	aelig: '\u00E6',
	af: '\u2061',
	Afr: '\uD835\uDD04',
	afr: '\uD835\uDD1E',
	Agrave: '\u00C0',
	agrave: '\u00E0',
	alefsym: '\u2135',
	aleph: '\u2135',
	Alpha: '\u0391',
	alpha: '\u03B1',
	Amacr: '\u0100',
	amacr: '\u0101',
	amalg: '\u2A3F',
	AMP: '\u0026',
	amp: '\u0026',
	And: '\u2A53',
	and: '\u2227',
	andand: '\u2A55',
	andd: '\u2A5C',
	andslope: '\u2A58',
	andv: '\u2A5A',
	ang: '\u2220',
	ange: '\u29A4',
	angle: '\u2220',
	angmsd: '\u2221',
	angmsdaa: '\u29A8',
	angmsdab: '\u29A9',
	angmsdac: '\u29AA',
	angmsdad: '\u29AB',
	angmsdae: '\u29AC',
	angmsdaf: '\u29AD',
	angmsdag: '\u29AE',
	angmsdah: '\u29AF',
	angrt: '\u221F',
	angrtvb: '\u22BE',
	angrtvbd: '\u299D',
	angsph: '\u2222',
	angst: '\u00C5',
	angzarr: '\u237C',
	Aogon: '\u0104',
	aogon: '\u0105',
	Aopf: '\uD835\uDD38',
	aopf: '\uD835\uDD52',
	ap: '\u2248',
	apacir: '\u2A6F',
	apE: '\u2A70',
	ape: '\u224A',
	apid: '\u224B',
	apos: '\u0027',
	ApplyFunction: '\u2061',
	approx: '\u2248',
	approxeq: '\u224A',
	Aring: '\u00C5',
	aring: '\u00E5',
	Ascr: '\uD835\uDC9C',
	ascr: '\uD835\uDCB6',
	Assign: '\u2254',
	ast: '\u002A',
	asymp: '\u2248',
	asympeq: '\u224D',
	Atilde: '\u00C3',
	atilde: '\u00E3',
	Auml: '\u00C4',
	auml: '\u00E4',
	awconint: '\u2233',
	awint: '\u2A11',
	backcong: '\u224C',
	backepsilon: '\u03F6',
	backprime: '\u2035',
	backsim: '\u223D',
	backsimeq: '\u22CD',
	Backslash: '\u2216',
	Barv: '\u2AE7',
	barvee: '\u22BD',
	Barwed: '\u2306',
	barwed: '\u2305',
	barwedge: '\u2305',
	bbrk: '\u23B5',
	bbrktbrk: '\u23B6',
	bcong: '\u224C',
	Bcy: '\u0411',
	bcy: '\u0431',
	bdquo: '\u201E',
	becaus: '\u2235',
	Because: '\u2235',
	because: '\u2235',
	bemptyv: '\u29B0',
	bepsi: '\u03F6',
	bernou: '\u212C',
	Bernoullis: '\u212C',
	Beta: '\u0392',
	beta: '\u03B2',
	beth: '\u2136',
	between: '\u226C',
	Bfr: '\uD835\uDD05',
	bfr: '\uD835\uDD1F',
	bigcap: '\u22C2',
	bigcirc: '\u25EF',
	bigcup: '\u22C3',
	bigodot: '\u2A00',
	bigoplus: '\u2A01',
	bigotimes: '\u2A02',
	bigsqcup: '\u2A06',
	bigstar: '\u2605',
	bigtriangledown: '\u25BD',
	bigtriangleup: '\u25B3',
	biguplus: '\u2A04',
	bigvee: '\u22C1',
	bigwedge: '\u22C0',
	bkarow: '\u290D',
	blacklozenge: '\u29EB',
	blacksquare: '\u25AA',
	blacktriangle: '\u25B4',
	blacktriangledown: '\u25BE',
	blacktriangleleft: '\u25C2',
	blacktriangleright: '\u25B8',
	blank: '\u2423',
	blk12: '\u2592',
	blk14: '\u2591',
	blk34: '\u2593',
	block: '\u2588',
	bne: '\u003D\u20E5',
	bnequiv: '\u2261\u20E5',
	bNot: '\u2AED',
	bnot: '\u2310',
	Bopf: '\uD835\uDD39',
	bopf: '\uD835\uDD53',
	bot: '\u22A5',
	bottom: '\u22A5',
	bowtie: '\u22C8',
	boxbox: '\u29C9',
	boxDL: '\u2557',
	boxDl: '\u2556',
	boxdL: '\u2555',
	boxdl: '\u2510',
	boxDR: '\u2554',
	boxDr: '\u2553',
	boxdR: '\u2552',
	boxdr: '\u250C',
	boxH: '\u2550',
	boxh: '\u2500',
	boxHD: '\u2566',
	boxHd: '\u2564',
	boxhD: '\u2565',
	boxhd: '\u252C',
	boxHU: '\u2569',
	boxHu: '\u2567',
	boxhU: '\u2568',
	boxhu: '\u2534',
	boxminus: '\u229F',
	boxplus: '\u229E',
	boxtimes: '\u22A0',
	boxUL: '\u255D',
	boxUl: '\u255C',
	boxuL: '\u255B',
	boxul: '\u2518',
	boxUR: '\u255A',
	boxUr: '\u2559',
	boxuR: '\u2558',
	boxur: '\u2514',
	boxV: '\u2551',
	boxv: '\u2502',
	boxVH: '\u256C',
	boxVh: '\u256B',
	boxvH: '\u256A',
	boxvh: '\u253C',
	boxVL: '\u2563',
	boxVl: '\u2562',
	boxvL: '\u2561',
	boxvl: '\u2524',
	boxVR: '\u2560',
	boxVr: '\u255F',
	boxvR: '\u255E',
	boxvr: '\u251C',
	bprime: '\u2035',
	Breve: '\u02D8',
	breve: '\u02D8',
	brvbar: '\u00A6',
	Bscr: '\u212C',
	bscr: '\uD835\uDCB7',
	bsemi: '\u204F',
	bsim: '\u223D',
	bsime: '\u22CD',
	bsol: '\u005C',
	bsolb: '\u29C5',
	bsolhsub: '\u27C8',
	bull: '\u2022',
	bullet: '\u2022',
	bump: '\u224E',
	bumpE: '\u2AAE',
	bumpe: '\u224F',
	Bumpeq: '\u224E',
	bumpeq: '\u224F',
	Cacute: '\u0106',
	cacute: '\u0107',
	Cap: '\u22D2',
	cap: '\u2229',
	capand: '\u2A44',
	capbrcup: '\u2A49',
	capcap: '\u2A4B',
	capcup: '\u2A47',
	capdot: '\u2A40',
	CapitalDifferentialD: '\u2145',
	caps: '\u2229\uFE00',
	caret: '\u2041',
	caron: '\u02C7',
	Cayleys: '\u212D',
	ccaps: '\u2A4D',
	Ccaron: '\u010C',
	ccaron: '\u010D',
	Ccedil: '\u00C7',
	ccedil: '\u00E7',
	Ccirc: '\u0108',
	ccirc: '\u0109',
	Cconint: '\u2230',
	ccups: '\u2A4C',
	ccupssm: '\u2A50',
	Cdot: '\u010A',
	cdot: '\u010B',
	cedil: '\u00B8',
	Cedilla: '\u00B8',
	cemptyv: '\u29B2',
	cent: '\u00A2',
	CenterDot: '\u00B7',
	centerdot: '\u00B7',
	Cfr: '\u212D',
	cfr: '\uD835\uDD20',
	CHcy: '\u0427',
	chcy: '\u0447',
	check: '\u2713',
	checkmark: '\u2713',
	Chi: '\u03A7',
	chi: '\u03C7',
	cir: '\u25CB',
	circ: '\u02C6',
	circeq: '\u2257',
	circlearrowleft: '\u21BA',
	circlearrowright: '\u21BB',
	circledast: '\u229B',
	circledcirc: '\u229A',
	circleddash: '\u229D',
	CircleDot: '\u2299',
	circledR: '\u00AE',
	circledS: '\u24C8',
	CircleMinus: '\u2296',
	CirclePlus: '\u2295',
	CircleTimes: '\u2297',
	cirE: '\u29C3',
	cire: '\u2257',
	cirfnint: '\u2A10',
	cirmid: '\u2AEF',
	cirscir: '\u29C2',
	ClockwiseContourIntegral: '\u2232',
	CloseCurlyDoubleQuote: '\u201D',
	CloseCurlyQuote: '\u2019',
	clubs: '\u2663',
	clubsuit: '\u2663',
	Colon: '\u2237',
	colon: '\u003A',
	Colone: '\u2A74',
	colone: '\u2254',
	coloneq: '\u2254',
	comma: '\u002C',
	commat: '\u0040',
	comp: '\u2201',
	compfn: '\u2218',
	complement: '\u2201',
	complexes: '\u2102',
	cong: '\u2245',
	congdot: '\u2A6D',
	Congruent: '\u2261',
	Conint: '\u222F',
	conint: '\u222E',
	ContourIntegral: '\u222E',
	Copf: '\u2102',
	copf: '\uD835\uDD54',
	coprod: '\u2210',
	Coproduct: '\u2210',
	COPY: '\u00A9',
	copy: '\u00A9',
	copysr: '\u2117',
	CounterClockwiseContourIntegral: '\u2233',
	crarr: '\u21B5',
	Cross: '\u2A2F',
	cross: '\u2717',
	Cscr: '\uD835\uDC9E',
	cscr: '\uD835\uDCB8',
	csub: '\u2ACF',
	csube: '\u2AD1',
	csup: '\u2AD0',
	csupe: '\u2AD2',
	ctdot: '\u22EF',
	cudarrl: '\u2938',
	cudarrr: '\u2935',
	cuepr: '\u22DE',
	cuesc: '\u22DF',
	cularr: '\u21B6',
	cularrp: '\u293D',
	Cup: '\u22D3',
	cup: '\u222A',
	cupbrcap: '\u2A48',
	CupCap: '\u224D',
	cupcap: '\u2A46',
	cupcup: '\u2A4A',
	cupdot: '\u228D',
	cupor: '\u2A45',
	cups: '\u222A\uFE00',
	curarr: '\u21B7',
	curarrm: '\u293C',
	curlyeqprec: '\u22DE',
	curlyeqsucc: '\u22DF',
	curlyvee: '\u22CE',
	curlywedge: '\u22CF',
	curren: '\u00A4',
	curvearrowleft: '\u21B6',
	curvearrowright: '\u21B7',
	cuvee: '\u22CE',
	cuwed: '\u22CF',
	cwconint: '\u2232',
	cwint: '\u2231',
	cylcty: '\u232D',
	Dagger: '\u2021',
	dagger: '\u2020',
	daleth: '\u2138',
	Darr: '\u21A1',
	dArr: '\u21D3',
	darr: '\u2193',
	dash: '\u2010',
	Dashv: '\u2AE4',
	dashv: '\u22A3',
	dbkarow: '\u290F',
	dblac: '\u02DD',
	Dcaron: '\u010E',
	dcaron: '\u010F',
	Dcy: '\u0414',
	dcy: '\u0434',
	DD: '\u2145',
	dd: '\u2146',
	ddagger: '\u2021',
	ddarr: '\u21CA',
	DDotrahd: '\u2911',
	ddotseq: '\u2A77',
	deg: '\u00B0',
	Del: '\u2207',
	Delta: '\u0394',
	delta: '\u03B4',
	demptyv: '\u29B1',
	dfisht: '\u297F',
	Dfr: '\uD835\uDD07',
	dfr: '\uD835\uDD21',
	dHar: '\u2965',
	dharl: '\u21C3',
	dharr: '\u21C2',
	DiacriticalAcute: '\u00B4',
	DiacriticalDot: '\u02D9',
	DiacriticalDoubleAcute: '\u02DD',
	DiacriticalGrave: '\u0060',
	DiacriticalTilde: '\u02DC',
	diam: '\u22C4',
	Diamond: '\u22C4',
	diamond: '\u22C4',
	diamondsuit: '\u2666',
	diams: '\u2666',
	die: '\u00A8',
	DifferentialD: '\u2146',
	digamma: '\u03DD',
	disin: '\u22F2',
	div: '\u00F7',
	divide: '\u00F7',
	divideontimes: '\u22C7',
	divonx: '\u22C7',
	DJcy: '\u0402',
	djcy: '\u0452',
	dlcorn: '\u231E',
	dlcrop: '\u230D',
	dollar: '\u0024',
	Dopf: '\uD835\uDD3B',
	dopf: '\uD835\uDD55',
	Dot: '\u00A8',
	dot: '\u02D9',
	DotDot: '\u20DC',
	doteq: '\u2250',
	doteqdot: '\u2251',
	DotEqual: '\u2250',
	dotminus: '\u2238',
	dotplus: '\u2214',
	dotsquare: '\u22A1',
	doublebarwedge: '\u2306',
	DoubleContourIntegral: '\u222F',
	DoubleDot: '\u00A8',
	DoubleDownArrow: '\u21D3',
	DoubleLeftArrow: '\u21D0',
	DoubleLeftRightArrow: '\u21D4',
	DoubleLeftTee: '\u2AE4',
	DoubleLongLeftArrow: '\u27F8',
	DoubleLongLeftRightArrow: '\u27FA',
	DoubleLongRightArrow: '\u27F9',
	DoubleRightArrow: '\u21D2',
	DoubleRightTee: '\u22A8',
	DoubleUpArrow: '\u21D1',
	DoubleUpDownArrow: '\u21D5',
	DoubleVerticalBar: '\u2225',
	DownArrow: '\u2193',
	Downarrow: '\u21D3',
	downarrow: '\u2193',
	DownArrowBar: '\u2913',
	DownArrowUpArrow: '\u21F5',
	DownBreve: '\u0311',
	downdownarrows: '\u21CA',
	downharpoonleft: '\u21C3',
	downharpoonright: '\u21C2',
	DownLeftRightVector: '\u2950',
	DownLeftTeeVector: '\u295E',
	DownLeftVector: '\u21BD',
	DownLeftVectorBar: '\u2956',
	DownRightTeeVector: '\u295F',
	DownRightVector: '\u21C1',
	DownRightVectorBar: '\u2957',
	DownTee: '\u22A4',
	DownTeeArrow: '\u21A7',
	drbkarow: '\u2910',
	drcorn: '\u231F',
	drcrop: '\u230C',
	Dscr: '\uD835\uDC9F',
	dscr: '\uD835\uDCB9',
	DScy: '\u0405',
	dscy: '\u0455',
	dsol: '\u29F6',
	Dstrok: '\u0110',
	dstrok: '\u0111',
	dtdot: '\u22F1',
	dtri: '\u25BF',
	dtrif: '\u25BE',
	duarr: '\u21F5',
	duhar: '\u296F',
	dwangle: '\u29A6',
	DZcy: '\u040F',
	dzcy: '\u045F',
	dzigrarr: '\u27FF',
	Eacute: '\u00C9',
	eacute: '\u00E9',
	easter: '\u2A6E',
	Ecaron: '\u011A',
	ecaron: '\u011B',
	ecir: '\u2256',
	Ecirc: '\u00CA',
	ecirc: '\u00EA',
	ecolon: '\u2255',
	Ecy: '\u042D',
	ecy: '\u044D',
	eDDot: '\u2A77',
	Edot: '\u0116',
	eDot: '\u2251',
	edot: '\u0117',
	ee: '\u2147',
	efDot: '\u2252',
	Efr: '\uD835\uDD08',
	efr: '\uD835\uDD22',
	eg: '\u2A9A',
	Egrave: '\u00C8',
	egrave: '\u00E8',
	egs: '\u2A96',
	egsdot: '\u2A98',
	el: '\u2A99',
	Element: '\u2208',
	elinters: '\u23E7',
	ell: '\u2113',
	els: '\u2A95',
	elsdot: '\u2A97',
	Emacr: '\u0112',
	emacr: '\u0113',
	empty: '\u2205',
	emptyset: '\u2205',
	EmptySmallSquare: '\u25FB',
	emptyv: '\u2205',
	EmptyVerySmallSquare: '\u25AB',
	emsp: '\u2003',
	emsp13: '\u2004',
	emsp14: '\u2005',
	ENG: '\u014A',
	eng: '\u014B',
	ensp: '\u2002',
	Eogon: '\u0118',
	eogon: '\u0119',
	Eopf: '\uD835\uDD3C',
	eopf: '\uD835\uDD56',
	epar: '\u22D5',
	eparsl: '\u29E3',
	eplus: '\u2A71',
	epsi: '\u03B5',
	Epsilon: '\u0395',
	epsilon: '\u03B5',
	epsiv: '\u03F5',
	eqcirc: '\u2256',
	eqcolon: '\u2255',
	eqsim: '\u2242',
	eqslantgtr: '\u2A96',
	eqslantless: '\u2A95',
	Equal: '\u2A75',
	equals: '\u003D',
	EqualTilde: '\u2242',
	equest: '\u225F',
	Equilibrium: '\u21CC',
	equiv: '\u2261',
	equivDD: '\u2A78',
	eqvparsl: '\u29E5',
	erarr: '\u2971',
	erDot: '\u2253',
	Escr: '\u2130',
	escr: '\u212F',
	esdot: '\u2250',
	Esim: '\u2A73',
	esim: '\u2242',
	Eta: '\u0397',
	eta: '\u03B7',
	ETH: '\u00D0',
	eth: '\u00F0',
	Euml: '\u00CB',
	euml: '\u00EB',
	euro: '\u20AC',
	excl: '\u0021',
	exist: '\u2203',
	Exists: '\u2203',
	expectation: '\u2130',
	ExponentialE: '\u2147',
	exponentiale: '\u2147',
	fallingdotseq: '\u2252',
	Fcy: '\u0424',
	fcy: '\u0444',
	female: '\u2640',
	ffilig: '\uFB03',
	fflig: '\uFB00',
	ffllig: '\uFB04',
	Ffr: '\uD835\uDD09',
	ffr: '\uD835\uDD23',
	filig: '\uFB01',
	FilledSmallSquare: '\u25FC',
	FilledVerySmallSquare: '\u25AA',
	fjlig: '\u0066\u006A',
	flat: '\u266D',
	fllig: '\uFB02',
	fltns: '\u25B1',
	fnof: '\u0192',
	Fopf: '\uD835\uDD3D',
	fopf: '\uD835\uDD57',
	ForAll: '\u2200',
	forall: '\u2200',
	fork: '\u22D4',
	forkv: '\u2AD9',
	Fouriertrf: '\u2131',
	fpartint: '\u2A0D',
	frac12: '\u00BD',
	frac13: '\u2153',
	frac14: '\u00BC',
	frac15: '\u2155',
	frac16: '\u2159',
	frac18: '\u215B',
	frac23: '\u2154',
	frac25: '\u2156',
	frac34: '\u00BE',
	frac35: '\u2157',
	frac38: '\u215C',
	frac45: '\u2158',
	frac56: '\u215A',
	frac58: '\u215D',
	frac78: '\u215E',
	frasl: '\u2044',
	frown: '\u2322',
	Fscr: '\u2131',
	fscr: '\uD835\uDCBB',
	gacute: '\u01F5',
	Gamma: '\u0393',
	gamma: '\u03B3',
	Gammad: '\u03DC',
	gammad: '\u03DD',
	gap: '\u2A86',
	Gbreve: '\u011E',
	gbreve: '\u011F',
	Gcedil: '\u0122',
	Gcirc: '\u011C',
	gcirc: '\u011D',
	Gcy: '\u0413',
	gcy: '\u0433',
	Gdot: '\u0120',
	gdot: '\u0121',
	gE: '\u2267',
	ge: '\u2265',
	gEl: '\u2A8C',
	gel: '\u22DB',
	geq: '\u2265',
	geqq: '\u2267',
	geqslant: '\u2A7E',
	ges: '\u2A7E',
	gescc: '\u2AA9',
	gesdot: '\u2A80',
	gesdoto: '\u2A82',
	gesdotol: '\u2A84',
	gesl: '\u22DB\uFE00',
	gesles: '\u2A94',
	Gfr: '\uD835\uDD0A',
	gfr: '\uD835\uDD24',
	Gg: '\u22D9',
	gg: '\u226B',
	ggg: '\u22D9',
	gimel: '\u2137',
	GJcy: '\u0403',
	gjcy: '\u0453',
	gl: '\u2277',
	gla: '\u2AA5',
	glE: '\u2A92',
	glj: '\u2AA4',
	gnap: '\u2A8A',
	gnapprox: '\u2A8A',
	gnE: '\u2269',
	gne: '\u2A88',
	gneq: '\u2A88',
	gneqq: '\u2269',
	gnsim: '\u22E7',
	Gopf: '\uD835\uDD3E',
	gopf: '\uD835\uDD58',
	grave: '\u0060',
	GreaterEqual: '\u2265',
	GreaterEqualLess: '\u22DB',
	GreaterFullEqual: '\u2267',
	GreaterGreater: '\u2AA2',
	GreaterLess: '\u2277',
	GreaterSlantEqual: '\u2A7E',
	GreaterTilde: '\u2273',
	Gscr: '\uD835\uDCA2',
	gscr: '\u210A',
	gsim: '\u2273',
	gsime: '\u2A8E',
	gsiml: '\u2A90',
	Gt: '\u226B',
	GT: '\u003E',
	gt: '\u003E',
	gtcc: '\u2AA7',
	gtcir: '\u2A7A',
	gtdot: '\u22D7',
	gtlPar: '\u2995',
	gtquest: '\u2A7C',
	gtrapprox: '\u2A86',
	gtrarr: '\u2978',
	gtrdot: '\u22D7',
	gtreqless: '\u22DB',
	gtreqqless: '\u2A8C',
	gtrless: '\u2277',
	gtrsim: '\u2273',
	gvertneqq: '\u2269\uFE00',
	gvnE: '\u2269\uFE00',
	Hacek: '\u02C7',
	hairsp: '\u200A',
	half: '\u00BD',
	hamilt: '\u210B',
	HARDcy: '\u042A',
	hardcy: '\u044A',
	hArr: '\u21D4',
	harr: '\u2194',
	harrcir: '\u2948',
	harrw: '\u21AD',
	Hat: '\u005E',
	hbar: '\u210F',
	Hcirc: '\u0124',
	hcirc: '\u0125',
	hearts: '\u2665',
	heartsuit: '\u2665',
	hellip: '\u2026',
	hercon: '\u22B9',
	Hfr: '\u210C',
	hfr: '\uD835\uDD25',
	HilbertSpace: '\u210B',
	hksearow: '\u2925',
	hkswarow: '\u2926',
	hoarr: '\u21FF',
	homtht: '\u223B',
	hookleftarrow: '\u21A9',
	hookrightarrow: '\u21AA',
	Hopf: '\u210D',
	hopf: '\uD835\uDD59',
	horbar: '\u2015',
	HorizontalLine: '\u2500',
	Hscr: '\u210B',
	hscr: '\uD835\uDCBD',
	hslash: '\u210F',
	Hstrok: '\u0126',
	hstrok: '\u0127',
	HumpDownHump: '\u224E',
	HumpEqual: '\u224F',
	hybull: '\u2043',
	hyphen: '\u2010',
	Iacute: '\u00CD',
	iacute: '\u00ED',
	ic: '\u2063',
	Icirc: '\u00CE',
	icirc: '\u00EE',
	Icy: '\u0418',
	icy: '\u0438',
	Idot: '\u0130',
	IEcy: '\u0415',
	iecy: '\u0435',
	iexcl: '\u00A1',
	iff: '\u21D4',
	Ifr: '\u2111',
	ifr: '\uD835\uDD26',
	Igrave: '\u00CC',
	igrave: '\u00EC',
	ii: '\u2148',
	iiiint: '\u2A0C',
	iiint: '\u222D',
	iinfin: '\u29DC',
	iiota: '\u2129',
	IJlig: '\u0132',
	ijlig: '\u0133',
	Im: '\u2111',
	Imacr: '\u012A',
	imacr: '\u012B',
	image: '\u2111',
	ImaginaryI: '\u2148',
	imagline: '\u2110',
	imagpart: '\u2111',
	imath: '\u0131',
	imof: '\u22B7',
	imped: '\u01B5',
	Implies: '\u21D2',
	in: '\u2208',
	incare: '\u2105',
	infin: '\u221E',
	infintie: '\u29DD',
	inodot: '\u0131',
	Int: '\u222C',
	int: '\u222B',
	intcal: '\u22BA',
	integers: '\u2124',
	Integral: '\u222B',
	intercal: '\u22BA',
	Intersection: '\u22C2',
	intlarhk: '\u2A17',
	intprod: '\u2A3C',
	InvisibleComma: '\u2063',
	InvisibleTimes: '\u2062',
	IOcy: '\u0401',
	iocy: '\u0451',
	Iogon: '\u012E',
	iogon: '\u012F',
	Iopf: '\uD835\uDD40',
	iopf: '\uD835\uDD5A',
	Iota: '\u0399',
	iota: '\u03B9',
	iprod: '\u2A3C',
	iquest: '\u00BF',
	Iscr: '\u2110',
	iscr: '\uD835\uDCBE',
	isin: '\u2208',
	isindot: '\u22F5',
	isinE: '\u22F9',
	isins: '\u22F4',
	isinsv: '\u22F3',
	isinv: '\u2208',
	it: '\u2062',
	Itilde: '\u0128',
	itilde: '\u0129',
	Iukcy: '\u0406',
	iukcy: '\u0456',
	Iuml: '\u00CF',
	iuml: '\u00EF',
	Jcirc: '\u0134',
	jcirc: '\u0135',
	Jcy: '\u0419',
	jcy: '\u0439',
	Jfr: '\uD835\uDD0D',
	jfr: '\uD835\uDD27',
	jmath: '\u0237',
	Jopf: '\uD835\uDD41',
	jopf: '\uD835\uDD5B',
	Jscr: '\uD835\uDCA5',
	jscr: '\uD835\uDCBF',
	Jsercy: '\u0408',
	jsercy: '\u0458',
	Jukcy: '\u0404',
	jukcy: '\u0454',
	Kappa: '\u039A',
	kappa: '\u03BA',
	kappav: '\u03F0',
	Kcedil: '\u0136',
	kcedil: '\u0137',
	Kcy: '\u041A',
	kcy: '\u043A',
	Kfr: '\uD835\uDD0E',
	kfr: '\uD835\uDD28',
	kgreen: '\u0138',
	KHcy: '\u0425',
	khcy: '\u0445',
	KJcy: '\u040C',
	kjcy: '\u045C',
	Kopf: '\uD835\uDD42',
	kopf: '\uD835\uDD5C',
	Kscr: '\uD835\uDCA6',
	kscr: '\uD835\uDCC0',
	lAarr: '\u21DA',
	Lacute: '\u0139',
	lacute: '\u013A',
	laemptyv: '\u29B4',
	lagran: '\u2112',
	Lambda: '\u039B',
	lambda: '\u03BB',
	Lang: '\u27EA',
	lang: '\u27E8',
	langd: '\u2991',
	langle: '\u27E8',
	lap: '\u2A85',
	Laplacetrf: '\u2112',
	laquo: '\u00AB',
	Larr: '\u219E',
	lArr: '\u21D0',
	larr: '\u2190',
	larrb: '\u21E4',
	larrbfs: '\u291F',
	larrfs: '\u291D',
	larrhk: '\u21A9',
	larrlp: '\u21AB',
	larrpl: '\u2939',
	larrsim: '\u2973',
	larrtl: '\u21A2',
	lat: '\u2AAB',
	lAtail: '\u291B',
	latail: '\u2919',
	late: '\u2AAD',
	lates: '\u2AAD\uFE00',
	lBarr: '\u290E',
	lbarr: '\u290C',
	lbbrk: '\u2772',
	lbrace: '\u007B',
	lbrack: '\u005B',
	lbrke: '\u298B',
	lbrksld: '\u298F',
	lbrkslu: '\u298D',
	Lcaron: '\u013D',
	lcaron: '\u013E',
	Lcedil: '\u013B',
	lcedil: '\u013C',
	lceil: '\u2308',
	lcub: '\u007B',
	Lcy: '\u041B',
	lcy: '\u043B',
	ldca: '\u2936',
	ldquo: '\u201C',
	ldquor: '\u201E',
	ldrdhar: '\u2967',
	ldrushar: '\u294B',
	ldsh: '\u21B2',
	lE: '\u2266',
	le: '\u2264',
	LeftAngleBracket: '\u27E8',
	LeftArrow: '\u2190',
	Leftarrow: '\u21D0',
	leftarrow: '\u2190',
	LeftArrowBar: '\u21E4',
	LeftArrowRightArrow: '\u21C6',
	leftarrowtail: '\u21A2',
	LeftCeiling: '\u2308',
	LeftDoubleBracket: '\u27E6',
	LeftDownTeeVector: '\u2961',
	LeftDownVector: '\u21C3',
	LeftDownVectorBar: '\u2959',
	LeftFloor: '\u230A',
	leftharpoondown: '\u21BD',
	leftharpoonup: '\u21BC',
	leftleftarrows: '\u21C7',
	LeftRightArrow: '\u2194',
	Leftrightarrow: '\u21D4',
	leftrightarrow: '\u2194',
	leftrightarrows: '\u21C6',
	leftrightharpoons: '\u21CB',
	leftrightsquigarrow: '\u21AD',
	LeftRightVector: '\u294E',
	LeftTee: '\u22A3',
	LeftTeeArrow: '\u21A4',
	LeftTeeVector: '\u295A',
	leftthreetimes: '\u22CB',
	LeftTriangle: '\u22B2',
	LeftTriangleBar: '\u29CF',
	LeftTriangleEqual: '\u22B4',
	LeftUpDownVector: '\u2951',
	LeftUpTeeVector: '\u2960',
	LeftUpVector: '\u21BF',
	LeftUpVectorBar: '\u2958',
	LeftVector: '\u21BC',
	LeftVectorBar: '\u2952',
	lEg: '\u2A8B',
	leg: '\u22DA',
	leq: '\u2264',
	leqq: '\u2266',
	leqslant: '\u2A7D',
	les: '\u2A7D',
	lescc: '\u2AA8',
	lesdot: '\u2A7F',
	lesdoto: '\u2A81',
	lesdotor: '\u2A83',
	lesg: '\u22DA\uFE00',
	lesges: '\u2A93',
	lessapprox: '\u2A85',
	lessdot: '\u22D6',
	lesseqgtr: '\u22DA',
	lesseqqgtr: '\u2A8B',
	LessEqualGreater: '\u22DA',
	LessFullEqual: '\u2266',
	LessGreater: '\u2276',
	lessgtr: '\u2276',
	LessLess: '\u2AA1',
	lesssim: '\u2272',
	LessSlantEqual: '\u2A7D',
	LessTilde: '\u2272',
	lfisht: '\u297C',
	lfloor: '\u230A',
	Lfr: '\uD835\uDD0F',
	lfr: '\uD835\uDD29',
	lg: '\u2276',
	lgE: '\u2A91',
	lHar: '\u2962',
	lhard: '\u21BD',
	lharu: '\u21BC',
	lharul: '\u296A',
	lhblk: '\u2584',
	LJcy: '\u0409',
	ljcy: '\u0459',
	Ll: '\u22D8',
	ll: '\u226A',
	llarr: '\u21C7',
	llcorner: '\u231E',
	Lleftarrow: '\u21DA',
	llhard: '\u296B',
	lltri: '\u25FA',
	Lmidot: '\u013F',
	lmidot: '\u0140',
	lmoust: '\u23B0',
	lmoustache: '\u23B0',
	lnap: '\u2A89',
	lnapprox: '\u2A89',
	lnE: '\u2268',
	lne: '\u2A87',
	lneq: '\u2A87',
	lneqq: '\u2268',
	lnsim: '\u22E6',
	loang: '\u27EC',
	loarr: '\u21FD',
	lobrk: '\u27E6',
	LongLeftArrow: '\u27F5',
	Longleftarrow: '\u27F8',
	longleftarrow: '\u27F5',
	LongLeftRightArrow: '\u27F7',
	Longleftrightarrow: '\u27FA',
	longleftrightarrow: '\u27F7',
	longmapsto: '\u27FC',
	LongRightArrow: '\u27F6',
	Longrightarrow: '\u27F9',
	longrightarrow: '\u27F6',
	looparrowleft: '\u21AB',
	looparrowright: '\u21AC',
	lopar: '\u2985',
	Lopf: '\uD835\uDD43',
	lopf: '\uD835\uDD5D',
	loplus: '\u2A2D',
	lotimes: '\u2A34',
	lowast: '\u2217',
	lowbar: '\u005F',
	LowerLeftArrow: '\u2199',
	LowerRightArrow: '\u2198',
	loz: '\u25CA',
	lozenge: '\u25CA',
	lozf: '\u29EB',
	lpar: '\u0028',
	lparlt: '\u2993',
	lrarr: '\u21C6',
	lrcorner: '\u231F',
	lrhar: '\u21CB',
	lrhard: '\u296D',
	lrm: '\u200E',
	lrtri: '\u22BF',
	lsaquo: '\u2039',
	Lscr: '\u2112',
	lscr: '\uD835\uDCC1',
	Lsh: '\u21B0',
	lsh: '\u21B0',
	lsim: '\u2272',
	lsime: '\u2A8D',
	lsimg: '\u2A8F',
	lsqb: '\u005B',
	lsquo: '\u2018',
	lsquor: '\u201A',
	Lstrok: '\u0141',
	lstrok: '\u0142',
	Lt: '\u226A',
	LT: '\u003C',
	lt: '\u003C',
	ltcc: '\u2AA6',
	ltcir: '\u2A79',
	ltdot: '\u22D6',
	lthree: '\u22CB',
	ltimes: '\u22C9',
	ltlarr: '\u2976',
	ltquest: '\u2A7B',
	ltri: '\u25C3',
	ltrie: '\u22B4',
	ltrif: '\u25C2',
	ltrPar: '\u2996',
	lurdshar: '\u294A',
	luruhar: '\u2966',
	lvertneqq: '\u2268\uFE00',
	lvnE: '\u2268\uFE00',
	macr: '\u00AF',
	male: '\u2642',
	malt: '\u2720',
	maltese: '\u2720',
	Map: '\u2905',
	map: '\u21A6',
	mapsto: '\u21A6',
	mapstodown: '\u21A7',
	mapstoleft: '\u21A4',
	mapstoup: '\u21A5',
	marker: '\u25AE',
	mcomma: '\u2A29',
	Mcy: '\u041C',
	mcy: '\u043C',
	mdash: '\u2014',
	mDDot: '\u223A',
	measuredangle: '\u2221',
	MediumSpace: '\u205F',
	Mellintrf: '\u2133',
	Mfr: '\uD835\uDD10',
	mfr: '\uD835\uDD2A',
	mho: '\u2127',
	micro: '\u00B5',
	mid: '\u2223',
	midast: '\u002A',
	midcir: '\u2AF0',
	middot: '\u00B7',
	minus: '\u2212',
	minusb: '\u229F',
	minusd: '\u2238',
	minusdu: '\u2A2A',
	MinusPlus: '\u2213',
	mlcp: '\u2ADB',
	mldr: '\u2026',
	mnplus: '\u2213',
	models: '\u22A7',
	Mopf: '\uD835\uDD44',
	mopf: '\uD835\uDD5E',
	mp: '\u2213',
	Mscr: '\u2133',
	mscr: '\uD835\uDCC2',
	mstpos: '\u223E',
	Mu: '\u039C',
	mu: '\u03BC',
	multimap: '\u22B8',
	mumap: '\u22B8',
	nabla: '\u2207',
	Nacute: '\u0143',
	nacute: '\u0144',
	nang: '\u2220\u20D2',
	nap: '\u2249',
	napE: '\u2A70\u0338',
	napid: '\u224B\u0338',
	napos: '\u0149',
	napprox: '\u2249',
	natur: '\u266E',
	natural: '\u266E',
	naturals: '\u2115',
	nbsp: '\u00A0',
	nbump: '\u224E\u0338',
	nbumpe: '\u224F\u0338',
	ncap: '\u2A43',
	Ncaron: '\u0147',
	ncaron: '\u0148',
	Ncedil: '\u0145',
	ncedil: '\u0146',
	ncong: '\u2247',
	ncongdot: '\u2A6D\u0338',
	ncup: '\u2A42',
	Ncy: '\u041D',
	ncy: '\u043D',
	ndash: '\u2013',
	ne: '\u2260',
	nearhk: '\u2924',
	neArr: '\u21D7',
	nearr: '\u2197',
	nearrow: '\u2197',
	nedot: '\u2250\u0338',
	NegativeMediumSpace: '\u200B',
	NegativeThickSpace: '\u200B',
	NegativeThinSpace: '\u200B',
	NegativeVeryThinSpace: '\u200B',
	nequiv: '\u2262',
	nesear: '\u2928',
	nesim: '\u2242\u0338',
	NestedGreaterGreater: '\u226B',
	NestedLessLess: '\u226A',
	NewLine: '\u000A',
	nexist: '\u2204',
	nexists: '\u2204',
	Nfr: '\uD835\uDD11',
	nfr: '\uD835\uDD2B',
	ngE: '\u2267\u0338',
	nge: '\u2271',
	ngeq: '\u2271',
	ngeqq: '\u2267\u0338',
	ngeqslant: '\u2A7E\u0338',
	nges: '\u2A7E\u0338',
	nGg: '\u22D9\u0338',
	ngsim: '\u2275',
	nGt: '\u226B\u20D2',
	ngt: '\u226F',
	ngtr: '\u226F',
	nGtv: '\u226B\u0338',
	nhArr: '\u21CE',
	nharr: '\u21AE',
	nhpar: '\u2AF2',
	ni: '\u220B',
	nis: '\u22FC',
	nisd: '\u22FA',
	niv: '\u220B',
	NJcy: '\u040A',
	njcy: '\u045A',
	nlArr: '\u21CD',
	nlarr: '\u219A',
	nldr: '\u2025',
	nlE: '\u2266\u0338',
	nle: '\u2270',
	nLeftarrow: '\u21CD',
	nleftarrow: '\u219A',
	nLeftrightarrow: '\u21CE',
	nleftrightarrow: '\u21AE',
	nleq: '\u2270',
	nleqq: '\u2266\u0338',
	nleqslant: '\u2A7D\u0338',
	nles: '\u2A7D\u0338',
	nless: '\u226E',
	nLl: '\u22D8\u0338',
	nlsim: '\u2274',
	nLt: '\u226A\u20D2',
	nlt: '\u226E',
	nltri: '\u22EA',
	nltrie: '\u22EC',
	nLtv: '\u226A\u0338',
	nmid: '\u2224',
	NoBreak: '\u2060',
	NonBreakingSpace: '\u00A0',
	Nopf: '\u2115',
	nopf: '\uD835\uDD5F',
	Not: '\u2AEC',
	not: '\u00AC',
	NotCongruent: '\u2262',
	NotCupCap: '\u226D',
	NotDoubleVerticalBar: '\u2226',
	NotElement: '\u2209',
	NotEqual: '\u2260',
	NotEqualTilde: '\u2242\u0338',
	NotExists: '\u2204',
	NotGreater: '\u226F',
	NotGreaterEqual: '\u2271',
	NotGreaterFullEqual: '\u2267\u0338',
	NotGreaterGreater: '\u226B\u0338',
	NotGreaterLess: '\u2279',
	NotGreaterSlantEqual: '\u2A7E\u0338',
	NotGreaterTilde: '\u2275',
	NotHumpDownHump: '\u224E\u0338',
	NotHumpEqual: '\u224F\u0338',
	notin: '\u2209',
	notindot: '\u22F5\u0338',
	notinE: '\u22F9\u0338',
	notinva: '\u2209',
	notinvb: '\u22F7',
	notinvc: '\u22F6',
	NotLeftTriangle: '\u22EA',
	NotLeftTriangleBar: '\u29CF\u0338',
	NotLeftTriangleEqual: '\u22EC',
	NotLess: '\u226E',
	NotLessEqual: '\u2270',
	NotLessGreater: '\u2278',
	NotLessLess: '\u226A\u0338',
	NotLessSlantEqual: '\u2A7D\u0338',
	NotLessTilde: '\u2274',
	NotNestedGreaterGreater: '\u2AA2\u0338',
	NotNestedLessLess: '\u2AA1\u0338',
	notni: '\u220C',
	notniva: '\u220C',
	notnivb: '\u22FE',
	notnivc: '\u22FD',
	NotPrecedes: '\u2280',
	NotPrecedesEqual: '\u2AAF\u0338',
	NotPrecedesSlantEqual: '\u22E0',
	NotReverseElement: '\u220C',
	NotRightTriangle: '\u22EB',
	NotRightTriangleBar: '\u29D0\u0338',
	NotRightTriangleEqual: '\u22ED',
	NotSquareSubset: '\u228F\u0338',
	NotSquareSubsetEqual: '\u22E2',
	NotSquareSuperset: '\u2290\u0338',
	NotSquareSupersetEqual: '\u22E3',
	NotSubset: '\u2282\u20D2',
	NotSubsetEqual: '\u2288',
	NotSucceeds: '\u2281',
	NotSucceedsEqual: '\u2AB0\u0338',
	NotSucceedsSlantEqual: '\u22E1',
	NotSucceedsTilde: '\u227F\u0338',
	NotSuperset: '\u2283\u20D2',
	NotSupersetEqual: '\u2289',
	NotTilde: '\u2241',
	NotTildeEqual: '\u2244',
	NotTildeFullEqual: '\u2247',
	NotTildeTilde: '\u2249',
	NotVerticalBar: '\u2224',
	npar: '\u2226',
	nparallel: '\u2226',
	nparsl: '\u2AFD\u20E5',
	npart: '\u2202\u0338',
	npolint: '\u2A14',
	npr: '\u2280',
	nprcue: '\u22E0',
	npre: '\u2AAF\u0338',
	nprec: '\u2280',
	npreceq: '\u2AAF\u0338',
	nrArr: '\u21CF',
	nrarr: '\u219B',
	nrarrc: '\u2933\u0338',
	nrarrw: '\u219D\u0338',
	nRightarrow: '\u21CF',
	nrightarrow: '\u219B',
	nrtri: '\u22EB',
	nrtrie: '\u22ED',
	nsc: '\u2281',
	nsccue: '\u22E1',
	nsce: '\u2AB0\u0338',
	Nscr: '\uD835\uDCA9',
	nscr: '\uD835\uDCC3',
	nshortmid: '\u2224',
	nshortparallel: '\u2226',
	nsim: '\u2241',
	nsime: '\u2244',
	nsimeq: '\u2244',
	nsmid: '\u2224',
	nspar: '\u2226',
	nsqsube: '\u22E2',
	nsqsupe: '\u22E3',
	nsub: '\u2284',
	nsubE: '\u2AC5\u0338',
	nsube: '\u2288',
	nsubset: '\u2282\u20D2',
	nsubseteq: '\u2288',
	nsubseteqq: '\u2AC5\u0338',
	nsucc: '\u2281',
	nsucceq: '\u2AB0\u0338',
	nsup: '\u2285',
	nsupE: '\u2AC6\u0338',
	nsupe: '\u2289',
	nsupset: '\u2283\u20D2',
	nsupseteq: '\u2289',
	nsupseteqq: '\u2AC6\u0338',
	ntgl: '\u2279',
	Ntilde: '\u00D1',
	ntilde: '\u00F1',
	ntlg: '\u2278',
	ntriangleleft: '\u22EA',
	ntrianglelefteq: '\u22EC',
	ntriangleright: '\u22EB',
	ntrianglerighteq: '\u22ED',
	Nu: '\u039D',
	nu: '\u03BD',
	num: '\u0023',
	numero: '\u2116',
	numsp: '\u2007',
	nvap: '\u224D\u20D2',
	nVDash: '\u22AF',
	nVdash: '\u22AE',
	nvDash: '\u22AD',
	nvdash: '\u22AC',
	nvge: '\u2265\u20D2',
	nvgt: '\u003E\u20D2',
	nvHarr: '\u2904',
	nvinfin: '\u29DE',
	nvlArr: '\u2902',
	nvle: '\u2264\u20D2',
	nvlt: '\u003C\u20D2',
	nvltrie: '\u22B4\u20D2',
	nvrArr: '\u2903',
	nvrtrie: '\u22B5\u20D2',
	nvsim: '\u223C\u20D2',
	nwarhk: '\u2923',
	nwArr: '\u21D6',
	nwarr: '\u2196',
	nwarrow: '\u2196',
	nwnear: '\u2927',
	Oacute: '\u00D3',
	oacute: '\u00F3',
	oast: '\u229B',
	ocir: '\u229A',
	Ocirc: '\u00D4',
	ocirc: '\u00F4',
	Ocy: '\u041E',
	ocy: '\u043E',
	odash: '\u229D',
	Odblac: '\u0150',
	odblac: '\u0151',
	odiv: '\u2A38',
	odot: '\u2299',
	odsold: '\u29BC',
	OElig: '\u0152',
	oelig: '\u0153',
	ofcir: '\u29BF',
	Ofr: '\uD835\uDD12',
	ofr: '\uD835\uDD2C',
	ogon: '\u02DB',
	Ograve: '\u00D2',
	ograve: '\u00F2',
	ogt: '\u29C1',
	ohbar: '\u29B5',
	ohm: '\u03A9',
	oint: '\u222E',
	olarr: '\u21BA',
	olcir: '\u29BE',
	olcross: '\u29BB',
	oline: '\u203E',
	olt: '\u29C0',
	Omacr: '\u014C',
	omacr: '\u014D',
	Omega: '\u03A9',
	omega: '\u03C9',
	Omicron: '\u039F',
	omicron: '\u03BF',
	omid: '\u29B6',
	ominus: '\u2296',
	Oopf: '\uD835\uDD46',
	oopf: '\uD835\uDD60',
	opar: '\u29B7',
	OpenCurlyDoubleQuote: '\u201C',
	OpenCurlyQuote: '\u2018',
	operp: '\u29B9',
	oplus: '\u2295',
	Or: '\u2A54',
	or: '\u2228',
	orarr: '\u21BB',
	ord: '\u2A5D',
	order: '\u2134',
	orderof: '\u2134',
	ordf: '\u00AA',
	ordm: '\u00BA',
	origof: '\u22B6',
	oror: '\u2A56',
	orslope: '\u2A57',
	orv: '\u2A5B',
	oS: '\u24C8',
	Oscr: '\uD835\uDCAA',
	oscr: '\u2134',
	Oslash: '\u00D8',
	oslash: '\u00F8',
	osol: '\u2298',
	Otilde: '\u00D5',
	otilde: '\u00F5',
	Otimes: '\u2A37',
	otimes: '\u2297',
	otimesas: '\u2A36',
	Ouml: '\u00D6',
	ouml: '\u00F6',
	ovbar: '\u233D',
	OverBar: '\u203E',
	OverBrace: '\u23DE',
	OverBracket: '\u23B4',
	OverParenthesis: '\u23DC',
	par: '\u2225',
	para: '\u00B6',
	parallel: '\u2225',
	parsim: '\u2AF3',
	parsl: '\u2AFD',
	part: '\u2202',
	PartialD: '\u2202',
	Pcy: '\u041F',
	pcy: '\u043F',
	percnt: '\u0025',
	period: '\u002E',
	permil: '\u2030',
	perp: '\u22A5',
	pertenk: '\u2031',
	Pfr: '\uD835\uDD13',
	pfr: '\uD835\uDD2D',
	Phi: '\u03A6',
	phi: '\u03C6',
	phiv: '\u03D5',
	phmmat: '\u2133',
	phone: '\u260E',
	Pi: '\u03A0',
	pi: '\u03C0',
	pitchfork: '\u22D4',
	piv: '\u03D6',
	planck: '\u210F',
	planckh: '\u210E',
	plankv: '\u210F',
	plus: '\u002B',
	plusacir: '\u2A23',
	plusb: '\u229E',
	pluscir: '\u2A22',
	plusdo: '\u2214',
	plusdu: '\u2A25',
	pluse: '\u2A72',
	PlusMinus: '\u00B1',
	plusmn: '\u00B1',
	plussim: '\u2A26',
	plustwo: '\u2A27',
	pm: '\u00B1',
	Poincareplane: '\u210C',
	pointint: '\u2A15',
	Popf: '\u2119',
	popf: '\uD835\uDD61',
	pound: '\u00A3',
	Pr: '\u2ABB',
	pr: '\u227A',
	prap: '\u2AB7',
	prcue: '\u227C',
	prE: '\u2AB3',
	pre: '\u2AAF',
	prec: '\u227A',
	precapprox: '\u2AB7',
	preccurlyeq: '\u227C',
	Precedes: '\u227A',
	PrecedesEqual: '\u2AAF',
	PrecedesSlantEqual: '\u227C',
	PrecedesTilde: '\u227E',
	preceq: '\u2AAF',
	precnapprox: '\u2AB9',
	precneqq: '\u2AB5',
	precnsim: '\u22E8',
	precsim: '\u227E',
	Prime: '\u2033',
	prime: '\u2032',
	primes: '\u2119',
	prnap: '\u2AB9',
	prnE: '\u2AB5',
	prnsim: '\u22E8',
	prod: '\u220F',
	Product: '\u220F',
	profalar: '\u232E',
	profline: '\u2312',
	profsurf: '\u2313',
	prop: '\u221D',
	Proportion: '\u2237',
	Proportional: '\u221D',
	propto: '\u221D',
	prsim: '\u227E',
	prurel: '\u22B0',
	Pscr: '\uD835\uDCAB',
	pscr: '\uD835\uDCC5',
	Psi: '\u03A8',
	psi: '\u03C8',
	puncsp: '\u2008',
	Qfr: '\uD835\uDD14',
	qfr: '\uD835\uDD2E',
	qint: '\u2A0C',
	Qopf: '\u211A',
	qopf: '\uD835\uDD62',
	qprime: '\u2057',
	Qscr: '\uD835\uDCAC',
	qscr: '\uD835\uDCC6',
	quaternions: '\u210D',
	quatint: '\u2A16',
	quest: '\u003F',
	questeq: '\u225F',
	QUOT: '\u0022',
	quot: '\u0022',
	rAarr: '\u21DB',
	race: '\u223D\u0331',
	Racute: '\u0154',
	racute: '\u0155',
	radic: '\u221A',
	raemptyv: '\u29B3',
	Rang: '\u27EB',
	rang: '\u27E9',
	rangd: '\u2992',
	range: '\u29A5',
	rangle: '\u27E9',
	raquo: '\u00BB',
	Rarr: '\u21A0',
	rArr: '\u21D2',
	rarr: '\u2192',
	rarrap: '\u2975',
	rarrb: '\u21E5',
	rarrbfs: '\u2920',
	rarrc: '\u2933',
	rarrfs: '\u291E',
	rarrhk: '\u21AA',
	rarrlp: '\u21AC',
	rarrpl: '\u2945',
	rarrsim: '\u2974',
	Rarrtl: '\u2916',
	rarrtl: '\u21A3',
	rarrw: '\u219D',
	rAtail: '\u291C',
	ratail: '\u291A',
	ratio: '\u2236',
	rationals: '\u211A',
	RBarr: '\u2910',
	rBarr: '\u290F',
	rbarr: '\u290D',
	rbbrk: '\u2773',
	rbrace: '\u007D',
	rbrack: '\u005D',
	rbrke: '\u298C',
	rbrksld: '\u298E',
	rbrkslu: '\u2990',
	Rcaron: '\u0158',
	rcaron: '\u0159',
	Rcedil: '\u0156',
	rcedil: '\u0157',
	rceil: '\u2309',
	rcub: '\u007D',
	Rcy: '\u0420',
	rcy: '\u0440',
	rdca: '\u2937',
	rdldhar: '\u2969',
	rdquo: '\u201D',
	rdquor: '\u201D',
	rdsh: '\u21B3',
	Re: '\u211C',
	real: '\u211C',
	realine: '\u211B',
	realpart: '\u211C',
	reals: '\u211D',
	rect: '\u25AD',
	REG: '\u00AE',
	reg: '\u00AE',
	ReverseElement: '\u220B',
	ReverseEquilibrium: '\u21CB',
	ReverseUpEquilibrium: '\u296F',
	rfisht: '\u297D',
	rfloor: '\u230B',
	Rfr: '\u211C',
	rfr: '\uD835\uDD2F',
	rHar: '\u2964',
	rhard: '\u21C1',
	rharu: '\u21C0',
	rharul: '\u296C',
	Rho: '\u03A1',
	rho: '\u03C1',
	rhov: '\u03F1',
	RightAngleBracket: '\u27E9',
	RightArrow: '\u2192',
	Rightarrow: '\u21D2',
	rightarrow: '\u2192',
	RightArrowBar: '\u21E5',
	RightArrowLeftArrow: '\u21C4',
	rightarrowtail: '\u21A3',
	RightCeiling: '\u2309',
	RightDoubleBracket: '\u27E7',
	RightDownTeeVector: '\u295D',
	RightDownVector: '\u21C2',
	RightDownVectorBar: '\u2955',
	RightFloor: '\u230B',
	rightharpoondown: '\u21C1',
	rightharpoonup: '\u21C0',
	rightleftarrows: '\u21C4',
	rightleftharpoons: '\u21CC',
	rightrightarrows: '\u21C9',
	rightsquigarrow: '\u219D',
	RightTee: '\u22A2',
	RightTeeArrow: '\u21A6',
	RightTeeVector: '\u295B',
	rightthreetimes: '\u22CC',
	RightTriangle: '\u22B3',
	RightTriangleBar: '\u29D0',
	RightTriangleEqual: '\u22B5',
	RightUpDownVector: '\u294F',
	RightUpTeeVector: '\u295C',
	RightUpVector: '\u21BE',
	RightUpVectorBar: '\u2954',
	RightVector: '\u21C0',
	RightVectorBar: '\u2953',
	ring: '\u02DA',
	risingdotseq: '\u2253',
	rlarr: '\u21C4',
	rlhar: '\u21CC',
	rlm: '\u200F',
	rmoust: '\u23B1',
	rmoustache: '\u23B1',
	rnmid: '\u2AEE',
	roang: '\u27ED',
	roarr: '\u21FE',
	robrk: '\u27E7',
	ropar: '\u2986',
	Ropf: '\u211D',
	ropf: '\uD835\uDD63',
	roplus: '\u2A2E',
	rotimes: '\u2A35',
	RoundImplies: '\u2970',
	rpar: '\u0029',
	rpargt: '\u2994',
	rppolint: '\u2A12',
	rrarr: '\u21C9',
	Rrightarrow: '\u21DB',
	rsaquo: '\u203A',
	Rscr: '\u211B',
	rscr: '\uD835\uDCC7',
	Rsh: '\u21B1',
	rsh: '\u21B1',
	rsqb: '\u005D',
	rsquo: '\u2019',
	rsquor: '\u2019',
	rthree: '\u22CC',
	rtimes: '\u22CA',
	rtri: '\u25B9',
	rtrie: '\u22B5',
	rtrif: '\u25B8',
	rtriltri: '\u29CE',
	RuleDelayed: '\u29F4',
	ruluhar: '\u2968',
	rx: '\u211E',
	Sacute: '\u015A',
	sacute: '\u015B',
	sbquo: '\u201A',
	Sc: '\u2ABC',
	sc: '\u227B',
	scap: '\u2AB8',
	Scaron: '\u0160',
	scaron: '\u0161',
	sccue: '\u227D',
	scE: '\u2AB4',
	sce: '\u2AB0',
	Scedil: '\u015E',
	scedil: '\u015F',
	Scirc: '\u015C',
	scirc: '\u015D',
	scnap: '\u2ABA',
	scnE: '\u2AB6',
	scnsim: '\u22E9',
	scpolint: '\u2A13',
	scsim: '\u227F',
	Scy: '\u0421',
	scy: '\u0441',
	sdot: '\u22C5',
	sdotb: '\u22A1',
	sdote: '\u2A66',
	searhk: '\u2925',
	seArr: '\u21D8',
	searr: '\u2198',
	searrow: '\u2198',
	sect: '\u00A7',
	semi: '\u003B',
	seswar: '\u2929',
	setminus: '\u2216',
	setmn: '\u2216',
	sext: '\u2736',
	Sfr: '\uD835\uDD16',
	sfr: '\uD835\uDD30',
	sfrown: '\u2322',
	sharp: '\u266F',
	SHCHcy: '\u0429',
	shchcy: '\u0449',
	SHcy: '\u0428',
	shcy: '\u0448',
	ShortDownArrow: '\u2193',
	ShortLeftArrow: '\u2190',
	shortmid: '\u2223',
	shortparallel: '\u2225',
	ShortRightArrow: '\u2192',
	ShortUpArrow: '\u2191',
	shy: '\u00AD',
	Sigma: '\u03A3',
	sigma: '\u03C3',
	sigmaf: '\u03C2',
	sigmav: '\u03C2',
	sim: '\u223C',
	simdot: '\u2A6A',
	sime: '\u2243',
	simeq: '\u2243',
	simg: '\u2A9E',
	simgE: '\u2AA0',
	siml: '\u2A9D',
	simlE: '\u2A9F',
	simne: '\u2246',
	simplus: '\u2A24',
	simrarr: '\u2972',
	slarr: '\u2190',
	SmallCircle: '\u2218',
	smallsetminus: '\u2216',
	smashp: '\u2A33',
	smeparsl: '\u29E4',
	smid: '\u2223',
	smile: '\u2323',
	smt: '\u2AAA',
	smte: '\u2AAC',
	smtes: '\u2AAC\uFE00',
	SOFTcy: '\u042C',
	softcy: '\u044C',
	sol: '\u002F',
	solb: '\u29C4',
	solbar: '\u233F',
	Sopf: '\uD835\uDD4A',
	sopf: '\uD835\uDD64',
	spades: '\u2660',
	spadesuit: '\u2660',
	spar: '\u2225',
	sqcap: '\u2293',
	sqcaps: '\u2293\uFE00',
	sqcup: '\u2294',
	sqcups: '\u2294\uFE00',
	Sqrt: '\u221A',
	sqsub: '\u228F',
	sqsube: '\u2291',
	sqsubset: '\u228F',
	sqsubseteq: '\u2291',
	sqsup: '\u2290',
	sqsupe: '\u2292',
	sqsupset: '\u2290',
	sqsupseteq: '\u2292',
	squ: '\u25A1',
	Square: '\u25A1',
	square: '\u25A1',
	SquareIntersection: '\u2293',
	SquareSubset: '\u228F',
	SquareSubsetEqual: '\u2291',
	SquareSuperset: '\u2290',
	SquareSupersetEqual: '\u2292',
	SquareUnion: '\u2294',
	squarf: '\u25AA',
	squf: '\u25AA',
	srarr: '\u2192',
	Sscr: '\uD835\uDCAE',
	sscr: '\uD835\uDCC8',
	ssetmn: '\u2216',
	ssmile: '\u2323',
	sstarf: '\u22C6',
	Star: '\u22C6',
	star: '\u2606',
	starf: '\u2605',
	straightepsilon: '\u03F5',
	straightphi: '\u03D5',
	strns: '\u00AF',
	Sub: '\u22D0',
	sub: '\u2282',
	subdot: '\u2ABD',
	subE: '\u2AC5',
	sube: '\u2286',
	subedot: '\u2AC3',
	submult: '\u2AC1',
	subnE: '\u2ACB',
	subne: '\u228A',
	subplus: '\u2ABF',
	subrarr: '\u2979',
	Subset: '\u22D0',
	subset: '\u2282',
	subseteq: '\u2286',
	subseteqq: '\u2AC5',
	SubsetEqual: '\u2286',
	subsetneq: '\u228A',
	subsetneqq: '\u2ACB',
	subsim: '\u2AC7',
	subsub: '\u2AD5',
	subsup: '\u2AD3',
	succ: '\u227B',
	succapprox: '\u2AB8',
	succcurlyeq: '\u227D',
	Succeeds: '\u227B',
	SucceedsEqual: '\u2AB0',
	SucceedsSlantEqual: '\u227D',
	SucceedsTilde: '\u227F',
	succeq: '\u2AB0',
	succnapprox: '\u2ABA',
	succneqq: '\u2AB6',
	succnsim: '\u22E9',
	succsim: '\u227F',
	SuchThat: '\u220B',
	Sum: '\u2211',
	sum: '\u2211',
	sung: '\u266A',
	Sup: '\u22D1',
	sup: '\u2283',
	sup1: '\u00B9',
	sup2: '\u00B2',
	sup3: '\u00B3',
	supdot: '\u2ABE',
	supdsub: '\u2AD8',
	supE: '\u2AC6',
	supe: '\u2287',
	supedot: '\u2AC4',
	Superset: '\u2283',
	SupersetEqual: '\u2287',
	suphsol: '\u27C9',
	suphsub: '\u2AD7',
	suplarr: '\u297B',
	supmult: '\u2AC2',
	supnE: '\u2ACC',
	supne: '\u228B',
	supplus: '\u2AC0',
	Supset: '\u22D1',
	supset: '\u2283',
	supseteq: '\u2287',
	supseteqq: '\u2AC6',
	supsetneq: '\u228B',
	supsetneqq: '\u2ACC',
	supsim: '\u2AC8',
	supsub: '\u2AD4',
	supsup: '\u2AD6',
	swarhk: '\u2926',
	swArr: '\u21D9',
	swarr: '\u2199',
	swarrow: '\u2199',
	swnwar: '\u292A',
	szlig: '\u00DF',
	Tab: '\u0009',
	target: '\u2316',
	Tau: '\u03A4',
	tau: '\u03C4',
	tbrk: '\u23B4',
	Tcaron: '\u0164',
	tcaron: '\u0165',
	Tcedil: '\u0162',
	tcedil: '\u0163',
	Tcy: '\u0422',
	tcy: '\u0442',
	tdot: '\u20DB',
	telrec: '\u2315',
	Tfr: '\uD835\uDD17',
	tfr: '\uD835\uDD31',
	there4: '\u2234',
	Therefore: '\u2234',
	therefore: '\u2234',
	Theta: '\u0398',
	theta: '\u03B8',
	thetasym: '\u03D1',
	thetav: '\u03D1',
	thickapprox: '\u2248',
	thicksim: '\u223C',
	ThickSpace: '\u205F\u200A',
	thinsp: '\u2009',
	ThinSpace: '\u2009',
	thkap: '\u2248',
	thksim: '\u223C',
	THORN: '\u00DE',
	thorn: '\u00FE',
	Tilde: '\u223C',
	tilde: '\u02DC',
	TildeEqual: '\u2243',
	TildeFullEqual: '\u2245',
	TildeTilde: '\u2248',
	times: '\u00D7',
	timesb: '\u22A0',
	timesbar: '\u2A31',
	timesd: '\u2A30',
	tint: '\u222D',
	toea: '\u2928',
	top: '\u22A4',
	topbot: '\u2336',
	topcir: '\u2AF1',
	Topf: '\uD835\uDD4B',
	topf: '\uD835\uDD65',
	topfork: '\u2ADA',
	tosa: '\u2929',
	tprime: '\u2034',
	TRADE: '\u2122',
	trade: '\u2122',
	triangle: '\u25B5',
	triangledown: '\u25BF',
	triangleleft: '\u25C3',
	trianglelefteq: '\u22B4',
	triangleq: '\u225C',
	triangleright: '\u25B9',
	trianglerighteq: '\u22B5',
	tridot: '\u25EC',
	trie: '\u225C',
	triminus: '\u2A3A',
	TripleDot: '\u20DB',
	triplus: '\u2A39',
	trisb: '\u29CD',
	tritime: '\u2A3B',
	trpezium: '\u23E2',
	Tscr: '\uD835\uDCAF',
	tscr: '\uD835\uDCC9',
	TScy: '\u0426',
	tscy: '\u0446',
	TSHcy: '\u040B',
	tshcy: '\u045B',
	Tstrok: '\u0166',
	tstrok: '\u0167',
	twixt: '\u226C',
	twoheadleftarrow: '\u219E',
	twoheadrightarrow: '\u21A0',
	Uacute: '\u00DA',
	uacute: '\u00FA',
	Uarr: '\u219F',
	uArr: '\u21D1',
	uarr: '\u2191',
	Uarrocir: '\u2949',
	Ubrcy: '\u040E',
	ubrcy: '\u045E',
	Ubreve: '\u016C',
	ubreve: '\u016D',
	Ucirc: '\u00DB',
	ucirc: '\u00FB',
	Ucy: '\u0423',
	ucy: '\u0443',
	udarr: '\u21C5',
	Udblac: '\u0170',
	udblac: '\u0171',
	udhar: '\u296E',
	ufisht: '\u297E',
	Ufr: '\uD835\uDD18',
	ufr: '\uD835\uDD32',
	Ugrave: '\u00D9',
	ugrave: '\u00F9',
	uHar: '\u2963',
	uharl: '\u21BF',
	uharr: '\u21BE',
	uhblk: '\u2580',
	ulcorn: '\u231C',
	ulcorner: '\u231C',
	ulcrop: '\u230F',
	ultri: '\u25F8',
	Umacr: '\u016A',
	umacr: '\u016B',
	uml: '\u00A8',
	UnderBar: '\u005F',
	UnderBrace: '\u23DF',
	UnderBracket: '\u23B5',
	UnderParenthesis: '\u23DD',
	Union: '\u22C3',
	UnionPlus: '\u228E',
	Uogon: '\u0172',
	uogon: '\u0173',
	Uopf: '\uD835\uDD4C',
	uopf: '\uD835\uDD66',
	UpArrow: '\u2191',
	Uparrow: '\u21D1',
	uparrow: '\u2191',
	UpArrowBar: '\u2912',
	UpArrowDownArrow: '\u21C5',
	UpDownArrow: '\u2195',
	Updownarrow: '\u21D5',
	updownarrow: '\u2195',
	UpEquilibrium: '\u296E',
	upharpoonleft: '\u21BF',
	upharpoonright: '\u21BE',
	uplus: '\u228E',
	UpperLeftArrow: '\u2196',
	UpperRightArrow: '\u2197',
	Upsi: '\u03D2',
	upsi: '\u03C5',
	upsih: '\u03D2',
	Upsilon: '\u03A5',
	upsilon: '\u03C5',
	UpTee: '\u22A5',
	UpTeeArrow: '\u21A5',
	upuparrows: '\u21C8',
	urcorn: '\u231D',
	urcorner: '\u231D',
	urcrop: '\u230E',
	Uring: '\u016E',
	uring: '\u016F',
	urtri: '\u25F9',
	Uscr: '\uD835\uDCB0',
	uscr: '\uD835\uDCCA',
	utdot: '\u22F0',
	Utilde: '\u0168',
	utilde: '\u0169',
	utri: '\u25B5',
	utrif: '\u25B4',
	uuarr: '\u21C8',
	Uuml: '\u00DC',
	uuml: '\u00FC',
	uwangle: '\u29A7',
	vangrt: '\u299C',
	varepsilon: '\u03F5',
	varkappa: '\u03F0',
	varnothing: '\u2205',
	varphi: '\u03D5',
	varpi: '\u03D6',
	varpropto: '\u221D',
	vArr: '\u21D5',
	varr: '\u2195',
	varrho: '\u03F1',
	varsigma: '\u03C2',
	varsubsetneq: '\u228A\uFE00',
	varsubsetneqq: '\u2ACB\uFE00',
	varsupsetneq: '\u228B\uFE00',
	varsupsetneqq: '\u2ACC\uFE00',
	vartheta: '\u03D1',
	vartriangleleft: '\u22B2',
	vartriangleright: '\u22B3',
	Vbar: '\u2AEB',
	vBar: '\u2AE8',
	vBarv: '\u2AE9',
	Vcy: '\u0412',
	vcy: '\u0432',
	VDash: '\u22AB',
	Vdash: '\u22A9',
	vDash: '\u22A8',
	vdash: '\u22A2',
	Vdashl: '\u2AE6',
	Vee: '\u22C1',
	vee: '\u2228',
	veebar: '\u22BB',
	veeeq: '\u225A',
	vellip: '\u22EE',
	Verbar: '\u2016',
	verbar: '\u007C',
	Vert: '\u2016',
	vert: '\u007C',
	VerticalBar: '\u2223',
	VerticalLine: '\u007C',
	VerticalSeparator: '\u2758',
	VerticalTilde: '\u2240',
	VeryThinSpace: '\u200A',
	Vfr: '\uD835\uDD19',
	vfr: '\uD835\uDD33',
	vltri: '\u22B2',
	vnsub: '\u2282\u20D2',
	vnsup: '\u2283\u20D2',
	Vopf: '\uD835\uDD4D',
	vopf: '\uD835\uDD67',
	vprop: '\u221D',
	vrtri: '\u22B3',
	Vscr: '\uD835\uDCB1',
	vscr: '\uD835\uDCCB',
	vsubnE: '\u2ACB\uFE00',
	vsubne: '\u228A\uFE00',
	vsupnE: '\u2ACC\uFE00',
	vsupne: '\u228B\uFE00',
	Vvdash: '\u22AA',
	vzigzag: '\u299A',
	Wcirc: '\u0174',
	wcirc: '\u0175',
	wedbar: '\u2A5F',
	Wedge: '\u22C0',
	wedge: '\u2227',
	wedgeq: '\u2259',
	weierp: '\u2118',
	Wfr: '\uD835\uDD1A',
	wfr: '\uD835\uDD34',
	Wopf: '\uD835\uDD4E',
	wopf: '\uD835\uDD68',
	wp: '\u2118',
	wr: '\u2240',
	wreath: '\u2240',
	Wscr: '\uD835\uDCB2',
	wscr: '\uD835\uDCCC',
	xcap: '\u22C2',
	xcirc: '\u25EF',
	xcup: '\u22C3',
	xdtri: '\u25BD',
	Xfr: '\uD835\uDD1B',
	xfr: '\uD835\uDD35',
	xhArr: '\u27FA',
	xharr: '\u27F7',
	Xi: '\u039E',
	xi: '\u03BE',
	xlArr: '\u27F8',
	xlarr: '\u27F5',
	xmap: '\u27FC',
	xnis: '\u22FB',
	xodot: '\u2A00',
	Xopf: '\uD835\uDD4F',
	xopf: '\uD835\uDD69',
	xoplus: '\u2A01',
	xotime: '\u2A02',
	xrArr: '\u27F9',
	xrarr: '\u27F6',
	Xscr: '\uD835\uDCB3',
	xscr: '\uD835\uDCCD',
	xsqcup: '\u2A06',
	xuplus: '\u2A04',
	xutri: '\u25B3',
	xvee: '\u22C1',
	xwedge: '\u22C0',
	Yacute: '\u00DD',
	yacute: '\u00FD',
	YAcy: '\u042F',
	yacy: '\u044F',
	Ycirc: '\u0176',
	ycirc: '\u0177',
	Ycy: '\u042B',
	ycy: '\u044B',
	yen: '\u00A5',
	Yfr: '\uD835\uDD1C',
	yfr: '\uD835\uDD36',
	YIcy: '\u0407',
	yicy: '\u0457',
	Yopf: '\uD835\uDD50',
	yopf: '\uD835\uDD6A',
	Yscr: '\uD835\uDCB4',
	yscr: '\uD835\uDCCE',
	YUcy: '\u042E',
	yucy: '\u044E',
	Yuml: '\u0178',
	yuml: '\u00FF',
	Zacute: '\u0179',
	zacute: '\u017A',
	Zcaron: '\u017D',
	zcaron: '\u017E',
	Zcy: '\u0417',
	zcy: '\u0437',
	Zdot: '\u017B',
	zdot: '\u017C',
	zeetrf: '\u2128',
	ZeroWidthSpace: '\u200B',
	Zeta: '\u0396',
	zeta: '\u03B6',
	Zfr: '\u2128',
	zfr: '\uD835\uDD37',
	ZHcy: '\u0416',
	zhcy: '\u0436',
	zigrarr: '\u21DD',
	Zopf: '\u2124',
	zopf: '\uD835\uDD6B',
	Zscr: '\uD835\uDCB5',
	zscr: '\uD835\uDCCF',
	zwj: '\u200D',
	zwnj: '\u200C',
});

/**
 * @deprecated use `HTML_ENTITIES` instead
 * @see HTML_ENTITIES
 */
exports.entityMap = exports.HTML_ENTITIES;


/***/ }),
/* 59 */
/***/ (function(module, exports, __webpack_require__) {

var NAMESPACE = __webpack_require__(56).NAMESPACE;

//[4]   	NameStartChar	   ::=   	":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
//[4a]   	NameChar	   ::=   	NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
//[5]   	Name	   ::=   	NameStartChar (NameChar)*
var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF
var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')

//S_TAG,	S_ATTR,	S_EQ,	S_ATTR_NOQUOT_VALUE
//S_ATTR_SPACE,	S_ATTR_END,	S_TAG_SPACE, S_TAG_CLOSE
var S_TAG = 0;//tag name offerring
var S_ATTR = 1;//attr name offerring
var S_ATTR_SPACE=2;//attr name end and space offer
var S_EQ = 3;//=space?
var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
var S_ATTR_END = 5;//attr value end and no space(quot end)
var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
var S_TAG_CLOSE = 7;//closed el<el />

/**
 * Creates an error that will not be caught by XMLReader aka the SAX parser.
 *
 * @param {string} message
 * @param {any?} locator Optional, can provide details about the location in the source
 * @constructor
 */
function ParseError(message, locator) {
	this.message = message
	this.locator = locator
	if(Error.captureStackTrace) Error.captureStackTrace(this, ParseError);
}
ParseError.prototype = new Error();
ParseError.prototype.name = ParseError.name

function XMLReader(){

}

XMLReader.prototype = {
	parse:function(source,defaultNSMap,entityMap){
		var domBuilder = this.domBuilder;
		domBuilder.startDocument();
		_copy(defaultNSMap ,defaultNSMap = {})
		parse(source,defaultNSMap,entityMap,
				domBuilder,this.errorHandler);
		domBuilder.endDocument();
	}
}
function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
	function fixedFromCharCode(code) {
		// String.prototype.fromCharCode does not supports
		// > 2 bytes unicode chars directly
		if (code > 0xffff) {
			code -= 0x10000;
			var surrogate1 = 0xd800 + (code >> 10)
				, surrogate2 = 0xdc00 + (code & 0x3ff);

			return String.fromCharCode(surrogate1, surrogate2);
		} else {
			return String.fromCharCode(code);
		}
	}
	function entityReplacer(a){
		var k = a.slice(1,-1);
		if (Object.hasOwnProperty.call(entityMap, k)) {
			return entityMap[k];
		}else if(k.charAt(0) === '#'){
			return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
		}else{
			errorHandler.error('entity not found:'+a);
			return a;
		}
	}
	function appendText(end){//has some bugs
		if(end>start){
			var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
			locator&&position(start);
			domBuilder.characters(xt,0,end-start);
			start = end
		}
	}
	function position(p,m){
		while(p>=lineEnd && (m = linePattern.exec(source))){
			lineStart = m.index;
			lineEnd = lineStart + m[0].length;
			locator.lineNumber++;
			//console.log('line++:',locator,startPos,endPos)
		}
		locator.columnNumber = p-lineStart+1;
	}
	var lineStart = 0;
	var lineEnd = 0;
	var linePattern = /.*(?:\r\n?|\n)|.*$/g
	var locator = domBuilder.locator;

	var parseStack = [{currentNSMap:defaultNSMapCopy}]
	var closeMap = {};
	var start = 0;
	while(true){
		try{
			var tagStart = source.indexOf('<',start);
			if(tagStart<0){
				if(!source.substr(start).match(/^\s*$/)){
					var doc = domBuilder.doc;
	    			var text = doc.createTextNode(source.substr(start));
	    			doc.appendChild(text);
	    			domBuilder.currentElement = text;
				}
				return;
			}
			if(tagStart>start){
				appendText(tagStart);
			}
			switch(source.charAt(tagStart+1)){
			case '/':
				var end = source.indexOf('>',tagStart+3);
				var tagName = source.substring(tagStart + 2, end).replace(/[ \t\n\r]+$/g, '');
				var config = parseStack.pop();
				if(end<0){

	        		tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
	        		errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
	        		end = tagStart+1+tagName.length;
	        	}else if(tagName.match(/\s</)){
	        		tagName = tagName.replace(/[\s<].*/,'');
	        		errorHandler.error("end tag name: "+tagName+' maybe not complete');
	        		end = tagStart+1+tagName.length;
				}
				var localNSMap = config.localNSMap;
				var endMatch = config.tagName == tagName;
				var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase()
		        if(endIgnoreCaseMach){
		        	domBuilder.endElement(config.uri,config.localName,tagName);
					if(localNSMap){
						for (var prefix in localNSMap) {
							if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
								domBuilder.endPrefixMapping(prefix);
							}
						}
					}
					if(!endMatch){
		            	errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName ); // No known test case
					}
		        }else{
		        	parseStack.push(config)
		        }

				end++;
				break;
				// end elment
			case '?':// <?...?>
				locator&&position(tagStart);
				end = parseInstruction(source,tagStart,domBuilder);
				break;
			case '!':// <!doctype,<![CDATA,<!--
				locator&&position(tagStart);
				end = parseDCC(source,tagStart,domBuilder,errorHandler);
				break;
			default:
				locator&&position(tagStart);
				var el = new ElementAttributes();
				var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
				//elStartEnd
				var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
				var len = el.length;


				if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
					el.closed = true;
					if(!entityMap.nbsp){
						errorHandler.warning('unclosed xml attribute');
					}
				}
				if(locator && len){
					var locator2 = copyLocator(locator,{});
					//try{//attribute position fixed
					for(var i = 0;i<len;i++){
						var a = el[i];
						position(a.offset);
						a.locator = copyLocator(locator,{});
					}
					domBuilder.locator = locator2
					if(appendElement(el,domBuilder,currentNSMap)){
						parseStack.push(el)
					}
					domBuilder.locator = locator;
				}else{
					if(appendElement(el,domBuilder,currentNSMap)){
						parseStack.push(el)
					}
				}

				if (NAMESPACE.isHTML(el.uri) && !el.closed) {
					end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder)
				} else {
					end++;
				}
			}
		}catch(e){
			if (e instanceof ParseError) {
				throw e;
			}
			errorHandler.error('element parse error: '+e)
			end = -1;
		}
		if(end>start){
			start = end;
		}else{
			//TODO: 这里有可能sax回退，有位置错误风险
			appendText(Math.max(tagStart,start)+1);
		}
	}
}
function copyLocator(f,t){
	t.lineNumber = f.lineNumber;
	t.columnNumber = f.columnNumber;
	return t;
}

/**
 * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
 * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
 */
function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){

	/**
	 * @param {string} qname
	 * @param {string} value
	 * @param {number} startIndex
	 */
	function addAttribute(qname, value, startIndex) {
		if (el.attributeNames.hasOwnProperty(qname)) {
			errorHandler.fatalError('Attribute ' + qname + ' redefined')
		}
		el.addValue(
			qname,
			// @see https://www.w3.org/TR/xml/#AVNormalize
			// since the xmldom sax parser does not "interpret" DTD the following is not implemented:
			// - recursive replacement of (DTD) entity references
			// - trimming and collapsing multiple spaces into a single one for attributes that are not of type CDATA
			value.replace(/[\t\n\r]/g, ' ').replace(/&#?\w+;/g, entityReplacer),
			startIndex
		)
	}
	var attrName;
	var value;
	var p = ++start;
	var s = S_TAG;//status
	while(true){
		var c = source.charAt(p);
		switch(c){
		case '=':
			if(s === S_ATTR){//attrName
				attrName = source.slice(start,p);
				s = S_EQ;
			}else if(s === S_ATTR_SPACE){
				s = S_EQ;
			}else{
				//fatalError: equal must after attrName or space after attrName
				throw new Error('attribute equal must after attrName'); // No known test case
			}
			break;
		case '\'':
		case '"':
			if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
				){//equal
				if(s === S_ATTR){
					errorHandler.warning('attribute value must after "="')
					attrName = source.slice(start,p)
				}
				start = p+1;
				p = source.indexOf(c,start)
				if(p>0){
					value = source.slice(start, p);
					addAttribute(attrName, value, start-1);
					s = S_ATTR_END;
				}else{
					//fatalError: no end quot match
					throw new Error('attribute value no end \''+c+'\' match');
				}
			}else if(s == S_ATTR_NOQUOT_VALUE){
				value = source.slice(start, p);
				addAttribute(attrName, value, start);
				errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
				start = p+1;
				s = S_ATTR_END
			}else{
				//fatalError: no equal before
				throw new Error('attribute value must after "="'); // No known test case
			}
			break;
		case '/':
			switch(s){
			case S_TAG:
				el.setTagName(source.slice(start,p));
			case S_ATTR_END:
			case S_TAG_SPACE:
			case S_TAG_CLOSE:
				s =S_TAG_CLOSE;
				el.closed = true;
			case S_ATTR_NOQUOT_VALUE:
			case S_ATTR:
				break;
				case S_ATTR_SPACE:
					el.closed = true;
				break;
			//case S_EQ:
			default:
				throw new Error("attribute invalid close char('/')") // No known test case
			}
			break;
		case ''://end document
			errorHandler.error('unexpected end of input');
			if(s == S_TAG){
				el.setTagName(source.slice(start,p));
			}
			return p;
		case '>':
			switch(s){
			case S_TAG:
				el.setTagName(source.slice(start,p));
			case S_ATTR_END:
			case S_TAG_SPACE:
			case S_TAG_CLOSE:
				break;//normal
			case S_ATTR_NOQUOT_VALUE://Compatible state
			case S_ATTR:
				value = source.slice(start,p);
				if(value.slice(-1) === '/'){
					el.closed  = true;
					value = value.slice(0,-1)
				}
			case S_ATTR_SPACE:
				if(s === S_ATTR_SPACE){
					value = attrName;
				}
				if(s == S_ATTR_NOQUOT_VALUE){
					errorHandler.warning('attribute "'+value+'" missed quot(")!');
					addAttribute(attrName, value, start)
				}else{
					if(!NAMESPACE.isHTML(currentNSMap['']) || !value.match(/^(?:disabled|checked|selected)$/i)){
						errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
					}
					addAttribute(value, value, start)
				}
				break;
			case S_EQ:
				throw new Error('attribute value missed!!');
			}
//			console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
			return p;
		/*xml space '\x20' | #x9 | #xD | #xA; */
		case '\u0080':
			c = ' ';
		default:
			if(c<= ' '){//space
				switch(s){
				case S_TAG:
					el.setTagName(source.slice(start,p));//tagName
					s = S_TAG_SPACE;
					break;
				case S_ATTR:
					attrName = source.slice(start,p)
					s = S_ATTR_SPACE;
					break;
				case S_ATTR_NOQUOT_VALUE:
					var value = source.slice(start, p);
					errorHandler.warning('attribute "'+value+'" missed quot(")!!');
					addAttribute(attrName, value, start)
				case S_ATTR_END:
					s = S_TAG_SPACE;
					break;
				//case S_TAG_SPACE:
				//case S_EQ:
				//case S_ATTR_SPACE:
				//	void();break;
				//case S_TAG_CLOSE:
					//ignore warning
				}
			}else{//not space
//S_TAG,	S_ATTR,	S_EQ,	S_ATTR_NOQUOT_VALUE
//S_ATTR_SPACE,	S_ATTR_END,	S_TAG_SPACE, S_TAG_CLOSE
				switch(s){
				//case S_TAG:void();break;
				//case S_ATTR:void();break;
				//case S_ATTR_NOQUOT_VALUE:void();break;
				case S_ATTR_SPACE:
					var tagName =  el.tagName;
					if (!NAMESPACE.isHTML(currentNSMap['']) || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
						errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!')
					}
					addAttribute(attrName, attrName, start);
					start = p;
					s = S_ATTR;
					break;
				case S_ATTR_END:
					errorHandler.warning('attribute space is required"'+attrName+'"!!')
				case S_TAG_SPACE:
					s = S_ATTR;
					start = p;
					break;
				case S_EQ:
					s = S_ATTR_NOQUOT_VALUE;
					start = p;
					break;
				case S_TAG_CLOSE:
					throw new Error("elements closed character '/' and '>' must be connected to");
				}
			}
		}//end outer switch
		//console.log('p++',p)
		p++;
	}
}
/**
 * @return true if has new namespace define
 */
function appendElement(el,domBuilder,currentNSMap){
	var tagName = el.tagName;
	var localNSMap = null;
	//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
	var i = el.length;
	while(i--){
		var a = el[i];
		var qName = a.qName;
		var value = a.value;
		var nsp = qName.indexOf(':');
		if(nsp>0){
			var prefix = a.prefix = qName.slice(0,nsp);
			var localName = qName.slice(nsp+1);
			var nsPrefix = prefix === 'xmlns' && localName
		}else{
			localName = qName;
			prefix = null
			nsPrefix = qName === 'xmlns' && ''
		}
		//can not set prefix,because prefix !== ''
		a.localName = localName ;
		//prefix == null for no ns prefix attribute
		if(nsPrefix !== false){//hack!!
			if(localNSMap == null){
				localNSMap = {}
				//console.log(currentNSMap,0)
				_copy(currentNSMap,currentNSMap={})
				//console.log(currentNSMap,1)
			}
			currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
			a.uri = NAMESPACE.XMLNS
			domBuilder.startPrefixMapping(nsPrefix, value)
		}
	}
	var i = el.length;
	while(i--){
		a = el[i];
		var prefix = a.prefix;
		if(prefix){//no prefix attribute has no namespace
			if(prefix === 'xml'){
				a.uri = NAMESPACE.XML;
			}if(prefix !== 'xmlns'){
				a.uri = currentNSMap[prefix || '']

				//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
			}
		}
	}
	var nsp = tagName.indexOf(':');
	if(nsp>0){
		prefix = el.prefix = tagName.slice(0,nsp);
		localName = el.localName = tagName.slice(nsp+1);
	}else{
		prefix = null;//important!!
		localName = el.localName = tagName;
	}
	//no prefix element has default namespace
	var ns = el.uri = currentNSMap[prefix || ''];
	domBuilder.startElement(ns,localName,tagName,el);
	//endPrefixMapping and startPrefixMapping have not any help for dom builder
	//localNSMap = null
	if(el.closed){
		domBuilder.endElement(ns,localName,tagName);
		if(localNSMap){
			for (prefix in localNSMap) {
				if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
					domBuilder.endPrefixMapping(prefix);
				}
			}
		}
	}else{
		el.currentNSMap = currentNSMap;
		el.localNSMap = localNSMap;
		//parseStack.push(el);
		return true;
	}
}
function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
	if(/^(?:script|textarea)$/i.test(tagName)){
		var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
		var text = source.substring(elStartEnd+1,elEndStart);
		if(/[&<]/.test(text)){
			if(/^script$/i.test(tagName)){
				//if(!/\]\]>/.test(text)){
					//lexHandler.startCDATA();
					domBuilder.characters(text,0,text.length);
					//lexHandler.endCDATA();
					return elEndStart;
				//}
			}//}else{//text area
				text = text.replace(/&#?\w+;/g,entityReplacer);
				domBuilder.characters(text,0,text.length);
				return elEndStart;
			//}

		}
	}
	return elStartEnd+1;
}
function fixSelfClosed(source,elStartEnd,tagName,closeMap){
	//if(tagName in closeMap){
	var pos = closeMap[tagName];
	if(pos == null){
		//console.log(tagName)
		pos =  source.lastIndexOf('</'+tagName+'>')
		if(pos<elStartEnd){//忘记闭合
			pos = source.lastIndexOf('</'+tagName)
		}
		closeMap[tagName] =pos
	}
	return pos<elStartEnd;
	//}
}

function _copy (source, target) {
	for (var n in source) {
		if (Object.prototype.hasOwnProperty.call(source, n)) {
			target[n] = source[n];
		}
	}
}

function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
	var next= source.charAt(start+2)
	switch(next){
	case '-':
		if(source.charAt(start + 3) === '-'){
			var end = source.indexOf('-->',start+4);
			//append comment source.substring(4,end)//<!--
			if(end>start){
				domBuilder.comment(source,start+4,end-start-4);
				return end+3;
			}else{
				errorHandler.error("Unclosed comment");
				return -1;
			}
		}else{
			//error
			return -1;
		}
	default:
		if(source.substr(start+3,6) == 'CDATA['){
			var end = source.indexOf(']]>',start+9);
			domBuilder.startCDATA();
			domBuilder.characters(source,start+9,end-start-9);
			domBuilder.endCDATA()
			return end+3;
		}
		//<!DOCTYPE
		//startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId)
		var matchs = split(source,start);
		var len = matchs.length;
		if(len>1 && /!doctype/i.test(matchs[0][0])){
			var name = matchs[1][0];
			var pubid = false;
			var sysid = false;
			if(len>3){
				if(/^public$/i.test(matchs[2][0])){
					pubid = matchs[3][0];
					sysid = len>4 && matchs[4][0];
				}else if(/^system$/i.test(matchs[2][0])){
					sysid = matchs[3][0];
				}
			}
			var lastMatch = matchs[len-1]
			domBuilder.startDTD(name, pubid, sysid);
			domBuilder.endDTD();

			return lastMatch.index+lastMatch[0].length
		}
	}
	return -1;
}



function parseInstruction(source,start,domBuilder){
	var end = source.indexOf('?>',start);
	if(end){
		var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
		if(match){
			var len = match[0].length;
			domBuilder.processingInstruction(match[1], match[2]) ;
			return end+2;
		}else{//error
			return -1;
		}
	}
	return -1;
}

function ElementAttributes(){
	this.attributeNames = {}
}
ElementAttributes.prototype = {
	setTagName:function(tagName){
		if(!tagNamePattern.test(tagName)){
			throw new Error('invalid tagName:'+tagName)
		}
		this.tagName = tagName
	},
	addValue:function(qName, value, offset) {
		if(!tagNamePattern.test(qName)){
			throw new Error('invalid attribute:'+qName)
		}
		this.attributeNames[qName] = this.length;
		this[this.length++] = {qName:qName,value:value,offset:offset}
	},
	length:0,
	getLocalName:function(i){return this[i].localName},
	getLocator:function(i){return this[i].locator},
	getQName:function(i){return this[i].qName},
	getURI:function(i){return this[i].uri},
	getValue:function(i){return this[i].value}
//	,getIndex:function(uri, localName)){
//		if(localName){
//
//		}else{
//			var qName = uri
//		}
//	},
//	getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
//	getType:function(uri,localName){}
//	getType:function(i){},
}



function split(source,start){
	var match;
	var buf = [];
	var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
	reg.lastIndex = start;
	reg.exec(source);//skip <
	while(match = reg.exec(source)){
		buf.push(match);
		if(match[1])return buf;
	}
}

exports.XMLReader = XMLReader;
exports.ParseError = ParseError;


/***/ }),
/* 60 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/**
 * JSONP : Implémentation du protocole JSONP de la plateforme Géoportail
 *
 * @module JSONP
 * @private
 * @alias Gp.Protocols.JSONP
 */


// cf. https://github.com/sobstel/jsonp.js
var JSONP = {

    /**
     * Construction d'un identifiant statique basé sur le timestamp,
     * et qui s'incremente de +1 à chaque appel
     */
    uuid : (function () {
        var id = Math.floor(Date.now());
        return function () {
            return id++;
        };
    })(),

    /**
     * Cette fonction réalise l'appel du service fourni via le paramètre "options.url"
     * en mettant en œuvre le protocole JSONP.
     *
     * @method call
     * @static
     * @param {Object} options - parametres d'invocation du service en JSONP
     * @param {String} options.url - URL du service à invoquer (indépendamment du protocole JSONP).
     *  Cette URL contient déjà les paramètres du service.
     *  Si le paramètre dédié à la mise en oeuvre du protocole JSONP (callback=xxx) n'est pas présent, il est rajouté par la fonction ;
     *  sa valeur est déterminée en fonction du paramètre callbackName.
     * @param {Number} [options.timeOut = 0] - Nombre de ms au bout duquel on considère que le service n'a pas répondu.
     *  Une valeur de 0 pour ce paramètre permet de désactiver la gestion du timeOut.
     * @param {String} [options.callbackSuffix = null] - Suffixe de la fonction de callback à rajouter sur l'URL.
     *  Si aucun suffixe n'est spécifié (cas par défaut), on utilisera l'identifiant this.uuid () comme suffixe. Ex: "callback1458574396582 ()"
     * @param {String} [options.callbackName = gp.protocol.jsonp] - Valeur du paramètre callback à rajouter sur l'URL.
     *  Si l'URL fournie contient déjà le paramètre callback, le paramètre callbackName ne sera pas pris en compte.
     *  La fonction de callback est créée dynamiquement par la fonction JSONP ;
     *  elle a deux fonctions :
     *    elle annule la condition de timeOut
     *    puis appelle la fonction fournie par l'utilisateur via le paramètre onResponse.
     * @param {Function} options.onResponse - Nom de la fonction qui sera appelée lors de la réception des résultats du service.
     *  Ce paramètre sera ignoré si l'URL contient déjà le paramètre callback.
     *  La fonction de rappel appelée sera alors celle ayant pour nom la valeur de ce paramètre.
     * @param {Function} [options.onTimeOut] - Nom de la fonction qui sera appelée en cas de non réponse du service.
     *  Le temps au bout duquel on considère que le service n'a pas répondu est déterminé par le paramètre timeOut.
     *  @example
     *  var options = {
     *      url : 'http://localhost/some/test.json&callback=myResults',
     *      timeOut : 100,
     *      callbackName : 'myResults',
     *      callbackSuffix : "",
     *      onResponse : function (response) {
     *          console.log('results : ', response);
     *      },
     *
     *   };
     *   JSONP.call(options);
     */
    call : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("JSONP");
        logger.trace("[JSONP::call ()]");

        // analyse parametres

        if (!options) {
            logger.error("missing parameter : options !");
            throw new Error("missing parameter : options !");
        }

        if (!options.url) {
            logger.error("missing parameter : options.url !");
            throw new Error("missing parameter : options.url !");
        }

        if (!options.timeOut) {
            logger.info("setting 'options.timeOut' default value");
            options.timeOut = 0;
        }

        // FIXME si un callback coté client a été mis en place,
        // cette condition sur cette methode n'a pas de sens !?
        if (!options.onResponse) {
            logger.error("missing parameter : options.onResponse !");
            throw new Error("missing parameter : options.onResponse !");
            // FIXME doit on definir un callback interne par defaut !?
            // options.onResponse = function (data) {
            //    console.log("response callback (inner) : ", data);
            // };
        }

        // ID du callback à utiliser : null ou string.
        // si l'utilisateur a spécifié un suffixe pour le callback, on le récupère comme un ID (ex: options.callbackSuffix = "")
        // sinon, on utilise un timestamp : this.uuid ()
        var callbackId = (typeof options.callbackSuffix === "string") ? options.callbackSuffix : this.uuid();

        // on recherche le parametre callback et son nom de fonction dans l'url
        var urlHasCallbackKey = false;
        var urlHasCallbackName = false;

        var idx = options.url.indexOf("callback=");

        if (idx !== -1) {
            urlHasCallbackKey = true;
            // extraction callbackName de l'url : entre "callback=" et "&" ou fin de ligne
            var j = options.url.indexOf("&", idx);
            if (j === -1) {
                j = options.url.length;
            }

            // on ecrase le parametre options.callbackName s'il avait été défini
            var callbackName = options.url.substring(idx + 9, j);

            if (callbackName) {
                urlHasCallbackName = true;
                options.callbackName = callbackName;
                logger.info("setting 'options.callbackName' value (" + options.callbackName + ") from 'options.url' parameter");
            }
        }

        // on ajoute le parametre callback dans l'URL s'il n'existe pas
        if (!urlHasCallbackKey) {
            // gestion des autres param. et "?"
            var k = options.url.indexOf("?");
            if (k === -1) {
                // aucun param., ni de '?'
                options.url = options.url + "?" + "callback=";
            } else if (k === options.url.length) {
                // uniquement le '?'
                options.url = options.url + "callback=";
            } else {
                // le '?' et les param. existent
                options.url = options.url + "&" + "callback=";
            }
            logger.info("setting callback default key in 'options.url' : " + options.url);
        }

        // utilisation de la fonction callback coté client ?
        var HasCallbackName = options.callbackName ? true : urlHasCallbackName;

        // on ajoute le nom de la fonction callback dans l'URL si elle n'existe pas
        if (!urlHasCallbackName) {
            // fonction callback par defaut
            if (!options.callbackName) {
                logger.info("setting 'options.callbackName' default value");
                options.callbackName = "callback"; // ou "gp.protocol.jsonp" ?
                // info : si on ne veut pas gerer d'ID dans le callback,
                // options.callbackSuffix = ""
                if (callbackId || callbackId === "") {
                    options.callbackName += callbackId;
                }
            }
            options.url = options.url.replace("callback=", "callback=" + options.callbackName);
            logger.info("setting callback function name in 'options.url' : " + options.url);
        }

        // timeOut par defaut
        if (!options.onTimeOut) {
            logger.info("setting 'options.onTimeOut' default value");
            /** callback timeout par defaut */
            options.onTimeOut = function (/* error */) {
                console.log("TimeOut while invoking url : " + options.url);
            };
        }

        if (!HasCallbackName) {
            var self = this;

            // event du timeout
            var onTimeOutTrigger = null;

            // declenche le timeout si > à 0 !
            if (options.timeOut > 0) {
                onTimeOutTrigger = window.setTimeout(
                    function () {
                        /** fonction de reponse du service */
                        window[options.callbackName] = function () {};
                        options.onTimeOut();
                        self._deleteScript(callbackId);
                    }, options.timeOut);
            }

            // FIXME le nom de la fonction n'accepte pas de namespace !
            // ex. Gp.Function.callback
            /**
            * fonction de reponse du service
            * @param {Object} data - data
            * @private
            */
            window[options.callbackName] = function (data) {
                window.clearTimeout(onTimeOutTrigger);
                options.onResponse(data);
                self._deleteScript(callbackId);
            };
        }

        this._createScript(callbackId, options.url);
    },

    /**
    * create Script
    * @param {String} callbackId - callback Id
    * @param {String} url - url
    * @private
    */
    _createScript : function (callbackId, url) {
        var scriptu;
        var scripto = document.getElementById("results" + callbackId);

        scriptu = document.createElement("script");
        scriptu.setAttribute("type", "text/javascript");
        scriptu.setAttribute("src", url);
        scriptu.setAttribute("charset", "UTF-8");
        scriptu.setAttribute("id", "results" + callbackId);
        scriptu.setAttribute("async", "true"); // FIXME async ?
        // head ou body ou autres ?
        var node = document.documentElement || document.getElementsByTagName("head")[0];
        if (scripto === null) {
            node.appendChild(scriptu);
        } else {
            // s'il existe déjà, on le remplace !
            node.replaceChild(scriptu, scripto);
        }
    },

    /**
    * delete Script
    * @param {String} callbackId - callback Id
    * @private
    */
    _deleteScript : function (callbackId) {
        var script = document.getElementById("results" + callbackId);
        if (script) {
            var node = script.parentNode || document.documentElement;
            if (!node) {
                return;
            }
            node.removeChild(script);
        }
    }
};

/* harmony default export */ __webpack_exports__["default"] = (JSONP);


/***/ }),
/* 61 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Errors raised by API for one among three reasons : wrong API usage, underlying service error or unknown reason.
 *
 * @property {String} message - Error message
 * @property {Number} status - Error status : when {@link Gp.Error.TYPE_SRVERR}, gives the [HTTP status of the underlying web service response]{@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes} ; -1 otherwise.
 * @property {String} type - Error type ({@link Gp.Error.TYPE_SRVERR}, {@link Gp.Error.TYPE_USEERR} or {@link Gp.Error.TYPE_UNKERR}).
 *
 * @namespace
 * @alias Gp.Error
 * @param {Object|String} error - Options for creating error object. Can be a String (message) or an Object.
 * @param {String} error.message - Error message to return to user.
 * @param {enum} [error.type=TYPE_UNKERR] - Error type
 * @param {status} [error.status=-1] - Error status : when {@link Gp.Error.TYPE_SRVERR}, gives the [HTTP status of the underlying web service response]{@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}.
 *
 */
function ErrorService (error) {
    if (!(this instanceof ErrorService)) {
        throw new TypeError("ErrorService constructor cannot be called as a function.");
    }

    var e = error;
    if (typeof error === "string" || error instanceof String) {
        this.message = error;
        this.status = -1;
        this.type = ErrorService.TYPE_UNKERR;
    } else {
        this.message = e.message || "undefined!?";
        this.type = e.type;
        this.status = e.status || -1;
    }

    this.name = "ErrorService";
    this.stack = (new Error()).stack;
}

/**
 * Error raised when underlying geoportal service answers on error.
 *
 * @type {String}
 * @constant
 * @static
 */
ErrorService.TYPE_SRVERR = "SERVICE_ERROR";
/**
 * Error raised when funcion use is inappropriate
 *
 * @type {String}
 * @constant
 * @static
 */
ErrorService.TYPE_USEERR = "USAGE_ERROR";
/**
 * Error raised when API can't perform the job for a reason other than the two other ones.
 *
 * @type {String}
 * @constant
 * @static
 */
ErrorService.TYPE_UNKERR = "UNKNOWN_ERROR";

/**
 * @lends module:ErrorService
 */
ErrorService.prototype = Object.create(Error.prototype, {
    constructor : {
        value : ErrorService,
        writable : true,
        configurable : true
    }
});

/* harmony default export */ __webpack_exports__["default"] = (ErrorService);


/***/ }),
/* 62 */
/***/ (function(module) {

module.exports = JSON.parse("{\"_from\":\"geoportal-access-lib@3.4.2\",\"_id\":\"geoportal-access-lib@3.4.2\",\"_inBundle\":false,\"_integrity\":\"sha512-dg7lW+4jhlMQzWp95ejqJLVDYgBQeTY7/ypP7qo3GS2ci4KghdgaFeFftUFbEbOSKQ6cn7FUbBTXAKB6uUADlw==\",\"_location\":\"/geoportal-access-lib\",\"_phantomChildren\":{},\"_requested\":{\"type\":\"version\",\"registry\":true,\"raw\":\"geoportal-access-lib@3.4.2\",\"name\":\"geoportal-access-lib\",\"escapedName\":\"geoportal-access-lib\",\"rawSpec\":\"3.4.2\",\"saveSpec\":null,\"fetchSpec\":\"3.4.2\"},\"_requiredBy\":[\"/\"],\"_resolved\":\"https://registry.npmjs.org/geoportal-access-lib/-/geoportal-access-lib-3.4.2.tgz\",\"_shasum\":\"8f92a231104f195dbd098add811ae1367877ef7d\",\"_spec\":\"geoportal-access-lib@3.4.2\",\"_where\":\"/home/runner/work/geoportal-extensions/geoportal-extensions\",\"author\":{\"name\":\"IGNF\"},\"bugs\":{\"url\":\"https://github.com/IGNF/geoportal-access-lib/issues\"},\"bundleDependencies\":false,\"date\":\"14/05/2024\",\"dependencies\":{\"@xmldom/xmldom\":\"^0.8.10\",\"es6-promise\":\"^4.2.4\",\"node-fetch\":\"^2.6.1\"},\"deprecated\":false,\"description\":\"French Geoportal resources access library\",\"devDependencies\":{\"@babel/core\":\"^7.12.10\",\"@babel/plugin-transform-template-literals\":\"^7.12.1\",\"@babel/preset-env\":\"^7.12.11\",\"babel-loader\":\"^8.2.2\",\"chai\":\"^4.1.2\",\"clean-webpack-plugin\":\"^3.0.0\",\"copy-webpack-plugin\":\"^5.1.2\",\"eslint\":\"^7.18.0\",\"eslint-config-standard\":\"^16.0.2\",\"eslint-loader\":\"^4.0.2\",\"eslint-plugin-import\":\"^2.22.1\",\"eslint-plugin-node\":\"^11.1.0\",\"eslint-plugin-promise\":\"^4.2.1\",\"eslint-plugin-standard\":\"^5.0.0\",\"glob\":\"^7.1.2\",\"handlebars-layouts\":\"^3.1.4\",\"handlebars-webpack-plugin\":\"^1.4.1\",\"html-webpack-plugin\":\"^4.5.1\",\"istanbul-instrumenter-loader\":\"^3.0.1\",\"jsdoc-webpack-plugin\":\"^0.3.0\",\"loglevel\":\"^1.6.1\",\"mocha\":\"^7.2.0\",\"mocha-loader\":\"^5.1.5\",\"mocha-webpack\":\"^2.0.0-beta.0\",\"mochawesome\":\"^6.2.1\",\"nyc\":\"^15.1.0\",\"path\":\"^0.12.7\",\"replace-bundle-webpack-plugin\":\"^1.0.0\",\"sinon\":\"^9.2.4\",\"sinon-es6\":\"0.0.3\",\"speed-measure-webpack-plugin\":\"^1.4.2\",\"string-template\":\"^1.0.0\",\"terser-webpack-plugin\":\"^2.3.8\",\"webpack\":\"^4.46.0\",\"webpack-cli\":\"^3.3.12\",\"webpack-dev-server\":\"^3.11.2\",\"webpack-node-externals\":\"^2.5.2\",\"webpack-shell-plugin\":\"^0.5.0\"},\"homepage\":\"https://github.com/IGNF/geoportal-access-lib#readme\",\"keywords\":[\"geoplateforme\",\"geoportail\",\"webservice\",\"javascript\",\"es6\"],\"license\":\"CECILL-B\",\"main\":\"dist/GpServices-src.js\",\"module\":\"src/Gp.js\",\"name\":\"geoportal-access-lib\",\"nyc\":{\"include\":[\"src/**/*.js\"],\"instrument\":false,\"sourceMap\":false},\"optionalDependencies\":{},\"peerDependencies\":{},\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/IGNF/geoportal-access-lib.git\"},\"scripts\":{\"build\":\"webpack --mode=none\",\"build:dev\":\"webpack --mode=development\",\"build:prod\":\"webpack --mode=production\",\"clean\":\"echo \\\"Warning: no yet implemented!\\\" && exit 0\",\"cover\":\"nyc --reporter=lcov --reporter=text npm run test\",\"doc\":\"npm run doc:serve\",\"doc:serve\":\"webpack-dev-server --content-base jsdoc --port 9001 --open\",\"eslint\":\"eslint src/\",\"sample\":\"npm run sample:serve\",\"sample:serve\":\"webpack-dev-server --mode=none --open-page samples/index-src.html --https --content-base . --output-public-path '/dist/' --port 9001 --open\",\"sample:serve:dev\":\"webpack-dev-server --mode=development --open-page samples/index-map.html --content-base . --output-public-path '/dist/' --port 9001 --open\",\"sample:serve:prod\":\"webpack-dev-server --mode=production --open-page samples/index-prod.html --content-base . --output-public-path '/dist/' --port 9001 --open\",\"setup\":\"npm install\",\"test\":\"mocha-webpack --reporter mochawesome --reporter-options reportDir=test-report,reportFilename=index --webpack-config ./test/webpack/webpack.test.js --glob \\\"test_*.js\\\" test/spec/\",\"test:end-to-end:serve\":\"webpack-dev-server --hot --config ./test/webpack/webpack.end-to-end.serve.js\",\"test:end-to-end:serve:docker\":\"webpack-dev-server --hot --config ./test/webpack/webpack.end-to-end.serve.docker.js\",\"test:serve\":\"webpack-dev-server --hot --config ./test/webpack/webpack.test.serve.js\",\"test:serve:docker\":\"webpack-dev-server --hot --config ./test/webpack/webpack.test.serve.docker.js\"},\"version\":\"3.4.2\"}");

/***/ }),
/* 63 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
// cette classe contient les URLs par defaut des services.
//  DefaultUrlService.Alti.url(key)[elevation-json]
//  DefaultUrlService.Alti.url(key)[elevation-xml]
//  DefaultUrlService.Alti.url(key)[profil-json]
//  DefaultUrlService.Alti.url(key)[profil-xml]
//  DefaultUrlService.ProcessIsoCurve.url(key)
//  DefaultUrlService.AutoComplete.url(key)
//  DefaultUrlService.ReverseGeocode.url(key)
//  DefaultUrlService.Geocode.url(key)
//  DefaultUrlService.Route.url(key)

// Example :
//
// DefaultUrlService.Alti.url('alti')[elevation-json]
//  output {String} -> http://wxs.ign.fr/calcul/alti/rest/elevation.json
//
// DefaultUrlService.Alti.url('calcul')
// output {Object|String}
// -> http://wxs.ign.fr/calcul/alti/rest/elevation.json
// -> http://wxs.ign.fr/calcul/alti/rest/elevation.xml
// -> http://wxs.ign.fr/calcul/alti/rest/elevationLine.json
// -> http://wxs.ign.fr/calcul/alti/rest/elevationLine.xml
//
// ssl by default.
//
// Force to not do ssl :
// DefaultUrlService.ssl = false;
//
// DefaultUrlService.AutoComplete.url('calcul')
// output {Object|String}
// -> https://wxs.ign.fr/calcul/ols/apis/completion

/**
 * Default Geoportal web services URLs access.
 *
 * @namespace
 * @alias Gp.Services.DefaultUrl
 */
var DefaultUrlService = {

    /** if set true, require the use of https protocol */
    ssl : true,

    /**
    * base new-url of geoplateforme services (ssl protocol management)
    * @param {String} path - path
    * @returns {String} url
    */
    newUrl : function (path) {
        var NEW_GPF_HOSTNAME = "data.geopf.fr";

        // comportement par défaut => https
        // sinon, il est fixé par l'option 'ssl' (false => http)
        var _protocol;
        if (DefaultUrlService.ssl === false) {
            _protocol = "http://";
        } else {
            _protocol = "https://";
        }

        return _protocol + NEW_GPF_HOSTNAME + path;
    },

    /**
     * Elevation web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns elevation service default urls with or without geoportal access key given as a parameter. The result is a javascript object with different urls given used protocols ("elevation-json", "elevation-xml", "profil-json" or "profil-xml").
     */
    Alti : {
        new_key : {
            // rest
            "elevation-json" : "/altimetrie/1.0/calcul/alti/rest/elevation.json",
            "elevation-xml" : "/altimetrie/1.0/calcul/alti/rest/elevation.xml",
            "profil-json" : "/altimetrie/1.0/calcul/alti/rest/elevationLine.json",
            "profil-xml" : "/altimetrie/1.0/calcul/alti/rest/elevationLine.xml"
        },

        /**
        * newurl from geoplateforme service
        * @param {String} key - key
        * @returns {String} url
        */
        newUrl : function () {
            return {
                // rest
                "elevation-json" : DefaultUrlService.newUrl(this.new_key["elevation-json"]),
                "elevation-xml" : DefaultUrlService.newUrl(this.new_key["elevation-xml"]),
                "profil-json" : DefaultUrlService.newUrl(this.new_key["profil-json"]),
                "profil-xml" : DefaultUrlService.newUrl(this.new_key["profil-xml"])
            };
        }
    },
    /**
     * IsoCurve web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns isocurve service default urls with or without geoportal access key given as a parameter. The result is a javascript object with different urls given used protocols ("iso-json" or "iso-xml").
     */
    ProcessIsoCurve : {

        new_key : "/navigation/isochrone",

        /**
        * url from geoplateforme service
        * @returns {String} url
        */
        newUrl : function () {
            return DefaultUrlService.newUrl(this.new_key);
        }
    },
    /**
     * Config web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns config service default urls with or without geoportal access key given as a parameter.
     */
    Config : {
        _key : "https://raw.githubusercontent.com/IGNF/geoportal-configuration/new-url/dist/",
        /**
        * url
        * @param {String} key - key
        * @returns {String} url
        */
        url : function (key) {
            // key must be an array of one or several keys
            if (!Array.isArray(key)) {
                key = key.split(",");
            }
            // not homogeneous with others geoportal services URLs
            var url = [];
            for (var i = 0; i < key.length; i++) {
                url[i] = this._key + key[i] + "Config.json";
            }
            return url;
        }
    },
    /**
     * Autocompletion web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns autocomplete service default urls with or without geoportal access key given as a parameter. The result is a String.
     */
    AutoComplete : {
        new_key : "/geocodage/completion",

        /**
        * url from geoplateforme service
        * @returns {String} url
        */
        newUrl : function () {
            return DefaultUrlService.newUrl(this.new_key);
        }
    },
    /**
     * Reverse geocoding web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns reverse geocoding service default urls with or without geoportal access key given as a parameter. The result is a String.
     */
    ReverseGeocode : {
        new_key : "/geocodage/reverse",

        /**
        * url from geoplateforme service
        * @returns {String} url
        */
        newUrl : function () {
            return DefaultUrlService.newUrl(this.new_key);
        }
    },
    /**
     * Geocoding web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns geocoding service default urls with or without geoportal access key given as a parameter. The result is a String.
     */
    Geocode : {
        new_key : "/geocodage/search",

        /**
        * url from geoplateforme service
        * @returns {String} url
        */
        newUrl : function () {
            return DefaultUrlService.newUrl(this.new_key);
        }
    },
    /**
     * Routing web service access
     *
     * @member {Object}
     * @property {Function} url (key) - Returns routing service default urls with or without geoportal access key given as a parameter. The result is a javascript object with different urls given used protocols.
     */
    Route : {
        new_key : "/navigation/itineraire",

        /**
        * url from geoplateforme service
        * @returns {String} url
        */
        newUrl : function () {
            return DefaultUrlService.newUrl(this.new_key);
        }
    }
};

/* harmony default export */ __webpack_exports__["default"] = (DefaultUrlService);


/***/ }),
/* 64 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Response object for {@link module:Services~getConfig Gp.Services.getConfig ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Object} generalOptions - General properties for default map configuration resources.
 * @property {Object} generalOptions.apiKeys - Object that associates apiKey (s) with an array of resources IDs availables with that key.
 * @property {String} generalOptions.title - Underlying web service Title.
 * @property {String} generalOptions.defaultGMLGFIStyle - XSL URL used by default to translate an XML GetFeatureInfo response into an HTML array.
 * @property {String} generalOptions.theme - default theme (FIXME : for what ?)
 * @property {Array.<Float>} generalOptions.wgs84Resolutions - geographical resolutions Array for each [zoom level of the Geoportal platform]{@link http://api.ign.fr/tech-docs-js/webmaster/layers.html#Geoportal_resolutions} from 0 to 21. Expressed in degrees/pixel.
 * @property {Object} layers - Associative array mapping resources availables IDs (keys) with their properties (values given as {@link Gp.Services.Config.Layer}).
 * @property {Object} tileMatrixSets - Associative Array mapping TileMatrixSets IDs (keys) availables with their properties (values given as {@link Gp.Services.Config.TileMatrixSet}).
 *
 * @namespace
 * @alias Gp.Services.GetConfigInterface
 */
function ConfigInterface () {
    if (!(this instanceof ConfigInterface)) {
        throw new TypeError("ConfigInterface constructor cannot be called as a function.");
    }

    this.generalOptions = {
        apiKeys : {},
        title : null,
        defaultGMLGFIStyle : null,
        theme : null,
        wgs84Resolutions : []
    };

    this.layers = {};

    this.tileMatrixSets = {};
}

ConfigInterface.prototype = {

    /*
     * Constructor (alias)
     */
    constructor : ConfigInterface,

    /**
     * Check if config is loaded for a given key
     *
     * @param {String} apiKey - Access key to Geoportal platform
     * @returns {Boolean} isKeyConfLoaded - true if config of the key is already loaded, false otherwise
     */
    isKeyConfLoaded : function (apiKey) {
        if (!apiKey) {
            return;
        }
        if (this.generalOptions.apiKeys[apiKey]) {
            return true;
        }
        return false;
    },

    /**
     * Returns an array of Geoportal layers identifiers, corresponding to an API contract key.
     *
     * @param {String} apiKey - Access key to Geoportal platform
     * @returns {Array} apiKeys - Array of geoportal layers identifiers
     */
    getLayersId : function (apiKey) {
        return this.generalOptions.apiKeys[apiKey];
    },

    /**
     * Returns the id of a Geoportal layer with its name and its service.
     *
     * @param {String} layerName - name of the layer (ex. "ORTHOIMAGERY.ORTHOPHOTOS")
     * @param {String} service   - name of the service (ex. "WMS" ou "WMTS")
     * @returns {String} Id of the layer (ex. "ORTHOIMAGERY.ORTHOPHOTOS$GEOPORTAIL:OGC:WMTS")
     */
    getLayerId : function (layerName, service) {
        if (!layerName || !service) {
            return;
        }
        var layerId = null;

        // layer
        // key : [layerName]$[contexte]:OGC:[service]
        // ex : "ORTHOIMAGERY.ORTHOPHOTOS$GEOPORTAIL:OGC:WMTS"

        // service
        // key : [layerName]$[contexte];[service]
        // ex : PositionOfInterest$OGC:OPENLS;ReverseGeocode

        if (this.layers) {
            var layers = this.layers;
            for (var key in layers) {
                if (layers.hasOwnProperty(key)) {
                    var parts = key.split("$");
                    if (layerName === parts[0]) {
                        if (parts[1]) {
                            var servicePartsLayer = parts[1].split(":");
                            var servicePartsService = parts[1].split(";");

                            if (servicePartsService[1] === service.toUpperCase()) {
                                layerId = key;
                                break;
                            }
                            if (servicePartsLayer[2] === service.toUpperCase()) {
                                layerId = key;
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (!layerId) {
            return;
        }
        return layerId;
    },

    /**
     * Returns an associative array of Geoportal layers configurations, corresponding to an API contract key.
     * If no key is specified, all layers from configuration are returned.
     *
     * @param {String} apiKey - Access key to Geoportal platform
     * @returns {Object} layers - Object which properties are layers identifiers.
     */
    getLayersConf : function (apiKey) {
        var layers = {};
        var layersIdArray = this.getLayersId(apiKey);
        if (layersIdArray) {
            for (var i = 0; i < layersIdArray.length; i++) {
                var lyrId = layersIdArray[i];
                layers[lyrId] = this.layers[lyrId];
            }
        }
        return layers;
    },

    /**
     * Returns a geoportal layer configuration, given its identifier
     *
     * @param {String} layerId - Geoportal layer identifier (e.g. "GEOGRAPHICALGRIDSYSTEMS.MAPS$GEOPORTAIL:OGC:WMTS")
     * @return {Object} layer - Layer configuration
     */
    getLayerConf : function (layerId) {
        if (!this.layers) {
            return;
        }
        return this.layers[layerId];
    },

    /**
     * Get all parameters needed to display a WMS or WMTS layer given its name, its service and its key
     *
     * @param {String} layerName - name of the layer (ex. "ORTHOIMAGERY.ORTHOPHOTOS")
     * @param {String} service   - name of the service (ex. "WMS" ou "WMTS")
     * @param {String} [apiKey]  - Contract API key
     * @returns {Object} params  - params of the service (WMS or WMTS) for the given layer
     * @returns {String} params.url        - Url of the service to reach to display the layer
     * @returns {String} params.version    - Version of the service
     * @returns {String} params.styles     - Default style of the layer
     * @returns {String} params.format     - Default format of the layer
     * @returns {String} params.projection - Default projection of the layer
     * @returns {Number} params.minScale   - Min scale denominator of the layer
     * @returns {Number} params.maxScale   - Max scale denominator of the layer
     * @returns {Gp.BBox} params.extent    - Extent of the layer, in the projection of the layer
     * @returns {Array} params.legends     - Array of legends associated to the layer
     * @returns {Array} params.title       - Name of the layer, readable by a human
     * @returns {Array} params.description - Description of the layer
     * @returns {String} params.[TMSLink]          - Id of the Tile Matrix Set (TMS), in the case of WMTS layer
     * @returns {Gp.Point} params.[matrixOrigin]   - Originof the tile matrix (top left corner), in the case of WMTS layer
     * @returns {Array} params.[nativeResolutions] - Array with the resolution of each level of the tile matrix set, in the case of WMTS layer
     * @returns {Array} params.[matrixIds]         - Array with the ID of each level of the tile matrix set, in the case of WMTS layer
     */
    getLayerParams : function (layerName, service) {
        var params = {};

        if ((service === "WMS" || Object.keys(this.tileMatrixSets).length !== 0) && Object.keys(this.layers).length !== 0) {
            // get the layerId of the layer
            var layerId = this.getLayerId(layerName, service);

            if (layerId) {
                // get the layer Conf Object
                var layerConf = this.getLayerConf(layerId);

                var keys = this.getLayerKey(layerId);
                if (keys.length === 0) {
                    return;
                }

                // get services params
                for (var i = 0; i < keys.length; i++) {
                    // only one serverUrl is saved in Gp.Config : with multiKeys, we have to retrieve the key used in the serverUrl property
                    if (layerConf.serviceParams.serverUrl[keys[i]]) {
                        params.url = layerConf.serviceParams.serverUrl[keys[i]];
                    }
                }

                const wmsTypeRegex = /\/v\//;
                // WMS vector style always empty (not in getCap)
                if (wmsTypeRegex.test(params.url)) {
                    params.styles = " ";
                } else {
                    // WMS raster style is defined in getCap
                    params.styles = layerConf.styles[0].name;
                }

                params.version = layerConf.serviceParams.version;
                params.format = layerConf.formats[0].name;
                params.projection = layerConf.defaultProjection;

                // get layer info and constraints
                params.minScale = layerConf.globalConstraint.minScaleDenominator;
                params.maxScale = layerConf.globalConstraint.maxScaleDenominator;
                params.extent = layerConf.globalConstraint.bbox;
                params.legends = layerConf.legends;
                params.title = layerConf.title;
                params.description = layerConf.description;

                if (service === "WMS") {
                    params.metadata = layerConf.metadata;
                }

                // Informations  non disponibles avec les getCap
                // params.metadata = layerConf.getMetadata();
                // params.originators = layerConf.getOriginators();
                // params.quicklookUrl = layerConf.getQuicklookUrl();

                // WMTS : get the tileMatrixSetLimits
                if (layerConf.wmtsOptions) {
                    params.tileMatrixSetLimits = layerConf.wmtsOptions.tileMatrixSetLimits;
                    var TMSLink = layerConf.wmtsOptions.tileMatrixSetLink;
                    if (TMSLink) {
                        params.TMSLink = TMSLink;
                        var tmsConf = this.getTMSConf(TMSLink);
                        // Get matrix origin : Gp.Point = Object{x:Float, y:Float}
                        // params.matrixOrigin = tmsConf.getTopLeftCorner();
                        params.matrixIds = Object.keys(tmsConf.tileMatrices);
                        params.tileMatrices = tmsConf.tileMatrices;
                        // by default, pseudo mercator resolutions
                        params.nativeResolutions = tmsConf.nativeResolutions || this.getTMSConf("PM").nativeResolutions;
                    }
                }
            }
        }
        return params;
    },

    /**
     * Get the contract key(s) associated to a given layer.
     *
     * @param {String} layerId - Geoportal layer identifier (e.g. "GEOGRAPHICALGRIDSYSTEMS.MAPS$GEOPORTAIL:OGC:WMTS")
     * @return {Array} layerKey - array of key(s) associated to the given layer
     */
    getLayerKey : function (layerId) {
        var layerKey = [];
        if (this.generalOptions && this.generalOptions.apiKeys && Object.keys(this.generalOptions.apiKeys).length !== 0) {
            var resourcesByKey = this.generalOptions.apiKeys;
            for (var key in resourcesByKey) {
                var resourcesArray = resourcesByKey[key];
                resourcesArray.forEach(function (arrayLayerId) {
                    if (arrayLayerId === layerId) {
                        layerKey.push(key);
                    }
                });
            }
        }
        return layerKey;
    },

    /**
     * Returns an associative array of Tile Matrix Sets configurations.
     *
     * @return {Object} tileMatrixSets - Object which properties are TMS identifiers
     *
     */
    getTileMatrixSets : function () {
        return this.tileMatrixSets;
    },

    /**
     * Returns a Tile Matrix Sets configuration, given its identifier.
     *
     * @param {String} tmsID - Tile Matrix Set identifier (e.g. : "PM")
     * @return {Object} tileMatrixSet - Tile Matrix Set configuration
     */
    getTMSConf : function (tmsID) {
        if (!this.tileMatrixSets) {
            return;
        }
        return this.tileMatrixSets[tmsID];
    },

    /**
     * Get global constraints for a given Layer : extent, minScale, maxScale, projection
     *
     * @param {String} layerId - Geoportal layer identifier (e.g. "GEOGRAPHICALGRIDSYSTEMS.MAPS$GEOPORTAIL:OGC:WMTS")
     * @returns {Object} params - layer constraints
     * @returns {String} params.projection - default layer projection
     * @returns {Number} params.minScale   - layer min scale denominator
     * @returns {Number} params.maxScale   - layer max scale denominator
     * @returns {Gp.BBox} params.extent    - layer extent expressed in the layer projection
     */
    getGlobalConstraints : function (layerId) {
        var params = {};

        if (layerId) {
            // get layer configuration object
            var layerConf = this.getLayerConf(layerId);
            params.projection = layerConf.defaultProjection;
            params.minScale = layerConf.globalConstraint.minScaleDenominator;
            params.maxScale = layerConf.globalConstraint.maxScaleDenominator;
            params.extent = layerConf.globalConstraint.bbox;
        }

        return params;
    }

};

/* harmony default export */ __webpack_exports__["default"] = (ConfigInterface);


/***/ }),
/* 65 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(63);
/* harmony import */ var _Request_AltiRequestFactory__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(66);
/* harmony import */ var _Response_AltiResponseFactory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(73);









/**
 * @classdesc
 *
 * Appel du service d'altimétrie du Géoportail
 *
 * @todo gestion du parma. output et callback
 * @todo outputFormat (REST) et format (WPS)
 * @todo La reponse JSON peut encapsuler un XML !
 *
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.Alti
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {Array.<Object>} options.positions - Tableau ({lon:float,lat:float}) contenant les coordonnées des points (CRS:84)
 *      dont on veut connaître les altitudes (ou à partir desquelles on va calculer le profil).
 *      Chaque élément du tableau est un objet JavaScript avec deux attributs : lon et lat, qui sont des flottants.
 *      Minimum 2 éléments si on souhaite calculer un profil altimétrique (ElevationLine).
 *      Maximum 50 éléments.
 *
 * @param {String} options.outputFormat - Le format de la réponse du service alti : 'xml' ou 'json'.
 *      Ce paramètre déterminera l'extension '.xml' ou '.json' du service dans le cas de l'API REST,
 *      ou la valeur du paramètre 'format' dans le cas de la norme WPS.
 *      Nécessaire si serverUrl est renseigné, et qu'on souhaite passer par l'API REST,
 *      pour connaître le format dans lequel sera fournie la réponse (pour son traitement).
 *      Non nécessaire pour la norme WPS. Par défaut, ce paramètre vaut 'json'.
 *
 * @param {Number} [options.sampling] - Nombre de points à utiliser pour déterminer le tracé d'un profil altimétrique, compris entre 2 et 5000.
 *      A spécifier lorsqu'on souhaite accéder à cette fonctionnalité.
 *      Dans ce cas, les points fournis en entrée (au minimum de deux) servent à déterminer l'axe planimétrique
 *      le long duquel le profil doit être calculé.
 *      Si le paramètre sampling n'est pas spécifié ou moins de deux points sont fournis,
 *      c'est le service Elevation qui sera interrogé (altitudes simples calculées pour les points fournis).
 *      Une valeur de sampling strictement inférieure à 2 déclenchera un échantillonnage avec la valeur par défaut du service (3 points).
 *
 * @param {String} [options.api] - Manière d'accéder au service : 'REST' (via l'API REST) ou 'WPS' (via la norme WPS).
 *      Par défaut, on utilise l'API REST.
 *
 * @param {Boolean} [options.zonly] - Permet de ne récupérer que les altitudes en sortie s'il vaut 'true'.
 *      Vaut 'false' par défaut.
 *
 * @param {String} [options.resource] - Resource utilisée pour réaliser le calcul.
 *
 * @example
 *   var options = {
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      protocol : 'JSONP', // JSONP|XHR
 *      proxyURL : null,
 *      httpMethod : 'GET', // GET|POST
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      positions : [{lon:, lat:}, {lon:, lat:}],
 *      outputFormat : 'json' // json|xml
 *      sampling : 3,
 *      api : 'REST', // REST|WPS
 *      zonly : false // false|true,
 *      resource : "resource-par-defaut"
 *   };
 *
 */
function Alti (options) {
    if (!(this instanceof Alti)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "Alti"));
    }

    /**
     * Nom de la classe (heritage)
     * FIXME instance ou classe ?
     */
    this.CLASSNAME = "Alti";

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].apply(this, arguments);

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Services.Alti");
    this.logger.trace("[Constructeur Alti (options)]");

    // #####################
    // analyse des options
    // #####################

    if (!options.positions) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "positions"));
    }

    if (options.positions.length === 0) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "positions"));
    }

    // ajout des options spécifiques au service
    this.options.positions = options.positions;

    // format de réponse du service : "json" ou "xml" (valeur par défaut), en minuscule !
    this.options.outputFormat = (typeof options.outputFormat === "string") ? options.outputFormat.toLowerCase() : "xml";

    // ressource utilisée pour le calcul altimétrique
    this.options.resource = options.resource || "ign_rge_alti_wld";

    // sampling
    this.options.sampling = options.sampling || null;

    // type d'api utilisé pour requeter le service, en majuscule !
    this.options.api = (typeof options.api === "string") ? options.api.toUpperCase() : "REST";

    // l'api ne peut être interrogée qu'en GET.
    if (this.options.api === "REST") {
        this.options.httpMethod = "GET";
    }

    // param. zonly
    this.options.zonly = options.zonly || false;

    // param. measures
    this.options.measures = options.measures || false;

    // gestion de l'url du service par defaut
    // si l'url n'est pas renseignée, il faut utiliser les urls par defaut
    // en fonction du type d'api, REST ou WPS, du format de reponse demandé (outputFormat)
    // ainsi que sur le type de service (profil ou elevation)
    if (!this.options.serverUrl) {
        var lstUrlByDefault = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__["default"].Alti.newUrl();
        var urlFound = null;
        switch (this.options.api) {
            case "WPS":
                urlFound = lstUrlByDefault.wps;
                break;
            case "REST":
                var key = (options.sampling ? "profil" : "elevation") + "-" + this.options.outputFormat;
                urlFound = lstUrlByDefault[key];
                break;
            default:
                throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_UNKNOWN", "api"));
        }

        if (!urlFound) {
            throw new Error("Url by default not found !");
        }
        this.options.serverUrl = urlFound;
        this.logger.trace("Server URL by default : " + this.options.serverUrl);
    }

    // gestion du type de service
    // si l'extension de l'url est .json ou .xml, on surcharge le format de sortie (outputFormat)
    var idx = this.options.serverUrl.lastIndexOf(".");
    if (idx !== -1) {
        var extension = this.options.serverUrl.substring(idx + 1);
        if (extension && extension.length < 5) { // FIXME extension de moins de 4 car. ...
            this.logger.trace("Server Extension URL : " + extension);
            switch (extension.toLowerCase()) {
                case "json":
                case "xml":
                    this.options.outputFormat = extension.toLowerCase();
                    break;
                default:
                    throw new Error("type of service : unknown or unsupported (json or xml) !");
            }
        }
    }
}

/**
 * @lends module:Alti#
 */
Alti.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].prototype, {
    // todo
    // getter/setter
});

/**
 * Constructeur (alias)
 */
Alti.prototype.constructor = Alti;

/**
 * Création de la requête (overwrite)
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Alti.prototype.buildRequest = function (error, success) {
    // utilisation en mode callback
    var options = {
        httpMethod : this.options.httpMethod,
        // callback
        onSuccess : function (result) {
            // sauvegarde de la requete !
            this.request = result;
            success.call(this, this.request);
        },
        onError : error,
        scope : this,
        // spécifique au service :
        resource : this.options.resource,
        positions : this.options.positions,
        outputFormat : this.options.outputFormat,
        sampling : this.options.sampling,
        api : this.options.api,
        zonly : this.options.zonly,
        measures : this.options.measures
    };

    _Request_AltiRequestFactory__WEBPACK_IMPORTED_MODULE_5__["default"].build(options);
};

/**
 * Analyse de la reponse (overwrite)
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Alti.prototype.analyzeResponse = function (error, success) {
    // INFO
    // Factory pour masquer la complexité du retour du service qui renvoie soit
    //  - une 'string' qui contient du XML ou JSON natif en mode XHR
    //  - un objet JSON qui est natif ou encapsulé

    if (this.response) {
        var options = {
            response : this.response,
            outputFormat : this.options.outputFormat, // utile pour parser la string en mode XHR : JSON ou XML !
            rawResponse : this.options.rawResponse,
            onError : error,
            onSuccess : success,
            scope : this
        };

        _Response_AltiResponseFactory__WEBPACK_IMPORTED_MODULE_6__["default"].build(options);
    } else {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/* harmony default export */ __webpack_exports__["default"] = (Alti);


/***/ }),
/* 66 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(61);
/* harmony import */ var _AltiRequestREST__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(67);
/* harmony import */ var _AltiRequestWPS__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(71);
/**
 * Creation d'une requête en REST ou WPS
 * (Factory)
 *
 * @module AltiRequestFactory
 * @alias Gp.Services.Alti.Request.AltiRequestFactory
 * @private
 */





var AltiRequestFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Alti
     *
     * @example
     *   var options = {
     *      httpMethod : 'GET', // GET|POST
     *      onSuccess : function (response) {},
     *      onError : function (error) {},
     *      scope : this,
     *      positions : [{lon:, lat:}, {lon:, lat:}],
     *      outputFormat : 'json' // json|xml
     *      sampling : 3,
     *      api : 'REST', // REST|WPS
     *      zonly : false // false|true
     *   };
     *
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("AltiRequestFactory");
        logger.trace(["AltiRequestFactory::build()"]);

        var request = null;

        // on factorise les options par groupe;
        // - global,
        // - param, les params pour les data inputs
        // - wps, les param du service
        // - callback

        var settings = {
            // ajout des valeurs par defaut spécifiques au service
            type : options.sampling ? "Profil" : "Elevation",
            method : options.httpMethod,
            param : {
                positions : null,
                delimiter : null, // FIXME par defaut, on ne le met pas en place car ça fait planter la requête !?
                indent : null, // par defaut
                crs : null, // par defaut
                format : null, // (only to POST)
                sampling : null, // (only use by Profil)
                zonly : null, // (only use by Elevation)
                measures : null // (only use by Elevation)
            }
        };

        // surcharge des valeurs obligatoires
        settings.param.positions = options.positions;
        settings.param.format = options.outputFormat;
        settings.param.sampling = options.sampling;
        settings.param.zonly = options.zonly;
        settings.param.measures = options.measures;
        settings.param.resource = options.resource;

        // gestion des callback
        var bOnError = !!(options.onError !== null && typeof options.onError === "function"); // cast variable to boolean
        var bOnSuccess = !!(options.onSuccess !== null && typeof options.onSuccess === "function");

        var message = null;
        switch (options.api) {
            case "REST":
                // FIXME les exceptions ne sont pas 'catchées' sur le constructeur !
                var myReq = new _AltiRequestREST__WEBPACK_IMPORTED_MODULE_2__["default"](settings);
                if (!myReq.processRequestString()) {
                    message = "Error in process request (rest) !";
                    if (bOnError) {
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"](message));
                        return;
                    }
                    throw new Error(message);
                }
                request = myReq.requestString;
                break;
            case "WPS":
                // ajout des valeurs par defaut spécifiques au service WPS
                settings.wps = {
                    service : null, // par defaut
                    version : null, // par defaut
                    identifier : null, // par defaut
                    rawdataoutput : null, // par defaut
                    request : null // par defaut
                };

                request = _AltiRequestWPS__WEBPACK_IMPORTED_MODULE_3__["default"].build(settings);
                if (!request) {
                    message = "Error in process request (wps) !";
                    if (bOnError) {
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"](message));
                        return;
                    }
                    throw new Error(message);
                }
                break;
            default:
                message = "Type of API is not supported by service (REST or WPS) !";
                if (bOnError) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"](message));
                    return;
                }
                throw new Error(message);
        }

        if (bOnSuccess) {
            options.onSuccess.call(options.scope, request);
        }

        return request;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AltiRequestFactory);


/***/ }),
/* 67 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _model_AltiElevationRequest__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(68);
/* harmony import */ var _model_AltiProfilRequest__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70);
/* jshint multistr : true */






/**
 * @classdesc
 * Classe de gestion des requêtes de type REST sur le service altimetrique.
 *
 * @todo Le service Alti n'implemente pas le POST !?
 * @constructor
 * @alias Gp.Services.Alti.Request.AltiRequestREST
 * @param {Object} options - options
 * @param {Object}   options.param.positions - tableau de coordonnées lon/lat
 * @param {String}   options.param.delimiter - '|'
 * @param {Boolean}  options.param.indent - false|true
 * @param {String}   options.param.crs - 'CRS:84'
 * @param {String}   options.param.sampling - 3
 * @param {String}   options.param.resource - 'rge_alti_corse2a_float32_zip_lamb93'
 * @param {Boolean}  options.param.zonly - false|true
 * @param {Boolean}  options.param.measures - false|true
 * @param {String}   options.param.format - "JSON|XML"
 * @param {String}   options.type - "Profil|Elevation"
 * @param {String}   options.method - GET|POST
 *
 * @example
 *      var options = {
 *           type : 'Profil', // Elevation
 *           method : 'GET',  // par defaut
 *           param : {
 *               positions : [
 *                   {lon:'1.11', lat:'1.11'},
 *                   {lon:'1.10', lat:'1.10'},
 *                   {lon:'1.12', lat:'1.12'}
 *               ],
 *               delimiter : ";",         // par defaut
 *               indent    : true,        // par defaut
 *               crs       : 'EPSG:4326', // par defaut
 *               format    : 'json',      // par defaut (only to POST)
 *               sampling  : 3 ,          // par defaut (only use by Profil)
 *               zonly     : false        // par defaut (only use by Elevation)
 *               measures  : false        // par defaut (only use by Elevation)
 *           }
 *      };
 *
 *      var result;
 *      try {
 *          var obj = new AltiRequestREST (options);
 *          if (! obj.processRequestString ()) {
 *              throw new Error("Request empty !?")
 *          }
 *          result = obj.requestString;
 *      } catch (e) {
 *          // exceptions...
 *      }
 * @private
 */
function AltiRequestREST (options) {
    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("AltiRequestREST");
    this.logger.trace("[Constructeur AltiRequestREST ()]");

    if (!(this instanceof AltiRequestREST)) {
        throw new TypeError("AltiRequestREST constructor cannot be called as a function.");
    }

    this.options = options || {};

    // existance des options
    if (!this.options) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "options"));
    }

    // type de requete : Altitude ou Profil
    // (param. à determiner en fonction des parametres d'entrée)
    if (!this.options.type) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "type (Elevation or Profil)"));
    }

    // construction du modele de requête
    // (test du type d'objet candidat)
    this.DataObject = null;
    switch (this.options.type) {
        case "Elevation":
            this.DataObject = new _model_AltiElevationRequest__WEBPACK_IMPORTED_MODULE_2__["default"](this.options.param);
            break;
        case "Profil":
            this.DataObject = new _model_AltiProfilRequest__WEBPACK_IMPORTED_MODULE_3__["default"](this.options.param);
            break;
        default:
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_TYPE", "type (Elevation or Profil)"));
    }

    /**
     * methode.
     * Par defaut, "GET".
     */
    this.method = this.options.method || "GET";
}

AltiRequestREST.prototype = {

    /**
     * request
     * @type {String}
     */
    requestString : null,

    /**
     * Constructeur (alias)
     */
    constructor : AltiRequestREST,

    /**
     * Template de la requête.
     */
    template : {
        get : {
            // FIXME on retire le param 'delimiter' : &delimiter='__DELIMITER__'
            value : "lon=__LON__&lat=__LAT__&indent=__INDENT__&crs='__CRS__'&resource=__RESOURCE__&measures=__MEASURES__",
            input : {
                point : "&zonly=__ZONLY__",
                profil : "&sampling=__SAMPLING__"
            }
        },
        post : {
            // FIXME on retire le param 'delimiter' : delimiter='__DELIMITER__'\n\
            value : "lon=__LON__\n" +
                "lat=__LAT__\n" +
                "indent=__INDENT__\n" +
                "crs='__CRS__'\n" +
                "resource='__RESOURCE__'\n" +
                "measures='__MEASURES__'\n",
            input : {
                point : "zonly=__ZONLY__\n",
                profil : "sampling=__SAMPLING__"
            }
        }
    },

    /**
     * Construction de la requête.
     *
     * @example
     * // GET  out : lon=0.2367,2.1570&lat=48.0551,46.6077&delimiter=,&indent=true&zonly=true&crs='CRS:84'
     * // POST out : Not yet supported method POST !
     * @returns {String}
     */
    processRequestString : function () {
        this.logger.trace("AltiRequestREST::processRequestString ()");

        var template = "";
        if (this.method === "POST") {
            template = this.template.post.value;
        } else if (this.method === "GET") {
            template = this.template.get.value;
        }

        template = template.replace(/__LON__/g, this.DataObject.getLon());
        template = template.replace(/__LAT__/g, this.DataObject.getLat());
        // FIXME on retire le param 'delimiter'
        // template = template.replace(/__DELIMITER__/g, this.DataObject.delimiter);
        template = template.replace(/__INDENT__/g, this.DataObject.indent);
        template = template.replace(/__CRS__/g, this.DataObject.crs);
        template = template.replace(/__RESOURCE__/g, this.DataObject.resource);
        template = template.replace(/__MEASURES__/g, this.DataObject.measures);

        // ajout +
        template = template + this.__addDataInputs();
        this.logger.trace("traduction tmpl", template);

        // sauvegarde
        this.requestString = template;

        return this.requestString;
    },

    /**
     * Ajout de parametres spécifiques (ex. zonly)
     *
     * @returns {String}
     */
    __addDataInputs : function () {
        this.logger.trace("AltiRequestREST::addDataInput ()");

        var myTemplate;
        if (this.method === "POST") {
            myTemplate = this.template.post;
        } else if (this.method === "GET") {
            myTemplate = this.template.get;
        } else {
            throw new Error("No other HTTP method supported by the service !");
        }

        var tmpl = null;
        if (this.DataObject.CLASSNAME === "AltiElevationRequest") {
            tmpl = myTemplate.input.point;
            return tmpl.replace(/__ZONLY__/g, this.DataObject.zonly.toString());
        } else if (this.DataObject.CLASSNAME === "AltiProfilRequest") {
            tmpl = myTemplate.input.profil;
            return tmpl.replace(/__SAMPLING__/g, this.DataObject.sampling);
        } else {
            throw new Error("No other object supported than elevation or profil !?");
        }
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AltiRequestREST);


/***/ }),
/* 68 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _AltiRequest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69);




/**
 * @classdesc
 *
 * Classe de gestion des param. des requêtes de type POINT du service altimetrique.
 *
 * @constructor
 * @alias Gp.Services.Alti.Request.AltiElevationRequest
 * @param {Object} options - options
 * @param {Boolean}  options.zonly - false|true
 *
 * @private
 */
function AltiElevationRequest (options) {
    if (!(this instanceof AltiElevationRequest)) {
        throw new TypeError("AltiElevationRequest constructor cannot be called as a function.");
    }

    /**
     * Nom de la classe (heritage)
     */
    this.CLASSNAME = "AltiElevationRequest";

    // appel du constructeur par heritage
    _AltiRequest__WEBPACK_IMPORTED_MODULE_1__["default"].apply(this, arguments);

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur AltiElevationRequest ()]");

    /**
     * Z uniquement.
     * true|false
     */
    this.zonly = this.options.zonly || false; // test des options héritées !
}

/**
 * @lends module:AltiElevationRequest#
 */

AltiElevationRequest.prototype = Object.create(_AltiRequest__WEBPACK_IMPORTED_MODULE_1__["default"].prototype, {

    /**
     * Setter/getter pour "zonly"
     */
    zonly : {
        /** getter */
        get : function () {
            return this._zonly;
        },
        /** setter */
        set : function (z) {
            this._zonly = z;
        }
    }

});

/**
 * Constructeur (alias)
 */
AltiElevationRequest.prototype.constructor = AltiElevationRequest;

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Array}
 */
AltiElevationRequest.prototype.getData = function () {
    // par glop..., appel de AltiRequest::getData () !
    var map = [];
    map.push({
        k : "lon",
        v : this.getLon()
    });
    map.push({
        k : "lat",
        v : this.getLat()
    });
    // map.push({k : "delimiter", v : this.delimiter}); // FIXME on retire le param "delimiter"
    map.push({
        k : "indent",
        v : this.indent
    });
    map.push({
        k : "crs",
        v : this.crs
    });
    map.push({
        k : "zonly",
        v : this.zonly
    });
    map.push({
        k : "format",
        v : this.format
    });
    map.push({
        k : "resource",
        v : this.resource
    });

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (AltiElevationRequest);


/***/ }),
/* 69 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);



/**
 * @classdesc
 * Classe de gestion des param. des requêtes du service altimetrique.
 *
 * @constructor
 * @alias Gp.Services.Alti.Request.AltiRequest
 * @param {Object} options - options
 * @param {Object}   options.positions - tableau de coordonnées lon/lat
 * @param {String}   options.delimiter - "|"
 * @param {Boolean}  options.indent - false|true
 * @param {String}   options.crs - "CRS:84"
 * @param {String}   options.format - "JSON|XML"
 *
 * @private
 */
function AltiRequest (options) {
    if (!(this instanceof AltiRequest)) {
        throw new TypeError("AltiRequest constructor cannot be called as a function.");
    }

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur AltiRequest ()]");

    /**
     * Options en paramêtres du constructeur.
     */
    this.options = options || {};

    /**
     * Liste des coordonnées.
     * @example
     * var c = [{lon : "", lat : ""}, {lon : "", lat : ""}];
     */
    this.positions = this.options.positions || [];

    /**
     * Caractère de séparation.
     * Par defaut, "|".
     */
    this.delimiter = this.options.delimiter || "|";

    /**
     * Indentation.
     * true|false
     */
    this.indent = this.options.indent || false;

    /**
     * Projection.
     * Par defaut, CRS:84.
     */
    this.crs = this.options.crs || "CRS:84";

    /**
     * format de sortie.
     * Par defaut, "json".
     */
    this.format = this.options.format || "json";

    /*
     * Ressource utilisée
    */
    this.resource = this.options.resource;

    /**
     * Réponse détaillée (source & accuracy)
     * true|false
    */
    this.measures = this.options.measures || false;
}

/**
 * CLASSNAME
 */
AltiRequest.CLASSNAME = "AltiRequest";

AltiRequest.prototype = {

    /**
     * @lends module:AltiRequest#
     */

    /**
     * Constructeur (alias)
     */
    constructor : AltiRequest,

    /**
     * Ajout d"une liste de coordonnées.
     *
     * @param {Object[]} lstPosition - liste de positions
     * @example
     * obj.setPositions ([{lon : "0.15", lat : "0.15"}, {lon : "1.15", lat : "1.15"}]);
     */
    setPositions : function (lstPosition) {
        var positions = [];
        for (var i = 0; i < lstPosition.length; i++) {
            var o = lstPosition[i];
            if (o.lon && o.lat) {
                positions.push(o);
            }
        }

        this.positions = positions;
    },

    /**
     * Liste des coordonnées.
     *
     * @param {Int} pos - position
     * @returns {positions}
     * @example
     * obj.getPositions ();  // [{lon : "", lat : ""}, {lon : "", lat : ""}]
     * obj.getPositions (0); // [{lon : "", lat : ""}]
     */
    getPositions : function (pos) {
        // FIXME test if not a number !?
        if (!pos) {
            return this.positions;
        }

        var index = this.positions.length - 1;
        if (pos > index || pos < index) {
            this.logger.warn("index out of range !");
            return this.positions;
        }

        return this.positions[pos];
    },

    /**
     * Ajout d"une liste de coordonnées.
     *
     * @param {Object[]} lstPosition - liste de positions
     * @example
     * obj.addPositions ([{lon : "0.15", lat : "0.15"}, {lon : "1.15", lat : "1.15"}]);
     */
    addPositions : function (lstPosition) {
        for (var i = 0; i < lstPosition.length; i++) {
            var o = lstPosition[i];
            if (o.lon && o.lat) {
                this.positions.push(lstPosition[i]);
            }
        }
    },

    /**
     * Retourne la liste des longitudes avec un caractère de séparation.
     *
     * @returns {String} - une liste de longitudes
     * @example
     * // out : 0.2367|2.1570|43.789|...
     */
    getLon : function () {
        var lstLon = [];
        for (var i = 0; i < this.positions.length; i++) {
            lstLon.push(this.positions[i].lon);
        }
        this.logger.trace(lstLon);
        return lstLon.join(this.delimiter);
    },

    /**
     * Retourne la liste des lattitudes avec un caractère de séparation.
     *
     * @returns {String} - une liste de lattitudes
     * @example
     * // out : 0.2367|2.1570|43.789|...
     */
    getLat : function () {
        var lstLat = [];
        for (var i = 0; i < this.positions.length; i++) {
            lstLat.push(this.positions[i].lat);
        }
        this.logger.trace(lstLat);
        return lstLat.join(this.delimiter);
    }

};

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Object[]}
 */
AltiRequest.prototype.getData = function () {
    var map = [];

    map.push({
        k : "lon",
        v : this.getLon()
    });
    map.push({
        k : "lat",
        v : this.getLat()
    });
    map.push({
        k : "delimiter",
        v : this.delimiter
    });
    map.push({
        k : "indent",
        v : this.indent
    });
    map.push({
        k : "crs",
        v : this.crs
    });
    map.push({
        k : "format",
        v : this.format
    });

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (AltiRequest);


/***/ }),
/* 70 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _AltiRequest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69);




/**
 * @classdesc
 * Classe de gestion des param. des requêtes de type PROFIL du service altimetrique.
 *
 * @constructor
 * @alias Gp.Services.Alti.Request.AltiProfilRequest
 * @param {Object}   options - options
 * @param {String}   options.sampling - 3
 *
 * @private
 */
function AltiProfilRequest (options) {
    if (!(this instanceof AltiProfilRequest)) {
        throw new TypeError("AltiProfilRequest constructor cannot be called as a function.");
    }

    /**
     * Nom de la classe (heritage)
     */
    this.CLASSNAME = "AltiProfilRequest";

    // appel du constructeur par heritage
    _AltiRequest__WEBPACK_IMPORTED_MODULE_1__["default"].apply(this, arguments);

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur AltiProfilRequest ()]");

    /**
     * Sampling
     * Par defaut, 3
     */
    this.sampling = this.options.sampling || 3; // test des options héritées !
}

/**
 * @lends module:AltiProfilRequest#
 */

AltiProfilRequest.prototype = Object.create(_AltiRequest__WEBPACK_IMPORTED_MODULE_1__["default"].prototype, {

    /**
     * Setter/getter pour "sampling"
     */
    sampling : {
        /** getter */
        get : function () {
            return this._sampling;
        },
        /** setter */
        set : function (value) {
            this._sampling = value;
        }
    }
});

/**
 * Constructeur (alias)
 */
AltiProfilRequest.prototype.constructor = AltiProfilRequest;

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Object[]}
 */
AltiProfilRequest.prototype.getData = function () {
    // par glop..., appel de AltiRequest::getData () !
    var map = [];
    map.push({
        k : "lon",
        v : this.getLon()
    });
    map.push({
        k : "lat",
        v : this.getLat()
    });
    // map.push({k : "delimiter", v : this.delimiter}); // FIXME on retire le param "delimiter"
    map.push({
        k : "indent",
        v : this.indent
    });
    map.push({
        k : "crs",
        v : this.crs
    });
    map.push({
        k : "sampling",
        v : this.sampling
    });
    map.push({
        k : "format",
        v : this.format
    });
    map.push({
        k : "resource",
        v : this.resource
    });

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (AltiProfilRequest);


/***/ }),
/* 71 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Formats_WPS__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(72);
/* harmony import */ var _model_AltiElevationRequest__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(68);
/* harmony import */ var _model_AltiProfilRequest__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70);
/**
 * Classe d'interface des requêtes de type WPS sur le service altimetrique.
 * (Factory)
 *
 * @module Gp.Services.Alti.Request.AltiRequestWPS
 * @alias Gp.Services.Alti.Request.AltiRequestWPS
 * @private
 */






var AltiRequestWPS = {

    /**
     * Interface unique de construction de la requête.
     *
     * @method build
     * @param {Object} options - options
     * @param {Object}   options.param.positions - tableau de coordonnées lon/lat
     * @param {String}   options.param.delimiter - '|'
     * @param {Boolean}  options.param.indent - false|true
     * @param {String}   options.param.crs - 'CRS:84'
     * @param {String}   options.param.sampling - 3
     * @param {Boolean}  options.param.zonly - false|true
     * @param {String}   options.param.format - "JSON|XML" (only to POST)
     * @param {String}   options.wps.service - "WPS"
     * @param {String}   options.wps.version - "1.0.0"
     * @param {String}   options.wps.identifier - "gs:WPSElevation|gs:WPSLineElevation"
     * @param {String}   options.wps.rawdataoutput - "result"
     * @param {String}   options.wps.request - "Execute"
     * @param {String}   options.type - "Profil|Elevation"
     * @param {String}   options.method - GET|POST
     * @example
     *      var options = {
     *           type : 'Profil', // Elevation
     *           method : 'GET',  // par defaut
     *           param : {
     *               positions : [
     *                   {lon:'1.11', lat:'1.11'},
     *                   {lon:'1.10', lat:'1.10'},
     *                   {lon:'1.12', lat:'1.12'}
     *               ],
     *               delimiter : ";",         // par defaut
     *               indent    : true,        // par defaut
     *               crs       : 'EPSG:4326', // par defaut
     *               format    : 'json',      // par defaut (only to POST)
     *               sampling  : 3 ,          // par defaut (only use by Profil)
     *               zonly     : false,       // par defaut (only use by Elevation)
     *           },
     *           wps : {
     *                 service : 'WPS',         // par defaut
     *                 version : '1.0.0',       // par defaut
     *                 identifier : 'gs:WPS',   // par defaut, Elevation = gs:WPSElevation, Profil = gs:WPSLineElevation
     *                 rawdataoutput : 'result',// par defaut
     *                 request : 'Execute'      // par defaut
     *           }
     *       };
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("AltiRequestWPS");
        logger.trace(["AltiRequestWPS::build()"]);

        // existance des options
        if (!options) {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "options"));
        }

        // type de requete : Altitude ou Profil
        // (param. à determiner en fonction des parametres d'entrée)
        if (!options.type) {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "type (Elevation or Profil)"));
        }

        // construction du modele de requête
        // (test du type d'objet candidat)
        var DataObject = null;
        switch (options.type) {
            case "Elevation":
                // surcharge
                options.wps.identifier = "gs:WPSElevation";
                DataObject = new _model_AltiElevationRequest__WEBPACK_IMPORTED_MODULE_3__["default"](options.param);
                break;
            case "Profil":
                // surcharge
                options.wps.identifier = "gs:WPSLineElevation";
                DataObject = new _model_AltiProfilRequest__WEBPACK_IMPORTED_MODULE_4__["default"](options.param);
                break;
            default:
                throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_TYPE", "type (Elevation or Profil)"));
        }

        // construction de la requête WPS
        var settings = {
            data : DataObject,
            method : options.method,
            param : options.wps
        };

        var rqstWPS = new _Formats_WPS__WEBPACK_IMPORTED_MODULE_2__["default"](settings);

        if (!rqstWPS.processRequestString()) {
            throw new Error("Enable to process request !");
        }

        return rqstWPS.requestString;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AltiRequestWPS);


/***/ }),
/* 72 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);


/**
 * @classdesc
 * Standard WPS
 *
 * @constructor
 * @alias Gp.Formats.WPS
 * @param {Object} options - options
 * @param {Object}   options.data - objet
 * @param {String}   options.method - POST|GET
 * @param {String}   options.param.service - "WPS"
 * @param {String}   options.param.version - "1.0.0"
 * @param {String}   options.param.identifier - "gs:WPSElevation|gs:WPSLineElevation"
 * @param {String}   options.param.rawdataoutput - "result"
 * @param {String}   options.param.request - "Execute"
 * @param {Function} options.onsuccess - function callback success (TODO)
 * @param {Function} options.onerror   - function callback error   (TODO)
 * @private
 */
function WPS (options) {
    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur WPS()]");

    if (!(this instanceof WPS)) {
        throw new TypeError("WPS constructor cannot be called as a function.");
    }

    this.options = options || {};

    /**
     * Objet DATA
     */
    this.DataObject = this.options.data;

    if (!this.DataObject) {
        throw new TypeError("This data object is not defined !");
    }

    /**
     * param service.
     * Par defaut, "WPS".
     */
    this.paramservice = this.options.param.service || "WPS";

    /**
     * param version.
     * Par defaut, "1.0.0".
     */
    this.paramversion = this.options.param.version || "1.0.0";

    /**
     * param identifier
     * Par defaut, "gs:WPS"
     */
    this.paramidentifier = this.options.param.identifier || "gs:WPS";

    /**
     * param rawdataoutput
     * Par defaut, "result".
     */
    this.paramrawdataoutput = this.options.param.rawdataoutput || "result";

    /**
     * param request
     * Par defaut, "Execute".
     */
    this.paramrequest = this.options.param.request || "Execute";

    /**
     * methode.
     * Par defaut, "GET".
     */
    this.method = this.options.method || "GET";
}

WPS.prototype = {

    /**
     * @lends module:WPS#
     */

    /**
     * request
     * @type {String}
     */
    requestString : null,

    /**
     * Constructeur (alias)
     */
    constructor : WPS,

    /**
     * Template de la requête.
     */
    template : {
        get : {
            value : "service=__SERVICE__" +
                "&version=__VERSION__" +
                "&rawdataoutput=__RAWDATAOUTPUT__" +
                "&identifier=__IDENTIFIER__" +
                "&request=__REQUEST__" +
                "&datainputs=<!-- __DATAINPUTS__ -->",

            input : "__KEY__=__DATA__"

        },
        post : {

            value : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                "<wps:__REQUEST__ version=\"__VERSION__\" service=\"__SERVICE__\" " +
                "__NAMESPACE__ __SCHEMALOCATION__>" +
                "<ows:Identifier>__IDENTIFIER__</ows:Identifier>" +
                "<wps:DataInputs>" +
                "<!-- __DATAINPUTS__ -->" +
                "</wps:DataInputs>" +
                "<wps:ResponseForm>" +
                "<wps:RawDataOutput>" +
                "<ows:Identifier>__RAWDATAOUTPUT__</ows:Identifier>" +
                "</wps:RawDataOutput>" +
                "</wps:ResponseForm>" +
                "</wps:__REQUEST__>",

            input : "<wps:Input>" +
                "<ows:Identifier>__KEY__</ows:Identifier>" +
                "<wps:Data>" +
                "<wps:LiteralData>__DATA__</wps:LiteralData>" +
                "</wps:Data>" +
                "</wps:Input>"
        }
    },

    /**
     * Namespace par defaut de la requete POST.
     *
     * @returns {String} namespace
     */
    namespaceByDefault : function () {
        var ns = [
            "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
            "xmlns=\"http://www.opengis.net/wps/1.0.0\"",
            "xmlns:wfs=\"http://www.opengis.net/wfs\"",
            "xmlns:wps=\"http://www.opengis.net/wps/1.0.0\"",
            "xmlns:ows=\"http://www.opengis.net/ows/1.1\"",
            "xmlns:gml=\"http://www.opengis.net/gml\"",
            "xmlns:ogc=\"http://www.opengis.net/ogc\"",
            "xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\"",
            "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
        ];

        return ns.join(" ");
    },

    /**
     * Schemalocation par defaut.
     *
     * @returns {String} schemaLocation
     */
    schemaLocationByDefault : function () {
        return "xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\"";
    },

    /**
     * Construction de la requête.
     *
     * @example
     * // GET  out :
     * //  service=__SERVICE__
     * //  &version=__VERSION__
     * //  &rawdataoutput=__RAWDATAOUTPUT__
     * //  &identifier=__IDENTIFIER__
     * //  &request=__REQUEST__
     * //  &datainputs="__DATAINPUTS__"
     * //  avec __DATAINPUTS__ = __KEY__=__DATA__;...
     *
     * // POST out :
     * //      <?xml version=\"1.0\" encoding=\"UTF-8\"?>
     * //      <wps:__REQUEST__ version=\"__VERSION__\" service=\"__SERVICE__\"
     * //         __NAMESPACE__ __SCHEMALOCATION__>
     * //          <ows:Identifier>__IDENTIFIER__</ows:Identifier>
     * //          <wps:DataInputs>
     * //              <!-- __DATAINPUTS__ -->
     * //          </wps:DataInputs>
     * //          <wps:ResponseForm>
     * //              <wps:RawDataOutput>
     * //              <ows:Identifier>__RAWDATAOUTPUT__</ows:Identifier>
     * //              </wps:RawDataOutput>
     * //          </wps:ResponseForm>
     * //      </wps:__REQUEST__>",
     * //      avec __DATAINPUTS__
     * //             <wps:Input>
     * //                  <ows:Identifier>__KEY__</ows:Identifier>
     * //                  <wps:Data>
     * //                    <wps:LiteralData>__DATA__</wps:LiteralData>
     * //                  </wps:Data>
     * //              </wps:Input>
     *
     * @returns {Boolean} validation de la construction de la requete
     */
    processRequestString : function () {
        this.logger.trace("WPS::processRequestString ()");

        var template = "";
        if (this.method === "POST") {
            template = this.template.post.value;
        } else if (this.method === "GET") {
            template = this.template.get.value;
        } else {
            this.logger.error("No other method supported by the service !");
            return false;
        }

        template = template.replace(/__SERVICE__/g, this.paramservice);
        template = template.replace(/__VERSION__/g, this.paramversion);
        template = template.replace(/__RAWDATAOUTPUT__/g, this.paramrawdataoutput);
        template = template.replace(/__IDENTIFIER__/g, this.paramidentifier);
        template = template.replace(/__REQUEST__/g, this.paramrequest);

        // ajout +
        if (this.method === "POST") {
            template = template.replace(/__NAMESPACE__/g, this.namespaceByDefault);
            template = template.replace(/__SCHEMALOCATION__/g, this.schemaLocationByDefault);
        }

        // ajout des datainputs
        template = template.replace(/<!-- __DATAINPUTS__ -->/g, this.__addDataInputs());

        if (!template) {
            this.logger.warn("traduction tmpl : empty request !?");
            return false;
        }

        this.requestString = template;
        this.logger.trace("traduction tmpl", template);

        return true;
    },

    /**
     * Ajout des données
     *
     * @returns {String} Données concaténées dans une chaine
     */
    __addDataInputs : function () {
        this.logger.trace("WPS::__addDataInputs ()");

        // c'est un peu grossier...
        var tmpl = this.method === "GET" ? this.template.get.input : this.template.post.input;
        var sep = this.method === "GET" ? ";" : "";

        var result = "";
        var that = this;
        var map = this.DataObject.getData();
        for (var i = 0; i < map.length; i++) {
            // FIXME closure ?
            (function (j) {
                if (sep) {
                    sep = (j === map.length - 1) ? "" : ";";
                }
                result = result.concat(that.__addDataInput(tmpl, map[j].k, map[j].v), sep);
            })(i);
        }

        return result;
    },

    /**
     * Ajout d'une donnée.
     *
     * @param {String} tmpl - template
     * @param {String} key - clef
     * @param {String} data - valeur
     * @returns {String} chaine avec les substitutions clef/valeur
     */
    __addDataInput : function (tmpl, key, data) {
        var tmp = tmpl;
        tmp = tmp.replace(/__KEY__/g, key);
        tmp = tmp.replace(/__DATA__/g, data);
        return tmp;
    },

    /**
     * Definir le mode de requête
     *
     * @param {String} method - GET|POST
     */
    setMethod : function (method) {
        if (method === "GET" || method === "POST") {
            this.method = method;
        } else {
            this.logger.warn("support only GET and POST method !");
        }
    },

    /**
     * Retourne le mode de requete (GET|POST).
     *
     * @returns {AltiRequest.options.mode|String} methode (GET|POST)
     */
    getMethod : function () {
        return this.method;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (WPS);


/***/ }),
/* 73 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _Formats_XML__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(74);
/* harmony import */ var _Formats_AltiResponseReader__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(75);
/* harmony import */ var _model_AltiResponse__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(76);
/* harmony import */ var _model_Elevation__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(77);
/**
 * Factory pour générer une reponse JSON à partir d'un XML ou d'un JSON
 * (Factory)
 *
 * @module AltiResponseFactory
 * @private
 * @alias Gp.Services.Alti.Response.AltiResponseFactory
 */








var AltiResponseFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Alti
     *
     * @example
     *   var options = {
     *      response :
     *      outputFormat :
     *      rawResponse :
     *      scope :
     *      onSuccess :
     *      onError :
     *   };
     *
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("AltiResponseFactory");
        logger.trace(["AltiResponseFactory::build()"]);

        var data = null;

        if (options.response) {
            if (options.rawResponse) {
                logger.trace("analyze response : raw");
                data = options.response;
            } else {
                switch (options.outputFormat) {
                    case "xml":
                        logger.trace("analyze response : xml");

                        try {
                            var p = new _Formats_XML__WEBPACK_IMPORTED_MODULE_3__["default"]({
                                reader : _Formats_AltiResponseReader__WEBPACK_IMPORTED_MODULE_4__["default"]
                            });

                            if (typeof options.response === "string") {
                                p.setXMLString(options.response);
                            } else {
                                p.setXMLDoc(options.response);
                            }

                            data = p.parse();

                            if (!data) {
                                throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION_2"));
                            }
                        } catch (e) {
                            var message = e.message;
                            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                                message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", message),
                                status : 200,
                                type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR
                            }));
                            return;
                        }

                        break;

                    case "json":
                        logger.trace("analyze response : json");
                        logger.trace("analyze response : ", typeof options.response);

                        var JSONResponse = null;
                        if (typeof options.response === "string") {
                            JSONResponse = JSON.parse(options.response);
                        } else {
                            JSONResponse = options.response;
                        }

                        // le service renvoie t il une erreur ?
                        if (JSONResponse && JSONResponse.error) {
                            // ex. {"error": {"code": "BAD_PARAMETER","description": "The values () cannot be parsed as a valid longitude (double value such as -180 < lat < 180)."}}
                            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                                message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", JSONResponse.error.description),
                                status : 200,
                                type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR
                            }));
                            return;
                        }

                        // analyse de la reponse
                        if (JSONResponse) {
                            var elevations = JSONResponse.elevations;
                            var altiResponse = new _model_AltiResponse__WEBPACK_IMPORTED_MODULE_5__["default"]();
                            var elevation;
                            if (Array.isArray(elevations) && elevations.length) {
                                for (var i = 0; i < elevations.length; i++) {
                                    elevation = new _model_Elevation__WEBPACK_IMPORTED_MODULE_6__["default"]();

                                    if (typeof elevations[i] === "object") {
                                        // elevations[i] est un objet elevation
                                        if (elevations[i].lon) {
                                            elevation.lon = elevations[i].lon;
                                        }
                                        if (elevations[i].lat) {
                                            elevation.lat = elevations[i].lat;
                                        }
                                        if (elevations[i].z) {
                                            elevation.z = elevations[i].z;
                                        }
                                        if (elevations[i].acc) {
                                            elevation.acc = elevations[i].acc;
                                        }
                                        if (elevations[i].measures) {
                                            elevation.measures = elevations[i].measures;
                                        }
                                    } else if (typeof elevations[i] === "number") {
                                        // elevations[i] est un nombre, dans le cas de zonly=true notamment
                                        elevation.z = elevations[i];
                                    }

                                    if (Array.isArray(altiResponse.elevations)) {
                                        altiResponse.elevations.push(elevation);
                                    }
                                }
                            }
                            data = altiResponse;
                        }

                        if (!data) {
                            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                                message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_ANALYSE_2"),
                                type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_UNKERR,
                                status : -1
                            }));
                            return;
                        }
                        break;

                    default:
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                            message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_FORMAT_2"),
                            type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_UNKERR,
                            status : -1
                        }));
                        return;
                }

                // Si la réponse contenait une exception renvoyée par le service
                if (data.exceptionReport) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", data.exceptionReport),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR,
                        status : 200
                    }));
                    return;
                } else if (data.error) {
                    var errorMess = data.error.description;
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", errorMess),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR,
                        status : 200
                    }));
                    return;
                }
            }
        } else {
            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
            return;
        }

        options.onSuccess.call(options.scope, data);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AltiResponseFactory);


/***/ }),
/* 74 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* global require */


// import __xmldom from "xmldom";

/**
 * @classdesc
 *
 * Classe permettant d'écrire ou de lire du XML, sous forme de document DOM,
 * éventuellement selon des clés de lecture (readers) ou d'écriture (writers) spécifiques.
 *
 * @constructor
 * @alias Gp.Formats.XML
 *
 * @param {Object} [options] - options du format XML
 *
 * @param {Object} [options.reader] - Instance d'un Reader de service (AltiResponseReader, GeocodeRequestReader, etc.)
 *      utile pour interpréter le XML lorsque sa structure est connue.
 *      Ce reader doit comporter au moins une fonction statique read (root) permettant d'initialiser la lecture.
 *
 * @param {Object} [options.writers] - writers
 *
 * @param {String} [options.xmlString] - chaîne de caractère contenant du XML à interpréter.
 *
 * @private
 */
function XML (options) {
    if (!(this instanceof XML)) {
        throw new TypeError("XML constructor cannot be called as a function.");
    }

    // FIXME : notion de singleton

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur XML ()]");

    /**
     * Chaîne de caractères contenant le texte XML
     * @type {String}
     */
    this.xmlString = null;

    /**
     * DOM Element correspondant à la structure du XML.
     * @type {DOMElement}
     */
    this.xmlDoc = null;

    /**
     * Objet contenant des fonctions de lecture des différentes balises XML.
     * @type {Object}
     */
    this.reader = null;

    // traitement des paramètres d'options s'il y en a
    if (options) {
        if (options.xmlString && typeof options.xmlString === "string") {
            this.xmlString = options.xmlString;
            // Si une chaine de caractère a été passée en entrée : on la transforme aussi en XML document
            this.xmlDoc = __getXMLDOC(options.xmlString);
        }
        if (options.reader) {
            this.setReader(options.reader);
        }
    }
}

XML.prototype = {

    /**
     * @lends module:XML
     */

    /*
     * Constructeur (alias)
     */
    constructor : XML,

    /**
     * Méthode permettant de récupérer la chaîne de caractères associée au format XML
     *
     * @returns {String} xmlString - la chaîne de caractères correspondant au format XML
     */
    getXMLString : function () {
        return this.xmlString;
    },

    /**
     * Méthode permettant d'attribuer une chaîne de caractères au format XML (attribut xmlString).
     * La méthode va aussi transformer cette chaîne de caractères en document XML,
     * afin de remplir l'attribut xmlDoc.
     *
     * @param {String} xmlString - la chaîne de caractères correspondant au format XML
     */
    setXMLString : function (xmlString) {
        if (xmlString && typeof xmlString === "string") {
            this.xmlString = xmlString;
            this.xmlDoc = __getXMLDOC(xmlString);
        }
    },

    /**
     * Méthode permettant de récupérer les readers associés au format XML, s'ils ont été définis
     *
     * @return {Object} readers - les readers associés au format XML, s'ils existent,
     *      sous forme d'une collection de fonctions
     */
    getReader : function () {
        return this.reader;
    },

    /**
     * Méthode permettant d'attribuer des readers, sous la forme d'un objet de fonctions (node, data),
     *      lorsqu'ils n'ont pas été définis lors de l'instanciation par exemple (new XML (options)).
     *
     * @param {Object} reader - Instance d'un Reader de service (AltiResponseReader, GeocodeRequestReader, etc.)
     *      utile pour interpréter le XML lorsque sa structure est connue.
     *      Ce reader doit comporter au moins une fonction statique read (root) permettant d'initialiser la lecture.
     */
    setReader : function (reader) {
        if (reader && reader.read && typeof reader.read === "function") {
            this.reader = reader;
        }
    },

    /**
     * Méthode permettant de récupérer le document XML associé au format, s'il existe.
     *
     * @return {DOMElement} xmlDoc - le document XML (DOM document node) s'il existe
     */
    getXMLDoc : function () {
        return this.xmlDoc;
    },

    /**
     * Setter
     */
    setXMLDoc : function (doc) {
        this.xmlDoc = doc;
    },
    /**
     * Méthode initialisant la lecture du XML, à partir d'un XML Document :
     *      création d'un objet JavaScript contenant les informations du XML,
     *      sauf dans le cas où il n'existe pas de XML Document à interpréter (retourne un objet vide).
     *
     * @return {Object} [parserOutput] - un objet JavaScript contenant les informations du XML :
     * - soit toutes les informations si aucun reader n'a été spécifié à la création du format
     * - soit les informations spécifiées dans le reader.
     */
    parse : function () {
        // build xml document from xmlString
        if (!this.xmlDoc && this.xmlString) {
            this.xmlDoc = __getXMLDOC(this.xmlString);
        }
        if (this.xmlDoc) {
            var root = __getRootNode(this.xmlDoc);
            if (root) {
                var parserOutput;
                // call reader if exists
                if (this.reader && this.reader.read) {
                    parserOutput = this.reader.read(root);
                } else {
                    parserOutput = {};
                    parserOutput[root.nodeName] = __readDefault(root);
                }
                return parserOutput;
            } else {
                return {};
            }
        }
    }

};

/**
 * Méthode de la classe (privée) permettant de créer un XML Document à partir d'une chaîne de caractères XML,
 *      en utilisant DOMParser () lorsque c'est possible.
 *      For more information, see: https://dvcs.w3.org/hg/innerhtml/raw-file/tip/index.html#the-domparser-interface
 *
 * @private
 * @memberof XML
 * @method __getXMLDOC
 * @param {String} xmlString - xml string to be converted into DOM element
 * @return {DOMElement} - the corresponding XML Document
 */
function __getXMLDOC (xmlString) {
    if (typeof window === "undefined") {
        // env. nodejs
        var DOMParser = __webpack_require__(54).DOMParser; // __xmldom.DOMParser;
        return new DOMParser().parseFromString(xmlString, "text/xml");
    } else {
        // env. browser

        var parser;
        var xmlDoc;
        var errorMsg = "Erreur lors du parsing de la réponse du service : XML non conforme";

        if (window.ActiveXObject) {
            // Internet Explorer < 9
            xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = false;
            xmlDoc.loadXML(xmlString);
            var parseError = xmlDoc.parseError;
            if (parseError.errorCode) {
                if (parseError.line && parseError.linepos) {
                    errorMsg += "( ligne " + parseError.line + ", colonne " + parseError.linepos;
                }
                if (parseError.reason) {
                    errorMsg += ":  " + parseError.reason + ")";
                }
                throw new Error(errorMsg);
            }
            return xmlDoc;
        } else if (window.DOMParser) {
            // les autres (Chrome, Mozilla, IE >= 9)
            parser = new window.DOMParser();
            try {
                xmlDoc = parser.parseFromString(xmlString, "text/xml");
            } catch (e) {
                // Internet Explorer browser raises exception if xmlString is not valid XML
                if (e.message === "SyntaxError") {
                    throw new Error(errorMsg);
                } else {
                    throw new Error("Erreur lors du parsing de la réponse du service : " + e.message);
                }
            }
            // look for parsing error in case no exception was raised
            if (xmlDoc.getElementsByTagName("parsererror").length > 0) {
                var parsererror = xmlDoc.getElementsByTagName("parsererror");
                for (var i = 0; i < parsererror.length; i++) {
                    var content = parsererror[i].innerHTML;
                    // except in case parsererror is just because of huge xml, but parsing is done.
                    if (content.indexOf("Huge input lookup") === -1) {
                        errorMsg += "(" + content + ")";
                        throw new Error(errorMsg);
                    }
                }
            } else if (!xmlDoc.documentElement) { // may happen in chrome browser
                throw new Error(errorMsg);
            }
            return xmlDoc;
        } else {
            // FIXME
            throw new Error("Incompatible DOM Parser pour ce navigateur !");
        }
    }
}

/**
 * Méthode de la classe (privée) permettant de récupérer le noeud racine du document,
 *      à partir d'un document node (nodeType=9), puis lecture de ce noeud (readNode)
 *
 * @private
 * @memberof XML
 * @method __getRootNode
 * @param {DOMElement} [xmlDoc] - a Document Node
 * @return {DOMElement} root - the document root node
 */
function __getRootNode (xmlDoc) {
    var root;
    if (xmlDoc.nodeType === 9) {
        // INFO : nodeType 9 represents the entire document (the root-node of the DOM tree)
        root = xmlDoc.documentElement;
    } else if (xmlDoc.nodeType === 1) {
        root = xmlDoc;
    }
    return root;
}

/**
 * Méthode de la classe (privée) permettant de lire automatiquement un noeud XML,
 *      lorsqu'aucun reader spécifique n'a été spécifié (parser brut)
 *
 * @private
 * @memberof XML
 * @method readDefault
 * @param {DOMElement} node - a DOM element node
 * @example final data object looks like :
 *          data = {
 *              attributeName: attributeValue,
 *              childName: {
 *                  attributeName: attributeValue,
 *                  attributeName: attributeValue,
 *                  childName: {
 *                      "textContent": textContent
 *                  },
 *                  childName: {
 *                      childName: {
 *                          attributeName:attributeValue
 *                      }
 *                  }
 *              }
 *          }
 */
function __readDefault (node) {
    var data = {};

    // if element node has attributes, set their values to data
    if (node.attributes.length > 0) {
        var dataAttributes = __getAttributes(node);
        data["attributes"] = dataAttributes;
    }

    // if element node has childNodes, read them and set them to data
    if (node.hasChildNodes()) {
        var childData = {};
        var child;
        var children = node.childNodes;

        for (var i = 0; i < children.length; i++) {
            child = children[i];

            if (child.nodeType === 3) { // TEXT_NODE
                data["textContent"] = child.nodeValue;
            } else if (child.nodeType === 1) {
                childData = __readDefault(child);

                if (!data[child.nodeName]) {
                    // store childData in an object
                    data[child.nodeName] = childData;
                } else {
                    // in case several childNodes has the same name : store them in an array.
                    // if data[nodeName] already exists but is not an array
                    if (!Array.isArray(data[child.nodeName])) {
                        var old = data[child.nodeName];
                        data[child.nodeName] = [];
                        data[child.nodeName].push(old);
                    }
                    data[child.nodeName].push(childData);
                }
            }
            // TODO : manage other node types (4=CDATA, etc)
        }
    }

    return data;
}

/**
 * Méthode de la classe (privée) permettant de récupérer les attributs d'un noeud élément
 *
 * @private
 * @memberof XML
 * @method __getAttributes
 * @param {DOMElement} node - noeud contenant l'attribut recherché
 * @return {Object} nodeAttributes - objet contenant les noms et valeurs des différents attributs
 */
function __getAttributes (node) {
    if (node.attributes.length > 0) {
        var nodeAttributes = {};
        var attributes = node.attributes;
        for (var i = 0; i < attributes.length; i++) {
            var attribute = attributes[i];
            nodeAttributes[attribute.nodeName] = attribute.nodeValue;
        }
        return nodeAttributes;
    }
}

/* harmony default export */ __webpack_exports__["default"] = (XML);


/***/ }),
/* 75 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Response_model_AltiResponse__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(76);
/* harmony import */ var _Response_model_Elevation__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(77);
/* harmony import */ var _Response_model_Measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(78);

/**
 * Fonction retournant un objet contenant des clés de lecture (readers)
 *      qui permettent de parser des réponses XML du service Altimétrique du Géoportail
 *      (calcul altimétrique simple ou profil altimétrique d'une courbe),
 *      lorsque le paramètre output = xml,
 *      afin de récupérer les élévations retournées.
 *
 * @module AltiResponseReader
 * @alias Gp.Services.Alti.Formats.AltiResponseReader
 * @private
 */

// import Logger from "../../../Utils/LoggerByDefault";




/**
 *
 * Objet AltiResponseReader
 *
 * @member {Object} AltiResponseReader
 *
 * @property {Object} AltiResponseReader.READERS - Objet contenant des fonctions de lecture, appelées "readers"
 *      dont chaque clé correspond au nom d'un tag du XML que l'on souhaite lire
 *      et la valeur associée est une fonction (node, data)
 *      où node est un noeud du document DOM
 *      et data est un objet où l'on stocke les informations lues dans le XML.
 *
 * @property {Method} AltiResponseReader.READERS.elevations -  Lecture d'un noeud "elevations" de la réponse XML
 *      du service alti, correspondant logiquement à la racine du document
 *      (contient un ou plusieurs childNodes correspondant chacun à une élévation retournée)
 *
 * @property {Method} AltiResponseReader.READERS.elevation - Lecture d'un noeud "elevation" de la réponse xml du service alti.
 *      (contient un ou 4 childNode (s) correspondant à l'altitude (z) et éventuellement lat, lon, et acc)
 *
 * @property {Method} AltiResponseReader.READERS.lat - Lecture d'un noeud "lat" de la réponse xml du service alti.
 *      (contient une valeur de latitude, qui est un flottant)
 *
 * @property {Method} AltiResponseReader.READERS.lon - Lecture d'un noeud "lon" de la réponse xml du service alti.
 *      (contient une valeur de longitude, qui est un flottant)
 *
 * @property {Method} AltiResponseReader.READERS.z - Lecture d'un noeud "z" de la réponse xml du service alti.
 *      (contient une valeur d'altitude, qui est un flottant)
 *
 * @property {Method} AltiResponseReader.READERS.acc - Lecture d'un noeud "acc" de la réponse xml du service alti.
 *      (contient une valeur de précision, qui est un flottant)
 *
 * @property {Method} AltiResponseReader.READERS.measures - Lecture d'un noeud "measures" de la réponse xml du service alti.
 *      (contient une valeur de précision, qui est un flottant)
 *
 * @property {Method} AltiResponseReader.READERS.source_name - Lecture d'un noeud "source_name" de la réponse xml du service alti.
 *      (pour remplir l'éventuel objet measure)
 *
 * @property {Method} AltiResponseReader.READERS.source_mesure - Lecture d'un noeud "source_mesure" de la réponse xml du service alti.
 *      (pour remplir l'éventuel objet measure)
 *
 * @property {Method} AltiResponseReader.READERS.exceptionreport - Lecture d'un noeud "ExceptionReport" de la réponse xml du service alti.
 *
 * @property {Method} AltiResponseReader.READERS.exception - Lecture d'un noeud "Exception" de la réponse xml du service alti.
 *
 * @property {Method} AltiResponseReader.read - Méthode permettant de lancer la lecture d'une réponse XML du service altimétrique,
 *      à l'aide des readers de la classe.
 *
 */
var AltiResponseReader = {};

AltiResponseReader.READERS = {

    /**
     * Lecture d'un noeud "elevations" de la réponse XML du service alti, correspondant logiquement à la racine du document
     *      (contient un ou plusieurs childNodes correspondant chacun à une élévation retournée)
     *
     * @param {DOMElement} root - racine de la réponse XML
     * @static
     * @memberof AltiResponseReader
     * @returns {Object} Retourne un objet de type AltiResponse
     */
    elevations : function (root) {
        // INFO : on passe en paramètre l'objet en entrée elevations, vide, à remplir.
        var altiResponse = new _Response_model_AltiResponse__WEBPACK_IMPORTED_MODULE_0__["default"]();

        if (root.hasChildNodes()) {
            var children = root.childNodes;
            var child;
            var elevation;

            for (var i = 0; i < children.length; i++) {
                child = children[i];

                if (AltiResponseReader.READERS[child.nodeName]) {
                    elevation = AltiResponseReader.READERS[child.nodeName](child);
                    altiResponse.elevations.push(elevation);
                }
            }
        }

        return altiResponse;
    },

    /**
     * Lecture d'un noeud "elevation" de la réponse xml du service alti.
     *      (contient un ou 5 childNode (s) correspondant à l'altitude (z) et éventuellement lat, lon, acc et measures)
     *
     * @param {DOMElement} node - noeud elevation à lire pour récupérer les informations de l'élévation retournée (z [, lon, lat, acc, measures])
     * @return {Array} elevationResponse - format de la réponse en sortie, instance de AltiResponse
     * @static
     * @memberof AltiResponseReader
     */
    elevation : function (node) {
        var elevation = new _Response_model_Elevation__WEBPACK_IMPORTED_MODULE_1__["default"]();

        if (node.hasChildNodes()) {
            var children = node.childNodes;
            var child;
            for (var i = 0; i < children.length; i++) {
                child = children[i];
                if (AltiResponseReader.READERS[child.nodeName]) {
                    // INFO : on passe en paramètre l'objet en entrée elevation, vide, à remplir.
                    AltiResponseReader.READERS[child.nodeName](child, elevation);
                }
            }
        }
        return elevation;
    },

    /**
     * Lecture d'un noeud "lat" de la réponse xml du service alti.
     *      (contient une valeur de latitude, qui est un flottant)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la latitude
     * @param {Object} elevation - objet dans lequel stocker la latitude retournée
     * @static
     * @memberof AltiResponseReader
     */
    lat : function (node, elevation) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            elevation.lat = parseFloat(textNode.nodeValue);
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : latitude attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "lon" de la réponse xml du service alti.
     *      (contient une valeur de longitude, qui est un flottant)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la longitude
     * @param {Object} elevation - objet dans lequel stocker la longitude retournée
     * @static
     * @memberof AltiResponseReader
     */
    lon : function (node, elevation) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            elevation.lon = parseFloat(textNode.nodeValue);
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : longitude attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "z" de la réponse xml du service alti.
     *      (contient une valeur d'altitude, qui est un flottant)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer l'altitude
     * @param {Object} elevationObject - objet dans lequel stocker l'altitude retournée : elevation ou measure
     * @static
     * @memberof AltiResponseReader
     */
    z : function (node, elevationObject) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            if (elevationObject) {
                elevationObject.z = parseFloat(textNode.nodeValue);
            } else {
                elevationObject = new _Response_model_Elevation__WEBPACK_IMPORTED_MODULE_1__["default"]();
                elevationObject.z = parseFloat(textNode.nodeValue);
                return elevationObject;
            }
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : altitude attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "acc" de la réponse xml du service alti.
     *      (contient une valeur de précision, qui est un flottant)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la précision
     * @param {Object} elevationObject - objet dans lequel stocker la précision retournée : elevation ou measure
     * @static
     * @memberof AltiResponseReader
     */
    acc : function (node, elevationObject) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            elevationObject.acc = parseFloat(textNode.nodeValue);
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : précision (acc) attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "source_name" de la réponse xml du service alti.
     *      (contient le nom de la source, qui est un string)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la précision
     * @param {Object} measure - objet dans lequel stocker le nom de la source retourné
     * @static
     * @memberof AltiResponseReader
     */
    source_name : function (node, measure) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            measure.source_name = textNode.nodeValue;
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : source_name attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "source_measure" de la réponse xml du service alti.
     *      (contient le nom de la mesure, qui est un string)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la précision
     * @param {Object} measure - objet dans lequel stocker le nom de la source retourné
     * @static
     * @memberof AltiResponseReader
     */
    source_measure : function (node, measure) {
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            measure.source_measure = textNode.nodeValue;
        } else {
            throw new Error("Erreur dans la lecture de la réponse du service : source_measure attendue mais absente");
        }
    },

    /**
     * Lecture d'un noeud "measures" et de ses enfants "measure" de la réponse xml du service alti.
     *      (contient une valeur de précision, qui est un flottant)
     *
     * @param {DOMElement} node - noeud à lire pour récupérer la précision
     * @param {Object} elevation - objet dans lequel stocker la précision retournée
     * @static
     * @memberof AltiResponseReader
     */
    measures : function (node, elevation) {
        elevation.measures = [];
        var measure;
        if (node.hasChildNodes()) {
            var children = node.childNodes;
            var measureNode;
            var measureChildren;
            for (var i = 0; i < children.length; i++) {
                measure = new _Response_model_Measure__WEBPACK_IMPORTED_MODULE_2__["default"]();
                measureNode = children[i];
                measureChildren = measureNode.childNodes;
                for (var j = 0; j < measureChildren.length; j++) {
                    if (AltiResponseReader.READERS[measureChildren[j].nodeName]) {
                        // INFO : on passe en paramètre l'objet en entrée elevation, vide, à remplir.
                        AltiResponseReader.READERS[measureChildren[j].nodeName](measureChildren[j], measure);
                    } else {
                        throw new Error("Erreur dans la lecture de la réponse du service : measures attendues mais absentes");
                    }
                }
                elevation.measures.push(measure);
            }
        }
    },

    /**
     * Lecture d'un noeud "ExceptionReport" de la réponse xml du service alti.
     *
     * @param {DOMElement} node - noeud à lire pour récupérer l'exception
     * @return {Object} exceptionReport - objet contenant l'exception
     * @static
     * @memberof AltiResponseReader
     */
    exceptionreport : function (node) {
        var response = {};

        if (node.hasChildNodes()) {
            var children = node.childNodes;
            var child;
            for (var i = 0; i < children.length; i++) {
                child = children[i];
                if (child.nodeName === "Exception") {
                    response.exceptionReport = AltiResponseReader.READERS.exception(child);
                }
            }
        }

        return response;
    },

    /**
     * Lecture d'un noeud "Exception" de la réponse xml du service alti.
     *
     * @param {DOMElement} node - noeud à lire pour récupérer l'exception
     * @return {Object} exceptionReport - objet contenant l'exception, avec deux attributs :
     *      {String} exceptionReport.exceptionCode - qui contient l'identifiant du code de l'exception
     *      {String} exceptionReport.exception - qui contient le message de l'exception
     * @static
     * @memberof AltiResponseReader
     */
    exception : function (node) {
        var exceptionReport = {};

        // get exception code
        var exceptionCode = node.getAttribute("exceptionCode");
        if (exceptionCode) {
            exceptionReport.exceptionCode = exceptionCode;
        }

        // get exception message
        var textNode = node.firstChild;
        if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
            exceptionReport.exception = textNode.nodeValue;
        }

        return exceptionReport;
    },

    /**
     * Lecture d'un noeud "Error" de la réponse xml du service alti.
     *
     * @param {DOMElement} node - noeud à lire pour récupérer l'exception
     * @return {Object} error - objet contenant l'exception
     * @static
     */
    error : function (node) {
        var response = {
            error : {}
        };
        // get error code and description
        if (node.hasChildNodes()) {
            var children = node.childNodes;
            var child;
            for (var i = 0; i < children.length; i++) {
                child = children[i];
                var textNode;
                // get error code
                if (child.nodeType === 1 && child.nodeName === "code") { // 1 === node.ELEMENT_NODE
                    textNode = child.firstChild;
                    if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
                        response.error.code = textNode.nodeValue;
                    }
                }
                // get error description
                if (child.nodeType === 1 && child.nodeName === "description") { // 1 === node.ELEMENT_NODE
                    textNode = child.firstChild;
                    if (textNode && textNode.nodeType === 3) { // 3 === node.TEXT_NODE
                        response.error.description = textNode.nodeValue;
                    }
                }
            }
        }
        return response;
    }

};

/**
 * Méthode permettant de lancer la lecture d'une réponse XML du service altimétrique,
 *      à l'aide des readers de la classe.
 *
 * @method AltiResponseReader.read
 * @param {DOMElement} root - racine de la réponse XML à lire
 * @static
 * @memberof AltiResponseReader
 */
AltiResponseReader.read = function (root) {
    if (root.nodeName === "elevations") {
        var altiResponse = AltiResponseReader.READERS.elevations(root);
        return altiResponse;
    } else if (root.nodeName === "ExceptionReport") {
        var exceptionReport = AltiResponseReader.READERS.exceptionreport(root);
        return exceptionReport;
    } else if (root.nodeName === "error") {
        var error = AltiResponseReader.READERS.error(root);
        return error;
    } else {
        throw new Error("Erreur lors de la lecture de la réponse : elle n'est pas au format attendu.");
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AltiResponseReader);


/***/ }),
/* 76 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Response object for {@link module:Services~getAltitude Gp.Services.getAltitude ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Array.<Gp.Services.Alti.Elevation>} elevations - Elevations array.
 *
 * @namespace
 * @alias Gp.Services.AltiResponse
 */
function AltiResponse () {
    if (!(this instanceof AltiResponse)) {
        throw new TypeError("AltiResponse constructor cannot be called as a function.");
    }

    this.elevations = [];
}

AltiResponse.prototype = {

    constructor : AltiResponse

};

/* harmony default export */ __webpack_exports__["default"] = (AltiResponse);


/***/ }),
/* 77 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Single elevation object returned by underlying web service. Contains at least, one elevation (z). May also contain point coordinates and elevation accuracy if "zonly" parameter wasn't set to true.
 *
 * @property {Float} lat - Point latitude. (only if zonly=false)
 * @property {Float} lon - Point longitude. (only if zonly=false)
 * @property {Float} z - Point elevation.
 * @property {Float} acc - Accuracy of elevation for this point. (only if zonly=false)
 *
 * @namespace
 * @alias Gp.Services.Alti.Elevation
 */
function Elevation () {
    if (!(this instanceof Elevation)) {
        throw new TypeError("Elevation constructor cannot be called as a function.");
    }

    this.z = null;
}

Elevation.prototype = {

    constructor : Elevation

};

/* harmony default export */ __webpack_exports__["default"] = (Elevation);


/***/ }),
/* 78 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Single measure object returned by underlying web service if measures = true and zonly = false
 *
 * @property {String} source_name - Name of the source
 * @property {String} source_measure - Name of the measure
 * @property {Float} z - Point elevation.
 * @property {Float} acc - Accuracy of elevation for this point. (only if zonly=false)
 *
 * @namespace
 * @alias Gp.Services.Alti.Measure
 */
function Measure () {
    if (!(this instanceof Measure)) {
        throw new TypeError("Measure constructor cannot be called as a function.");
    }

    this.source_name = null;
    this.source_measure = null;
    this.z = null;
    this.acc = null;
}

Measure.prototype = {

    constructor : Measure

};

/* harmony default export */ __webpack_exports__["default"] = (Measure);


/***/ }),
/* 79 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(63);
/* harmony import */ var _Request_GeocodeRequestFactory__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(80);
/* harmony import */ var _Response_GeocodeResponseFactory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(83);








/**
 * @classdesc
 * Appel du service de géocodage direct du Géoportail :
 *     envoi de la requête construite selon les paramètres en options,
 *     éventuellement parsing et analyse  de la réponse,
 *     retour d'une réponse en paramètre de la fonction onSuccess.
 *
 *
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.Geocode
 *
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {String|Object} options.query - Nom de l'adresse, du toponyme, de l'unité administrative ou de la parcelle cadastrale recherchée.
 *
 * @param {Object} [options.filters] - Les propriétés possibles de cet objet sont décrites ci-après.
 * @param {String} [options.filters.[prop]] - Critère supplémentaire pour filtrer la recherche sous la forme
 *      d'un couple clé/valeur à définir selon les possibilités du serveur ajouté à la requête.
 *      Le service de géocodage du Géoportail permet de filtrer les adresses postales avec les propriétés :
 *          "postalCode", "inseeCode", "city".
 *      Il permet également de filtrer les toponymes avec les propriétés :
 *          "postalCode", "inseeCode", "type".
 *      Enfin, il permet de filtrer les parcelles cadastrales avec les propriétés :
 *          "codeDepartement", "codeCommune", "nomCommune", "codeCommuneAbs", "codeArrondissement", "section", "numero", "feuille".
 *
 * @param {String} [options.index = "StreetAddress"] - Type de l'objet recherché.
 *      Le service de géocodage du Géoportail permet de rechercher des 'PositionOfInterest' pour des toponymes, des 'StreetAddress'
 *      pour des adresses postales ou des 'CadastralParcel' pour des parcelles cadastrales.
 *      L'index 'location' regroupe les indexes 'StreetAddress' et 'PositionOfInterest'.
 *      D'autres types pourront être rajoutés selon l'évolution du service.
 *      Par défaut, index = 'StreetAddress'.
 *
 * @param {Object} options.position - Position du point de référence pour le calcul de proximité exprimée dans le système de référence spécifié par le srs.
 *      @param {Float} options.position.lon - Longitude du point de référence pour le calcul de proximité.
 *      @param {Float} options.position.lat - Latitude du point de référence pour le calcul de proximité.
 *
 * @param {Number} [options.maximumResponses] - Nombre de réponses maximal que l'on souhaite recevoir.
 *      Pas de valeur par défaut.
 *      Si le serveur consulté est celui du Géoportail, la valeur par défaut sera donc celle du service : 20.
 *
 * @param {Boolean} [options.returnTrueGeometry = false] - Booléen indiquant si l'on souhaite récupérer la géométrie vraie des objects géolocalisés.
 *      false par défaut.
 *
 *
 * @example
 *   var options = {
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      proxyURL : null,
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      position : {lon:, lat:},
 *      index : 'StreetAddress',
 *      query : '10 rue du pont Machin-ville'
 *      (...)
 *   };
 */
function Geocode (options_) {
    if (!(this instanceof Geocode)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "Geocode"));
    }

    /**
     * Nom de la classe (heritage)
     * FIXME instance ou classe ?
     */
    this.CLASSNAME = "Geocode";

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Services.Geocode");
    this.logger.trace("[Constructeur Geocode (options)]");

    var options = this.patchOptionConvertor(options_);
    if (!options.serverUrl) {
        options.serverUrl = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__["default"].Geocode.newUrl();
    }

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].apply(this, [options]);

    if (!options.hasOwnProperty("query")) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "query"));
    }

    // ajout des options spécifiques au service
    this.options.query = options.query;

    // on definit l'index par defaut
    if (!options.index) {
        this.options.index = options.index = "StreetAddress";
    }

    if (options.filters) {
        var filter = Object.keys(options.filters);
        for (var i = 0; i < filter.length; i++) {
            var key = filter[i];
            // on supprime les filtres vides
            if (typeof options.filters[key] === "undefined" ||
                (typeof options.filters[key] === "object" && Object.keys(options.filters[key]).length === 0) ||
                (typeof options.filters[key] === "string" && options.filters[key].length === 0) ||
                (Array.isArray(options.filters[key]) && options.filters[key].length === 0)
            ) {
                delete this.options.filters[key];
            }
        }
    }

    this.options.index = options.index || "StreetAddress";
    this.options.maximumResponses = options.maximumResponses || 20;
}

/**
 * @lends module:Geocode#
 */
Geocode.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].prototype, {
    // todo
    // getter/setter
});

/*
 * Constructeur (alias)
 */
Geocode.prototype.constructor = Geocode;

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Object} options_ - options du service
 * @return {Object} - options
 */
Geocode.prototype.patchOptionConvertor = function (options_) {
    const options = options_;

    if (options.hasOwnProperty("location")) {
        this.logger.warn("The parameter 'location' is deprecated");

        if (!options.query) {
            options.query = options.location;
        }
        delete options.location;
    }

    if (options.filterOptions) {
        this.logger.warn("The parameter 'filterOptions' is deprecated");

        if (!options.filters) {
            options.filters = options.filterOptions;

            if (options.filters.type) {
                this.logger.warn("The parameter 'filterOptions.type' is deprecated");
                if (!options.index) {
                    if (Array.isArray(options.filters.type) && options.filters.type.length > 0) {
                        options.index = options.filters.type[0];
                    } else {
                        options.index = options.filters.type;
                    }
                }
                delete options.filters.type;
            }

            if (options.filters.bbox) {
                this.logger.warn("The parameter 'filterOptions.bbox' is deprecated");
                delete options.filters.bbox;
            }
        }
        delete options.filterOptions;
    }

    if (options.position) {
        if (options.position.x) {
            this.logger.warn("The parameter 'position.x' is deprecated");

            if (!options.position.lon) {
                options.position.lon = options.position.x;
            }
            delete options.position.x;
        }

        if (options.position.y) {
            this.logger.warn("The parameter 'position.y' is deprecated");

            if (!options.position.lat) {
                options.position.lat = options.position.y;
            }
            delete options.position.y;
        }
    }

    if (options.returnFreeForm) {
        this.logger.warn("The parameter 'returnFreeForm' is deprecated");
        delete options.returnFreeForm;
    }

    if (options.srs) {
        this.logger.warn("The parameter 'srs' is deprecated");
        delete options.srs;
    }

    return options;
};

/**
 * Création de la requête (overwrite)
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Geocode.prototype.buildRequest = function (error, success) {
    var options = {
        httpMethod : this.options.httpMethod,
        // options specifiques du service
        geocodeMethod : "search",
        query : this.options.query,
        index : this.options.index,
        returnTrueGeometry : this.options.returnTrueGeometry,
        position : this.options.position,
        maxResp : this.options.maximumResponses,
        filters : this.options.filters
    };

    this.request = _Request_GeocodeRequestFactory__WEBPACK_IMPORTED_MODULE_5__["default"].build(options);

    // on teste si la requete a bien été construite !
    (!this.request)
        ? error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_REQUEST_BUILD")))
        : success.call(this, this.request);
};

/**
 * Analyse de la reponse (overwrite)
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Geocode.prototype.analyzeResponse = function (error, success) {
    /* INFO :
         Etape 1 : Création de la requête (URL)
            -> stockage de la requête dans this.request
         Etape 2 : Envoi de la requête
            -> appel du protocol XHR, et envoi (par ex send ())
            -> récupération de la réponse JSON dans la fonction onSuccess () (this.response)
            -> si code HTTP 200 et pas de message d'erreur : etape 3
            -> si code HTTP != 200 : lancement de la fonction de callback onFailure avec le message d'erreur
         Etape 3 : Analyse de la réponse JSON (si rawResponse === false )
            -> appel du parser pour récupérer le document
         Etape 4 : Lancement de la fonction de callback onSuccess avec la réponse :
            -> JSON (si rawResponse === true)
            -> ou geocodedLocations
    */

    if (this.response) {
        var options = {
            response : this.response,
            rawResponse : this.options.rawResponse,
            onError : error,
            onSuccess : success,
            scope : this
        };

        _Response_GeocodeResponseFactory__WEBPACK_IMPORTED_MODULE_6__["default"].build(options);
    } else {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/* harmony default export */ __webpack_exports__["default"] = (Geocode);


/***/ }),
/* 80 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _GeocodeRequestREST__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(81);



/**
 * Creation d'une requête
 * (Factory)
 *
 * @module GeocodeRequestFactory
 * @alias Gp.Services.Geocode.Request.GeocodeRequestFactory
 * @private
 */
var GeocodeRequestFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Geocode
     *
     * @example
     *   var options = {
     *      // options specifiques du service
     *      geocodeMethod:
     *      query:
     *      filters:
     *      maximumResponses:
     *   };
     *   var result = GeocodeRequestFactory.build(options);
     *   if (!result) {
     *       // error...
     *   }
     * @returns {String} request
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("GeocodeRequestFactory");
        logger.trace(["GeocodeRequestFactory::build()"]);

        var settings = options || {};

        var myReq = new _GeocodeRequestREST__WEBPACK_IMPORTED_MODULE_1__["default"](settings);
        if (!myReq.processRequestString()) {
            throw new Error("Error process request (rest) !");
        }
        var request = myReq.requestString;

        logger.trace(request);

        return request;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (GeocodeRequestFactory);


/***/ }),
/* 81 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _model_GeocodeParamREST__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(82);





/**
 * @classdesc
 * Classe de gestion des requêtes de type REST sur le service de calcul d'itineraire
 * (uniquement en GET)
 *
 * @constructor
 * @alias Gp.Services.Geocode.Request.GeocodeRequestREST
 * @param {Object} options - options definies dans le composant Route
 *
 * @example
 * var options = {
 *      (...)
 * };
 *
 * @private
 */
function GeocodeRequestREST (options) {
    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("GeocodeRequestREST");
    this.logger.trace("[Constructeur GeocodeRequestREST ()]");

    if (!(this instanceof GeocodeRequestREST)) {
        throw new TypeError("GeocodeRequestREST constructor cannot be called as a function.");
    }

    // existance des options
    if (!options) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "options"));
    }

    /** liste des options */
    this.settings = options;
}

GeocodeRequestREST.prototype = {

    /**
     * @lends module:GeocodeRequestREST#
     */

    /**
     * request
     * @type {String}
     */
    requestString : null,

    /**
     * Constructeur (alias)
     */
    constructor : GeocodeRequestREST,

    /**
     * Construction de la requête.
     *
     * @returns {String} request
     */
    processRequestString : function () {
        var request = "";

        // Mapping des options avec le service de l'API REST
        const oParams = new _model_GeocodeParamREST__WEBPACK_IMPORTED_MODULE_2__["default"](this.settings);

        const params = oParams.getParams();
        for (var i = 0; i < params.length; i++) {
            var o = params[i];
            if (request) {
                request += "&";
            }
            request += o.k + "=" + o.v;
        }

        if (!this.settings.geocodeMethod || (this.settings.geocodeMethod !== "search" && this.settings.geocodeMethod !== "reverse")) {
            throw new Error("Error geocodeMethod not valid");
        }

        this.requestString = "?" + request;
        this.logger.trace(this.requestString);

        return this.requestString;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (GeocodeRequestREST);


/***/ }),
/* 82 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);



/**
 * @classdesc
 * Classe de gestion des param. des requêtes du service de calcul d'itineraire (REST).
 *      Permet le mapping avec les options du service.
 * @constructor
 * @alias Gp.Services.Route.Request.RouteParamREST
 * @param {Object} options - options
 *
 * @private
 */
function GeocodeParamREST (options) {
    if (!(this instanceof GeocodeParamREST)) {
        throw new TypeError("GeocodeParamREST constructor cannot be called as a function.");
    }

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur GeocodeParamREST ()]");

    /**
     * Options en paramêtres du constructeur.
     */
    this.options = options || {};

    // methode de geocodage
    if (!this.options.geocodeMethod || (this.options.geocodeMethod !== "search" && this.options.geocodeMethod !== "reverse")) {
        throw new Error("Error geocodeMethod not valid");
    }
    this.geocodeMethod = this.options.geocodeMethod;

    // mapping des options avec l'API REST
    this.query = (typeof this.options !== "undefined") ? this.options.query : null;

    this.searchGeometry = this.options.searchGeometry || null;

    this.index = this.options.index || null;

    this.lon = this.options.position && this.options.position.lon ? this.options.position.lon : null;

    this.lat = this.options.position && this.options.position.lat ? this.options.position.lat : null;

    this.maxResp = this.options.maxResp || null;

    this.returnTrueGeometry = this.options.returnTrueGeometry || null;

    this.filters = this.options.filters || {};
}

/**
 * CLASSNAME
 */
GeocodeParamREST.CLASSNAME = "GeocodeParamREST";

GeocodeParamREST.prototype = {

    /**
     * @lends module:GeocodeParamREST#
     */

    /**
     * Constructeur (alias)
     */
    constructor : GeocodeParamREST,

    /**
     * Retourne les filtres
     * @returns {String} les filtres
     */
    getFilters : function () {
        var filters = {};
        for (var prop in this.filters) {
            if (this.filters.hasOwnProperty(prop)) {
                filters[prop] = this.filters[prop];
            }
        }
        return filters;
    },

    /**
     * Retourne l'index
     * @returns {String} l'index
     */
    getIndex : function () {
        if (this.index === undefined) {
            return null;
        }
        if (this.index === "StreetAddress") {
            return "address";
        } else if (this.index === "CadastralParcel") {
            return "parcel";
        } else if (this.index === "PositionOfInterest") {
            return "poi";
        } else if (this.index === "location") {
            return "location";
        }
        return this.index;
    },

    /**
     * Retourne la géométrie de recherche
     * @returns {String} la géométrie de recherche au format json
     */
    getSearchGeometry : function () {
        return JSON.stringify(this.searchGeometry);
    }
};

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Array} liste de paramêtres
 */
GeocodeParamREST.prototype.getParams = function () {
    var map = [];

    if (this.geocodeMethod === "search") {
        map.push({
            k : "q",
            v : this.query
        });
    }

    if (this.index) {
        map.push({
            k : "index",
            v : this.getIndex()
        });
    }

    if (this.geocodeMethod === "reverse" && this.searchGeometry) {
        map.push({
            k : "searchgeom",
            v : this.getSearchGeometry()
        });
    }

    if (this.lon && this.lat) {
        map.push({
            k : "lon",
            v : this.lon
        });
        map.push({
            k : "lat",
            v : this.lat
        });
    }

    if (this.maxResp) {
        map.push({
            k : "limit",
            v : this.maxResp
        });
    }

    if (this.returnTrueGeometry) {
        map.push({
            k : "returntruegeometry",
            v : this.returnTrueGeometry
        });
    }

    const filters = this.getFilters();
    for (var key in filters) {
        map.push({
            k : key,
            v : filters[key]
        });
    }

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (GeocodeParamREST);


/***/ }),
/* 83 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(61);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Formats_GeocodeResponseParser__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84);
/**
 * Factory pour générer une reponse JSON à partir d'un XML
 * (Factory)
 *
 * @module GeocodeResponseFactory
 * @alias Gp.Services.Geocode.Response.GeocodeResponseFactory
 * @private
 */
// import Logger from "../../../Utils/LoggerByDefault";




var GeocodeReponseFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Geocode
     *
     * @example
     *   var options = {
     *      response :
     *      rawResponse :
     *      scope :
     *      onSuccess :
     *      onError :
     *   };
     *
     */
    build : function (options) {
        // data de type GeocodeResponse
        var data = null;

        if (options.response) {
            if (options.rawResponse) {
                data = options.response;
            } else {
                try {
                    const parser = new _Formats_GeocodeResponseParser__WEBPACK_IMPORTED_MODULE_2__["default"]();
                    data = parser.parse(options.response);

                    if (!data) {
                        throw new Error("L'analyse de la réponse du service !?");
                    }
                } catch (e) {
                    var message = e.message;
                    if (typeof options.response === "string") {
                        message += "('" + options.response + "')";
                    } else {
                        message += "('" + options.response.documentElement.innerHTML + "')";
                    }
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_ANALYSE", message),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_UNKERR,
                        status : -1
                    }));
                    return;
                }

                // Si la réponse contenait une exception renvoyée par le service
                if (data.exceptionReport) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", data.exceptionReport),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_SRVERR,
                        status : 200 // FIXME : 200 ?
                    }));
                    return;
                }
            }
        } else {
            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"]({
                message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY"),
                type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_0__["default"].TYPE_SRVERR,
                status : -1 // FIXME : status response
            }));
            return;
        }

        options.onSuccess.call(options.scope, data);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (GeocodeReponseFactory);


/***/ }),
/* 84 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(61);
/* harmony import */ var _Response_model_GeocodeResponse__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(85);
/* harmony import */ var _Response_model_GeocodedLocation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(86);
// import Logger from "../../../Utils/LoggerByDefault";





/**
 * Fonction retournant un objet contenant des clés de lecture (readers)
 *      qui permettent de parser des réponses XML du service de géocodage direct du Géoportail
 *      afin de récupérer les résultats retournés.
 * @module GeocodeResponseParser
 * @alias Gp.Services.Geocode.Formats.GeocodeResponseParser
 * @private
 */

/**
 * @classdesc
 *
 * Classe permettant de parser une réponse GeoJSON
 *
 * @constructor
 * @alias Gp.Formats.GeocodeResponseParser
 *
 * @private
 */
function GeocodeResponseParser () {
    if (!(this instanceof GeocodeResponseParser)) {
        throw new TypeError("GeocodeResponseParser constructor cannot be called as a function.");
    }
}

GeocodeResponseParser.prototype = {

    /**
     * @lends module:GeocodeResponseParser
     */

    /*
     * Constructeur (alias)
     */
    constructor : GeocodeResponseParser,

    /**
     * Méthode permettant de lancer la lecture d'une réponse GeoJSON,
     *
     * @param {String} json - réponse au format GeoJSON
     * @return {Object} geocodeResponse|exceptionReport : l'objet contenant les informations de la réponse GeoJSON,
     *      sous la forme d'un objet GeocodeResponse, ou un objet littéral exceptionReport si le service a renvoyé une exception.
     */
    parse : function (json) {
        var geocodeResponse = new _Response_model_GeocodeResponse__WEBPACK_IMPORTED_MODULE_2__["default"]();

        const obj = JSON.parse(json);

        if (obj.type === "FeatureCollection") {
            for (var i = 0; i < obj.features.length; ++i) {
                _parseFeature(obj.features[i], geocodeResponse);
            }
        } else if (obj.type === "Feature") {
            _parseFeature(obj, geocodeResponse);
        } else if (obj.type === "SERVICE_ERROR") {
            return _parseError(obj);
        } else {
            var mess = _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_0__["default"].getMessage("SERVICE_RESPONSE_ANALYSE", obj.type);
            throw new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"]({
                message : mess,
                type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"].TYPE_UNKERR,
                status : 200
            });
        }

        return geocodeResponse;
    }
};

/**
 * Méthode permettant de parser un feature
 *
 * @private
 *
 * @param {Object} feature
 * @param {Object} geocodeResponse
 *
 * @memberof GeocodeResponseParser
 * @return {Object} objet GeocodedLocation
 */
function _parseFeature (feature, geocodeResponse) {
    var location = new _Response_model_GeocodedLocation__WEBPACK_IMPORTED_MODULE_3__["default"]();
    if (feature.geometry && feature.geometry.type === "Point") {
        location.position = {
            lon : feature.geometry.coordinates[0],
            lat : feature.geometry.coordinates[1]
        };
    }
    if (feature.properties) {
        for (var prop in feature.properties) {
            if (prop === "score") {
                location.accuracy = feature.properties[prop];
            } else if (prop === "_type") {
                if (feature.properties[prop] === "address") {
                    location.type = "StreetAddress";
                } else if (feature.properties[prop] === "poi") {
                    location.type = "PositionOfInterest";
                } else if (feature.properties[prop] === "parcel" || feature.properties[prop] === "cadastral") {
                    location.type = "CadastralParcel";
                }
            } else {
                location.placeAttributes[prop] = feature.properties[prop];
            }
        }
        if (feature.properties._type === "address") {
            location.matchType = feature.properties.number !== undefined && feature.properties.number !== null ? "street number" : "street";
        }
    }
    geocodeResponse.locations.push(location);
}

/**
 * Méthode permettant de parser une erreur
 *
 * @private
 *
 * @param {Object} error
 *
 * @memberof GeocodeResponseParser
 * @return {Object}
 */
function _parseError (error) {
    return {
        exceptionReport : error
    };
}

/* harmony default export */ __webpack_exports__["default"] = (GeocodeResponseParser);


/***/ }),
/* 85 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Response object for {@link module:Services~geocode Gp.Services.geocode ()} or {@link module:Services~reverseGeocode Gp.Services.reverseGeocode ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Array.<Gp.Services.Geocode.GeocodedLocation>} locations - locations array.
 *
 * @namespace
 * @alias Gp.Services.GeocodeResponse
 */
function GeocodeResponse () {
    if (!(this instanceof GeocodeResponse)) {
        throw new TypeError("GeocodeResponse constructor cannot be called as a function.");
    }

    this.locations = [];
}

GeocodeResponse.prototype = {

    constructor : GeocodeResponse

};

/* harmony default export */ __webpack_exports__["default"] = (GeocodeResponse);


/***/ }),
/* 86 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Single location object returned by the underlying geocoding web service.
 *
 * @property {Gp.Point} position - Position of the location given in the requested coordinates system.
 * @property {String} type - location type "StreetAddress" (for an address), "PositionOfInterest" (for a place name) or "CadastralParcel" (for cadastral parcel).
 * @property {String} matchType - how geocoding is performed : "street number" (exact address), "street enhanced" (street number calculated by interpolation), "street" (only the street), "city" (only the city).
 * @property {Float} accuracy - Accuracy of the response towards the requested location between 0 (unaccurate) and 1 (exact match).
 * @property {Object} placeAttributes - Associative array matching the following attributes with their values given by the underlying web service :
 *
 * *Common attributes : *
 *
 * - **trueGeometry** - the 'real life' geometry if different from 'Point' type.
 *
 * *if type === "StreetAddress" :*
 *
 * - **number** - Street number.
 * - **postalCode** - PostCode
 * - **street** - Street name
 * - **city** - City
 * - **houseNumberInfos** - additional street number information
 * - **inseeCode** - INSEE Code
 *
 *
 * *if type === "PositionOfInterest" :*
 *
 * - **type** - Place name type
 * - **postalCode** - PostCode
 * - **toponyme** - Toponyme
 * - **extraFields** - additional place name properties
 * - **inseeCode** - INSEE Code
 *
 *
 * *si type = "CadastralParcel" :*
 *
 * - **codeCommuneAbs** - when a parcel comes from a city that was absorbed by another, code of that old city. "000" otherwise.
 * - **codeArrondissement** - arrondissement
 * - **identifiant** - cadastral parcel code
 * - **feuille** - Parcel Sheet (eg. "1").
 * - **numero** - Parcel Number (eg. "0041")
 * - **section** - Parcel Section (eg. "0D").
 * - **nomCommune** - Parcel municipality name.
 * - **codeCommune** - Parcel municipality.
 * - **codeDepartement** - Parcel Department.
 *
 * @namespace
 * @alias Gp.Services.Geocode.GeocodedLocation
 */
function GeocodedLocation () {
    if (!(this instanceof GeocodedLocation)) {
        throw new TypeError("GeocodedLocation constructor cannot be called as a function.");
    }

    this.position = null;

    this.matchType = null;

    this.placeAttributes = {};

    this.type = null;

    this.accuracy = null;

    /**
     * Nom de la classe : "GeocodedLocation"
     * @type {String}
     */
    this.CLASSNAME = "GeocodedLocation";
}

GeocodedLocation.prototype = {

    constructor : GeocodedLocation

};

/* harmony default export */ __webpack_exports__["default"] = (GeocodedLocation);


/***/ }),
/* 87 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(63);
/* harmony import */ var _Request_GeocodeRequestFactory__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(80);
/* harmony import */ var _Response_GeocodeResponseFactory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(83);








/**
 * @classdesc
 * Appel du service de géocodage inverse du Géoportail :
 *     envoi de la requête construite selon les paramètres en options,
 *     éventuellement parsing et analyse  de la réponse,
 *     retour d'une réponse en paramètre de la fonction onSuccess.
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.ReverseGeocode
 *
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {Object} options.position - Position du point de référence pour le calcul de proximité exprimée dans le système de référence spécifié par le srs.
 *      @param {Float} options.position.lon - Longitude du point de référence pour le calcul de proximité.
 *      @param {Float} options.position.lat - Latitude du point de référence pour le calcul de proximité.
 *
 * @param {Object} [options.filters] - Les propriétés possibles de cet objet.
 * @param {String} [options.filters.[proprietes du filtre]] - Critère supplémentaire pour filtrer la recherche sous la forme
 *      d'un couple clé/valeur à définir selon les possibilités du serveur ajouté à la requête.
 *      Le service de géocodage du Géoportail permet de filtrer les adresses postales avec les propriétés :
 *          "postalCode", "inseeCode", "city".
 *      Il permet également de filtrer les toponymes avec les propriétés :
 *          "postalCode", "inseeCode", "type".
 *      Enfin, il permet de filtrer les parcelles cadastrales avec les propriétés :
 *          "codeDepartement", "codeCommune", "nomCommune", "codeCommuneAbs", "codeArrondissement", "section", "numero", "feuille".
 *
 * @param {Object} [options.searchGeometry] - Emprise dans laquelle on souhaite effectuer la recherche.
 *      Les propriétés possibles de cet objet sont décrites ci-après.
 *      @param {String} options.searchGeometry.type   - Type de géometrie (Point|Circle|Linestring|Polygon)
 *      @param {Array.<Float>|Array.Array.<Float>} options.searchGeometry.coordinates - Coordonnées des points constituant la géométrie.
 *      @param {Float} options.searchGeometry.radius    - Rayon. Paramètre applicable uniquement pour le type 'Circle'.
 *
 * @param {String} [options.index = "StreetAddress"] - Type de l'objet recherché.
 *      Le service de géocodage du Géoportail permet de rechercher des 'PositionOfInterest' pour des toponymes, des 'StreetAddress'
 *      pour des adresses postales ou des 'CadastralParcel' pour des parcelles cadastrales. L'index 'location' permet une recherche
 *      multi-indexes en regroupant les indexes 'PositionOfInterest' et 'StreetAddress'.
 *      D'autres types pourront être rajoutés selon l'évolution du service.
 *      Par défaut, index = 'StreetAddress'.
 *
 * @param {Number} [options.maximumResponses] - Nombre de réponses maximal que l'on souhaite recevoir.
 *      Pas de valeur par défaut. Si le serveur consulté est celui du Géoportail, la valeur par défaut sera donc celle du service : 20s.
 *
 * @param {Boolean} [options.returnTrueGeometry] - Booléen indiquant si l'on souhaite récupérer la géométrie vraie des objects géolocalisés.
 *      false par défaut.
 *
 * @example
 *   var options = {
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      proxyURL : null,
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      index : 'StreetAddress',
 *      searchGeometry : {
 *          type : Circle,
 *          coordinates : [48, 2],
 *          radius : 100
 *      },
 *      position : {lon:2 , lat:48.5},
 *      maximumResponses : 25,
 *   };
 *
 */
function ReverseGeocode (options_) {
    if (!(this instanceof ReverseGeocode)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "ReverseGeocode"));
    }

    /**
     * Nom de la classe (heritage)
     * FIXME instance ou classe ?
     */
    this.CLASSNAME = "ReverseGeocode";

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Services.ReverseGeocode");
    this.logger.trace("[Constructeur ReverseGeocode (options)]");

    var options = this.patchOptionConvertor(options_);
    if (!options.serverUrl) {
        options.serverUrl = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__["default"].ReverseGeocode.newUrl();
    }

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].apply(this, [options]);

    if (!options.searchGeometry) {
        if (!options.position) {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "searchGeometry"));
        }
    } else {
        this.options.searchGeometry = options.searchGeometry;
    }

    // on definit l'index par defaut
    if (!options.index) {
        this.options.index = options.index = "StreetAddress";
    }

    if (options.filters) {
        var filter = Object.keys(options.filters);
        for (var i = 0; i < filter.length; i++) {
            var key = filter[i];
            // on supprime les filtres vides
            if (typeof options.filters[key] === "undefined" ||
                (typeof options.filters[key] === "object" && Object.keys(options.filters[key]).length === 0) ||
                (typeof options.filters[key] === "string" && options.filters[key].length === 0) ||
                (Array.isArray(options.filters[key]) && options.filters[key].length === 0)
            ) {
                delete this.options.filters[key];
            }
        }
    }

    this.options.position = options.position;
    this.options.index = options.index || "StreetAddress";
    this.options.maximumResponses = options.maximumResponses || 20;
}

/**
 * @lends module:ReverseGeocode#
 */
ReverseGeocode.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].prototype, {
    // todo
    // getter/setter
});

/*
 * Constructeur (alias)
 */
ReverseGeocode.prototype.constructor = ReverseGeocode;

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Object} options_ - options du service
 * @return {Object} - options
 */
ReverseGeocode.prototype.patchOptionConvertor = function (options_) {
    var options = options_;

    if (options.filterOptions) {
        this.logger.warn("The parameter 'filterOptions' is deprecated");

        if (options.filterOptions.type) {
            this.logger.warn("The parameter 'filterOptions.type' is deprecated");
            if (!options.index) {
                if (Array.isArray(options.filterOptions.type) && options.filterOptions.type.length > 0) {
                    options.index = options.filterOptions.type[0];
                } else {
                    options.index = options.filterOptions.type;
                }
            }
            delete options.filterOptions.type;
        }

        if (options.filterOptions.bbox) {
            this.logger.warn("The parameter 'filterOptions.bbox' is deprecated");
            if (!options.searchGeometry) {
                // convertir la geometrie
                options.searchGeometry = this.bbox2Json(options.filterOptions.bbox);
            }
            delete options.filterOptions.bbox;
        }

        if (options.filterOptions.circle) {
            this.logger.warn("The parameter 'filterOptions.circle' is deprecated");
            if (!options.searchGeometry) {
                // convertir la geometrie
                options.searchGeometry = this.circle2Json(options.filterOptions.circle);
            }
            delete options.filterOptions.circle;
        }

        if (options.filterOptions.polygon) {
            this.logger.warn("The parameter 'filterOptions.polygon' is deprecated");
            if (!options.searchGeometry) {
                // convertir la geometrie
                options.searchGeometry = this.polygon2Json(options.filterOptions.polygon);
            }
            delete options.filterOptions.polygon;
        }

        if (!options.filters && Object.keys(options.filterOptions).length > 0) {
            options.filters = options.filterOptions;
        }

        delete options.filterOptions;
    }

    if (options.position) {
        if (options.position.x) {
            this.logger.warn("The parameter 'position.x' is deprecated");

            if (!options.position.lon) {
                options.position.lon = options.position.x;
            }
            delete options.position.x;
        }

        if (options.position.y) {
            this.logger.warn("The parameter 'position.y' is deprecated");

            if (!options.position.lat) {
                options.position.lat = options.position.y;
            }
            delete options.position.y;
        }
    }

    if (options.srs) {
        this.logger.warn("The parameter 'srs' is deprecated");
        delete options.srs;
    }

    return options;
};

/**
 * (overwrite)
 * Création de la requête
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
ReverseGeocode.prototype.buildRequest = function (error, success) {
    var options = {
        httpMethod : this.options.httpMethod,
        // options specifiques du service
        geocodeMethod : "reverse",
        searchGeometry : this.options.searchGeometry,
        index : this.options.index,
        position : this.options.position,
        returnTrueGeometry : this.options.returnTrueGeometry,
        maxResp : this.options.maximumResponses,
        filters : this.options.filters
    };

    this.request = _Request_GeocodeRequestFactory__WEBPACK_IMPORTED_MODULE_5__["default"].build(options);

    // on teste si la requete a bien été construite !
    (!this.request)
        ? error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_REQUEST_BUILD")))
        : success.call(this, this.request);
};

/**
 * (overwrite)
 * Analyse de la reponse
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
ReverseGeocode.prototype.analyzeResponse = function (error, success) {
    if (this.response) {
        var options = {
            response : this.response,
            rawResponse : this.options.rawResponse,
            onError : error,
            onSuccess : success,
            scope : this
        };

        _Response_GeocodeResponseFactory__WEBPACK_IMPORTED_MODULE_6__["default"].build(options);
    } else {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Array} bbox - bbox
 * @return {Object} - geometrie au format json
 */
ReverseGeocode.prototype.bbox2Json = function (bbox) {
    return {
        type : "Polygon",
        coordinates : [[
            [bbox.left, bbox.top],
            [bbox.right, bbox.top],
            [bbox.right, bbox.bottom],
            [bbox.left, bbox.bottom],
            [bbox.left, bbox.top]
        ]]
    };
};

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Object} circle - circle
 * @return {Object} - geometrie au format json
 */
ReverseGeocode.prototype.circle2Json = function (circle) {
    return {
        type : "Circle",
        radius : circle.radius,
        coordinates : [circle.x, circle.y]
    };
};

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Array} polygon - polygon
 * @return {Object} - geometrie au format json
 */
ReverseGeocode.prototype.polygon2Json = function (polygon) {
    var jsonGeom = {
        type : "Polygon",
        coordinates : [[]]
    };

    for (var i = 0; i < polygon.length; ++i) {
        jsonGeom.coordinates[0].push([polygon[i].x, polygon[i].y]);
    }

    return jsonGeom;
};

/**
 * Codes EPSG géographiques (lat/lon). Utiles car les coordonnées doivent être inversées.
 */
ReverseGeocode.geoEPSG = ["EPSG:4326"];

/* harmony default export */ __webpack_exports__["default"] = (ReverseGeocode);


/***/ }),
/* 88 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63);
/* harmony import */ var _Response_AutoCompleteResponseFactory__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(89);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(45);
/* harmony import */ var _Utils_Helper__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(47);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(61);








/**
 * @classdesc
 * Appel du service d'autocomplétion du Géoportail :
 * envoi de la requête construite selon les paramètres en options,
 * éventuellement parsing et analyse  de la réponse,
 * retour d'une réponse en paramètre de la fonction onSuccess.
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.AutoComplete
 *
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {String} options.text - La chaîne de caractère à compléter.
 *      Cette chaîne n'est pas "URL encodée".
 *      C'est l'API qui s'occupe de l'encoder pour l'inclure dans la requête.
 *
 * @param {Array.<String>} [options.type = ["StreetAddress"]] - Type de l'objet recherché.
 *      Le service d'autocomplétion du Géoportail permet de rechercher des toponymes 'PositionOfInterest' et/ou des adresses postales 'StreetAddress'.
 *      D'autres types pourront être rajoutés selon l'évolution du service.
 *      Par défaut, type = ['StreetAddress'].
 *
 * @param {String} [options.territory] - Limitation de la zone de recherche de localisants.
 *      Le service d'autocomplétion du Géoportail permet de limiter la recherche à la métropole et la Corse : options.territory = 'METROPOLE',
 *      DOMS TOMS : options.territory = 'DOMTOM', ou à un département : options.territory = '31'
 *      Pas de valeur par défaut.
 *      La valeur par défaut est donc celle du service.
 *      Le service d'autocomplétion du Géoportail renvoie toutes les informations quand aucun territoire n'est spécifié.
 *
 * @param {Number} [options.maximumResponses = 10] - Nombre de réponses maximal que l'on souhaite recevoir.
 *      Pas de valeur par défaut.
 *      La valeur par défaut sera donc celle du service : 10.
 *
 * @example
 *   var options = {
 *      // options communes aux services
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      protocol : 'JSONP', // JSONP|XHR
 *      proxyURL : null,
 *      httpMethod : 'GET', // GET|POST
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      text : "",
 *      type : "StreetAddress",
 *      territory : 'METROPOLE',
 *      maximumResponses : 10
 *   };
 */
function AutoComplete (options_) {
    if (!(this instanceof AutoComplete)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_4__["default"].getMessage("CLASS_CONSTRUCTOR", "AutoComplete"));
    }

    /**
     * Nom de la classe (heritage)
     * FIXME instance ou classe ?
     */
    this.CLASSNAME = "AutoComplete";

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__["default"].getLogger("Gp.Services.AutoComplete");
    this.logger.trace("[Constructeur AutoComplete (options)]");

    var options = this.patchOptionConvertor(options_);

    if (!options.serverUrl) {
        options.serverUrl = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_1__["default"].AutoComplete.newUrl();
    }

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_0__["default"].apply(this, arguments);

    if (!options.text) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_4__["default"].getMessage("PARAM_MISSING", "text"));
    }

    // ajout des options spécifiques au service
    this.options.text = options.text;

    // on definit des parametres par defaut
    if (!options.type) {
        options.type = ["StreetAddress,PositionOfInterest"];
    }

    this.options.type = options.type;
    this.options.territory = options.terr || "";
    this.options.maximumResponses = options.maximumResponses || 10;

    // INFO
    // le service ne repond pas en mode POST (405 Method Not Allowed)
    if (this.options.protocol === "XHR" && this.options.httpMethod === "POST") {
        this.logger.warn("Le service ne gére pas le mode d'interrogation en POST, on bascule sur du GET !");
        this.options.httpMethod = "GET"; // on surcharge !
    }

    // attributs d'instances

    /**
     * Format forcé de la réponse du service : "json"
     * sauf si l'on souhaite une reponse brute (options.rawResponse)
     */
    this.options.outputFormat = (this.options.rawResponse) ? "" : "json";
}

/**
 * @lends module:AutoComplete#
 */

AutoComplete.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_0__["default"].prototype, {
    // todo
    // getter/setter
});

/*
 * Constructeur (alias)
 */
AutoComplete.prototype.constructor = AutoComplete;

/**
 * Patch pour la convertion des options vers le nouveau formalisme.
 *
 * @param {Object} options_ - options du service
 * @return {Object} - options
 */
AutoComplete.prototype.patchOptionConvertor = function (options_) {
    const options = options_;

    if (options.filterOptions) {
        this.logger.warn("The parameter 'filterOptions' is deprecated");

        if (options.filterOptions.type) {
            this.logger.warn("The parameter 'filterOptions.type' is deprecated");
            if (!options.type) {
                options.type = options.filterOptions.type;
            }
        }

        if (options.filterOptions.territory) {
            this.logger.warn("The parameter 'filterOptions.territory' is deprecated");
            if (!options.terr) {
                options.terr = options.filterOptions.territory;
            }
        }

        delete options.filterOptions;
    }

    return options;
};

/**
 * (overwrite)
 * Création de la requête
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
AutoComplete.prototype.buildRequest = function (error, success) {
    // ex.
    // http://wxs.ign.fr/CLEF/ols/apis/completion?
    // text=Brie-Comt&
    // type=StreetAddress,PositionOfInterest&
    // territory=METROPOLE&
    // maximumResponses=10

    // traitement des param KPV sous forme de tableau
    var territory = "";
    if (this.options.territory) {
        territory = this.options.territory;
    }

    var type = "";
    if (this.options.type) {
        type = this.options.type.join(",");
    }

    // normalisation de la requete avec param KPV
    this.request = _Utils_Helper__WEBPACK_IMPORTED_MODULE_5__["default"].normalyzeParameters({
        text : encodeURIComponent(this.options.text),
        type : type,
        terr : territory,
        maximumResponses : this.options.maximumResponses
    });

    (!this.request)
        ? error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_6__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_4__["default"].getMessage("SERVICE_REQUEST_BUILD")))
        : success.call(this, this.request);
};

/**
 * (overwrite)
 * Analyse de la reponse
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback de succès de l'analyse de la réponse
 */
AutoComplete.prototype.analyzeResponse = function (error, success) {
    if (this.response) {
        var options = {
            response : this.response,
            rawResponse : this.options.rawResponse,
            onSuccess : success,
            onError : error,
            scope : this
        };

        _Response_AutoCompleteResponseFactory__WEBPACK_IMPORTED_MODULE_2__["default"].build(options);
    } else {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_6__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_4__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AutoComplete);


/***/ }),
/* 89 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _model_AutoCompleteResponse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(90);
/* harmony import */ var _model_SuggestedLocation__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(91);
/**
 * Factory pour générer une reponse JSON à partir d'un XML ou d'un JSON
 * (Factory)
 *
 * @module AutoCompleteResponseFactory
 * @private
 * @alias Gp.Services.AutoComplete.Response.AutoCompleteResponseFactory
 */






var AutoCompleteResponseFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Alti
     *
     * @example
     *   var options = {
     *      response :
     *      outputFormat :
     *      rawResponse :
     *      scope :
     *      onSuccess :
     *      onError :
     *   };
     *
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("AutoCompleteResponseFactory");
        logger.trace(["AutoCompleteResponseFactory::build()"]);

        var data = null;

        if (options.response) {
            if (options.rawResponse) {
                logger.trace("analyze response : raw");
                data = options.response;
            } else {
                var JSONResponse = null;
                if (typeof options.response === "string") {
                    JSONResponse = JSON.parse(options.response);
                } else {
                    JSONResponse = options.response;
                }

                // analyse de la réponse
                if (JSONResponse) {
                    // le service renvoie t il une erreur ?
                    if (JSONResponse.error) {
                        // ex. ?
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                            message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", JSONResponse.error.description),
                            status : JSONResponse.error.code,
                            type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR
                        }));
                        return;
                    }

                    // création de l'objet réponse
                    data = new _model_AutoCompleteResponse__WEBPACK_IMPORTED_MODULE_3__["default"]();

                    // boucle sur les résultats de l'autocomplétion
                    if (JSONResponse.results && Array.isArray(JSONResponse.results)) {
                        var suggestedLocation = null;

                        for (var i = 0; i < JSONResponse.results.length; i++) {
                            var result = JSONResponse.results[i];
                            suggestedLocation = new _model_SuggestedLocation__WEBPACK_IMPORTED_MODULE_4__["default"]();

                            if (result) {
                                if (result.country === "StreetAddress") {
                                    suggestedLocation.street = result.street;
                                    suggestedLocation.type = "StreetAddress";
                                } else if (result.country === "PositionOfInterest") {
                                    suggestedLocation.poi = result.street;
                                    suggestedLocation.type = "PositionOfInterest";
                                    suggestedLocation.poiType = result.poiType;
                                }

                                if (suggestedLocation.position) {
                                    suggestedLocation.position.x = result.x;
                                    suggestedLocation.position.y = result.y;
                                }

                                suggestedLocation.kind = result.kind;
                                suggestedLocation.commune = result.city;
                                suggestedLocation.fullText = result.fulltext;
                                suggestedLocation.postalCode = result.zipcode;
                                suggestedLocation.classification = result.classification;
                            }
                            // Ajout du résultat au tableau reverseGeocodedLocations de geocodedLocation
                            data.suggestedLocations.push(suggestedLocation);
                        }
                    } else {
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_FORMAT_3")));
                        return;
                    }

                    if (!data.suggestedLocations.length) {
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_FORMAT_3")));
                        return;
                    }
                }

                if (!data) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_ANALYSE_2"),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_UNKERR,
                        status : -1
                    }));
                    return;
                }

                // Si la réponse contenait une exception renvoyée par le service
                if (data.exceptionReport) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", data.exceptionReport),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR,
                        status : 200
                    }));
                    return;
                }
            }
        } else {
            // si la réponse (xmlString) est vide, on appelle le callback d'erreur
            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
            return;
        }

        // si tout s'est bien passé, on appelle le callback de succès
        options.onSuccess.call(options.scope, data);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (AutoCompleteResponseFactory);


/***/ }),
/* 90 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Response object for {@link module:Services~autoComplete Gp.Services.autoComplete ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Array.<Gp.Services.AutoComplete.SuggestedLocation>} suggestedLocations - SuggestedLocations array.
 *
 * @namespace
 * @alias Gp.Services.AutoCompleteResponse
 */
function AutoCompleteResponse () {
    if (!(this instanceof AutoCompleteResponse)) {
        throw new TypeError("AutoCompleteResponse constructor cannot be called as a function.");
    }

    this.suggestedLocations = [];
}

AutoCompleteResponse.prototype = {

    constructor : AutoCompleteResponse

};

/* harmony default export */ __webpack_exports__["default"] = (AutoCompleteResponse);


/***/ }),
/* 91 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Single SuggestedLocation Object returned by underlying web service.
 * Each suggested location represents a street address ("StreetAddress") or a place name ("PositionOfInterest").
 *
 * @property {String} type - Suggested location type : "StreetAddress" ou "PositionOfInterest"
 * @property {Gp.Point} position - Position of the suggested location given in requested coordinates system.
 * @property {String} commune - Suggested municipality
 * @property {String} fullText - Full text representation of the suggested location.
 * @property {String} postalCode - Suggested location postcode
 * @property {Integer} classification - Number used to classify the importance of the place where is the suggested location from 1 (most important) to 7 (less important).
 * @property {String} street - Street name of the suggested location ("StreetAddress" only).
 * @property {String} kind - Nature of the suggested location : "prefecture", "monument", "commune", ... for instance ("PositionOfInterest" only).
 *
 * @namespace
 * @alias Gp.Services.AutoComplete.SuggestedLocation
 */
function SuggestedLocation () {
    if (!(this instanceof SuggestedLocation)) {
        throw new TypeError("SuggestedLocation constructor cannot be called as a function.");
    }

    /* REPONSE :
        {
           "status" : "OK",
           "results" : [
              {
                 "country":"PositionOfInterest",
                 "x":-1.559185,
                 "y":47.952603,
                 "city":"Brie",
                 "zipcode":"35150",
                 "street":"corbe",
                 "kind":"Lieu-dit habité",
                 "fulltext":"corbe, 35150 Brie",
                 "classification":6
              },
              {
                 "country":"StreetAddress",
                 "x":1.538295,
                 "y":43.19646,
                 "city":"Brie",
                 "zipcode":"09700",
                 "street":"courreste",
                 "kind":"",
                 "fulltext":"courreste, 09700 Brie",
                 "classification":7
              }
           ]
        }
    */

    /* REPONSE EN ERREUR
        {
            status : "ERROR",
            results : [ ]
        }
    */

    /**
     * Suggested location type : "StreetAddress" ou "PositionOfInterest"
     * @type {String}
     */
    this.type = null;

    /**
     * Position of the suggested location given in requested coordinates system.
     * @type {Gp.Point}
     */
    this.position = {
        x : null,
        y : null
    };

    /**
     * Suggested municipality
     * @type {String}
     */
    this.commune = null;

    /**
     * Full text representation of the suggested location.
     * @type {String}
     */
    this.fullText = null;

    /**
     * Suggested location postcode
     * @type {Number}
     */
    this.postalCode = null;

    /**
     * Number used to classify the importance of the place where is the suggested location from 1 (most important) to 7 (less important).
     * @type {Integer}
     */
    this.classification = null;

    /**
     * Street name of the suggested location ("StreetAddress" only).
     * @type {String}
     */
    this.street = null;

    /**
     * Place name of the suggested location ("PositionOfInterest" only).
     * @type {String}
     */
    this.poi = null;

    /**
     * Nature of the suggested location : "prefecture", "monument", "commune", ... for instance ("PositionOfInterest" only).
     * @type {String}
     */
    this.kind = null;
}

SuggestedLocation.prototype = {

    constructor : SuggestedLocation
};

/* harmony default export */ __webpack_exports__["default"] = (SuggestedLocation);


/***/ }),
/* 92 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(63);
/* harmony import */ var _Request_RouteRequestFactory__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(93);
/* harmony import */ var _Response_RouteResponseFactory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(96);









/**
 * @classdesc
 * Appel du service d'itinéraire du Géoportail :
 *     envoi de la requête construite selon les paramètres en options,
 *     éventuellement parsing et analyse  de la réponse,
 *     retour d'une réponse en paramètre de la fonction onSuccess.
 *
 * @alias Gp.Services.Route
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {String} options.resource - La ressource utilisée pour le calcul. Ce paramètre devrait être obligatoire car il l'est dans l'appel au service. Mais il ne l'est pas pour des raisons de rétrocompatibilité.
 *
 * @param {String} options.outputFormat - Le format de la réponse du service itineraire : 'json' uniquement et par défaut.
 *
 * @param {String} [options.routePreference = "fastest"] - Mode de calcul à utiliser :
 * - le plus rapide « fastest »
 * - le plus court « shortest »
 * Par défaut : « fastest ».
 *
 * @param {Object} options.startPoint - Point de départ du calcul. Coordonnées exprimées en longitudes, latitudes (EPSG:4326)
 * @param {Float} options.startPoint.x - Abcisse du point de départ du calcul d'itinéraire.
 * @param {Float} options.startPoint.y - Ordonnée du point de départ du calcul d'itinéraire.
 *
 * @param {Object} options.endPoint - Point d'arrivée du calcul. Coordonnées exprimées en longitudes, latitudes (EPSG:4326)
 * @param {Float} options.endPoint.x - Abcisse du point d'arrivée du calcul d'itinéraire.
 * @param {Float} options.endPoint.y - Ordonnée du point d'arrivée du calcul d'itinéraire.
 *
 * @param {Object[]} [options.viaPoints] - Liste de point ({x:Float,y:Float}) intermédaires que l'itinéraire doit emprunter dans l'ordre du tableau.
 *      Coordonnées exprimées en longitudes, latitudes (EPSG:4326) :{x:float, y:float}
 *
 * @param {String} [options.graph = "voiture"] - Type de graphe utilisé : "Voiture" ou "Pieton".
 *      Détermine le profil de vitesses utilisé pour le calcul ainsi que les tronçons autorisés ou non.
 *      Par défaut, c'est la valeur "Voiture" qui sera utilisée.
 *
 * @param {String[]} [options.exclusions] - DEPRECATED: Critères d'exclusions à appliquer pour le calcul. (correspond au paramètre "avoidFeature" d'OpenLS)
 *      On précise ici le type de tronçons que l'on ne veut pas que l'itinéraire emprunte
 *      (valeurs possibles : « toll » (éviter les péages), « bridge », « tunnel »).
 *      Ce paramètre est conservé pour une rétrocompatibilité de l'api. Le nouveau paramètre à utiliser est options.constraints
 *
 * @param {Object[]} [options.constraints] - Critères de contraintes à appliquer sur un itinéraire. Les valeurs disponibles dépendent de la ressource utilisée. Il est donc utile de regarder le getCapabilities.
 * @param {String} [options.constraints.constraintType] - Type de la contrainte. Généralement "banned".
 * @param {String} [options.constraints.key] - Clé de la contrainte. Généralement "wayType".
 * @param {String} [options.constraints.operator] - Opérateur de la contrainte. Généralement "=".
 * @param {String} [options.constraints.value] - Valeur de la contrainte. Généralement "autoroute".
 *
 * @param {Boolean} [options.geometryInInstructions = false] - Indique si la géométrie de l'itinéraire doit être reprise morceau par morceau dans les instructions.
 *      (correspond au paramètre "provideGeometry" d'OpenLS) Par défaut : false.
 *
 * @param {Boolean} [options.provideBbox = true] - Indique si les instructions doivent être localisées par une bbox dans la réponse.
 *      Par défaut : true.
 *
 * @param {String} [options.distanceUnit = "m"] - Indique si la distance doit être exprimée en km ou m dans la réponse.
 *      Par défaut : m.
 * @param {String} [options.timeUnit = "second"] - Indique si la durée doit être exprimée en seconde, minute ou heure dans la réponse. Il peut-être formatté hh:mm::ss avec la valeur standard.
 *      Les valeurs possibles sont "standard", "second", "minute" ou "hour".
 *      Par défaut : "standard".
 *
 * @param {String} [options.srs] - Système de coordonnées dans lequel les paramètres géographiques en entrée et la réponse du service sont exprimés.
 *      Pas de valeur par défaut. Si le serveur consulté est celui du Géoportail, la valeur par défaut sera donc celle du service : 'EPSG:4326'.
 *
 * @param {String[]} [options.waysAttributes] - Nom des attributs des voies. Les valeurs disponibles dépendent de la ressource utilisée. Il est donc utile de regarder le getCapabilities.
 *
 * @example
 *  var options = {
 *      // options communes aux services
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      protocol : 'XHR',
 *      proxyURL : null,
 *      httpMethod : 'GET', // GET|POST
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      resource : 'bdtopo'
 *      outputFormat : 'json',
 *      startPoint : {
 *          x : 42.1121,
 *          y : 1.5557
 *      },
 *      endPoint : {
 *          x : 42.1121,
 *          y : 1.5557
 *      },
 *      provideBbox : true,
 *      exclusions : ["Bridge", "Tunnel", "Toll"],
 *      distanceUnit : "km",
 *      graph : "Voiture",
 *      geometryInInstructions : true,
 *      routePreference : "fastest"
 *  };
 *
 */
function Route (options) {
    if (!(this instanceof Route)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "Route"));
    }

    /**
     * Nom de la classe (heritage)
     */
    this.CLASSNAME = "Route";

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].apply(this, arguments);

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Services.Route");
    this.logger.trace("[Constructeur Route (options)]");

    if (!options.startPoint) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "startPoint"));
    }

    // on lance une exception afin d'eviter au service de le faire...
    if (options.startPoint.x === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "startPoint.x"));
    }

    if (options.startPoint.y === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "startPoint.y"));
    }

    if (!options.endPoint) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "endPoint"));
    }

    // on lance une exception afin d'eviter au service de le faire...
    if (options.endPoint.x === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "endPoint.x"));
    }

    if (options.endPoint.y === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "endPoint.y"));
    }

    // options par defaut

    // on passe l'option outputFormat en minuscules afin d'éviter des exceptions.
    if (options.outputFormat && options.outputFormat !== "json") {
        this.logger.warn("options.outputFormat could only be json");
    }
    this.options.outputFormat = "json";

    this.options.resource = options.resource || "bdtopo-osrm";
    this.options.startPoint = options.startPoint;
    this.options.endPoint = options.endPoint;
    this.options.viaPoints = options.viaPoints || [];
    this.options.routePreference = options.routePreference || "fastest";
    /** Gestion des anciennes valeurs de graph */
    if (options.graph) {
        if (options.graph === "Voiture") {
            this.options.graph = "car";
        }
        if (options.graph === "Pieton") {
            this.options.graph = "pedestrian";
        }
    } else {
        this.options.graph = "car";
    }
    this.options.constraints = [];
    if (options.constraints) {
        if (Array.isArray(options.constraints)) {
            for (var k = 0; k < options.constraints.length; k++) {
                this.options.constraints.push(options.constraints[k]);
            }
        } else {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_TYPE", "constraints"));
        }
    }

    /** Gestion de l'ancien paramètre exclusion */
    var constraintTunnel = {};
    var constraintPont = {};
    var constraintAutoroute = {};
    if (options.exclusions) {
        if (options.exclusions.length !== 0) {
            this.logger.warn("options.exclusions is DEPRECATED !!");
            for (var c = 0; c < options.exclusions.length; c++) {
                if (typeof options.exclusions[c] === "string") {
                    options.exclusions[c] = options.exclusions[c].toLowerCase();
                } else {
                    // on ne crée pas une erreur pour rétro-compatibilité avec les anciennes versions
                    continue;
                }
                if (options.exclusions[c] === "toll") {
                    constraintAutoroute.constraintType = "banned";
                    constraintAutoroute.key = "wayType";
                    constraintAutoroute.operator = "=";
                    constraintAutoroute.value = "autoroute";
                    this.options.constraints.push(constraintAutoroute);
                }
                if (options.exclusions[c] === "tunnel") {
                    constraintTunnel.constraintType = "banned";
                    constraintTunnel.key = "wayType";
                    constraintTunnel.operator = "=";
                    constraintTunnel.value = "tunnel";
                    this.options.constraints.push(constraintTunnel);
                }
                if (options.exclusions[c] === "bridge") {
                    constraintPont.constraintType = "banned";
                    constraintPont.key = "wayType";
                    constraintPont.operator = "=";
                    constraintPont.value = "pont";
                    this.options.constraints.push(constraintPont);
                }
            }
        }
    }

    this.options.geometryInInstructions = options.geometryInInstructions || false;
    this.options.provideBbox = options.provideBbox || true;
    this.options.distanceUnit = options.distanceUnit || "m";
    this.options.timeUnit = options.timeUnit || "second";
    this.options.expectedStartTime = null; // FIXME not yet implemented !
    this.options.srs = options.srs || "EPSG:4326";
    this.options.waysAttributes = options.waysAttributes || [];

    // gestion de l'url du service par defaut
    // si l'url n'est pas renseignée, il faut utiliser les urls par defaut
    if (!this.options.serverUrl) {
        var UrlByDefault = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__["default"].Route.newUrl();

        if (!UrlByDefault) {
            throw new Error("Url by default not found !");
        }
        this.options.serverUrl = UrlByDefault;
        this.logger.trace("Serveur URL par defaut : " + this.options.serverUrl);
    }
}

/**
 * @lends module:Route#
 */
Route.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].prototype, {
    // todo
    // getter/setter
});

/*
 * Constructeur (alias)
 */
Route.prototype.constructor = Route;

/**
 * (overwrite)
 * Création de la requête
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Route.prototype.buildRequest = function (error, success) {
    var options = {
        // spécifique au service
        resource : this.options.resource,
        startPoint : this.options.startPoint,
        endPoint : this.options.endPoint,
        viaPoints : this.options.viaPoints,
        provideBbox : this.options.provideBbox,
        constraints : this.options.constraints,
        distanceUnit : this.options.distanceUnit,
        timeUnit : this.options.timeUnit,
        graph : this.options.graph,
        geometryInInstructions : this.options.geometryInInstructions,
        routePreference : this.options.routePreference,
        srs : this.options.srs,
        waysAttributes : this.options.waysAttributes
    };

    this.request = _Request_RouteRequestFactory__WEBPACK_IMPORTED_MODULE_5__["default"].build(options);

    // on teste si la requete a bien été construite !
    if (!this.request) {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_REQUEST_BUILD")));
    } else {
        success.call(this, this.request);
    }
};

/**
 * (overwrite)
 * Analyse de la reponse
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
Route.prototype.analyzeResponse = function (error, success) {
    // INFO
    // Factory pour masquer la complexité du retour du service

    if (this.response) {
        var options = {
            distanceUnit : this.options.distanceUnit,
            timeUnit : this.options.timeUnit,
            response : this.response,
            outputFormat : this.options.outputFormat, // utile pour parser la string en mode XHR : JSON ou XML !
            rawResponse : this.options.rawResponse,
            onError : error,
            onSuccess : success,
            scope : this,
            geometryInInstructions : this.options.geometryInInstructions
        };

        _Response_RouteResponseFactory__WEBPACK_IMPORTED_MODULE_6__["default"].build(options);
    } else {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/* harmony default export */ __webpack_exports__["default"] = (Route);


/***/ }),
/* 93 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(61);
/* harmony import */ var _RouteRequestREST__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(94);




/**
 * Creation d'une requête REST en mode POST ou GET
 * (Factory)
 *
 * @module RouteRequestFactory
 * @alias Gp.Services.Route.Request.RouteRequestFactory
 * @private
 */
var RouteRequestFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Route
     *
     * @example
     *   // utilisation avec les callback
     *   var options = {
     *      (...)
     *      onSuccess : function (response) {},
     *      onError : function (error) {},
     *      // spécifique au service
     *      startPoint : {
     *          x : 42.1121,
     *          y : 1.5557
     *      },
     *      endPoint : {
     *          x : 42.1121,
     *          y : 1.5557
     *      },
     *      provideBbox : false,
     *      exclusions : ["bridge", "tunnel", "toll"],
     *      distanceUnit : "km",
     *      graph : "Voiture",
     *      geometryInInstructions : false,
     *      routePreference : "fastest"
     *   };
     *   RouteRequestFactory.build(options);
     *
     *   // utilisation sans callback
     *   var options = {...};
     *   try {
     *      var result = RouteRequestFactory.build(options);
     *      if (! result) { throw new Error("..."):}
     *   } catch (e) {
     *      // todo
     *   }
     * @returns {String} request
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("RouteRequestFactory");
        logger.trace(["RouteRequestFactory::build()"]);

        var request = null;

        var settings = options || {};

        // gestion des callback
        var bOnError = !!(options.onError !== null && typeof options.onError === "function");

        var message = null;

        // FIXME les exceptions ne sont pas 'catchées' sur le constructeur !
        var myReq = new _RouteRequestREST__WEBPACK_IMPORTED_MODULE_2__["default"](settings);
        if (!myReq.processRequestString()) {
            message = "Error process request (rest) !";
            if (bOnError) {
                options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_1__["default"](message));
                return;
            }
            throw new Error(message);
        }
        request = myReq.requestString;

        return request;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (RouteRequestFactory);


/***/ }),
/* 94 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _model_RouteParamREST__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(95);





/**
 * @classdesc
 * Classe de gestion des requêtes de type REST sur le service de calcul d'itineraire
 * (uniquement en GET)
 *
 * @constructor
 * @alias Gp.Services.Route.Request.RouteRequestREST
 * @param {Object} options - options definies dans le composant Route
 *
 * @example
 * var options = {
 *      (...)
 * };
 *
 * @private
 */
function RouteRequestREST (options) {
    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("RouteRequestREST");
    this.logger.trace("[Constructeur RouteRequestREST ()]");

    if (!(this instanceof RouteRequestREST)) {
        throw new TypeError("RouteRequestREST constructor cannot be called as a function.");
    }

    // existance des options
    if (!options) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "options"));
    }

    /** liste des options */
    this.settings = options;
}

RouteRequestREST.prototype = {

    /**
     * @lends module:RouteRequestREST#
     */

    /**
     * request
     * @type {String}
     */
    requestString : null,

    /**
     * Constructeur (alias)
     */
    constructor : RouteRequestREST,

    /**
     * Construction de la requête.
     *
     * @example
     * // GET  out : origin=2.416907353809513,48.8465772142297&destination=2.4248037771493673,48.84591353161838
     * // POST out : Not yet supported method POST !
     * @returns {String} request
     */
    processRequestString : function () {
        // INFO
        // construction simple sans template...,
        // mais en attendant que les services soient fixés, on taggue ce composant en mode PROTOTYPE !
        this.logger.warn(" PROTOTYPE !");

        // Mapping des options avec le service de l'API REST
        var oParams = new _model_RouteParamREST__WEBPACK_IMPORTED_MODULE_2__["default"](this.settings);
        var params = oParams.getParams();

        var request = "";
        for (var i = 0; i < params.length; i++) {
            var o = params[i];
            if (request) {
                request += "&";
            }
            request += o.k + "=" + o.v;
        }

        // Exemple :
        //  http://wxs.ign.fr/KEY/itineraire/rest/route.json?
        //  origin=&
        //  destination=&
        //  waypoints=&
        //  method=DISTANCE&
        //  graph=Pieton&
        //  graphName=Pieton&
        //  exclusions=&
        //  tolerance=10&
        //  srs=

        this.logger.trace(request);
        this.requestString = request;

        return this.requestString;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (RouteRequestREST);


/***/ }),
/* 95 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);



/**
 * @classdesc
 * Classe de gestion des param. des requêtes du service de calcul d'itineraire (REST).
 *      Permet le mapping avec les options du service.
 * @constructor
 * @alias Gp.Services.Route.Request.RouteParamREST
 * @param {Object} options - options
 *
 * @private
 */
function RouteParamREST (options) {
    if (!(this instanceof RouteParamREST)) {
        throw new TypeError("RouteParamREST constructor cannot be called as a function.");
    }

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur RouteParamREST ()]");
    /**
     * Options en paramêtres du constructeur.
     */
    this.options = options || {};

    // mapping des options avec l'API REST

    /** Ressource utilisée */
    this.resource = this.options.resource;

    /** Coordonnées du point de départ. */
    this.start = this.options.startPoint.x + "," + this.options.startPoint.y;

    /** Coordonnées du point d’arrivée. */
    this.end = this.options.endPoint.x + "," + this.options.endPoint.y;

    /** Coordonnées des étapes point de départ. */
    this.intermediates = this.options.viaPoints;

    /** Nom du profile à utiliser */
    this.profile = this.options.graph;

    /** projection (code EPSG comme epsg:4326 ou wgs84) */
    this.crs = this.options.srs;

    /** Liste des contraintes */
    this.constraints = this.options.constraints;

    /** Nom de l'optimisation à utiliser */
    this.optimization = this.options.routePreference;

    /** Format de sortie (résumé de l’itinéraire) */
    this.getSteps = (this.options.geometryInInstructions) ? "true" : "false";

    /** Unité des distances */
    this.distanceUnit = this.options.distanceUnit;

    /** Unité des durées */
    this.timeUnit = this.options.timeUnit;

    /** Attributs des voies */
    this.waysAttributes = this.options.waysAttributes;
}

/**
 * CLASSNAME
 */
RouteParamREST.CLASSNAME = "RouteParamREST";

RouteParamREST.prototype = {

    /**
     * @lends module:RouteParamREST#
     */

    /**
     * Constructeur (alias)
     */
    constructor : RouteParamREST,

    /**
     * Retourne une liste de points
     * @returns {String} une liste de points (sep '|')
     */
    getIntermediates : function () {
        var array = [];
        if (this.intermediates.length !== 0) {
            for (var i = 0; i < this.intermediates.length; i++) {
                var obj = this.intermediates[i];
                array.push(obj.x + "," + obj.y);
            }
        }

        return array.join("|");
    },

    /**
     * Retourne une liste d'attributs
     * @returns {String} une liste d'attributs (sep '|')
     */
    getWaysAttributes : function () {
        return this.waysAttributes.join("|");
    },

    /**
     * Retourne un profile
     * @returns {String} profile
     */
    getProfile : function () {
        return this.profile;
    },

    /**
     * Retourne un distanceUnit
     * @returns {String} distanceUnit
     */
    getDistanceUnit : function () {
        if (this.distanceUnit === "m") {
            return "meter";
        }
        if (this.distanceUnit === "km") {
            return "kilometer";
        }
        return "";
    },

    /**
     * Retourne une optimisation
     * @returns {String} optimization
     */
    getOptimization : function () {
        if (this.optimization) {
            return this.optimization;
        } else {
            return "";
        }
    },

    /**
     * Retourne la liste des constraints
     * @returns {String} une liste des constraints (sep '|')
     */
    getConstraints : function () {
        var constraintArray = [];

        if (this.constraints.length !== 0) {
            for (var k = 0; k < this.constraints.length; k++) {
                constraintArray.push(JSON.stringify(this.constraints[k]));
            }
        }
        return constraintArray.join("|");
    }
};

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Array} liste de paramêtres
 */
RouteParamREST.prototype.getParams = function () {
    var map = [];

    map.push({
        k : "resource",
        v : this.resource
    });

    map.push({
        k : "start",
        v : this.start
    });

    map.push({
        k : "end",
        v : this.end
    });

    map.push({
        k : "geometryFormat",
        v : "geojson"
    });

    if (this.optimization) {
        map.push({
            k : "optimization",
            v : this.getOptimization()
        });
    }

    if (this.intermediates) {
        map.push({
            k : "intermediates",
            v : this.getIntermediates()
        });
    }

    if (this.profile) {
        map.push({
            k : "profile",
            v : this.getProfile()
        });
    }

    if (this.constraints) {
        map.push({
            k : "constraints",
            v : this.getConstraints()
        });
    }

    if (this.crs) {
        map.push({
            k : "crs",
            v : this.crs
        });
    }

    if (this.distanceUnit) {
        map.push({
            k : "distanceUnit",
            v : this.getDistanceUnit()
        });
    }

    if (this.timeUnit) {
        map.push({
            k : "timeUnit",
            v : this.timeUnit
        });
    }

    if (this.waysAttributes) {
        map.push({
            k : "waysAttributes",
            v : this.getWaysAttributes()
        });
    }

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (RouteParamREST);


/***/ }),
/* 96 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _model_RouteResponse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(97);
/* harmony import */ var _model_RouteInstruction__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(98);






/**
 * Factory pour générer une reponse JSON à partir d'un XML ou d'un JSON
 * (Factory)
 *
 * @module RouteResponseFactory
 * @alias Gp.Services.Route.Response.RouteResponseFactory
 * @private
 */
var RouteResponseFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant Route
     *
     * @example
     *   var options = {
     *      response :
     *      outputFormat :
     *      rawResponse :
     *      scope :
     *      onSuccess :
     *      onError :
     *   };
     *
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("RouteResponseFactory");
        logger.trace("RouteResponseFactory::build()");

        var data = null;

        if (options.response) {
            if (options.rawResponse) {
                logger.trace("analyze response : raw");
                data = options.response;
            } else {
                logger.trace("analyze response : json");

                var JSONResponse;
                if (typeof options.response === "string") {
                    JSONResponse = JSON.parse(options.response);
                } else {
                    JSONResponse = options.response;
                }

                // construction de l'objet réponse JSON
                if (JSONResponse) {
                    // le service renvoie t il une erreur ?
                    if (JSONResponse.message) {
                        // ex. {"message":"message not null", "status":"ERROR"}
                        options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", JSONResponse.message)));
                        return;
                    }
                    var legs = [];
                    var legSteps = [];
                    var steps = [];

                    data = new _model_RouteResponse__WEBPACK_IMPORTED_MODULE_3__["default"]();

                    if (data.hasOwnProperty("totalTime")) {
                        data.totalTime = parseFloat(JSONResponse.duration);
                    }
                    if (data.hasOwnProperty("totalDistance")) {
                        data.totalDistance = parseFloat(JSONResponse.distance);
                    }

                    if (data.hasOwnProperty("bbox")) {
                        data.bbox.left = parseFloat(JSONResponse.bbox[0]);
                        data.bbox.bottom = parseFloat(JSONResponse.bbox[1]);
                        data.bbox.right = parseFloat(JSONResponse.bbox[2]);
                        data.bbox.top = parseFloat(JSONResponse.bbox[3]);
                    }

                    if (data.hasOwnProperty("routeGeometry") && !options.geometryInInstructions) {
                        data.routeGeometry = JSONResponse.geometry;
                    }

                    if (data.hasOwnProperty("routeInstructions") && options.geometryInInstructions) {
                        var legList = JSONResponse.portions;
                        var i;
                        if (Array.isArray(legList) && legList.length) {
                            for (i = 0; i < legList.length; i++) {
                                legs.push(legList[i]);
                            }
                        }
                        if (legs.length) {
                            for (i = 0; i < legs.length; i++) {
                                legSteps.push(legs[i].steps);
                            }
                        }
                        if (legSteps.length) {
                            for (i = 0; i < legSteps.length; i++) {
                                steps = steps.concat(legSteps[i]);
                            }
                        }

                        steps.forEach(function (step) {
                            data.routeInstructions.push(new _model_RouteInstruction__WEBPACK_IMPORTED_MODULE_4__["default"]());
                            data.routeInstructions[data.routeInstructions.length - 1].duration = step.duration;
                            data.routeInstructions[data.routeInstructions.length - 1].distance = step.distance;
                            data.routeInstructions[data.routeInstructions.length - 1].code = "";
                            data.routeInstructions[data.routeInstructions.length - 1].instruction = "";
                            data.routeInstructions[data.routeInstructions.length - 1].geometry = step.geometry;

                            // on ne souhaite pas de ce type de valeur...
                            if (step.name === "Valeur non renseignée") {
                                step.name = "";
                            }

                            switch (step.instruction.type) {
                                case "turn":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Tourner";
                                    break;
                                case "new name":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Continuer tout droit";
                                    break;
                                case "depart":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Départ";
                                    break;
                                case "arrive":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Arrivée";
                                    break;
                                case "merge":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Rejoindre";
                                    break;
                                case "ramp":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Prendre la bretelle";
                                    break;
                                case "on ramp":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Prendre la bretelle";
                                    break;
                                case "off ramp":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Prendre la sortie";
                                    break;
                                case "fork":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Sur la bifurcation, prendre";
                                    break;
                                case "end of road":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "À la fin de la route, prendre";
                                    break;
                                case "use lane":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Utiliser la file";
                                    break;
                                case "continue":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Continuer";
                                    break;
                                case "roundabout":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Au rond-point";
                                    break;
                                case "rotary":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Au rond-point";
                                    break;
                                case "roundabout turn":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "Au rond point, tourner";
                                    break;
                                case "notification":
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "";
                                    break;
                                default:
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += "?" + step.instruction.type + "?";
                                    break;
                            }

                            if (step.instruction.modifier) {
                                switch (step.instruction.modifier) {
                                    case "uturn":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction = "Faire demi-tour";
                                        break;
                                    case "sharp right":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " complètement à droite";
                                        break;
                                    case "right":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " à droite";
                                        break;
                                    case "slight right":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " légèrement à droite";
                                        break;
                                    case "straight":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction = "Continuer tout droit";
                                        break;
                                    case "slight left":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " lègèrement à gauche";
                                        break;
                                    case "left":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " à gauche";
                                        break;
                                    case "sharp left":
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " complètement à gauche";
                                        break;
                                    default:
                                        data.routeInstructions[data.routeInstructions.length - 1].instruction += " ?" + step.instruction.modifier + "?";
                                        break;
                                }
                            }

                            if (step.instruction.exit) {
                                data.routeInstructions[data.routeInstructions.length - 1].instruction += `${step.instruction.exit}e sortie`;
                            }

                            if (step.attributes.name) {
                                if (step.attributes.name.nom_1_droite || step.attributes.name.toponyme) {
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += " sur";
                                }

                                if (step.attributes.name.nom_1_droite) {
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += ` ${step.attributes.name.nom_1_droite}`;
                                }

                                if (step.attributes.name.toponyme) {
                                    data.routeInstructions[data.routeInstructions.length - 1].instruction += ` ${step.attributes.name.toponyme}`;
                                }
                            }
                        });
                    }
                }

                if (!data) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_ANALYSE", "json")));
                    return;
                }

                // Si la réponse contenait une exception renvoyée par le service
                if (data.exceptionReport) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION_2")));
                    return;
                }
            }
        } else {
            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
            return;
        }

        options.onSuccess.call(options.scope, data);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (RouteResponseFactory);


/***/ }),
/* 97 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * Response object for {@link module:Services~route Gp.Services.route ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Gp.BBox} bbox - Bounding Box of the route. Given when provideBBox parameter is used in function call.
 * @property {Object} routeGeometry - Geometry (expressed in [GeoJSON]{@link http://geojson.org/}) of the route.
 * @property {Array.<Gp.Services.Route.RouteInstruction>} routeInstructions - Instructions of the route.
 * @property {String} totalDistance - Length of the route. If distanceUnit parameter was set to "km" (default), totalDistance is a string containing the total distance expressed in kilometers, followed by " Km" (e.g. : "19.6 Km"). If distanceUnit parameter was set to "m", totalDistance is a string containing the total distance expressed in meters (e.g. : "19599.14").
 * @property {Float} totalTime - Route duration in seconds.
 *
 * @namespace
 * @alias Gp.Services.RouteResponse
 */
function RouteResponse () {
    if (!(this instanceof RouteResponse)) {
        throw new TypeError("RouteResponse constructor cannot be called as a function.");
    }

    this.totalTime = null;

    this.totalDistance = null;

    this.bbox = {
        left : null,
        right : null,
        top : null,
        bottom : null
    };

    this.routeGeometry = null; // FIXME can be null if option 'geometryInInstructions' is true !

    this.routeInstructions = [];
}

RouteResponse.prototype = {

    constructor : RouteResponse

};

/* harmony default export */ __webpack_exports__["default"] = (RouteResponse);


/***/ }),
/* 98 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Single Route Instruction object.
 *
 * @property {String} code - Instruction code :
 *
 * - "F" : Straight forward
 * - "B" : U-turn
 * - "L" : turn left
 * - "R" : turn right
 * - "BL" : turn left strongly
 * - "BR" : turn right strongly
 * - "FL" : turn lightly to the left
 * - "FR" : turn lightly to the right
 * - "round_about_entry" : round about entry
 * - "round_about_exit" : round about exit
 *
 * @property {String} instruction - Instruction text : translated code + street name
 * @property {Object} geometry - Geometry (expressed in [GeoJSON]{@link http://geojson.org/}) of the street.
 * @property {Float} distance - Length of the instruction. Expressed in km or m, depending on distanceUnit parameter.
 * @property {Float} duration - Instruction duration in seconds.
 *
 * @namespace
 * @alias Gp.Services.Route.RouteInstruction
 */
function RouteInstruction () {
    if (!(this instanceof RouteInstruction)) {
        throw new TypeError("RouteInstruction constructor cannot be called as a function.");
    }

    this.duration = null;

    this.distance = null;

    this.code = null;

    this.instruction = null;

    this.geometry = null; // FIXME can be null if option 'geometryInInstructions' is false !
}

RouteInstruction.prototype = {

    constructor : RouteInstruction

};

/* harmony default export */ __webpack_exports__["default"] = (RouteInstruction);


/***/ }),
/* 99 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _CommonService__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(46);
/* harmony import */ var _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(63);
/* harmony import */ var _Request_ProcessIsoCurveRequest__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(100);
/* harmony import */ var _Response_ProcessIsoCurveResponseFactory__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(102);









/**
 * @classdesc
 * Appel du service d'isochrone/distance du Géoportail :
 *     envoi de la requête construite selon les paramètres en options,
 *     éventuellement parsing et analyse  de la réponse,
 *     retour d'une réponse en paramètre de la fonction onSuccess.
 * @constructor
 * @extends {Gp.Services.CommonService}
 * @alias Gp.Services.ProcessIsoCurve
 * @param {Object} options - options spécifiques au service (+ les options heritées)
 *
 * @param {String} options.resource - La ressource utilisée pour le calcul : bdtopo-valhalla (par défaut) ou bdtopo-pgr.
 *
 * @param {String} options.outputFormat - Le format de la réponse du service iso : 'json' uniquement et par défaut.
 *
 * @param {Object} options.position - Point de départ du calcul.
 *      Coordonnées exprimées en longitudes, latitudes (EPSG:4326)
 *      @param {Float} options.position.x - Abcisse du point de départ du calcul d'isochrone/distance.
 *      @param {Float} options.position.y - Ordonnée du point de départ du calcul d'isochrone/distance.
 *
 * @param {String} options.srs - Projection.
 *      Système de coordonnées dans lequel les coordonnées du point « location » sont exprimées et
 *      dans lequel la géométrie de la courbe résultante sera exprimée.
 *      Par défaut, le système de coordonnées utilisé sera « EPSG:4326 ».
 *
 * @param {String} [options.graph = "voiture"] - Nom du graphe à utiliser pour le calcul (« Pieton » ou « Voiture »).
 *      La valeur par défaut est : «voiture»
 *
 * @param {Array.<String>} [options.exclusions] - DEPRECATED: Ce paramètre est conservé pour une rétrocompatibilité de l'api. Le nouveau paramètre à utiliser est options.constraints.
 *      Critères d'exclusions à appliquer pour le calcul.
 *      On précise ici le type de tronçons que l'on ne veut pas que l'isochrone/distance emprunte
 *      (valeurs possibles : « toll » (éviter les péages), « bridge », « tunnel »).
 *
 * @param {Object[]} [options.constraints] - Critères de contraintes à appliquer sur un itinéraire. Les valeurs disponibles dépendent de la ressource utilisée. Il est donc utile de regarder le getCapabilities.
 *      @param {String} [options.constraints.constraintType] - Type de la contrainte. Généralement "banned".
 *      @param {String} [options.constraints.key] - Clé de la contrainte. Généralement "wayType".
 *      @param {String} [options.constraints.operator] - Opérateur de la contrainte. Généralement "=".
 *      @param {String} [options.constraints.value] - Valeur de la contrainte. Généralement "autoroute".
 *
 * @param {String} [options.method = "time"] - Méthode utilisée pour le calcul de la courbe iso.
 *      Les valeurs possible sont "time" pour un calcul d'isochrone, "distance" pour un calcul d'isodistance.
 *      Pas de valeur spécifié équivaut à un calcul d'isochrone.
 *
 * @param {String} [options.distanceUnit = "m"] - Indique si la distance doit être exprimée en km ou m dans la réponse ("m" or "km").
 *
 * @param {String} [options.timeUnit = "second"] - Indique si la durée doit être exprimée en seconde, minute ou heure dans la réponse ("standard", "second", "minute", "hour"). Il peut-être formatté hh:mm::ss avec la valeur standard.
 *
 * @param {Float} options.time - Durée maximum (exprimée en secondes) à utiliser pour le calcul de la courbe à partir du ou jusqu'au point « location ».
 *      Ce paramètre doit être renseigné si l'option "méthod" a la valeur "time".
 *      Si l'option method n'est pas renseignée, ce paramètre doit être renseigné.
 *
 * @param {Float} options.distance - Distance maximum (exprimée en metres) à utiliser pour le calcul de la courbe à partir du ou j'usqu'au point « location ».
 *      Ce paramètre doit être renseigné si l'option "méthod" a la valeur "DISTANCE".
 *      Si l'option "method" n'est pas renseignée, ce paramètre sera ignoré.
 *
 * @param {Boolean} [options.reverse = false] - Indique si la géométrie résultante doit être lissée (« true ») pour ne pas avoir d'effet d'escalier.
 *      Par défaut, la valeur « false » est appliquée.
 *
 * @param {Boolean} [options.smoothing = false] - Indique si la géométrie résultante doit être lissée (« true ») pour ne pas avoir d'effet d'escalier.
 *      Par défaut, la valeur « false » est appliquée.
 *
 * @param {Boolean} [options.holes = false] - Indique si la géométrie résultante (surface) doit être retournée avec des trous (« true »).
 *      Par défaut, la valeur « false » est appliquée.
 *
 * @example
 *   var options = {
 *      // options communes aux services
 *      apiKey : null,
 *      serverUrl : 'http://localhost/service/',
 *      protocol : 'JSONP', // JSONP|XHR
 *      proxyURL : null,
 *      httpMethod : 'GET', // GET|POST
 *      timeOut : 10000, // ms
 *      rawResponse : false, // true|false
 *      scope : null, // this
 *      onSuccess : function (response) {},
 *      onFailure : function (error) {},
 *      // spécifique au service
 *      position : {
 *           x : 2.3242664298058053,
 *           y : 48.86118017324745
 *      },
 *      resource : bdtopo-valhalla,
 *      distance : 200,
 *      [time : ]
 *      method : "distance",
 *      graph : "voiture",
 *      reverse : false
 *  };
 */

function ProcessIsoCurve (options) {
    if (!(this instanceof ProcessIsoCurve)) {
        throw new TypeError(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("CLASS_CONSTRUCTOR", "ProcessIsoCurve"));
    }

    /**
     * Nom de la classe (heritage)
     * FIXME instance ou classe ?
     */
    this.CLASSNAME = "ProcessIsoCurve";

    // appel du constructeur par heritage
    _CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].apply(this, arguments);

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("Gp.Services.ProcessIsoCurve");
    this.logger.trace("[Constructeur ProcessIsoCurve (options)]");

    if (!options.position) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "position"));
    }

    // on lance une exception afin d'eviter au service de le faire...
    if (options.position.x === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "position.x"));
    }

    if (options.position.y === null) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_MISSING", "position.y"));
    }

    if (!options.time && !options.distance) {
        throw new Error("Parameter (s) 'distance' missing. Parameter time to calculate an isochrone, parameter distance for an isodistance");
    }

    // si on a que le paramètre "distance" en entrée, on calcule une isodistance.
    // Le paramètre "méthode" doit pour avoir une réponse du service, être passé à "distance"
    if (!options.time && options.distance) {
        this.options.method = "distance";
        // on supprime l'éventuel attribut time, résidu d'un appel antérieur
        if (this.options.time) {
            delete this.options.time;
        }
    }

    // si on a que le paramètre "time" en entrée, on calcule une isochrone.
    // Le paramètre "méthode" doit pour avoir une réponse du service, être passé à "time"
    if (options.time && !options.distance) {
        this.options.method = "time";
        // on supprime l'éventuel attribut time, résidu d'un appel antérieur
        if (this.options.distance) {
            delete this.options.distance;
        }
    }

    // au cas où on a ni l'un, ni l'autre...
    this.options.method = this.options.method || "time";

    // options par defaut du service
    // TODO: modifier la ressource lors de la mise en production du service
    this.options.resource = options.resource || "bdtopo-valhalla";
    this.options.exclusions = options.exclusions || [];
    this.options.reverse = options.reverse || false;
    this.options.srs = options.srs || "EPSG:4326";
    this.options.distanceUnit = options.distanceUnit || "m";
    this.options.timeUnit = options.timeUnit || "second";

    // options depreciees
    if (options.smoothing) {
        this.logger.warn("options.smoothing is DEPRECATED");
    }
    this.options.smoothing = false;
    if (options.holes) {
        this.logger.warn("options.holes is DEPRECATED");
    }
    this.options.holes = false;

    // Gestion du graphe
    if (options.graph) {
        if (options.graph === "Voiture") {
            this.options.graph = "car";
        }
        if (options.graph === "Pieton") {
            this.options.graph = "pedestrian";
        }
    } else {
        this.options.graph = "car";
    }

    // Gestions des contraintes
    this.options.constraints = [];
    if (options.constraints) {
        if (Array.isArray(options.constraints)) {
            for (var k = 0; k < options.constraints.length; k++) {
                this.options.constraints.push(options.constraints[k]);
            }
        } else {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_TYPE", "constraints"));
        }
    }

    // Gestion de l'ancien paramètre exclusions
    var constraintTunnel = {};
    var constraintPont = {};
    var constraintAutoroute = {};
    if (options.exclusions) {
        if (options.exclusions.length !== 0) {
            this.logger.warn("options.exclusions is DEPRECATED !!");
            for (var c = 0; c < options.exclusions.length; c++) {
                if (typeof options.exclusions[c] === "string") {
                    options.exclusions[c] = options.exclusions[c].toLowerCase();
                } else {
                    // on ne crée pas une erreur pour rétro-compatibilité avec les anciennes versions
                    continue;
                }
                if (options.exclusions[c] === "toll") {
                    constraintAutoroute.constraintType = "banned";
                    constraintAutoroute.key = "wayType";
                    constraintAutoroute.operator = "=";
                    constraintAutoroute.value = "autoroute";
                    this.options.constraints.push(constraintAutoroute);
                }
                if (options.exclusions[c] === "tunnel") {
                    constraintTunnel.constraintType = "banned";
                    constraintTunnel.key = "wayType";
                    constraintTunnel.operator = "=";
                    constraintTunnel.value = "tunnel";
                    this.options.constraints.push(constraintTunnel);
                }
                if (options.exclusions[c] === "bridge") {
                    constraintPont.constraintType = "banned";
                    constraintPont.key = "wayType";
                    constraintPont.operator = "=";
                    constraintPont.value = "pont";
                    this.options.constraints.push(constraintPont);
                }
            }
        }
    }

    // on passe l'option outputFormat en minuscules afin d'éviter des exceptions.
    this.options.outputFormat = (typeof options.outputFormat === "string") ? options.outputFormat.toLowerCase() : "json";
    if (options.outputFormat && options.outputFormat !== "json") {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_NOT_SUPPORT", "outputFormat"));
    }
    this.options.outputFormat = "json";

    // gestion de l'url du service par defaut
    // si l'url n'est pas renseignée, il faut utiliser les urls par defaut
    if (!this.options.serverUrl) {
        var urlFound = _DefaultUrlService__WEBPACK_IMPORTED_MODULE_4__["default"].ProcessIsoCurve.newUrl();
        if (!urlFound) {
            throw new Error("Url by default not found !");
        }
        this.options.serverUrl = urlFound;
        this.logger.trace("Serveur URL par defaut : " + this.options.serverUrl);
    }
}

/**
 * @lends module:ProcessIsoCurve#
 */
ProcessIsoCurve.prototype = Object.create(_CommonService__WEBPACK_IMPORTED_MODULE_3__["default"].prototype, {
    // todo
    // getter/setter
});

/*
 * Constructeur (alias)
 */
ProcessIsoCurve.prototype.constructor = ProcessIsoCurve;

/**
 * Création de la requête (overwrite)
 *
 * @param {Function} error   - callback des erreurs
 * @param {Function} success - callback
 */
ProcessIsoCurve.prototype.buildRequest = function (error, success) {
    try {
        var oIsoCurve = new _Request_ProcessIsoCurveRequest__WEBPACK_IMPORTED_MODULE_5__["default"](this.options);
        if (!oIsoCurve.processRequestString()) {
            throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_REQUEST_BUILD"));
        }

        this.request = oIsoCurve.requestString;
    } catch (e) {
        error.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](e.message));
        return;
    }

    success.call(this, this.request);
};

/**
 * (overwrite)
 * Analyse de la reponse
 *
 * @param {Function} onError   - callback des erreurs
 * @param {Function} onSuccess - callback de succès de l'analyse de la réponse
 */
ProcessIsoCurve.prototype.analyzeResponse = function (onError, onSuccess) {
    if (this.response) {
        var options = {
            response : this.response,
            outputFormat : this.options.outputFormat,
            rawResponse : this.options.rawResponse,
            onSuccess : onSuccess,
            onError : onError,
            scope : this
        };

        _Response_ProcessIsoCurveResponseFactory__WEBPACK_IMPORTED_MODULE_6__["default"].build(options);
    } else {
        onError.call(this, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
    }
};

/* harmony default export */ __webpack_exports__["default"] = (ProcessIsoCurve);


/***/ }),
/* 100 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _model_ProcessIsoCurveParam__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(101);





/**
 * @classdesc
 * Classe de gestion des requêtes sur le service de calcul d'isoschrone/isodistance.
 *  Les requêtes peuvent être en mode GET ou POST,
 *  et le format de sorti est en JSON.
 *
 * @constructor
 * @alias Gp.Services.ProcessIsoCurve.Request.ProcessIsoCurveRequest
 * @param {Object} options - options
 *
 * @example
 * var options = {
 *      httpMethod : 'GET', // GET|POST
 *      // spécifique au service
 *      position : {
 *          x : 2.3242664298058053,
 *          y : 48.86118017324745
 *      },
 *      graph : "car",
 *      method : 'time',
 *      time : 1000, //distance : 200
 *      reverse : false,
 *      srs : 'EPSG:4326'
 *  };
 *
 * try {
 *
 *      var oIsoCurve = new ProcessIsoCurveRequest (options);
 *      if (!oIsoCurve.processRequestString ()) {
 *          // error
 *      }
 *
 *      var request = oIsoCurve.requestString;
 *
 * } catch (e) {
 *      // error
 * }
 * @private
 */
function ProcessIsoCurveRequest (options) {
    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("ProcessIsoCurveRequest");
    this.logger.trace("[Constructeur ProcessIsoCurveRequest ()]");

    if (!(this instanceof ProcessIsoCurveRequest)) {
        throw new TypeError("ProcessIsoCurveRequest constructor cannot be called as a function.");
    }

    // existance des options
    if (!options) {
        throw new Error(_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("PARAM_EMPTY", "options"));
    }

    /**
     * Liste des options
     */
    this.settings = options;

    /**
     * Mode HTPP.
     * Par defaut, "GET".
     * @type {String}
     */
    this.mode = this.settings.httpMethod || "GET";
}

ProcessIsoCurveRequest.prototype = {

    /**
     * @lends module:ProcessIsoCurveRequest#
     */

    /**
     * Requête
     * @type {String}
     */
    requestString : null,

    /**
     * Constructeur (alias)
     */
    constructor : ProcessIsoCurveRequest,

    /**
     * Construction de la requête.
     *
     * @example
     * // GET  out :
     *   //  (http://wxs.ign.fr/KEY/isochrone?)
     *   //  resource=&
     *   //  point=&
     *   //  costValue=&
     *   //  costType=&
     *   //  profile=&
     *   //  constraints=&
     *   //  direction=&
     *   //  crs=
     *
     * // POST out :
     * {
     *  resource: "bduni-idf-pgr",
     *  point: "2.337306,48.849319",
     *  costValue: 100,
     *  costType: "time",
     *  profile: "car",
     *  constraints: [{
     *      constraintType: "banned",
     *      key: "ways_type",
     *      operator: "=",
     *      value: "autoroute"
     *  }]
     * }
     *
     * @returns {String} request
     */
    processRequestString : function () {
        var request = "";
        var i = 0;

        switch (this.mode) {
            case "GET":
                this.logger.trace("Process GET Request");

                // Mapping des options avec le service de l'API REST
                var oParams = new _model_ProcessIsoCurveParam__WEBPACK_IMPORTED_MODULE_2__["default"](this.settings);
                var params = oParams.getParams();

                for (i = 0; i < params.length; i++) {
                    var o = params[i];
                    if (request) {
                        request += "&";
                    }
                    request += o.k + "=" + o.v;
                }

                break;

            case "POST":
                this.logger.trace("Process POST Request");
                // creation du JSON
                var postRequest = {};

                postRequest.resource = this.settings.resource;

                postRequest.point = this.settings.position.x + "," + this.settings.position.y;

                if (this.settings.method === "distance") {
                    postRequest.costType = "distance";
                    postRequest.costValue = this.settings.distance;
                } else {
                    postRequest.costType = "time";
                    postRequest.costValue = this.settings.time;
                }

                postRequest.profile = this.settings.graph;

                if (this.settings.reverse) {
                    postRequest.direction = "arrival";
                } else {
                    postRequest.direction = "departure";
                }

                postRequest.constraints = this.settings.constraints;

                postRequest.distanceUnit = this.settings.distanceUnit;

                postRequest.timeUnit = this.settings.timeUnit;

                postRequest.crs = this.settings.srs;

                // conversion en chaîne de caractères
                request = JSON.stringify(postRequest);
                break;

            default:
                this.logger.error("No other HTTP method supported by the service !");
        }

        this.logger.trace(request);
        this.requestString = request;

        return this.requestString;
    }
};

/* harmony default export */ __webpack_exports__["default"] = (ProcessIsoCurveRequest);


/***/ }),
/* 101 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);



/**
 * @classdesc
 *
 * Classe de gestion des param. des requêtes du service de calcul des iso.
 * Permet le mapping avec les options du service.
 *
 * @constructor
 * @alias Gp.Services.ProcessIsoCurve.Request.ProcessIsoCurveParam
 * @param {Object} options - options
 * @private
 *
 */
function ProcessIsoCurveParam (options) {
    if (!(this instanceof ProcessIsoCurveParam)) {
        throw new TypeError("ProcessIsoCurveParam constructor cannot be called as a function.");
    }

    this.logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger();
    this.logger.trace("[Constructeur ProcessIsoCurveParam ()]");

    /**
     * Options en paramêtres du constructeur.
     */
    this.options = options || {};

    // mapping des options avec l'API REST

    /** Identifiant de l’isochrone */
    this.id = this.options.id;

    /** Resource */
    this.resource = this.options.resource;

    /** Coordonnées de départ (ou arrivée si le reverse est à true). */
    this.point = this.options.position;

    /** projection (code EPSG comme epsg:4326 ou wgs84) */
    this.crs = this.options.srs;

    /**
     * Profil de véhicule à utiliser pour le calcul.
     * Voiture ou Pieton
     */
    this.profile = this.options.graph;

    /** Liste des règles de restrictions à utiliser */
    this.constraints = this.options.constraints;

    this.reverse = this.options.reverse;

    this.timeUnit = this.options.timeUnit;

    this.distanceUnit = this.options.distanceUnit;

    /**
     * "time" pour isochrone ou "distance" for isodistance.
     * Par defaut, time...
     */
    if (this.options.method === "distance") {
        this.costType = "distance";
        this.costValue = this.options.distance;
        if (this.distanceUnit === "m" && this.costValue >= 50000) {
            this.distanceUnit = "km";
            this.costValue /= 1000;
        }
    } else {
        this.costType = "time";
        this.costValue = this.options.time;
    }
}

/**
 * CLASSNAME
 */
ProcessIsoCurveParam.CLASSNAME = "ProcessIsoCurveParam";

ProcessIsoCurveParam.prototype = {

    /**
     * @lends module:ProcessIsoCurveParam#
     */

    /**
     * Constructeur (alias)
     */
    constructor : ProcessIsoCurveParam,

    /**
     * Retourne le point
     * @returns {String} x,y
     */
    getLocation : function () {
        return this.point.x + "," + this.point.y;
    },

    /**
     * Retourne l'unité de la distance
     * @returns {String}
     */
    getDistanceUnit : function () {
        if (this.distanceUnit === "m") {
            return "meter";
        }
        if (this.distanceUnit === "km") {
            return "kilometer";
        }
        return "";
    },

    /**
     * Retourne la liste des contraintes
     * @returns {String}
     */
    getConstraints : function () {
        var constraintArray = [];

        if (this.constraints.length !== 0) {
            for (var k = 0; k < this.constraints.length; k++) {
                constraintArray.push(JSON.stringify(this.constraints[k]));
            }
        }
        return constraintArray.join("|");
    },

    /**
     * Retourne la direction
     * @returns {String}
     */
    getDirection : function () {
        if (this.reverse) {
            return "arrival";
        } else {
            return "departure";
        }
    }
};

/**
 * Tableau de clefs/valeurs pour param.
 *
 * @returns {Object[]} KVP
 */
ProcessIsoCurveParam.prototype.getParams = function () {
    var map = [];

    map.push({
        k : "resource",
        v : this.resource
    });

    map.push({
        k : "point",
        v : this.getLocation()
    });

    map.push({
        k : "direction",
        v : this.getDirection()
    });

    map.push({
        k : "costType",
        v : this.costType
    });

    map.push({
        k : "costValue",
        v : this.costValue
    });

    map.push({
        k : "profile",
        v : this.profile
    });

    map.push({
        k : "timeUnit",
        v : this.timeUnit
    });

    map.push({
        k : "distanceUnit",
        v : this.getDistanceUnit()
    });

    if (this.crs) {
        map.push({
            k : "crs",
            v : this.crs
        });
    }

    if (this.constraints) {
        map.push({
            k : "constraints",
            v : this.getConstraints()
        });
    }

    return map;
};

/* harmony default export */ __webpack_exports__["default"] = (ProcessIsoCurveParam);


/***/ }),
/* 102 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(44);
/* harmony import */ var _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45);
/* harmony import */ var _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(61);
/* harmony import */ var _model_ProcessIsoCurveResponse__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(103);





/**
 * Factory pour générer une reponse JSON à partir d'un JSON
 * (Factory)
 *
 * @module ProcessIsoCurveResponseFactory
 * @alias Gp.Services.ProcessIsoCurve.Response.ProcessIsoCurveResponseFactory
 * @private
 */
var ProcessIsoCurveResponseFactory = {

    /**
     * interface unique
     *
     * @method build
     * @static
     * @param {Object} options - options definies dans le composant ProcessIsoCurve
     *
     * @example
     *   var options = {
     *      response :
     *      outputFormat :
     *      rawResponse :
     *      scope :
     *      onSuccess :
     *      onError :
     *   };
     *
     */
    build : function (options) {
        // logger
        var logger = _Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("ProcessIsoCurveResponseFactory");
        logger.trace(["ProcessIsoCurveResponseFactory::build()"]);

        var data = null;

        if (options.response) {
            if (options.rawResponse) {
                logger.trace("analyze response : raw");
                data = options.response;
            } else {
                logger.trace("analyze response : json");

                var JSONResponse;
                if (typeof options.response === "string") {
                    JSONResponse = JSON.parse(options.response);
                } else {
                    JSONResponse = options.response;
                }

                // analyse de la reponse
                // création de l'objet de réponse
                data = new _model_ProcessIsoCurveResponse__WEBPACK_IMPORTED_MODULE_3__["default"]();

                // remplissage de l'objet créé avec les attribtuts de la réponse du service
                if (JSONResponse) {
                    if (JSONResponse.costType === "distance") {
                        data.time = "";
                        data.distance = JSONResponse.costValue;
                    } else {
                        data.time = JSONResponse.costValue;
                        data.distance = "";
                    }

                    data.message = "";
                    data.id = "";
                    data.srs = JSONResponse.crs;
                    data.geometry = JSONResponse.geometry;
                    var coords = JSONResponse.point.split(",");
                    if (data.location) {
                        data.location.x = coords[0];
                        data.location.y = coords[1];
                    }
                } else {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_ANALYSE", options.response)));
                    return;
                }

                // info : en cas de problèmes de droits (clé invalide ou autre), la réponse est au format XML !!
                // ex. <ExceptionReport><Exception exceptionCode="MissingParameter">Key does not exist or has expired</Exception></ExceptionReport>
                // mais le statut est 403, l'erreur est donc remontée plus tôt.
                if (data.exceptionReport) {
                    options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"]({
                        message : _Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EXCEPTION", data.exceptionReport),
                        type : _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"].TYPE_SRVERR,
                        status : 200
                    }));
                    return;
                }
            }
        } else {
            // si la réponse est vide, on appelle le callback d'erreur
            options.onError.call(options.scope, new _Exceptions_ErrorService__WEBPACK_IMPORTED_MODULE_2__["default"](_Utils_MessagesResources__WEBPACK_IMPORTED_MODULE_1__["default"].getMessage("SERVICE_RESPONSE_EMPTY")));
            return;
        }

        // si tout s'est bien passé, on appelle le callback de succès
        options.onSuccess.call(options.scope, data);
    }
};

/* harmony default export */ __webpack_exports__["default"] = (ProcessIsoCurveResponseFactory);


/***/ }),
/* 103 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);

/**
 * Response object for {@link module:Services~isoCurve Gp.Services.isoCurve ()} invocation when successful. Received as the argument of onSuccess callback function.
 *
 * @property {Float} distance - distance (expressed in meters) used for the request.
 * @property {Float} time - time (expressed in seconds) used for the request.
 * @property {Object} geometry - Geometry (expressed in [GeoJSON]{@link http://geojson.org/}) of the isocurve.
 * @property {String} id - request id (used by underlying webservice).
 * @property {Gp.Point} location - Position of the start or end point used for the request (expressed in "srs" coordinates system).
 * @property {String} message - message
 * @property {String} srs - Identifier of the coordinates system used for the isocurve.
 *
 * @namespace
 * @alias Gp.Services.IsoCurveResponse
 *
 */
function ProcessIsoCurveResponse () {
    if (!(this instanceof ProcessIsoCurveResponse)) {
        throw new TypeError("ProcessIsoCurveResponse constructor cannot be called as a function.");
    }

    this.message = null;

    this.id = null;

    this.location = {};
    this.location.x = null;
    this.location.y = null;

    this.srs = null;

    this.geometry = null;

    this.time = null;

    this.distance = null;
}

ProcessIsoCurveResponse.prototype = {

    constructor : ProcessIsoCurveResponse

};

/* harmony default export */ __webpack_exports__["default"] = (ProcessIsoCurveResponse);


/***/ }),
/* 104 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37);
/* harmony import */ var _Common_Controls_LocationSelectorDOM__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(105);
/* harmony import */ var _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(107);
/* harmony import */ var _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(108);
/* harmony import */ var _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(106);








var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("locationselector");

/**
* @classdesc
*
* LocationSelector Control.
*
* @private
* @constructor LocationSelector
* @alias LocationSelector
* @extends {L.Control}
* LocationSelector component. Enables to select a location, using autocompletion or picking location on the map
* @param {Object} [options] - component options
* @param {Boolean} [options.displayInfo = true] - whether to display info in a popup or not (not implemented yet) Default is true
* @param {Boolean} [options.disableReverse = false] - whether to enable/disable the reverse geocoding.
* @param {Object} [options.tag] - tag options
* @param {Number} [options.tag.id = 0] - order id number in a locations group, in case several LocationSelector are used. For instance in route case : departure tag id should be 0, arrival tag id should be 1, and other ones : 2, 3, ...
* @param {Number} [options.tag.unique = null] - locationSelector global component id (in case locationSelector is called by another graphic component, e.g. route control)
* @param {String} [options.tag.label = ">"] - text to display in component (e.g. "Departure"). Default is ">"
* @param {String} [options.tag.color = blue] - color of marker (blue, green, orange and red)
* @param {Boolean} [options.tag.display = true] - whether to display or hide component. Default is true
* @param {Boolean} [options.tag.addOption = false] - whether to display picto to add another LocationSelector (in case of route control)
* @param {Boolean} [options.tag.removeOption = false] - whether to display picto to remove a LocationSelector (in case of route control)
* @param {Object} [options.autocompleteOptions] - autocomplete service options
* @param {Object} [options.reverseGeocodeOptions] - reverse geocoding service options

* @example
*  var point = L.geoportalControl.LocationSelector({
*  });
*/
var LocationSelector = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends LocationSelector.prototype */{
  includes: _Common_Controls_LocationSelectorDOM__WEBPACK_IMPORTED_MODULE_4__["default"],
  /**
   * options by default
   *
   * @private
   */
  options: {
    position: "topleft",
    tag: {
      id: 0,
      // numero d'ordre sur un groupe de locations !
      unique: null,
      // numero unique pour tous les locations d'un groupe !
      label: ">",
      color: "blue",
      display: true,
      addOption: false,
      removeOption: false
    },
    disableReverse: false,
    // on l'active par defaut !
    displayInfo: true,
    autocompleteOptions: {},
    reverseGeocodeOptions: {}
  },
  /**
   * constructor
   * (extend to L.Control)
   *
   * @param {Object} options - options of component
   * @param {String}  [options.position] - position of component into a map.
   * @param {Object}  [options.tag] - options ...
   * @param {Object}  [options.autocompleteOptions] - autocomplete service options
   * @param {Object}  [options.reverseGeocodeOptions] - reverse geocoding service options
   *
   * @private
   */
  initialize: function initialize(options) {
    // FIXME pb de merge sur tag:{} !?
    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.setOptions(this, options);

    /** uuid */
    this._uid = this.options.tag.unique || null;

    /** mode drag&drop */
    this._activeDragAndDrop = false;
    this._pressedKeyOnDragAndDrop = false;

    /** container map */
    this._map = null;

    /** container principal des entrées  */
    this._inputsContainer = null;

    /** container du label du point */
    this._inputLabelContainer = null;

    /** container de la saisi de l'autocompletion */
    this._inputAutoCompleteContainer = null;

    /** container du pointer de saisi sur la carte */
    this._inputShowPointerContainer = null;

    /** container des coordonnées */
    this._inputCoordinateContainer = null;

    /**
     * coordonnées du point selectionné
     * Ces dernieres sont envoyées à l'API service IGN,
     */
    this._coordinate = null;

    /** container des reponses de l'autocompletion */
    this._suggestedContainer = null;

    /** listes des reponses de l'autocompletion */
    this._suggestedLocations = [];

    /** localisant */
    this._currentLocation = null;

    /** marker */
    this._marker = null;

    /** ressources du services d'autocompletion et geocodage inverse (ayant droit!) */
    this._resources = {};

    // creation du DOM dans le constructeur uniquement si ce composant
    // est appelé par un autre composant graphique
    this._container = this._uid ? this._initLayout() : null;
  },
  // ################################################################### //
  // ################## handlers for display graphic ################### //
  // ################################################################### //

  /**
   * this method is called by this.addTo(map)
   * and fills variable : this._container = this.onAdd(map)
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  onAdd: function onAdd( /* map */
  ) {
    // si on ajout ce composant à la carte en tant que objet graphique,
    // un uuid doit être generé automatiquement !
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].generate();

    // DOM du composant
    var container = this._initLayout();

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    return container;
  },
  /**
   * this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @private
   */
  onRemove: function onRemove( /* map */) {},
  // ################################################################### //
  // ########################## publics methods ######################## //
  // ################################################################### //

  /**
   * get coordinate
   * @returns {Object} Coordinate
   */
  getCoordinate: function getCoordinate() {
    return this._coordinate;
  },
  /**
   * set coordinate : {lon,lat || x,y || N,E}
   * @param {Object} coordinate - Coordinate
   */
  setCoordinate: function setCoordinate(coordinate) {
    this._displayResultOfCoordinate(coordinate);
  },
  /**
   * set map
   *
   * @param {Object} map - the map
   */
  setMap: function setMap(map) {
    if (!this._map) {
      this._map = map;
    }
  },
  /**
   * clean
   */
  clear: function clear() {
    this._setCursor();
    this._setMarker();
    this._clearResults();
    this._inputLabelContainer.click();
  },
  /**
   * disable/enable the drag&drop mode
   *
   * @param {Boolean} active - true:enable | false:disable
   */
  dragging: function dragging(active) {
    if (this._marker) {
      if (active) {
        this._marker.dragging.enable();
      } else {
        this._marker.dragging.disable();
      }
    }
  },
  // ################################################################### //
  // ########################## pivates methods ######################## //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  _initLayout: function _initLayout() {
    var id = this.options.tag.id;

    // create main container
    var container = this._createMainContainerElement();
    var inputs = this._inputsContainer = this._createLocationPointElement(id, this.options.tag.display);
    container.appendChild(inputs);
    var _inputLabel = this._inputLabelContainer = this._createLocationPointLabelElement(id, this.options.tag.label);
    inputs.appendChild(_inputLabel);
    var _inputAutoComplete = this._inputAutoCompleteContainer = this._createLocationAutoCompleteteInputElement(id);
    inputs.appendChild(_inputAutoComplete);
    var _inputCoordinate = this._inputCoordinateContainer = this._createLocationCoordinateInputElement(id);
    inputs.appendChild(_inputCoordinate);
    var _inputShowPointer = this._inputShowPointerContainer = this._createLocationPointerShowInputElement(id);
    inputs.appendChild(_inputShowPointer);
    var _inputPointer = this._createLocationPointerInputElement(id);
    inputs.appendChild(_inputPointer);
    if (this.options.tag.addOption) {
      var _inputAddStage = this._createLocationAddPointElement();
      inputs.appendChild(_inputAddStage);
    }
    if (this.options.tag.removeOption) {
      var _inputRemoveStage = this._createLocationRemovePointElement(id);
      inputs.appendChild(_inputRemoveStage);
    }
    var results = this._suggestedContainer = this._createLocationAutoCompleteResultElement(id);
    container.appendChild(results);
    return container;
  },
  // ################################################################### //
  // ################# privates methods use by events ################## //
  // ################################################################### //

  /**
   * this sends the label to the panel.
   *
   * @param {String} label - label suggested location
   *
   * @private
   */
  _setLabel: function _setLabel(label) {
    this._inputAutoCompleteContainer.value = label || "";
  },
  /**
   * this sends the coordinates to the panel.
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   *
   * @private
   */
  _setCoordinate: function _setCoordinate(oLatLng) {
    // structure
    // L.LatLng
    //     lat: 4.07249425916745
    //     lng: 2.4609375

    // FIXME les coordonnées en lat/lon sur du EPSG:4326 !
    // Mais règle sur les services : X -> LON et Y -> LAT
    this._coordinate = oLatLng;
    var lat = null;
    var lng = null;

    // decimal by default !
    lat = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__["default"].roundToDecimal(oLatLng.lat, 4);
    lng = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__["default"].roundToDecimal(oLatLng.lng, 4);

    // on envoie du lon/lat à l'affichage
    var value = lng + " , " + lat;
    this.GPdisplayCoordinate(value);
  },
  /**
   * this method is called by this.on*ResultsItemClick()
   * and move/zoom on a position.
   *
   * @param {Object} position - {lon: ..., lat: ...}
   *
   * @private
   */
  _setPosition: function _setPosition(position) {
    logger.log("_setPosition()", position);
    var map = this._map;
    // TODO zoom
    // map.setZoomAround(L.latLng(position), map.getMaxZoom(), true);
    // FIXME on veut du lat/lon sur Leaflet donc on inverse !
    map.panTo(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(position));
  },
  /**
   * this method is called by this.on*ResultsItemClick()
   * and displays a marker.
   * FIXME : marker IGN et informations ?
   *
   * @param {Object} position - position {lon: ..., lat: ...}
   * @param {Object|String} information - suggested or geocoded information
   * @param {Boolean} display - display a popup information
   *
   * @private
   */
  _setMarker: function _setMarker(position, information, display) {
    logger.log("_setMarker()", position, information, display);

    // sur du drag&drop, on garde le même marker !
    if (this._activeDragAndDrop) {
      return;
    }
    var map = this._map;
    // on supprime le marker, ainsi que les events
    // sur le drag&drop
    if (this._marker != null) {
      this._marker.off("mousedown", this.onMouseDownMarker, this);
      this._marker.off("dragstart", this.onStartDragMarker, this);
      this._marker.off("drag", this.onDragMarker, this);
      this._marker.off("dragend", this.onEndDragMarker, this);
      map.removeLayer(this._marker);
      this._marker = null;
    }
    if (position) {
      // cf. http://leafletjs.com/reference.html#marker-options
      var options = {
        icon: new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__["default"](this.options.tag.color),
        draggable: true,
        clickable: true,
        zIndexOffset: 1000
      };

      // FIXME on veut du lat/lon sur Leaflet donc on inverse !
      this._marker = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.marker(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(position), options);
      this._marker.on("mousedown", this.onMouseDownMarker, this);
      this._marker.on("dragstart", this.onStartDragMarker, this);
      this._marker.on("drag", this.onDragMarker, this);
      this._marker.on("dragend", this.onEndDragMarker, this);
      // this._marker.on("movestart", this.onStartMoveMarker, this);
      // this._marker.on("move",      this.onMoveMarker, this);
      // this._marker.on("moveend",   this.onEndMoveMarker, this);

      this._marker.addTo(map);

      // FIXME
      // doit on mettre une information
      // - correctement construite ?
      // - uniquement informatif ?
      // - RIEN ?
      if (display) {
        var popupContent = null;
        if (typeof information !== "string") {
          if (information.service === "GeocodedLocation") {
            popupContent = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_7__["default"].getGeocodedLocationFreeform(information.location);
          } else if (information.service === "SuggestedLocation") {
            popupContent = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_7__["default"].getSuggestedLocationFreeform(information.location);
          } else {
            popupContent = "sans informations.";
          }
        } else {
          popupContent = information;
        }
        this._marker.bindPopup(popupContent);
      }
    }
  },
  /**
   * this method is called by this.on()
   * and change the cursor of the map when entering a point.
   *
   * @param {String} cursor - cursor style
   *
   * @private
   */
  _setCursor: function _setCursor(cursor) {
    var div = this._map.getContainer();
    if (cursor) {
      div.style.cursor = cursor;
    } else {
      div.style.cursor = null;
    }
  },
  /**
   * this method is called by this.()
   * and it clears all results and the marker.
   *
   * @private
   */
  _clearResults: function _clearResults() {
    this._currentLocation = null;
    this._coordinate = null;
    this._clearSuggestedLocation();
  },
  /**
   * this method is called by this.onAutoCompleteSearchText()
   * and it clears all suggested location.
   *
   * @private
   */
  _clearSuggestedLocation: function _clearSuggestedLocation() {
    // suppression du dom
    this._suggestedLocations = [];
    if (this._suggestedContainer) {
      while (this._suggestedContainer.firstChild) {
        this._suggestedContainer.removeChild(this._suggestedContainer.firstChild);
      }
    }
  },
  // ################################################################### //
  // ############## privates methods use by autocomplete ############### //
  // ################################################################### //

  /**
   * this method is called by this.onAutoCompleteSearch()
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   * @param {String}   settings.text - text
   * @param {Function} settings.onSuccess - callback
   * @param {Function} settings.onFailure - callback
   *
   * @private
   */
  _requestAutoComplete: function _requestAutoComplete(settings) {
    logger.log("_requestAutoComplete()", settings);

    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si la parametre 'text' est vide !
    if (!settings.text) {
      return;
    }
    logger.log(settings);
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.autocompleteOptions);
    // ainsi que la recherche et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);

    // cas où la clef API n'est pas renseignée dans les options du service,
    // celle renseignée au niveau du controle ou la clé "calcul" par défaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.autoComplete(options);
  },
  /**
   * this method is called by this.onAutoCompleteSearchText()
   * and fills the container of the location list.
   * it creates a HTML Element per location
   * (cf. this. ...)
   *
   * @param {Object[]} locations - locations
   *
   * @private
   */
  _fillAutoCompletedLocationListContainer: function _fillAutoCompletedLocationListContainer(locations) {
    logger.log("_fillAutoCompletedLocationListContainer()", locations);
    if (!locations || locations.length === 0) {
      return;
    }

    // on vide la liste avant de la construire
    var element = this._suggestedContainer;
    if (element.childElementCount) {
      while (element.firstChild) {
        element.removeChild(element.firstChild);
      }
    }
    for (var i = 0; i < locations.length; i++) {
      // Proposals are dynamically filled in Javascript by autocomplete service
      this._createLocationAutoCompletedLocationElement(this.options.tag.id, locations[i], i);
    }

    // sauvegarde de l'etat des locations
    this._suggestedLocations = locations;
  },
  // ################################################################### //
  // ################# privates methods use by reverse ################# //
  // ################################################################### //

  /**
   * this method is called by this.onMouseMapClick() or this.onEndDragMarker()
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   * @param {String}   settings.position - position
   * @param {Function} settings.onSuccess - callback
   * @param {Function} settings.onFailure - callback
   *
   * @private
   */
  _requestReverseGeocode: function _requestReverseGeocode(settings) {
    logger.log("_requestReverseGeocode()", settings);

    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si la parametre 'position' est vide !
    if (!settings.searchGeometry || Object.keys(settings.searchGeometry).length === 0) {
      return;
    }
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.reverseGeocodeOptions);

    // ainsi que la positions et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);

    // on force qq options !
    // La table de geocodage est toujours par defaut : StreetAddress !
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      returnFreeForm: true,
      // FIXME cette option n'est pas implementée !?
      index: "StreetAddress"
    });

    // cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.reverseGeocode(options);
  },
  /**
   * display Coordinate on panel, and places the marker on map
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   * @private
   */
  _displayResultOfCoordinate: function _displayResultOfCoordinate(oLatLng) {
    // on transmet les coordonnées au panneau
    this._setCoordinate(oLatLng);

    // on met en place le marker
    this._setMarker(oLatLng, null, false);
    logger.log(this.getCoordinate());

    // on desactive l'event sur la map en activant le gestionnaire !
    this.onActivateMapPointClick();
  },
  /**
   * display Label on panel, and places the marker on map
   *
   * @param {Object} oLocation - location Object
   * @private
   */
  _displayResultOfLabel: function _displayResultOfLabel(oLocation) {
    // FIXME Le service est intérrogé en SRS EPSG:4326 par defaut,
    // donc on récupère du lat/lon en reponse.
    // mais on inverse car on souhaite transmettre des coordonnées en lon/lat...

    // FIXME on construit une addresse car l'option freeForm ne semble pas
    // être fonctionnelle...
    var label = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_7__["default"].getGeocodedLocationFreeform(oLocation);

    // on transmet les coordonnées au panneau,
    // même si on ne les affiche pas...
    this._setCoordinate({
      lat: oLocation.position.lat,
      lng: oLocation.position.lon
    });

    // on transmet le texte au panneau
    this._setLabel(label);
    var info = {
      service: "GeocodedLocation",
      location: oLocation
    };

    // on met en place le marker
    this._setMarker(oLocation.position, info, true);
    this._inputShowPointerContainer.checked = false;
    this._inputAutoCompleteContainer.className = "GPlocationOriginVisible";
    this._inputCoordinateContainer.className = "GPlocationOriginHidden";

    // on desactive l'event sur la map en activant le gestionnaire !
    this.onActivateMapPointClick();
  },
  // ################################################################### //
  // ###################### handlers events (dom) ###################### //
  // ################################################################### //

  /**
   * this method is called by event 'keyup' on 'GPLocationOrigin' tag input
   * (cf. this.), and it gets the value of input.
   * this value is passed as a parameter for the service autocomplete (text).
   * the results of the request are displayed into a drop down menu.
   * FIXME
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onAutoCompleteSearchText: function onAutoCompleteSearchText(e) {
    logger.log("onAutoCompleteSearchText()", e);
    var value = e.target.value;
    if (!value) {
      return;
    }

    // on sauvegarde le localisant
    this._currentLocation = value;

    // on limite les requêtes à partir de 3 car. saisie !
    if (value.length < 3) {
      return;
    }

    // INFORMATION
    // on effectue la requête au service d'autocompletion.
    // on met en place des callbacks afin de recuperer les resultats ou
    // les messages d'erreurs du service.
    // les resultats sont affichés dans une liste deroulante.
    var context = this;
    this._requestAutoComplete({
      text: value,
      maximumResponses: 5,
      // FIXME je limite le nombre de reponse car le container DOM est limité dans l'affichage !!!
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results) {
          var locations = results.suggestedLocations;
          context._fillAutoCompletedLocationListContainer(locations);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME
        // où affiche t on les messages : ex. 'No suggestion matching the search' ?
        // doit on nettoyer la liste des suggestions dernierement enregistrée :
        context._clearSuggestedLocation();
        logger.log(error.message);
      }
    });
  },
  /**
   * this method is called by event 'click' on 'GPautoCompleteResultsList' tag div
   * (cf. this._createAutoCompleteListElement), and it selects the location.
   * this location displays a marker on the map.
   * FIXME
   * TODO
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onAutoCompletedResultsItemClick: function onAutoCompletedResultsItemClick(e) {
    logger.log("onAutoCompletedResultsItemClick()", e);
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);
    logger.log(idx);
    logger.log(this._suggestedLocations[idx]);
    if (!idx) {
      return;
    }
    var position = {
      lon: this._suggestedLocations[idx].position.x,
      // LON !
      lat: this._suggestedLocations[idx].position.y // LAT !
    };
    var info = {
      service: "SuggestedLocation",
      location: this._suggestedLocations[idx]
    };
    var label = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_7__["default"].getSuggestedLocationFreeform(this._suggestedLocations[idx]);
    this._setLabel(label);
    this._setPosition(position);
    this._setMarker(position, info, this.options.displayInfo);

    // on sauvegarde le point courant
    this._coordinate = position;
  },
  /**
   * this method is called by event 'click' on '' tag input
   * (cf. this.), and it create or remove the event of click map.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onActivateMapPointClick: function onActivateMapPointClick(e) {
    logger.trace("onActivateMapPointClick()", e);
    var map = this._map;
    if (this._inputShowPointerContainer.checked) {
      if (!this._activeDragAndDrop) {
        map.on("click", this.onMouseMapClick, this);
        // on change le curseur
        this._setCursor("crosshair");
        // on supprime le marker
        this._setMarker();
        // on efface l'ancien resultat
        this._clearResults();
      }
    } else {
      if (!this._activeDragAndDrop) {
        map.off("click", this.onMouseMapClick, this);
        // on retablie le curseur d'origine
        this._setCursor();
      }
    }
  },
  /**
   * this method is called by event 'click' on '(n)' tag label
   * (cf. this.).
   * this point is erased.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onLocationClearPointClick: function onLocationClearPointClick(e) {
    logger.log("onLocationClearPointClick", e);
    this._setCursor();
    this._setMarker();
    this._clearResults();
    this._inputAutoCompleteContainer.focus();
  },
  /**
   * this method is called by event 'click' on '(n)' tag input
   * (cf. this.).
   * this point is deleted.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onLocationRemovePointClick: function onLocationRemovePointClick(e) {
    logger.log("onLocationRemovePointClick", e);
    this._setCursor();
    this._setMarker();
    this._clearResults();
  },
  /**
   * TODO this method is called by event 'click' on '(n)' tag input
   * (cf. this.).
   * this point is added as a parameter for the service Location.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onLocationAddPointClick: function onLocationAddPointClick(e) {
    logger.log("onLocationAddPointClick", e);
  },
  // ################################################################### //
  // #################### handlers events (control) #################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on map
   * (cf. this.onLocationMapPointClick), and it gets the coordinate of click on map.
   * this point is saved as a parameter for the service Location.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMouseMapClick: function onMouseMapClick(e) {
    logger.log("onMouseMapClick", e);

    // les coordonnées
    var oLatLng = e.latlng;

    // si le geocodage inverse est desactivé,
    // on transmet les coordonnées au panneau,
    // sinon, on transmet la reponse du service
    if (this.options.disableReverse) {
      // on transmet les coordonnées au panneau, puis on place le marker
      this._displayResultOfCoordinate(oLatLng);
    } else {
      // contexte
      var self = this;

      // on realise une requête au service, si la reponse est vide ou
      // en échec, on transmet les coordonnées !
      this._requestReverseGeocode({
        searchGeometry: {
          type: "Circle",
          coordinates: [oLatLng.lng, oLatLng.lat],
          radius: 50
        },
        maximumResponses: 1,
        // callback onSuccess
        onSuccess: function onSuccess(results) {
          logger.log(results);
          if (results.locations.length !== 0) {
            var oLocation = results.locations[0];
            self._displayResultOfLabel(oLocation);
          } else {
            self._displayResultOfCoordinate(oLatLng);
          }
        },
        // callback onFailure
        onFailure: function onFailure(error) {
          logger.log(error.message);
          self._displayResultOfCoordinate(oLatLng);
        }
      });
    }
  },
  /**
   * this method is called by event 'startdrag' on marker
   * and it initializes the drag&drop.
   *
   * @private
   */
  onStartDragMarker: function onStartDragMarker() {
    if (!this._marker) {
      return;
    }
    this._activeDragAndDrop = true;
    this._inputShowPointerContainer.checked = true;
    this._inputAutoCompleteContainer.className = "GPlocationOriginHidden";
    this._inputCoordinateContainer.className = "GPlocationOriginVisible";
    this._marker.unbindPopup();
    this._setLabel();
    this._clearResults();
  },
  /**
   * this method is called by event 'drag' on marker
   * and it updates the panel of coordinate.
   *
   * @private
   */
  onDragMarker: function onDragMarker() {
    if (!this._marker) {
      return;
    }
    this._activeDragAndDrop = false;
    this._inputShowPointerContainer.checked = true;

    // on transmet les coordonnées au panneau
    var oLatLng = this._marker.getLatLng();
    this._setCoordinate(oLatLng);
  },
  /**
   * this method is called by event 'enddrag' on marker
   * and it finishes the drag&drop.
   * this point is saved as a parameter for the service Location.
   *
   * @private
   */
  onEndDragMarker: function onEndDragMarker() {
    if (!this._marker) {
      return;
    }
    this._inputShowPointerContainer.checked = true;
    var oLatLng = this._marker.getLatLng();
    if (this._pressedKeyOnDragAndDrop) {
      // on transmet les coordonnées au panneau
      this._setCoordinate(oLatLng);
    } else {
      logger.log("No key pressed, so autocomplete solution !");
      this.onMouseMapClick({
        latlng: oLatLng
      });
    }

    // init
    this._activeDragAndDrop = false;
    this._pressedKeyOnDragAndDrop = false;
  },
  /**
   * this method is called by event 'mousedown' on marker..
   * this event gets the pressed key code.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMouseDownMarker: function onMouseDownMarker(e) {
    if (!this._marker) {
      return;
    }
    this._pressedKeyOnDragAndDrop = e.originalEvent.ctrlKey;
  }
});
/* harmony default export */ __webpack_exports__["default"] = (LocationSelector);

/***/ }),
/* 105 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(37);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);
/* harmony import */ var _Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(106);



var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("LocationSelectorDOM");
var LocationSelectorDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.className = this._addUID("GPlocationPoint"); // ceci permet de gerer les groupes de points !
    container.className += " GPwidget";
    return container;
  },
  /**
   * Create Container Point
   * see event !
   *
   * @param {Number} id - tag ID
   * @param {Number} display  - display
   * @returns {DOMElement} DOM element
   */
  _createLocationPointElement: function _createLocationPointElement(id, display) {
    var div = document.createElement("div");
    div.id = this._addUID("GPlocationPoint_" + id);
    div.className = display ? "GPflexInput GPlocationStageFlexInput" : "GPflexInput GPlocationStageFlexInputHidden";
    div.style.cssText = "";
    return div;
  },
  /**
   * Create Container Point
   * see event !
   *
   * @param {Number} id - tag ID
   * @param {String} text - label
   * @returns {DOMElement} DOM element
   */
  _createLocationPointLabelElement: function _createLocationPointLabelElement(id, text) {
    // contexte d'execution
    var self = this;
    var labelOrigin = document.createElement("label");
    labelOrigin.id = this._addUID("GPlocationOriginLabel_" + id);
    labelOrigin.htmlFor = this._addUID("GPlocationOrigin_" + id);
    labelOrigin.innerHTML = text;
    labelOrigin.addEventListener("click", function (e) {
      var i = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(this.id);
      var points = document.getElementsByClassName(self._addUID("GPlocationPoint"));
      for (var j = 0; j < points.length; j++) {
        var tag = points[j].childNodes[0].id;
        var id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
        document.getElementById(self._addUID("GPlocationPoint_" + id)).style.cssText = "";
      }
      document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).value = "";
      document.getElementById(self._addUID("GPlocationOrigin_" + i)).value = "";
      document.getElementById(self._addUID("GPlocationPoint_" + i)).style.cssText = "";
      document.getElementById(self._addUID("GPlocationOriginPointer_" + i)).checked = false;
      document.getElementById(self._addUID("GPlocationOrigin_" + i)).className = "GPlocationOriginVisible";
      document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).className = "GPlocationOriginHidden";
      if (document.getElementById(self._addUID("GPlocationStageRemove_" + i))) {
        document.getElementById(self._addUID("GPlocationStageRemove_" + i)).className = "GPlocationStageRemove";
      }
      if (document.getElementById(self._addUID("GPlocationStageAdd"))) {
        document.getElementById(self._addUID("GPlocationStageAdd")).className = "";
      }
      // document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).disabled = true;
      self.onLocationClearPointClick(e);
    });
    return labelOrigin;
  },
  /**
   * Create Input AutoComplete Point tag
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationAutoCompleteteInputElement: function _createLocationAutoCompleteteInputElement(id) {
    // contexte d'execution
    var self = this;
    var inputOrigin = document.createElement("input");
    inputOrigin.id = this._addUID("GPlocationOrigin_" + id);
    inputOrigin.className = "GPlocationOriginVisible";
    inputOrigin.type = "text";
    inputOrigin.placeholder = "Saisir une adresse";
    inputOrigin.autocomplete = "off";
    inputOrigin.addEventListener("keyup", function (e) {
      var charCode = e.which || e.keyCode;
      if (charCode === 13 || charCode === 10 || charCode === 38 || charCode === 40) {
        return;
      }
      var i = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(this.id);
      if (document.getElementById(self._addUID("GPlocationOrigin_" + i)).value.length > 2) {
        document.getElementById(self._addUID("GPlocationAutoCompleteList_" + i)).style.display = "block";
      } else {
        document.getElementById(self._addUID("GPlocationAutoCompleteList_" + i)).style.display = "none";
      }
      // gestionnaire d'evenement :
      // on récupère la valeur de saisie pour une requête sur le service d'autocompletion.
      // le resultat de la requête nous permet de recuperer les coordonnées du point...
      self.onAutoCompleteSearchText(e);
    });
    inputOrigin.addEventListener("keydown", function (e) {
      var charCode = e.which || e.keyCode;
      var container = document.getElementById(self._addUID("GPlocationAutoCompleteList_" + id));

      // si aucun container !?
      if (!container) {
        return;
      }
      var curr = container.getElementsByClassName("GPautoCompleteProposal current");
      var list = container.getElementsByClassName("GPautoCompleteProposal");

      // si aucune suggestion, on ne va pas plus loin !
      var length = list.length;
      if (!length) {
        return;
      }
      var current = null;

      // si aucun item courant, on prend le 1er !
      if (!curr.length) {
        current = list[0];
        current.className = "GPautoCompleteProposal current";
        current.style.color = "#000000";
        current.style["background-color"] = "#CEDBEF";
        return;
      } else {
        current = curr[0];
      }
      var index = parseInt(_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(current.id), 10);
      var next = index === length - 1 ? list[0] : list[index + 1];
      var prev = index === 0 ? list[length - 1] : list[index - 1];
      current.style["background-color"] = "";
      current.style.color = "";
      prev.style["background-color"] = "";
      prev.style.color = "";
      next.style["background-color"] = "";
      next.style.color = "";
      switch (charCode) {
        case 38:
          // arrow up
          logger.log("arrow up");
          current.className = "GPautoCompleteProposal";
          prev.className = "GPautoCompleteProposal current";
          prev.style.color = "#000000";
          prev.style["background-color"] = "#CEDBEF";
          break;
        case 40:
          // arrow down
          logger.log("arrow down");
          current.className = "GPautoCompleteProposal";
          next.className = "GPautoCompleteProposal current";
          next.style.color = "#000000";
          next.style["background-color"] = "#CEDBEF";
          break;
        case 13:
          // enter
          logger.log("enter");
          current.click(e);
          break;
      }
      current.focus();
    });
    return inputOrigin;
  },
  /**
   * Create Input Coordinate Point tag
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationCoordinateInputElement: function _createLocationCoordinateInputElement(id) {
    // contexte d'execution
    var self = this;
    var inputOriginCoord = document.createElement("input");
    inputOriginCoord.id = this._addUID("GPlocationOriginCoords_" + id);
    inputOriginCoord.className = "GPlocationOriginHidden";
    inputOriginCoord.type = "text";
    inputOriginCoord.disabled = false;
    inputOriginCoord.addEventListener("click", function () {
      var i = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(this.id);
      document.getElementById(self._addUID("GPlocationOriginLabel_" + i)).click();
    });
    return inputOriginCoord;
  },
  /**
   * Create Show Pointer tag
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationPointerShowInputElement: function _createLocationPointerShowInputElement(id) {
    var inputOriginPointer = document.createElement("input");
    inputOriginPointer.id = this._addUID("GPlocationOriginPointer_" + id);
    inputOriginPointer.type = "checkbox";
    return inputOriginPointer;
  },
  /**
   * Create Input Pointer tag
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationPointerInputElement: function _createLocationPointerInputElement(id) {
    // contexte d'execution
    var self = this;
    var labelOriginPointer = document.createElement("label");
    labelOriginPointer.id = this._addUID("GPlocationOriginPointerImg_" + id);
    labelOriginPointer.htmlFor = this._addUID("GPlocationOriginPointer_" + id);
    labelOriginPointer.className = "GPlocationOriginPointerImg";
    labelOriginPointer.title = "Pointer un lieu sur la carte";
    labelOriginPointer.addEventListener("click", function (e) {
      e.preventDefault();
      e.stopPropagation();
      var i = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(this.id);
      var points = document.getElementsByClassName(self._addUID("GPlocationPoint"));
      var j;
      var tag;
      var id;
      for (j = 0; j < points.length; j++) {
        tag = points[j].childNodes[0].id;
        id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
        if (i !== id) {
          document.getElementById(self._addUID("GPlocationOriginPointer_" + id)).checked = false;
          if (document.getElementById(self._addUID("GPlocationOriginCoords_" + id)).value === "Pointer un lieu sur la carte") {
            document.getElementById(self._addUID("GPlocationOriginCoords_" + id)).value = "";
            document.getElementById(self._addUID("GPlocationOrigin_" + id)).className = "GPlocationOriginVisible";
            document.getElementById(self._addUID("GPlocationOriginCoords_" + id)).className = "GPlocationOriginHidden";
          }
        }
      }
      if (document.getElementById(self._addUID("GPlocationOriginPointer_" + i)).checked) {
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).value = "";
        for (j = 0; j < points.length; j++) {
          tag = points[j].childNodes[0].id;
          id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
          document.getElementById(self._addUID("GPlocationPoint_" + id)).style.cssText = "";
        }
        if (document.getElementById(self._addUID("GPlocationStageRemove_" + i))) {
          document.getElementById(self._addUID("GPlocationStageRemove_" + i)).className = "GPlocationStageRemove";
        }
        if (document.getElementById(self._addUID("GPlocationStageAdd"))) {
          document.getElementById(self._addUID("GPlocationStageAdd")).className = "";
        }
        document.getElementById(self._addUID("GPlocationOriginPointer_" + i)).checked = false;
        document.getElementById(self._addUID("GPlocationOrigin_" + i)).className = "GPlocationOriginVisible";
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).className = "GPlocationOriginHidden";
      } else {
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).value = "Pointer un lieu sur la carte";
        for (j = 0; j < points.length; j++) {
          tag = points[j].childNodes[0].id;
          id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
          if (i === id) {
            document.getElementById(self._addUID("GPlocationPoint_" + id)).style.cssText = "";
          } else {
            document.getElementById(self._addUID("GPlocationPoint_" + id)).style.display = "none";
          }
        }
        if (document.getElementById(self._addUID("GPlocationStageRemove_" + i))) {
          document.getElementById(self._addUID("GPlocationStageRemove_" + i)).className = "GPlocationOriginHidden";
        }
        if (document.getElementById(self._addUID("GPlocationStageAdd"))) {
          document.getElementById(self._addUID("GPlocationStageAdd")).className = "GPlocationOriginHidden";
        }
        document.getElementById(self._addUID("GPlocationOriginPointer_" + i)).checked = true;
        document.getElementById(self._addUID("GPlocationOrigin_" + i)).className = "GPlocationOriginHidden";
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).className = "GPlocationOriginVisible";
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).disabled = true;
      }
      // gestionnaire d'evenement :
      // on stocke la valeur du point, utilisée pour la requête sur le service de calcul d'itiniraire
      self.onActivateMapPointClick(e);
    });
    return labelOriginPointer;
  },
  /**
   * Create Remove Point tag
   * see event !
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationRemovePointElement: function _createLocationRemovePointElement(id) {
    // contexte d'execution
    var self = this;
    var divRm = document.createElement("div");
    divRm.id = this._addUID("GPlocationStageRemove_" + id);
    divRm.className = "GPlocationStageRemove";
    divRm.title = "Supprimer l'étape";
    divRm.addEventListener("click", function (e) {
      var points = document.getElementsByClassName(self._addUID("GPlocationPoint"));
      var last = points.length - 1;
      var start = points[0].childNodes[0].id;
      var end = points[last].childNodes[0].id;
      var startID = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(start);
      var endID = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(end);
      if (id !== startID && id !== endID) {
        var i = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(this.id);
        document.getElementById(self._addUID("GPlocationPoint_" + i)).className = "GPflexInput GPlocationStageFlexInputHidden";
        document.getElementById(self._addUID("GPlocationOrigin_" + i)).value = "";
        document.getElementById(self._addUID("GPlocationOrigin_" + i)).className = "GPlocationOriginVisible";
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).value = "";
        document.getElementById(self._addUID("GPlocationOriginCoords_" + i)).className = "GPlocationOriginHidden";
        document.getElementById(self._addUID("GPlocationStageAdd")).style.display = "";
        // Moving up exclusions picto
        // var exclusionsPictoTop = document.getElementById(self._addUID("GPshowLocationExclusionsPicto")).style.top;
        // document.getElementById(self._addUID("GPshowLocationExclusionsPicto")).style.top = (parseInt(exclusionsPictoTop) - 33).toString() + "px";

        // gestionnaire d'evenement :
        // on supprime le point, utilisé pour la requête sur le service d'itiniraire
        self.onLocationRemovePointClick(e);
      }
    });
    return divRm;
  },
  /**
   * Create Add Point tag
   * see event !
   *
   * @returns {DOMElement} DOM element
   */
  _createLocationAddPointElement: function _createLocationAddPointElement() {
    // contexte d'execution
    var self = this;
    var divAdd = document.createElement("div");
    divAdd.id = this._addUID("GPlocationStageAdd");
    divAdd.title = "Ajouter une étape";
    divAdd.addEventListener("click", function (e) {
      var lastStage = 1;
      var nbStages = 0;
      var points = document.getElementsByClassName(self._addUID("GPlocationPoint"));
      for (var i = 1; i < points.length - 1; i++) {
        var tag = points[i].childNodes[0].id;
        var id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
        if (document.getElementById(self._addUID("GPlocationPoint_" + id))) {
          if (document.getElementById(self._addUID("GPlocationPoint_" + id)).className === "GPflexInput GPlocationStageFlexInputHidden") {
            if (lastStage === 1) {
              lastStage = id;
            }
          } else {
            nbStages++;
          }
        }
      }
      // FIXME algo à revoir : lastStage = id hors si id = 300 sur 3 points !?
      if (lastStage < points.length) {
        document.getElementById(self._addUID("GPlocationPoint_" + lastStage)).className = "GPflexInput GPlocationStageFlexInput";
        // Moving down exclusions picto
        // var exclusionsPictoTop = document.getElementById(self._addUID("GPshowLocationExclusionsPicto")).style.top;
        // document.getElementById(self._addUID("GPshowLocationExclusionsPicto")).style.top = (parseInt(exclusionsPictoTop) + 33).toString() + "px";
      }
      if (nbStages === 4) {
        document.getElementById(self._addUID("GPlocationStageAdd")).style.display = "none";
      }
      // gestionnaire d'evenement :
      // on ajoute le point, utilisé pour la requête sur le service d'itiniraire
      self.onLocationAddPointClick(e);
    });
    return divAdd;
  },
  /**
   * Create Results autocompletion to the point
   * see event!
   *
   * @param {Number} id - tag ID
   * @returns {DOMElement} DOM element
   */
  _createLocationAutoCompleteResultElement: function _createLocationAutoCompleteResultElement(id) {
    // contexte d'execution
    var self = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPlocationAutoCompleteList_" + id);
    div.className = "GPadvancedAutoCompleteList";
    if (div.addEventListener) {
      div.addEventListener("click", function (e) {
        self.onAutoCompletedResultsItemClick(e);
        document.getElementById(self._addUID("GPlocationAutoCompleteList_" + id)).style.display = "none";
      }, false);
    } else if (div.attachEvent) {
      div.attachEvent("onclick", function (e) {
        self.onAutoCompletedResultsItemClick(e);
        document.getElementById(self._addUID("GPlocationAutoCompleteList_" + id)).style.display = "none";
      });
    }
    return div;
  },
  /**
   * Autocompletion result to a point.
   * Proposals are dynamically filled in Javascript by autocomplete service
   *
   * TODO formaliser le contenu des reponse
   *
   * @param {Number} id - tag ID
   * @param {Object} location - suggested location result
   * @param {Number} n  - number of the point
   */
  _createLocationAutoCompletedLocationElement: function _createLocationAutoCompletedLocationElement(id, location, n) {
    var container = document.getElementById(this._addUID("GPlocationAutoCompleteList_" + id));
    var div = document.createElement("div");
    div.id = this._addUID("AutoCompletedLocation_" + n);
    div.className = "GPautoCompleteProposal";
    div.innerHTML = _Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_2__["default"].getSuggestedLocationFreeform(location);
    container.appendChild(div);
  },
  /**
  * Display Coordinate
  * @param {String} value - a Coordinate
  */
  GPdisplayCoordinate: function GPdisplayCoordinate(value) {
    var points = document.getElementsByClassName(this._addUID("GPlocationPoint"));
    for (var i = 0; i < points.length; i++) {
      var tag = points[i].childNodes[0].id;
      var id1 = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
      if (document.getElementById(this._addUID("GPlocationOriginPointer_" + id1)).checked) {
        document.getElementById(this._addUID("GPlocationOriginCoords_" + id1)).value = value;
        document.getElementById(this._addUID("GPlocationOriginCoords_" + id1)).disabled = false;
        for (var j = 0; j < points.length; j++) {
          tag = points[j].childNodes[0].id;
          var id2 = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
          document.getElementById(this._addUID("GPlocationPoint_" + id2)).style.cssText = "";
          if (document.getElementById(this._addUID("GPlocationStageRemove_" + id2))) {
            document.getElementById(this._addUID("GPlocationStageRemove_" + id2)).className = "GPlocationStageRemove";
          }
        }
        document.getElementById(this._addUID("GPlocationOriginPointer_" + id1)).checked = false;
        if (document.getElementById(this._addUID("GPlocationStageAdd"))) {
          document.getElementById(this._addUID("GPlocationStageAdd")).className = "";
        }
        return;
      }
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LocationSelectorDOM);

/***/ }),
/* 106 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
var GeocodeUtils = {
  /**
   * Return the freeform of a structured geocoded item
   *
   * @param {Object} geocodedLocation - Geocoded location
   * @returns {String} freeform string
   */
  getGeocodedLocationFreeform: function getGeocodedLocationFreeform(geocodedLocation) {
    var attributes = geocodedLocation.placeAttributes;
    if (attributes.label) {
      return attributes.label;
    } else if (geocodedLocation.type === "PositionOfInterest") {
      var resultToReturn = attributes.toponym;
      if (attributes.category && Array.isArray(attributes.category) && attributes.category.length >= 2 && attributes.category[0] === "administratif") {
        // gestion particulière des territoires administratifs
        resultToReturn = resultToReturn + ", " + attributes.category[1];
      } else {
        // gestion standard des POI non adminsitratifs
        if (attributes.postcode) {
          resultToReturn = resultToReturn + ", " + attributes.postcode[0];
          if (attributes.city) {
            resultToReturn = resultToReturn + " " + attributes.city[0];
          }
        }
      }
      return resultToReturn;
    } else if (geocodedLocation.type === "StreetAddress") {
      return (attributes.housenumber ? attributes.housenumber + " " : "") + attributes.street + " " + (attributes.postcode ? attributes.postcode + ", " : "") + attributes.city;
    } else if (geocodedLocation.type === "CadastralParcel") {
      return attributes.id;
    } else {
      return "...";
    }
  },
  /**
   * Return the freeform of a structured suggested item
   *
   * @param {Object} suggestedLocation - Suggested location
   * @returns {String} freeform string
   */
  getSuggestedLocationFreeform: function getSuggestedLocationFreeform(suggestedLocation) {
    if (suggestedLocation.fullText) {
      return suggestedLocation.fullText;
    } else {
      var values = [];
      values.push(suggestedLocation.street || "");
      values.push(suggestedLocation.postalCode || "");
      values.push(suggestedLocation.commune || "");
      if (suggestedLocation.type === "PositionOfInterest") {
        values.push(suggestedLocation.poi || "");
        values.push(suggestedLocation.kind || "");
      }
      return values.join(" - ");
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (GeocodeUtils);

/***/ }),
/* 107 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
* implementation :
* cf. http://uihacker.blogspot.fr/2011/07/javascript-formatting-latitudelongitude.html?m=1
* cf. http://andrew.hedges.name/experiments/convert_lat_long/
* FIXME formater la sortie
* cf. http://mottie.github.io/javascript-number-formatter/
* cf. https://github.com/j-/number-formatter
*
*/
/** ... */
var PositionFormater = {
  /** ... */
  NORTH: "N",
  /** ... */
  SOUTH: "S",
  /** ... */
  EAST: "E",
  /** ... */
  WEST: "O",
  /** ... */
  digitSecond: 2,
  /** ... */
  digitDecimal: 5,
  /** ... */
  digitRadian: 8,
  /**
   * @param {Number} inputNum -inputNum
   * @param {Integer} numPoints - numPoints
   *
   * @returns {Number} rounded result
   */
  roundToDecimal: function roundToDecimal(inputNum, numPoints) {
    var multiplier = Math.pow(10, numPoints);
    return Math.round(inputNum * multiplier) / multiplier;
  },
  /**
   * @param {Number} location -location
   *
   * @returns {Number} location in radian
   */
  decimalToRadian: function decimalToRadian(location) {
    var d = 0.01745329251994329577;
    return this.roundToDecimal(location * d, this.digitRadian);
  },
  /**
   * @param {Number} location -location
   *
   * @returns {Number} location in grade
   */
  decimalToGrade: function decimalToGrade(location) {
    var d = 1.11111111111111111111;
    return this.roundToDecimal(location * d, this.digitRadian);
  },
  /**
   * @param {Number} location -location
   * @param {String} hemisphere -hemisphere
   * @param {Boolean} obj -specifies if an object must be returned
   *
   * @returns {String|Object} DMS (String or Object depending on obj parameter value)
   */
  decimalToDMS: function decimalToDMS(location, hemisphere, obj) {
    if (location < 0) {
      location *= -1; // strip dash '-'
    }
    var degrees = Math.floor(location); // strip decimal remainer for degrees
    var minutesFromRemainder = (location - degrees) * 60; // multiply the remainer by 60
    var minutes = Math.floor(minutesFromRemainder); // get minutes from integer
    var secondsFromRemainder = (minutesFromRemainder - minutes) * 60; // multiply the remainer by 60
    var seconds = this.roundToDecimal(secondsFromRemainder, this.digitSecond); // get minutes by rounding to integer

    var dms = degrees + "° " + minutes + "' " + seconds + "\" ";
    if (hemisphere) {
      dms += hemisphere;
    }
    if (obj) {
      return {
        d: degrees,
        m: minutes,
        s: seconds,
        direction: hemisphere
      };
    }
    return dms;
  },
  /**
   * @param {Number} location -location
   * @param {Boolean} obj -specifies if an object must be returned
   *
   * @returns {String|Object} DMS (String or Object depending on obj parameter value)
   */
  decimalLatToDMS: function decimalLatToDMS(location, obj) {
    var hemisphere = location < 0 ? this.SOUTH : this.NORTH; // south if negative
    return this.decimalToDMS(location, hemisphere, obj);
  },
  /**
   * @param {Number} location -location
   * @param {Boolean} obj -specifies if an object must be returned
   *
   * @returns {String|Object} DMS (String or Object depending on obj parameter value)
   */
  decimalLonToDMS: function decimalLonToDMS(location, obj) {
    var hemisphere = location < 0 ? this.WEST : this.EAST; // west if negative
    return this.decimalToDMS(location, hemisphere, obj);
  },
  /**
   * @param {Number} degrees -degrees
   * @param {Number} minutes -minutes
   * @param {Number} seconds -seconds
   * @param {String} hemisphere -hemisphere
   *
   * @returns {Number} decimal
   */
  DMSToDecimal: function DMSToDecimal(degrees, minutes, seconds, hemisphere) {
    var ddVal = degrees + minutes / 60 + seconds / 3600;
    ddVal = hemisphere === this.SOUTH || hemisphere === this.WEST ? ddVal * -1 : ddVal;
    var decimal = this.roundToDecimal(ddVal, this.digitDecimal);
    return decimal;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (PositionFormater);

/***/ }),
/* 108 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);


var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("icondefault");

/**
 * @classdesc
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#icon" target="_blank">L.Icon.Default</a> native class.
 */
var IconDefault = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Icon.Default.extend( /** @lends IconDefault.prototype */{
  /**
  * Liste des icones
  *   TODO : image retina à convertir en x2...
  */
  images: {
    retina: {
      shadow: "data:image/png;base64,...",
      color: {
        blue: "data:image/png;base64,...",
        orange: "data:image/png;base64,...",
        red: "data:image/png;base64,...",
        green: "data:image/png;base64,..."
      }
    },
    shadow: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAApCAYAAACoYAD2AAAC5ElEQVRYw+2YW4/TMBCF45S0S1luXZCABy5CgLQgwf//S4BYBLTdJLax0fFqmB07nnQfEGqkIydpVH85M+NLjPe++dcPc4Q8Qh4hj5D/AaQJx6H/4TMwB0PeBNwU7EGQAmAtsNfAzoZkgIa0ZgLMa4Aj6CxIAsjhjOCoL5z7Glg1JAOkaicgvQBXuncwJAWjksLtBTWZe04CnYRktUGdilALppZBOgHGZcBzL6OClABvMSVIzyBjazOgrvACf1ydC5mguqAVg6RhdkSWQFj2uxfaq/BrIZOLEWgZdALIDvcMcZLD8ZbLC9de4yR1sYMi4G20S4Q/PWeJYxTOZn5zJXANZHIxAd4JWhPIloTJZhzMQduM89WQ3MUVAE/RnhAXpTycqys3NZALOBbB7kFrgLesQl2h45Fcj8L1tTSohUwuxhy8H/Qg6K7gIs+3kkaigQCOcyEXCHN07wyQazhrmIulvKMQAwMcmLNqyCVyMAI+BuxSMeTk3OPikLY2J1uE+VHQk6ANrhds+tNARqBeaGc72cK550FP4WhXmFmcMGhTwAR1ifOe3EvPqIegFmF+C8gVy0OfAaWQPMR7gF1OQKqGoBjq90HPMP01BUjPOqGFksC4emE48tWQAH0YmvOgF3DST6xieJgHAWxPAHMuNhrImIdvoNOKNWIOcE+UXE0pYAnkX6uhWsgVXDxHdTfCmrEEmMB2zMFimLVOtiiajxiGWrbU52EeCdyOwPEQD8LqyPH9Ti2kgYMf4OhSKB7qYILbBv3CuVTJ11Y80oaseiMWOONc/Y7kJYe0xL2f0BaiFTxknHO5HaMGMublKwxFGzYdWsBF174H/QDknhTHmHHN39iWFnkZx8lPyM8WHfYELmlLKtgWNmFNzQcC1b47gJ4hL19i7o65dhH0Negbca8vONZoP7doIeOC9zXm8RjuL0Gf4d4OYaU5ljo3GYiqzrWQHfJxA6ALhDpVKv9qYeZA8eM3EhfPSCmpuD0AAAAASUVORK5CYII=",
    color: {
      blue: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAGmklEQVRYw7VXeUyTZxjvNnfELFuyIzOabermMZEeQC/OclkO49CpOHXOLJl/CAURuYbQi3KLgEhbrhZ1aDwmaoGqKII6odATmH/scDFbdC7LvFqOCc+e95s2VG50X/LLm/f4/Z7neY/ne18aANCmAr5E/xZf1uDOkTcGcWR6hl9247tT5U7Y6SNvWsKT63P58qbfeLJG8M5qcgTknrvvrdDbsT7Ml+tv82X6vVxJE33aRmgSyYtcWVMqX97Yv2JvW39UhRE2HuyBL+t+gK1116ly06EeWFNlAmHxlQE0OMiV6mQCScusKRlhS3QLeVJdl1+23h5dY4FNB3thrbYboqptEFlphTC1hSpJnbRvxP4NWgsE5Jyz86QNNi/5qSUTGuFk1gu54tN9wuK2wc3o+Wc13RCmsoBwEqzGcZsxsvCSy/9wJKf7UWf1mEY8JWfewc67UUoDbDjQC+FqK4QqLVMGGR9d2wurKzqBk3nqIT/9zLxRRjgZ9bqQgub+DdoeCC03Q8j+0QhFhBHR/eP3U/zCln7Uu+hihJ1+bBNffLIvmkyP0gpBZWYXhKussK6mBz5HT6M1Nqpcp+mBCPXosYQfrekGvrjewd59/GvKCE7TbK/04/ZV5QZYVWmDwH1mF3xa2Q3ra3DBC5vBT1oP7PTj4C0+CcL8c7C2CtejqhuCnuIQHaKHzvcRfZpnylFfXsYJx3pNLwhKzRAwAhEqG0SpusBHfAKkxw3w4627MPhoCH798z7s0ZnBJ/MEJbZSbXPhER2ih7p2ok/zSj2cEJDd4CAe+5WYnBCgR2uruyEw6zRoW6/DWJ/OeAP8pd/BGtzOZKpG8oke0SX6GMmRk6GFlyAc59K32OTEinILRJRchah8HQwND8N435Z9Z0FY1EqtxUg+0SO6RJ/mmXz4VuS+DpxXC3gXmZwIL7dBSH4zKE50wESf8qwVgrP1EIlTO5JP9Igu0aexdh28F1lmAEGJGfh7jE6ElyM5Rw/FDcYJjWhbeiBYoYNIpc2FT/SILivp0F1ipDWk4BIEo2VuodEJUifhbiltnNBIXPUFCMpthtAyqws/BPlEF/VbaIxErdxPphsU7rcCp8DohC+GvBIPJS/tW2jtvTmmAeuNO8BNOYQeG8G/2OzCJ3q+soYB5i6NhMaKr17FSal7GIHheuV3uSCY8qYVuEm1cOzqdWr7ku/R0BDoTT+DT+ohCM6/CCvKLKO4RI+dXPeAuaMqksaKrZ7L3FE5FIFbkIceeOZ2OcHO6wIhTkNo0ffgjRGxEqogXHYUPHfWAC/lADpwGcLRY3aeK4/oRGCKYcZXPVoeX/kelVYY8dUGf8V5EBRbgJXT5QIPhP9ePJi428JKOiEYhYXFBqou2Guh+p/mEB1/RfMw6rY7cxcjTrneI1FrDyuzUSRm9miwEJx8E/gUmqlyvHGkneiwErR21F3tNOK5Tf0yXaT+O7DgCvALTUBXdM4YhC/IawPU+2PduqMvuaR6eoxSwUk75ggqsYJ7VicsnwGIkZBSXKOUww73WGXyqP+J2/b9c+gi1YAg/xpwck3gJuucNrh5JvDPvQr0WFXf0piyt8f8/WI0hV4pRxxkQZdJDfDJNOAmM0Ag8jyT6hz0WGXWuP94Yh2jcfjmXAGvHCMslRimDHYuHuDsy2QtHuIavznhbYURq5R57KpzBBRZKPJi8eQg48h4j8SDdowifdIrEVdU+gbO6QNvRRt4ZBthUaZhUnjlYObNagV3keoeru3rU7rcuceqU1mJBxy+BWZYlNEBH+0eH4vRiB+OYybU2hnblYlTvkHinM4m54YnxSyaZYSF6R3jwgP7udKLGIX6r/lbNa9N6y5MFynjWDtrHd75ZvTYAPO/6RgF0k76mQla3FGq7dO+cH8sKn0Vo7nDllwAhqwLPkxrHwWmHJOo+AKJ4rab5OgrM7rVu8eWb2Pu0Dh4eDgXoOfvp7Y7QeqknRmvcTBEyq9m/HQQSCSz6LHq3z0yzsNySRfMS253wl2KyRDbcZPcfJKjZmSEOjcxyi+Y8dUOtsIEH6R2wNykdqrkYJ0RV92H0W58pkfQk7cKevsLK10Py8SdMGfXNXATY+pPbyJR/ET6n9nIfztNtZYRV9XniQu9IA2vOVgy4ir7GCLVmmd+zjkH0eAF9Po6K61pmCXHxU5rHMYd1ftc3owjwRSVRzLjKvqZEty6cRUD7jGqiOdu5HG6MdHjNcNYGqfDm5YRzLBBCCDl/2bk8a8gdbqcfwECu62Fg/HrggAAAABJRU5ErkJggg==",
      orange: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAASAAAAEgARslrPgAABghJREFUWMOdl1uInGcdxn/feWa+mflmJmZbqVqKigewKK5goHgRSEm8EC88F6tBFLfgZbzJnVdRYWExrVBoXazWlAYL0dVisLBYzEUUSbeNjZQmxGZ3NjO7c57v/P69mNnD7MzuzvrCA8PM+/+e93n+h/cb7c9PzXKE9RHAG36+BXRPP3390CDtT3MHklSA7wKngVOWbaOhA5AkEUqpKnAFePHMM9eX9yeZrMQAzgHni14ln826ZLLu2KY0TfD7XXq9NoHffxX48Zmnr6+MkSyNK6kAl4ql8qlisYxpWagoJA16gIxs1E0bI1cAoNNuslFb94Env/jM9csj+0SEXaiIyN+9cuVU5dhxdEmI23XSoAOoIckOVBISt+vE7Q0KRY8H3v+BbM7Nv7w0Nzs3QrLHopdL5crHyqUKSbdB6ndA1BRIiVs1Mo5NySsD/GJpbvbkjpKds50rFL2T5VKZpNdAkmjiAzXDHOye8FvS2cC2LWZmHjAELv1xbrYyIFGCKKmIkvMlr4iK+0gaDe0ZQHcyWIUyVqGMmDZWvoRVKGO63sg+UMSdGq6bo+R5x0XJuYFdGqDxLa9UzJumQRp0R3y3ChU002Zjc5Pbd+6wGem8e/sO6+vrBGGIVagMTdmJScMepZIHGj/4ww8/a5jDevl63s2h4nAgfbhM1yOMQt67V+WjZ87y+VNPYmXzANz7x19YufQzilFIySsTt+vbcSrsYTlZnEymEgTBCV2U5EXJiUzGJg1aI9I1w6DZbPHoE+f5+Jee2iYAeGj2cR479zyNjo+SFN12xqzLZRxEyWld4EOWbRmIApVuJ1E3LaIwRLkzPPzYl8caUURwZz7Iw1/4Cq1WG8POjBSBCvvYtonAJ3URqeiaNlYpuuXg+wHlRz41kQBAKUX5w5+m1/PHKk7SBF0DEfFMgUjJMGnaro7WFGig0nhfAhEhjQI0TRuL1wwNFSkEfF2Ee3GSjp0kDXq4WZv7b19HJeNEWySrN/5G3nUQlezpJ4MkTRHhni4i1ThOuipNByfakhsHmIZGRnV565WLYyoA1t68RuONq3j5DKnfHiXRdKIoRkTuGl/9zIMCfC7rGJ/I5vOocGsQCoiQz7vc/8+/WH37BrnKgzjFY7RWb/Pu8mVWLv2UmUoOxzYGJFtxmobhZFmrd0hS9SPtpbOPApx0s/ZfH3moRNyujU5aO4eRcWl2AjZbPn6YYFsGXt6h4mUxDX0sxioep9kJeG+9ffVrz994fKsZX+v60bVuPzzhFo6RdHY1VtRDEp9S4RilgjPyMBX2iXu90dIbFsFm20fgJwCm7BTEzzda/u/zrjVspl2JVoq4vc40yyrO0OqGdPvxa9/41Y3XYfQ+udLshO8EQYyZK0454idAKTYafUTkwrblu0Z9KjBfb/pouvl/EZhuma4f0e7H//zm4htXt0n23HaL9VZQS5IU3c4emUTTNOoNH9hRsVcJAr7As7VWgJHJDTp4SpiFMv0oodGLbwm8MkoyescjIgtrm4GvlEI37SOo0Kk1AkTkwhOLK+keEtiDmggv1FshRrYwFYGRLRJEKfV2fFeEF/dW3F67tjB/txamIoKm65N37IJu2dRaEQLz3/71m9E4ybhdiMgtEVna7EQY+Qoial/oTo4oTqk2opqIPDepd/QDzjh/vxmDOtgq3cqy3ogQuPidF97qTiaZrAQRWW776bVOkGIW3jfZJidHqoTVRtwVkYX9psCkxO/GwnojRhvMlvGE2zmqzRgRfnn2Nzdb+5McnNbL9a56x48FI+vtSbaDaPDfjSQSmD9onh1kFyKSishCtZmgW/ZY2a5txojI4vd+e7N6CMmBdiHC4lojrcWpoDsuIGimhYhwp5amIlzgkKUf1gMgXZBnq40Ew8kNBmGuxHozAeSl7//u37cPJTmUYoCLdzdVJMNcgLDWFoTDVUxrFyJURVisNhVGzqPWVvQCWRJhZSqS4Qv3NFhYaw10rbUENC4MansaJYO/DtPgZi+QK7W20OrLsih5XZRMSTJdTrZHzWpzkIut76az62hrueXzHPDqUYL+B8XVKUzuUimfAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTA4LTE4VDE0OjUwOjU2KzAxOjAwFlCkXwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0wOC0xOFQxNDo1MDo1NiswMTowMGcNHOMAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAAAElFTkSuQmCC",
      red: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAAASAAAAEgARslrPgAABe5JREFUWMOdlWuIXGcZx3/nPbe5ZWbO2c0a8VIEpSq0io2QBT8FUlIFEbzfokUUKfgxIuSbn+JtYTEQqFQCQmkxVIiNFhcLwZoVtrFNt40ESrPEJju7s/eZM+f+Pn6Y2XVnZ3Zn0/fwcA7veZ/ze5//87zPMf56fJIHGB8Far3n20D79Nz1kU7GXw6G+MD3gdPAKdtxMJQFQJZEaK0bwBXg2Sfmrl87AHJi2LwJnAXOVf3xSrFcoVAuDyzKs4yw3SLY2iTqBC8BP31ibnZ+AHJ1MBIfeK7qeaeqno9l2+g4IQ86ILpvoXIczCMVAFob66wuLYXAmc/PXb/cB3nxsRN7AdfrY2MPe+Pj6Cjufnyk6Aa2XyfshLQ21glarae+8OrsxZ3N7JHoj3Xff9jzx8jWN8hbbdB6tOU5aXOVguNQ98YAfnv1+OTJHYgAPTt7pFY76Xk+2fo6kiSg8wEzLLMr25B32eoqjm0x8b5jpsBzLx6f9LsQARF8Ec7Vq1V0J0CSuM9ZFVxsr47t1RHHxq7XsL06Vq06AEqby5RLReq12lERzvbkEkC+VatWKpapyNtt6JERwfY9DMdmdW2NOwsLrCmDdxYWWFpaIopjbN/rarLLJw8C6rUqID/682MnTEsQgK9XSiV0nHQ17g2rViWOI95tLPOxJ89w4sx3sCvdarr3txnmf/kbqnFE3auTrqzu+OkgwC4WcAuuH0XRpBKhIsJkwbHJN9f79TcVG5tbPHruZ3z8qR/vAAA+8PgpPvf737Eehug8Rbn2gHQl10WE00rgw7ZtmdtVspMH2yKJY/TEBA996YsDVSsilD/0QR76ypfZ3GphFgp9AN3p4FgmAp9UIuIrQw2UpXJdwijGe+SRoQAArTXepz9FEEbdfOzylyxHddfWLEESLbpblrtPtM4AQafJvgARIY8iDMMY8DcM6a5BQiUY99I8H9hJHgSUHZvluVfRaToA2obc/8c/qbg2kqV9/oapyPIcwbinRKSRZnlb53l3R9vhRjGWAYV2i7cuXByIAmBx9l+sz8xQK7jkW1v9EKVI0hQRuWt+9dj7Bfhs0VSfKFZK6CDoq/lKucTya69x/+Y8pWPHcMd8Nu8s8M7lF5j/xa+ZKBVwTdWFbPsZBmaxwGIrINP6J8bzj34G4GTZcf7+kXqFtNns77SlMma5xEaUsBbGhFmGY5rUXBu/6GIpNeBjHz3KRpTw7lZ75ms3bzxudQXg5XaSzLbjZLI8Nka2srLrYLWRqEPdH6Pu2n0f050OaRD0l54yQIS1MELg5wDbEIBfrYbRCxW3MvDfkEyTLi+NavjdKMYn2Ixi2mn28jdu3nil1yCFnl3ZiNO3ozjtNb5DtPihbV+z2okRkfPDWn0uMLUSxhim9Z4AlufRThK20uzGN9/498wOhN0HUfSllShuZnmOKhXZ826kGYbBSicG0ed3S7g7EgRCgaebYYxZLvW/GWGW79HJM9bT7LbAn/oh/8/Jtk0vRkmotUY5zqGlMpSi2cvFt+dfz/dEYrDHmoLxh5Uwxjxy5FAAs1olynJWUn1XMJ7dW3FKGHpN3Y2yXEQwTDVSKuU6NKMEQaa+++brySBkUC5E5LaIXF2LE0zfR7Te11SpRJLlNJK8KSLPDDs76oA9Ti3H+UipVLHIUpggcOF7b73RHg4ZHgkicm0r17OtLMc6Oj5cpnKJXAv3U90Wken9uoAaUZzTS1GGIQxPeLFEI04RuPjkrfnN9wq5vKJ5OxTBrNb2JNtFFPw3lURg6qB+dpBciEguItONOEO5zkDZLoYpInLpB7fmGwdDRp/nS4sZzVQEVS6DCIZjIyIspOQC5xkx1O6/4D7WRuTpRpRhlkrdRlirsxRnIPL8D//z5p2RkH0O497rwt2cRBBUwQWExVwQZGQUPchAWxlmDcG41Eg0Zq1GM9EEoq4KxvyhIA/QaacXs+5z736+O3+YSEamZMduBaKuNFNhU9Q1EV6RwzEOnZOdxnk/7eZie+aQcj3QuLaJegZ46UGc/gcUeTtzDg/o4wAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxMi0wOC0xOFQxNDo1MDo1NiswMTowMBZQpF8AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTItMDgtMThUMTQ6NTA6NTYrMDE6MDBnDRzjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAABJRU5ErkJggg==",
      green: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wJCgoDDgqHD/MAAAZVSURBVFjDpZZtiFxXGcd/c+69M7PzurvdTTZNGvxQTCJqFSok+MmFQPSDUlsQhBaxWNhorQlWPxSKTYqsFLYGA8VCISDESIpCILYQW4xJNtHGGBooZtl16UrKNrMvM7N3Xu6555zHD7OZ7OzsW/Be/nBnznnO/zzP83/OcxKPv/IOW32KXzj2KFBc/nm7cuvl8IOXD21ql3j8lT9vsOjxfuB7wCHgoAoUCV8BYJsWRGaBc8DpvzwxfnF9kl90kxQ+f9wDXgReyg9kc8VkH4Wg2DUvdpqyXqRcKxOH5l3gZ+89OX5rDZLzqwhe7QfOZAcyB4fSO0h6KbSNqNt6F0lSJcn4WQA+bcyycHehATzz3pPjb6+cp0SEe8jvOdYvsRvPDmQOPpLZjRXLYjRPzYSIuC5EtsliNE9ZL7ItvY2dD+/sSRaDs8Nn9o90kLQ92HvcA87mduT27Mw8QiWuUDMhVuymMC5mPpoj42UYyu0A+M3wmf3D90lEQATgxfT29PDDPTup6jKx08gar6+CNf8XhEW9QEqlGNw16AFnhs/s72+FC6Gw79V+4KXtPUPUbZ3IRR07DVSSQlCkEBRRCdX+zvn5Lq/mohKFoEh2KDO4LB4ULUe+mxpI5RSKMA5xIm0Ug16SKsknjTtMfTxFGIdMfTzFzOIMoVmiGPQCdNjUTY3B9HZEeO5rv9/v+YggwncK6QKxxB3qyQU5aibk7iclvv3YUzz91WfJ+wUALsy+w+sf/opGusFgahuLerFt17BN0l4PQc7v10vmgJ/f98sccCDjZ5mP5jpIvITHYljm+QNH+NaupzrGDg59nc/m9/KDC08TD8UEyqdhG+1xh8PP+eglc0jhZLeXUp4V2yFPPxFQNzWymWwXAYAg7M5+hm/s+yZzzRIpL91hXzc1kioAJ59TQH9C3WOXNlJeitCEfLH3S2sSAFgxPNb7ZXQl7rJ3IiRaCxd9caLFgXUGcdJeyDiDiKBdtC6BE6FhGygv0WUvnsOKRZw0FHDHRg6HdCzWtHXyQZ4bn17HrBKEFdNaAMel0l/xcz5WbOd5hcI4A3BHiWPWaReKuNYOjEOMw2hDggQudpyceL3DC9cqXsZLl7g+9Q8KQYEls9S2FePwEgrbsIhjxuvb+2tJDYx/RXJuXzbI0dRR+xBwypDtyXLrvx9yLbzC9vR2HkoO8J9wkrMzp/nt+Bv0DKbwVUCj0VxxeEAQJKneDRErz/siAk5ONueiJzI7MrAirroe4zJC70NFphem+PnkUWzkUH6CZG9A364iXsKjulTprK98nqV6Fde0F/72/Q8+8hGh8u+fvl/Y89rVWn/tQDaXI6wu3e8ZYYzxLflsjlymU2UN2yAO4zUbVXNeIyLHAHzuJ/w1XY7/mN7mWKUBJHZUy9UttehsMUtYD7EN8/6lZ69fBmiFCxDLuWhBT0b90aN+zm9r/0EfEdfywjLaddRXJ45aYCxa0PjKp53FB0CqN0mzGWFC88/Lz12/sKIzrpjn5FRzLioZZ/B6fMTxQFAkiBY04mS0szOuYKlOHG0g8mazFOGlFGJly0jmfXQ9Rpf1bUT+tG6PX87PiWg+aiDgpbyWpLeARKCIyjHA6JWRG3ZVjxdWojJxpAT8rjkX4We9LSU7KATYhiWu6Bng9OpxtVYCxTHWLEX2XmE6tzGUnyAqx4hj7MrIDd1FsjpcIkJl4oXbYuW8rhqSfUkkduvCSymsdkRzUUmsvLWWp2o9OYqTsWhRb6pcP+ujyzHi5OTVH/8rXJNkLU9EhOrUCxdNzVw1NUN6ILlmsv2MhxhHcy4KgRPr5awr8Z3ghC7r5Uru3oif8YgWNMAb135ys7I+yYbx4O24aiZt5Ej2JjsvGSkPBKJ5rRHGNlLfuuESESqTP7IiLW+UrxBLG0E+aFW3cOrakZuzG5JsHC4BOKUrpuRM64ojTlB+AhGhOa8tMLpZHanN1FOZ/GEIvBlXYvweBSIk+wJ0q7r/8PejN6c3JdnSCevkZLSgtdhWLsSBLmtYdRD+H+ESKlOHZ8XJqbgaExQC4iWD0+58Zerwra2RbM7B8qX8hK7EiBN0WSPC6OoOun5O2NpbnT78kdXunKlbbOQuVqcPX5YtsqgH636M6bIGYbTj/rN5Trb+VKdHLtqme6s6PfLug9j9D/FCc1g2qf7VAAAAAElFTkSuQmCC"
    }
  },
  /**
   * constructor
   * (extend to L.Icon.Default)
   *
   * @param {String} color - blue, green or red, blue by default.
   * @param {Object} options - options of L.Icon
   */
  initialize: function initialize(color, options) {
    // on merge les options avec celles par defaut
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(this.options, options);
    var _color = null;
    var _images = /* (L.Browser.retina) ? this.images.retina : */this.images;
    switch (color) {
      case "red":
        _color = _images.color.red;
        break;
      case "green":
        _color = _images.color.green;
        break;
      case "orange":
        _color = _images.color.orange;
        break;
      case "blue":
        _color = _images.color.blue;
        break;
      default:
        _color = _images.color.blue;
    }

    // icones classiques
    this.options.iconUrl = _color;
    this.options.shadowUrl = _images.shadow;

    // icones pour écran Retina
    if (leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Browser.retina) {
      this.options.iconRetinaUrl = _color;
      this.options.shadowRetinaUrl = _images.shadow;
    }
  },
  /**
   * Overload function to ensure compatibility between versions 0.7.X and 1.0.X
   * (extend to L.Icon._getIconUrl)
   *
   * @param {String} name - name
   *
   * @returns {String} url
   *
   */
  _getIconUrl: function _getIconUrl(name) {
    logger.trace("OVERWRITTEN L.Icon.Default._getIconUrl(" + name + ")");
    return leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Icon.prototype._getIconUrl.call(this, name);
  }
});
/* harmony default export */ __webpack_exports__["default"] = (IconDefault);

/***/ }),
/* 109 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
var IsoDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPisochron");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################# Methods to display Main Panel ################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing panel
   *
   * @returns {DOMElement} DOM element
   */
  _createShowIsoElement: function _createShowIsoElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowIsochron");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show iso control
   * see event !
   *
   * @returns {DOMElement} DOM element
   */
  _createShowIsoPictoElement: function _createShowIsoPictoElement() {
    // contexte d'execution
    var context = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowIsochronPicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowIsochron");
    label.title = "Calculer une isochrone";

    // gestionnaire d'evenement :
    // on ouvre le menu de saisie du calcul d'isochrone
    // L'ouverture/Fermeture permet de faire le menage
    // (reinitialisation)
    if (label.addEventListener) {
      label.addEventListener("click", function (e) {
        context.onShowIsoPanelClick(e);
      });
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function (e) {
        context.onShowIsoPanelClick(e);
      });
    }
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowIsochronOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  // ################################################################### //
  // ################## Methods to display Inputs Panel ################ //
  // ################################################################### //

  /**
   * Create Container Panel
   *
   * FIXME
   * don't call this._createIsoPanelHeaderElement
   * don't call this._createIsoPanelFormElement
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelElement: function _createIsoPanelElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronPanel");
    div.className = "GPpanel";

    // div.appendChild(this._createIsoPanelHeaderElement());
    // div.appendChild(this._createIsoPanelFormElement());

    return div;
  },
  /**
   * Create Header Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelHeaderElement: function _createIsoPanelHeaderElement() {
    var self = this;
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var div = document.createElement("div");
    div.className = "GPpanelTitle";
    div.innerHTML = "Calcul d'isochrone";
    container.appendChild(div);

    // on desactive l'impl. reduction de la fenetre
    // var divReduce  = document.createElement("div");
    // divReduce.id = this._addUID("GPisochronPanelReduce");
    // divReduce.className = "GPpanelReduce";
    // divReduce.title = "Masquer le panneau";
    //
    // if (divReduce.addEventListener) {
    //     divReduce.addEventListener("click", function () {
    //         if ( typeof self.onReduceIsoPanelClick === "function") {
    //             document.getElementById(self._addUID("GPshowIsochron")).checked = false;
    //             self.onReduceIsoPanelClick();
    //         }
    //     }, false);
    // } else if (divReduce.attachEvent) {
    //     divReduce.attachEvent("onclick", function () {
    //         if ( typeof self.onReduceIsoPanelClick === "function") {
    //             document.getElementById(self._addUID("GPshowIsochron")).checked = false;
    //             self.onReduceIsoPanelClick();
    //         }
    //     });
    // }
    // container.appendChild(divReduce);

    var divClose = document.createElement("div");
    divClose.id = this._addUID("GPisochronPanelClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer le panneau";

    // Link panel close / visibility checkbox
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPshowIsochronPicto")).click();
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPshowIsochronPicto")).click();
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * Create Form
   * see evenement !
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormElement: function _createIsoPanelFormElement() {
    // contexte d'execution
    var self = this;
    var form = document.createElement("form");
    form.id = this._addUID("GPisochronForm");
    form.addEventListener("submit", function (e) {
      e.preventDefault();
      self.onIsoComputationSubmit(e);
      return false;
    });
    return form;
  },
  /**
   * Create Waiting Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoWaitingElement: function _createIsoWaitingElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronCalcWaitingContainer");
    div.className = "GPisochronCalcWaitingContainerHidden";
    var p = document.createElement("p");
    p.className = "GPisochronCalcWaiting";
    p.innerHTML = "Calcul en cours...";
    div.appendChild(p);
    return div;
  },
  // ################################################################### //
  // ############# Methods to the type choice into form ################ //
  // ################################################################### //

  /**
   * Create Container to type choice
   *
   * FIXME
   * don't call this._createIsoPanelFormTypeChoiceChronElement
   * don't call this._createIsoPanelFormTypeChoiceDistElement
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormTypeChoiceElement: function _createIsoPanelFormTypeChoiceElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronChoice");

    // div.appendChild(this._createIsoPanelFormTypeChoiceChronElement());
    // div.appendChild(this._createIsoPanelFormTypeChoiceDistElement());

    return div;
  },
  /**
   * Create Type choice Chron
   * see event !
   * FIXME event not useful
   * @param {Boolean} checked - checked
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormTypeChoiceChronElement: function _createIsoPanelFormTypeChoiceChronElement(checked) {
    var self = this;
    var div = document.createElement("div");
    div.className = "GPisochronChoiceAlt";
    var input = document.createElement("input");
    input.id = this._addUID("GPisochronChoiceAltChron");
    input.name = "GPisochronChoiceMode";
    input.type = "radio";
    input.checked = !!checked;
    if (input.addEventListener) {
      input.addEventListener("change", function (e) {
        document.getElementById(self._addUID("GPisochronValueChron")).className = "GPflexInput";
        document.getElementById(self._addUID("GPisochronValueDist")).className = "GPisochronValueHidden";
        self.onIsoTypeChoiceChange(e);
      }, false);
    } else if (input.attachEvent) {
      input.attachEvent("onchange", function () {
        document.getElementById(self._addUID("GPisochronValueChron")).className = "GPflexInput";
        document.getElementById(self._addUID("GPisochronValueDist")).className = "GPisochronValueHidden";
        self.onIsoTypeChoiceChange();
      });
    }
    // info: Internet explorer support
    input.value = "isochron";
    div.appendChild(input);
    var label = document.createElement("label");
    label.className = "GPisochronChoiceAltImg";
    label.htmlFor = this._addUID("GPisochronChoiceAltChron");
    div.appendChild(label);
    var span = document.createElement("span");
    span.id = this._addUID("GPisochronChoiceAltChronTxt");
    span.innerHTML = "isochrone";
    if (span.addEventListener) {
      span.addEventListener("click", function () {
        document.getElementById(self._addUID("GPisochronChoiceAltChron")).click();
      }, false);
    } else if (span.attachEvent) {
      span.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPisochronChoiceAltChron")).click();
      });
    }
    div.appendChild(span);
    return div;
  },
  /**
   * Create Type choice Dist
   * see event !
   * FIXME event not useful
   * @param {Boolean} checked - checked
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormTypeChoiceDistElement: function _createIsoPanelFormTypeChoiceDistElement(checked) {
    var self = this;
    var div = document.createElement("div");
    div.className = "GPisochronChoiceAlt";
    var input = document.createElement("input");
    input.id = this._addUID("GPisochronChoiceAltDist");
    input.name = "GPisochronChoiceMode";
    input.type = "radio";
    input.checked = !!checked;
    if (input.addEventListener) {
      input.addEventListener("change", function (e) {
        document.getElementById(self._addUID("GPisochronValueDist")).className = "GPflexInput";
        document.getElementById(self._addUID("GPisochronValueChron")).className = "GPisochronValueHidden";
        self.onIsoTypeChoiceChange(e);
      }, false);
    } else if (input.attachEvent) {
      input.attachEvent("onchange", function () {
        document.getElementById(self._addUID("GPisochronValueDist")).className = "GPflexInput";
        document.getElementById(self._addUID("GPisochronValueChron")).className = "GPisochronValueHidden";
        self.onIsoTypeChoiceChange();
      });
    }
    // info: Internet explorer support
    input.value = "isodistance";
    div.appendChild(input);
    var label = document.createElement("label");
    label.className = "GPisochronChoiceAltImg";
    label.htmlFor = this._addUID("GPisochronChoiceAltDist");
    div.appendChild(label);
    var span = document.createElement("span");
    span.id = this._addUID("GPisochronChoiceAltDistTxt");
    span.innerHTML = "isodistance";
    if (span.addEventListener) {
      span.addEventListener("click", function () {
        document.getElementById(self._addUID("GPisochronChoiceAltDist")).click();
      }, false);
    } else if (span.attachEvent) {
      span.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPisochronChoiceAltDist")).click();
      });
    }
    div.appendChild(span);
    return div;
  },
  // ################################################################### //
  // ############### Methods to the value iso into form ################ //
  // ################################################################### //

  /**
   * Create isochron inputs values
   * see event !
   * @param {Boolean} checked - checked
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormValueIsochronElement: function _createIsoPanelFormValueIsochronElement(checked) {
    // contexte
    var context = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronValueChron");
    div.className = checked ? "GPflexInput" : "GPisochronValueHidden";
    var label = document.createElement("label");
    label.id = this._addUID("GPisochronValueChronLabel");
    label.htmlFor = this._addUID("GPisochronValueChronInput");
    label.innerHTML = "Temps";
    div.appendChild(label);
    var input1 = document.createElement("input");
    input1.id = this._addUID("GPisochronValueChronInput1");
    input1.min = "0";
    input1.step = "1";
    input1.value = "0";
    input1.type = "number";
    if (input1.addEventListener) {
      input1.addEventListener("change", function (e) {
        if (typeof context.onIsoValueChronTimeMinuteChange === "function") {
          context.onIsoValueChronTimeHourChange(e);
        }
      });
    } else if (input1.attachEvent) {
      input1.attachEvent("onchange", function (e) {
        if (typeof context.onIsoValueChronTimeMinuteChange === "function") {
          context.onIsoValueChronTimeHourChange(e);
        }
      });
    }
    div.appendChild(input1);
    var label1 = document.createElement("label");
    label1.innerHTML = "h";
    div.appendChild(label1);
    var input2 = document.createElement("input");
    input2.id = this._addUID("GPisochronValueChronInput2");
    input2.min = "0";
    input2.max = "59";
    input2.step = "1";
    input2.value = "0";
    input2.type = "number";
    if (input2.addEventListener) {
      input2.addEventListener("change", function (e) {
        if (typeof context.onIsoValueChronTimeMinuteChange === "function") {
          context.onIsoValueChronTimeMinuteChange(e);
        }
      });
    } else if (input2.attachEvent) {
      input2.attachEvent("onchange", function (e) {
        if (typeof context.onIsoValueChronTimeMinuteChange === "function") {
          context.onIsoValueChronTimeMinuteChange(e);
        }
      });
    }
    div.appendChild(input2);
    var label2 = document.createElement("label");
    label2.innerHTML = "min";
    div.appendChild(label2);
    return div;
  },
  /**
   * Create isodistance inputs values
   * see event !
   * @param {Boolean} checked - checked
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormValueIsodistanceElement: function _createIsoPanelFormValueIsodistanceElement(checked) {
    // contexte
    var context = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronValueDist");
    div.className = checked ? "GPflexInput" : "GPisochronValueHidden";
    var label = document.createElement("label");
    label.id = this._addUID("GPisochronValueDistLabel");
    label.htmlFor = this._addUID("GPisochronValueDistInput");
    label.innerHTML = "Distance";
    div.appendChild(label);
    var input1 = document.createElement("input");
    input1.id = this._addUID("GPisochronValueDistInput");
    input1.min = "0";
    input1.step = "any";
    input1.value = "0";
    input1.type = "number";
    if (input1.addEventListener) {
      input1.addEventListener("change", function (e) {
        if (typeof context.onIsoValueDistChange === "function") {
          context.onIsoValueDistChange(e);
        }
      });
    } else if (input1.attachEvent) {
      input1.attachEvent("onchange", function (e) {
        if (typeof context.onIsoValueDistChange === "function") {
          context.onIsoValueDistChange(e);
        }
      });
    }
    div.appendChild(input1);
    var label1 = document.createElement("label");
    label1.innerHTML = "km";
    div.appendChild(label1);
    return div;
  },
  // ################################################################### //
  // ############ Methods to the mode choice into form ################# //
  // ################################################################### //

  /**
   * Create Container to Mode choice
   *
   * FIXME
   * don't call this._createIsoPanelFormModeChoiceTransportElement
   * don't call this._createIsoPanelFormModeChoiceDirectionElement
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormModeChoiceElement: function _createIsoPanelFormModeChoiceElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronModeChoice");

    // div.appendChild(this._createIsoPanelFormModeChoiceTransportElement());
    // div.appendChild(this._createIsoPanelFormModeChoiceDirectionElement());

    return div;
  },
  /**
   * Create Mode choice transport
   * see event !
   * FIXME event not useful
   * @param {Array} transports - transports in a list
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormModeChoiceTransportElement: function _createIsoPanelFormModeChoiceTransportElement(transports) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronTransportChoice");
    var span = document.createElement("span");
    span.className = "GPisochronModeLabel";
    span.innerHTML = "Mode de transport";
    div.appendChild(span);

    /* jshint -W083 */
    for (var i = 0; i < transports.length; i++) {
      var transport = transports[i];
      if (transport === "Voiture") {
        var inputCar = document.createElement("input");
        inputCar.id = this._addUID("GPisochronTransportCar");
        inputCar.type = "radio";
        inputCar.name = "GPisochronTransport";
        if (i === 0) {
          inputCar.checked = true;
        }
        // gestionnaire d'evenement :
        // on stocke le mode de transport,
        // utilisation pour la requête sur le service de calcul d'itiniraire
        if (inputCar.addEventListener) {
          inputCar.addEventListener("change", function (e) {
            context.onIsoModeTransportChange(e);
          });
        } else if (inputCar.attachEvent) {
          inputCar.attachEvent("onchange", function (e) {
            context.onIsoModeTransportChange(e);
          });
        }
        // info : internet explorer support
        inputCar.value = "Voiture";
        div.appendChild(inputCar);
        var labelCar = document.createElement("label");
        labelCar.className = "GPisochronTransportImg";
        labelCar.htmlFor = this._addUID("GPisochronTransportCar");
        labelCar.title = "Voiture";
        div.appendChild(labelCar);
      }
      if (transport === "Pieton") {
        var inputPedestrian = document.createElement("input");
        inputPedestrian.id = this._addUID("GPisochronTransportPedestrian");
        inputPedestrian.type = "radio";
        inputPedestrian.name = "GPisochronTransport";
        if (i === 0) {
          inputPedestrian.checked = true;
        }
        // gestionnaire d'evenement :
        // on stocke le mode de transport,
        // utilisation pour la requête sur le service de calcul d'itiniraire
        if (inputPedestrian.addEventListener) {
          inputPedestrian.addEventListener("change", function (e) {
            context.onIsoModeTransportChange(e);
          });
        } else if (inputPedestrian.attachEvent) {
          inputPedestrian.attachEvent("onchange", function (e) {
            context.onIsoModeTransportChange(e);
          });
        }
        // info : internet explorer support
        inputPedestrian.value = "Pieton";
        div.appendChild(inputPedestrian);
        var labelPedestrian = document.createElement("label");
        labelPedestrian.className = "GPisochronTransportImg";
        labelPedestrian.htmlFor = this._addUID("GPisochronTransportPedestrian");
        labelPedestrian.title = "Piéton";
        div.appendChild(labelPedestrian);
      }
    }
    return div;
  },
  /**
   * Create Mode choice direction
   * see event!
   *
   * @param {Array} directions - directions to display in list ("Departure", "Arrival"). First element will be selected by default
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormModeChoiceDirectionElement: function _createIsoPanelFormModeChoiceDirectionElement(directions) {
    // contexte d'execution
    var self = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPisochronDirectionChoice");
    var span = document.createElement("span");
    span.className = "GPisochronModeLabel";
    span.innerHTML = "Sens de parcours";
    div.appendChild(span);
    var select = document.createElement("select");
    select.id = this._addUID("GPisochronDirectionSelect");
    select.className = "GPinputSelect";
    // gestionnaire d'evenement :
    // on stocke la valeur du mode de calcul,
    // utilisation pour la requête sur le service de calcul d'iso
    select.addEventListener("change", function (e) {
      self.onIsoModeDirectionChange(e);
    });
    for (var i = 0; i < directions.length; i++) {
      var direction = directions[i];
      if (direction.toLowerCase() === "departure") {
        var departureOption = document.createElement("option");
        if (i === 0) {
          departureOption.selected = "selected";
        }
        departureOption.value = "departure";
        departureOption.text = "Départ";
        select.appendChild(departureOption);
      }
      if (direction.toLowerCase() === "arrival") {
        var arrivalOption = document.createElement("option");
        if (i === 0) {
          arrivalOption.selected = "selected";
        }
        arrivalOption.value = "arrival";
        arrivalOption.text = "Arrivée";
        select.appendChild(arrivalOption);
      }
    }
    div.appendChild(select);
    return div;
  },
  // ################################################################### //
  // ################# Methods to the choice exclusions ################ //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing Exclusions Options
   *
   * @returns {DOMElement} DOM element
   */
  _createShowIsoExclusionsElement: function _createShowIsoExclusionsElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowIsoExclusions");
    input.type = "checkbox";
    return input;
  },
  /**
   * Label to Exclusions Options
   *
   * @returns {DOMElement} DOM element
   */
  _createShowIsoExclusionsPictoElement: function _createShowIsoExclusionsPictoElement() {
    var label = document.createElement("label");
    label.id = this._addUID("GPshowIsoExclusionsPicto");
    label.className = "GPshowMoreOptionsImage GPshowMoreOptions GPshowIsoExclusionsPicto";
    label.htmlFor = this._addUID("GPshowIsoExclusions");
    label.title = "Exclusions";
    label.style.top = "240px";
    return label;
  },
  /**
   * Create Container to Exclusions
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormExclusionsElement: function _createIsoPanelFormExclusionsElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPisoExclusions");
    var span = document.createElement("span");
    span.className = "GPisoExclusionsLabel";
    span.innerHTML = "Passages autorisés";
    div.appendChild(span);

    // div.appendChild(this._createIsoPanelFormExclusionOptionsElement());

    return div;
  },
  /**
   * Create Exclusions Options
   * see event !
   * FIXME event not useful
   * @param {Array} exclusions - exclusions to display in list
   * @returns {DOMElement} DOM element
   */
  _createIsoPanelFormExclusionOptionsElement: function _createIsoPanelFormExclusionOptionsElement(exclusions) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.className = "GPisoExclusionsOptions";

    /* jshint -W083 */
    for (var value in exclusions) {
      if (exclusions.hasOwnProperty(value)) {
        var status = exclusions[value];
        switch (value) {
          case "toll":
            var inputToll = document.createElement("input");
            inputToll.id = this._addUID("GPisoExclusionsToll");
            inputToll.type = "checkbox";
            inputToll.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputToll.addEventListener) {
              inputToll.addEventListener("change", function (e) {
                context.onIsoExclusionsChange(e);
              });
            } else if (inputToll.attachEvent) {
              inputToll.attachEvent("onchange", function (e) {
                context.onIsoExclusionsChange(e);
              });
            }
            // info : internet explorer support
            inputToll.value = "Toll";
            div.appendChild(inputToll);
            var labelToll = document.createElement("label");
            labelToll.className = "GPisoExclusionsOption";
            labelToll.htmlFor = this._addUID("GPisoExclusionsToll");
            labelToll.innerHTML = "Péages";
            div.appendChild(labelToll);
            break;
          case "tunnel":
            var inputTunnel = document.createElement("input");
            inputTunnel.id = this._addUID("GPisoExclusionsTunnel");
            inputTunnel.type = "checkbox";
            inputTunnel.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputTunnel.addEventListener) {
              inputTunnel.addEventListener("change", function (e) {
                context.onIsoExclusionsChange(e);
              });
            } else if (inputTunnel.attachEvent) {
              inputTunnel.attachEvent("onchange", function (e) {
                context.onIsoExclusionsChange(e);
              });
            }
            // info : internet explorer support
            inputTunnel.value = "Tunnel";
            div.appendChild(inputTunnel);
            var labelTunnel = document.createElement("label");
            labelTunnel.className = "GPisoExclusionsOption";
            labelTunnel.htmlFor = this._addUID("GPisoExclusionsTunnel");
            labelTunnel.innerHTML = "Tunnels";
            div.appendChild(labelTunnel);
            break;
          case "bridge":
            var inputBridge = document.createElement("input");
            inputBridge.id = this._addUID("GPisoExclusionsBridge");
            inputBridge.type = "checkbox";
            inputBridge.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputBridge.addEventListener) {
              inputBridge.addEventListener("change", function (e) {
                context.onIsoExclusionsChange(e);
              });
            } else if (inputBridge.attachEvent) {
              inputBridge.attachEvent("onchange", function (e) {
                context.onIsoExclusionsChange(e);
              });
            }
            // info : internet explorer support
            inputBridge.value = "Bridge";
            div.appendChild(inputBridge);
            var labelBridge = document.createElement("label");
            labelBridge.className = "GPisoExclusionsOption";
            labelBridge.htmlFor = this._addUID("GPisoExclusionsBridge");
            labelBridge.innerHTML = "Ponts";
            div.appendChild(labelBridge);
            break;
        }
      }
    }
    return div;
  },
  // ################################################################### //
  // ############################### Submit Form ####################### //
  // ################################################################### //

  /**
   * Create Submit Form Element
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoSubmitFormElement: function _createIsoSubmitFormElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPisochronSubmit");
    input.className = "GPinputSubmit";
    input.type = "submit";
    input.value = "Calculer";
    return input;
  },
  // ################################################################### //
  // ############################### Reset picto ####################### //
  // ################################################################### //

  /**
   * Create Reset Picto Element
   *
   * @returns {DOMElement} DOM element
   */
  _createIsoFormResetElement: function _createIsoFormResetElement() {
    var self = this;
    var divReset = document.createElement("div");
    divReset.id = this._addUID("GPisochronReset");
    divReset.title = "Réinitialiser les paramètres";
    divReset.addEventListener("click", function (e) {
      self.onIsoResetClick(e);
    });
    return divReset;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (IsoDOM);

/***/ }),
/* 110 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37);
/* harmony import */ var _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(111);
/* harmony import */ var _Common_Controls_MousePositionDOM__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(112);
/* harmony import */ var _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(107);
/* harmony import */ var _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(113);
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }








var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("mouseposition");

/**
 * @classdesc
 *
 * Leaflet Control Class to display Mouse position in various CRS and altitude using the <a href="https://geoservices.ign.fr/documentation/geoservices/alti.html" target="_blank">altimetric web service of the Geoportal Platform</a>.
 *
 * Use {@link module:Controls.MousePosition L.geoportalControl.MousePosition()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.MousePosition
 */
var MousePosition = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends L.geoportalControl.MousePosition.prototype */{
  includes: _Common_Controls_MousePositionDOM__WEBPACK_IMPORTED_MODULE_5__["default"],
  /**
   * options by default
   *
   * @private
   */
  options: {
    position: "bottomleft",
    collapsed: true,
    units: [],
    systems: [],
    displayAltitude: true,
    displayCoordinates: true,
    editCoordinates: false,
    altitude: {
      triggerDelay: 200,
      responseDelay: 500,
      noDataValue: -99999,
      noDataValueTolerance: 90000,
      serviceOptions: {}
    }
  },
  /**
   * @constructor MousePosition
   *
   * @private
   * @alias MousePosition
   * @extends {L.Control}
   * @param {Object} options - options for function call.
   * @param {String}   [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {String}  [options.position] - position of component into the map, 'bottomleft' by default
   * @param {Boolean} [options.collapsed = true] - collapse mode, false by default
   * @param {Array}   [options.systems] - list of projection systems, GEOGRAPHIC, MERCATOR, LAMB93 and LAMB2E by default
   *      Each array element (=system) is an object with following properties :
   * @param {String}  options.systems.crs - Proj4 crs alias (from proj4 defs). e.g. : "EPSG:4326". Required
   * @param {String}  [options.systems.label] - CRS label to be displayed in control. Default is crs code (e.g. "EPSG:4326")
   * @param {String}  [options.systems.type] - CRS units type for coordinates conversion : "Geographical" or "Metric". Default: "Metric"
   * @param {Object}  [options.systems.geoBBox] - Aera covered by the system (WGS84 coordinates).
   * @param {Number}  options.systems.geoBBox.right - Right bound.
   * @param {Number}  options.systems.geoBBox.left - Left bound.
   * @param {Number}  options.systems.geoBBox.top - Top bound.
   * @param {Number}  options.systems.geoBBox.bottom - Bottom bound.
   * @param {Array}   [options.units] - list of units by system, Geographical and Metric by default
   *      Values may be "DEC" (decimal degrees), "DMS" (sexagecimal), "RAD" (radians) and "GON" (grades) for geographical coordinates,
   *      and "M" or "KM" for metric coordinates
   * @param {Boolean} [options.displayAltitude= true] - active/desactivate the altitude panel, if desactivate, have just the coordinate panel, true by default
   * @param {Boolean} [options.displayCoordinates= true] - active/desactivate the coordinate panel, if desactivate, have just the altitude panel, true by default
   * @param {Boolean} [options.editCoordinates = false] - add edit coordinates options. False by default.
   * @param {Object}  [options.altitude] - elevation configuration
   * @param {Object}  [options.altitude.serviceOptions] - options of elevation service
   * @param {Number}  [options.altitude.responseDelay] - latency for altitude request, 500 ms by default
   * @param {Number}  [options.altitude.triggerDelay] - immobilisation time of movement on the map to trigger the elevation calculation, 200 ms by default
   * @param {Number}  [options.altitude.noDataValue] - value used for altitude service no data (default is -99999). In this case, "---m" will be displayed instead of "-99999m"
   * @param {Number}  [options.altitude.noDataValueTolerance] - tolerance for no data value :
   *                  values in [noDataValue - noDataValueTolerance ; noDataValue + noDataValueTolerance] interval will not be displayed, but "---m" will be displayed instead.
   *                  Default is 90000
   * @example
   *  var MousePosition = L.geoportalControl.MousePosition({
   *      position : 'bottomleft',
   *      collapsed : false,
   *      displayAltitude : true,
   *      displayCoordinates : true,
   *      editCoordinates : false,
   *      altitude : {
   *           triggerDelay : 100,
   *           responseDelay : 500,
   *           noDataValue : -99999,
   *           noDataValueTolerance : 90000,
   *           serviceOptions : {}
   *      },
   *      systems : [
   *       {
   *          crs : L.CRS.EPSG4326,
   *          label : "Lon,Lat",
   *          type : "Geographical"
   *        },
   *       {
   *          crs : L.geoportalCRS.EPSG2154,
   *          label : "Lambert 93",
   *          type : "Metric"
   *        }
   *      ],
   *      units : ["DEC", "DMS"]
   *  });
   */
  initialize: function initialize(options) {
    // on merge les options avec celles par defaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(this.options, options);

    // uuid
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].generate();

    // initialisation des systemes de projections
    this._projectionSystems = [];
    this._initProjectionSystems();

    // initialisation des systemes des unités
    this._projectionUnits = {};
    this._initProjectionUnits();

    // detection du support : desktop ou tactile
    this._isDesktop = this._detectSupport();

    // on met en place un seuil sur le timer
    if (this.options.altitude.triggerDelay < 100) {
      this.options.altitude.triggerDelay = 100;
    }

    // timer sur le delai d'immobilisation du mouvement
    this._timer = this.options.altitude.triggerDelay;

    // Systeme de projection selectionné (cf. _initProjectionSystems)
    this._currentProjectionSystems = this._projectionSystems[0];

    // Container des systemes
    this._projectionSystemsContainer = null;

    /** Type d'unité de projection selectionnés : Geographical ou Metric (cf._initProjectionSystems ) */
    this._currentProjectionType = this._projectionSystems[0].type;

    // Unité de projection selectionnés (cf. _initProjectionUnits)
    this._currentProjectionUnits = this._projectionUnits[this._currentProjectionType][0].code;

    // Container des unités
    this._projectionUnitsContainer = null;

    /** Container de visualisation du panneau du composant */
    this._showContainer = null;
    this._pictoContainer = null;
    this._panelContainer = null;
    this._panelHeaderContainer = null;

    // gestion de l'affichage du panneau de l'altitude / coordonnées
    if (!this.options.displayAltitude && !this.options.displayCoordinates) {
      // on reactive cette option !
      this.options.displayCoordinates = true;
    }
    if (!this.options.displayCoordinates) {
      // si les coordonnées ne sont pas affichées : pas besoin de les éditer...
      this.options.editCoordinates = false;
    }

    /** Edition des coordonnées en cours ou non */
    this._isEditing = false;

    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.setOptions(this, this.options);
  },
  /**
   * this method is called by this.addTo(map) when the control is added on the map
   * and fills variable 'this._container = this.onAdd(map)',
   * and create events on map.
   * @param {Object} map - the map
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  onAdd: function onAdd(map) {
    // initialisation du DOM du composant
    var container = this._container = this._initLayout();

    // on met en place l'evenement sur la carte pour recuperer les coordonnées,
    // on l'active à l'ouverture du panneau uniquement !
    if (!this.options.collapsed) {
      // this.onShowMousePositionClick();
      // evenement valable pour le mode desktop !
      if (this._isDesktop) {
        map.on("mousemove", this.onMouseMove, this);
      } else {
        map.on("move", this.onMapMove, this);
      }
    }

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);

    // on stoppe la propagation de l'événement mousemove sur le container
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.addListener(container, "mousemove", leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.stopPropagation).addListener(container, "mousemove", leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.preventDefault);
    return container;
  },
  /**
   * this method is called when the control is removed from the map
   * and removes events on map.
   * @param {Object} map - the map
   *
   * @private
   */
  onRemove: function onRemove(map) {
    map.off("mousemove", this.onMouseMove);
  },
  /**
   * this method is called by the constructor and initialize the projection
   * systems.
   * getting coordinates in the requested projection :
   * see this.onMousePositionProjectionSystemChange()
   *
   * @private
   */
  _initProjectionSystems: function _initProjectionSystems() {
    // on donne la possibilité à l'utilisateur de modifier
    // la liste des systèmes à afficher
    // Ex. this.options.systems

    // systemes de projection disponible par defaut
    var projectionSystemsByDefault = [{
      label: "G\xE9ographique",
      crs: leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.CRS.Simple,
      // L.Projection.LonLat !
      type: "Geographical"
    }, {
      label: "Web Mercator",
      crs: leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.CRS.EPSG3395,
      // L.Projection.SphericalMercator !
      type: "Metric"
    }, {
      label: "Lambert 93",
      crs: _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"].EPSG2154,
      type: "Metric",
      geoBBox: {
        left: -9.86,
        bottom: 41.15,
        right: 10.38,
        top: 51.56
      }
    }, {
      label: "Lambert II \xE9tendu",
      crs: _CRS_CRS__WEBPACK_IMPORTED_MODULE_7__["default"].EPSG27572,
      type: "Metric",
      geoBBox: {
        left: -4.87,
        bottom: 42.33,
        right: 8.23,
        top: 51.14
      }
    }];
    var systems = this.options.systems;
    for (var i = 0; i < systems.length; i++) {
      // definition d'un systeme de reference
      var sys = systems[i];
      if (!sys.label) {
        logger.error("not defined !");
        continue;
      }
      if (!sys.crs) {
        logger.error("crs not defined !");
        continue;
      }
      if (!sys.type) {
        logger.warn("type srs not defined, use 'Metric' by default !");
        sys.type = "Metric";
      }
      this._projectionSystems.push(systems[i]);

      // it's a just a test ...
      var found = false;
      for (var j = 0; j < projectionSystemsByDefault.length; j++) {
        var obj = projectionSystemsByDefault[j];
        if (sys.crs === obj.crs) {
          found = true;
          logger.info("crs '{}' already configured by default", obj.code);
        }
      }
      if (!found) {
        logger.info("crs '{}' not found, it's a new projection", sys.code || sys.label);
      }
    }

    // au cas où...
    if (this._projectionSystems.length === 0) {
      this._projectionSystems = projectionSystemsByDefault;
    }

    // re-initilisation des codes pour gerer le lien entre _projectionSystems et select du mouse position (lien code/value)
    for (var k = 0; k < this._projectionSystems.length; ++k) {
      this._projectionSystems[k].code = k;
    }
  },
  /**
   * this method is called by the constructor and initialize the units.
   * getting coordinates in the requested units :
   * see this.onMousePositionProjectionUnitsChange()
   *
   * @private
   */
  _initProjectionUnits: function _initProjectionUnits() {
    // on donne la possibilité à l'utilisateur de modifier
    // la liste des unités à afficher
    // Ex.
    // this.options.units : ["DEC", "DMS"]

    // unités disponible par defaut
    var projectionUnitsByDefault = {
      Geographical: [{
        code: "DEC",
        label: "degrés décimaux",
        format: this._displayDEC
      }, {
        code: "DMS",
        label: "degrés sexagésimaux",
        format: this._displayDMS
      }, {
        code: "RAD",
        label: "radians",
        format: this._displayRAD
      }, {
        code: "GON",
        label: "grades",
        format: this._displayGON
      }],
      Metric: [{
        code: "M",
        label: "mètres",
        format: this._displayMeter
      }, {
        code: "KM",
        label: "kilomètres",
        format: this._displayKMeter
      }]
    };
    var units = this.options.units;
    for (var type in projectionUnitsByDefault) {
      if (projectionUnitsByDefault.hasOwnProperty(type)) {
        var found = false;
        for (var j = 0; j < projectionUnitsByDefault[type].length; j++) {
          var obj = projectionUnitsByDefault[type][j];
          for (var i = 0; i < units.length; i++) {
            var unit = units[i];
            if (obj.code === unit) {
              found = true;
              if (!this._projectionUnits[type]) {
                this._projectionUnits[type] = [];
              }
              this._projectionUnits[type].push(obj);
            }
          }
        }
        if (!found) {
          this._projectionUnits[type] = projectionUnitsByDefault[type];
        }
      }
    }

    // au cas où...
    if (Object.keys(this._projectionUnits).length === 0) {
      this._projectionUnits = projectionUnitsByDefault;
    }
  },
  /**
   * this method is called by the constructor.
   * this information is useful to switch to touch mode.
   * Detection : test for desktop or tactile
   *
   * @returns {Boolean} is desktop
   * @private
   */
  _detectSupport: function _detectSupport() {
    // TODO
    // Choix de gérer la détection dans le code du composant au lieu du DOM car :
    // Utilisation de l'implémentation Leaflet
    // http://leafletjs.com/reference.html#browser

    var isDesktop = true;
    var userAgent = window.navigator.userAgent.toLowerCase();
    if (userAgent.indexOf("iphone") !== -1 || userAgent.indexOf("ipod") !== -1 || userAgent.indexOf("ipad") !== -1 || userAgent.indexOf("android") !== -1 || userAgent.indexOf("mobile") !== -1 || userAgent.indexOf("blackberry") !== -1 || userAgent.indexOf("tablet") !== -1 || userAgent.indexOf("phone") !== -1 || userAgent.indexOf("touch") !== -1) {
      isDesktop = false;
    }
    if (userAgent.indexOf("msie") !== -1 || userAgent.indexOf("trident") !== -1) {
      isDesktop = true;
    }
    return isDesktop;
  },
  // ################################################################### //
  // ######################## methods handle dom ####################### //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  _initLayout: function _initLayout() {
    // create main container
    var container = this._createMainContainerElement();
    var inputShow = this._showContainer = this._createShowMousePositionElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (!this.options.collapsed) {
      inputShow.checked = true;
    }
    var picto = this._pictoContainer = this._createShowMousePositionPictoElement(this._isDesktop);
    container.appendChild(picto);
    var panel = this._panelContainer = this._createMousePositionPanelElement();
    var header = this._panelHeaderContainer = this._createMousePositionPanelHeaderElement();
    panel.appendChild(header);
    var basic = this._createMousePositionPanelBasicElement(this.options.displayAltitude, this.options.displayCoordinates, this.options.editCoordinates);
    panel.appendChild(basic);
    var arraySettings = this._createShowMousePositionSettingsElement(this.options.displayCoordinates);
    for (var j = 0; j < arraySettings.length; j++) {
      panel.appendChild(arraySettings[j]);
    }
    var settings = this._createMousePositionSettingsElement();
    var systems = this._projectionSystemsContainer = this._createMousePositionSettingsSystemsElement(this._projectionSystems);
    var units = this._projectionUnitsContainer = this._createMousePositionSettingsUnitsElement(this._projectionUnits[this._currentProjectionType]);
    settings.appendChild(systems);
    settings.appendChild(units);
    panel.appendChild(settings);
    container.appendChild(panel);

    // ce tag n'est pas à placer dans le container du controle,
    // mais dans celui de la map !
    var center = this._createMapCenter();
    var map = this._map;
    map.getContainer().appendChild(center);
    return container;
  },
  /**
   * this method is called by this.()
   * and it changes the elevation view panel into the dom.
   * FIXME call by ID !
   *
   * @param {Boolean} active - true:active, false:disable
   *
   * @private
   */
  _setElevationPanel: function _setElevationPanel(active) {
    var div = null;
    if (!active) {
      div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionAltitude"));
      div.style.display = "none";
    }
  },
  /**
   * this method is called by this.()
   * and it changes the coordinate view panel into the dom.
   * FIXME call by ID !
   *
   * @param {Boolean} active - true:active, false:disable
   *
   * @private
   */
  _setCoordinatePanel: function _setCoordinatePanel(active) {
    if (!active) {
      var div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionCoordinate"));
      div.style.display = "none";
    }
  },
  /**
   * this method is called by this.()
   * and it changes the settings view panel into the dom.
   * FIXME call by ID !
   *
   * @param {Boolean} active - true:active, false:disable
   *
   * @private
   */
  _setSettingsPanel: function _setSettingsPanel(active) {
    if (!active) {
      var divPicto = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPshowMousePositionSettingsPicto");
      var divPanel = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionSettings"));
      divPicto.style.display = "none";
      divPanel.style.display = "none";
    }
  },
  /**
   * this method is called by this.onMousePositionProjectionSystemChange()
   * when changes to a metric or a geographical units.
   *
   * @param {String} type - Geographical or Metric
   *
   * @private
   */
  _setTypeUnitsPanel: function _setTypeUnitsPanel(type) {
    var container = this._projectionUnitsContainer;

    // on supprime les enfants...
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
    var units = this._projectionUnits[type];
    for (var j = 0; j < units.length; j++) {
      var obj = units[j];
      var option = document.createElement("option");
      option.value = obj.code ? obj.code : j;
      option.text = obj.label || j;
      // option.label = obj.label;
      container.appendChild(option);
    }
    var projectionUnits = this._projectionUnits[type][0].code;
    if (this._currentProjectionUnits === "DMS" || projectionUnits === "DMS") {
      this._resetCoordinateElements(this.options.editCoordinates, type, projectionUnits);
      this._setEditMode(this._isEditing);
    }

    // le nouveau type de system ...
    this._currentProjectionType = type;

    // Mise a jour des elements labels et unites
    this._resetLabelElements(type);
    this._resetUnitElements(projectionUnits);

    // et comme on a changé de type de systeme,
    // il faut changer aussi d'unité !
    this._currentProjectionUnits = this._projectionUnits[type][0].code;
  },
  // ################################################################### //
  // ######################## method units format ###################### //
  // ################################################################### //

  /**
   * degreedecimal
   * @param {Object} oLatLng - coordinates
   *
   * @returns {Object} coordinates in decimal
   * @private
   */
  _displayDEC: function _displayDEC(oLatLng) {
    var coordinate = {};
    coordinate.lat = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].roundToDecimal(oLatLng.lat, 6);
    coordinate.lng = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].roundToDecimal(oLatLng.lng, 6);
    coordinate.unit = "°";
    return coordinate;
  },
  /**
   * degreedecimal2sexagecimal
   * @param {Object} oLatLng - coordinates
   *
   * @returns {Object} coordinates in DMS
   * @private
   */
  _displayDMS: function _displayDMS(oLatLng) {
    var coordinate = {};
    coordinate.lat = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalLatToDMS(oLatLng.lat, true);
    coordinate.lng = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalLonToDMS(oLatLng.lng, true);
    return coordinate;
  },
  /**
   * degreedecimal2radian
   * @param {Object} oLatLng - coordinates
   *
   * @returns {Object} coordinates in radian
   * @private
   */
  _displayRAD: function _displayRAD(oLatLng) {
    var coordinate = {};
    coordinate.lat = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalToRadian(oLatLng.lat);
    coordinate.lng = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalToRadian(oLatLng.lng);
    coordinate.unit = "rad";
    return coordinate;
  },
  /**
   * degreedecimal2grade
   * @param {Object} oLatLng - coordinates
   *
   * @returns {Object} coordinates in gon
   * @private
   */
  _displayGON: function _displayGON(oLatLng) {
    var coordinate = {};
    coordinate.lat = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalToGrade(oLatLng.lat);
    coordinate.lng = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_6__["default"].decimalToGrade(oLatLng.lng);
    coordinate.unit = "gon";
    return coordinate;
  },
  /**
   * meter
   * @param {Object} oXY - coordinates
   *
   * @returns {Object} coordinates in meters
   * @private
   */
  _displayMeter: function _displayMeter(oXY) {
    // on recoit toujours des coordonnées metriques
    var coordinate = {};
    coordinate.x = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.formatNum(oXY.x, 2);
    coordinate.y = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.formatNum(oXY.y, 2);
    coordinate.unit = "m";
    return coordinate;
  },
  /**
   * kilometer
   * @param {Object} oXY - coordinates
   *
   * @returns {Object} coordinates in km
   * @private
   */
  _displayKMeter: function _displayKMeter(oXY) {
    var coordinate = {};
    coordinate.x = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.formatNum(oXY.x / 1000, 2);
    coordinate.y = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.formatNum(oXY.y / 1000, 2);
    coordinate.unit = "km";
    return coordinate;
  },
  // ################################################################### //
  // ####################### method system project ##################### //
  // ################################################################### //

  /**
   * this method projects a coordinate to a specific projection.
   * FIXME
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   * @param {Object} crs - projection system (ex. GEOGRAPHIC, LAMB93, LAMB2E, MERCATOR, ...)
   * @returns {Object} oXY - coordinate
   * @private
   */
  _project: function _project(oLatLng, crs) {
    // cf. http://leafletjs.com/reference.html#iprojection
    // notre carte est dans la projection par defaut :
    // Spherical Mercator projection (EPSG:3857)
    // - GEOGRAPHIC : conversion native, L.CRS.Simple ou L.Projection.LngLat.project(latlng)
    // - LAMB93 : L.GeoportalCRS.EPSG2154 ou projection.project(latlng)
    // - LAMB2E : L.GeoportalCRS.EPSG27572 ou projection.project(latlng)
    // - MERCATOR ou EPSG:3395 : L.CRS.EPSG3395 ou L.Projection.Mercator.project(latlng)

    if (typeof crs === "function") {
      // "crs is an function !"... en mode AMD !
      crs = crs();
    }
    if (_typeof(crs) !== "object") {
      logger.log("crs is not an object !");
      return;
    }

    // pas de reprojection pour le systeme de projection natif !
    if (crs === leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.CRS.Simple) {
      return oLatLng;
    }
    if (!crs.projection || _typeof(crs.projection) !== "object") {
      logger.error("projection is not an object !");
      return;
    }
    var oPoint = crs.projection.project(oLatLng);

    // FIXME reprojeter du geographique en geographique cause qq problemes
    // Ex. LatLng en EPSG4326 !
    // FIXME probleme d'inversion d'axe sur les projections geographiques
    // Ex. EPSG:4326 -> lat/lon
    //     IGNF:RGF93G -> lon/lat
    if (this._currentProjectionType === "Geographical") {
      oPoint.lat = oPoint.y;
      oPoint.lng = oPoint.x;
    }
    if (!oPoint || Object.keys(oPoint).length === 0) {
      logger.error("Failed to project with crs code : " + crs.code);
    }
    return oPoint;
  },
  /**
   * this method unprojects a coordinate to a geographic projection.
   *
   * @param {Object} oXY - coordinate
   * @returns {Object} oLatLng - geographic coordinate (L.LatLng)
   * @private
   */
  _unproject: function _unproject(oXY) {
    // cf. http://leafletjs.com/reference.html#iprojection
    // notre carte est dans la projection par defaut :
    // Spherical Mercator projection (EPSG:3857)
    // - GEOGRAPHIC : conversion native, L.CRS.Simple ou L.Projection.LngLat.project(latlng)
    // - LAMB93 : L.GeoportalCRS.EPSG2154 ou projection.project(latlng)
    // - LAMB2E : L.GeoportalCRS.EPSG27572 ou projection.project(latlng)
    // - MERCATOR ou EPSG:3395 : L.CRS.EPSG3395 ou L.Projection.Mercator.project(latlng)

    var oSrs = this._currentProjectionSystems.crs;
    if (!oSrs) {
      logger.log("system crs not found");
      return;
    }
    if (typeof oSrs === "function") {
      // "crs is an function !"... en mode AMD !
      oSrs = oSrs();
    }
    if (_typeof(oSrs) !== "object") {
      logger.log("crs is not an object !");
      return;
    }

    // pas de reprojection pour le systeme de projection natif !
    if (oSrs === leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.CRS.Simple) {
      return {
        lat: oXY.y,
        lng: oXY.x
      };
    }
    if (this._currentProjectionType === "Geographical") {
      return {
        lat: oXY.y,
        lng: oXY.x
      };
    }
    if (!oSrs.projection || _typeof(oSrs.projection) !== "object") {
      logger.error("projection is not an object !");
      return;
    }
    var oLatLng = oSrs.projection.unproject(oXY);
    if (!oLatLng || Object.keys(oLatLng).length === 0) {
      logger.error("Failed to unproject coordinate");
    }
    return oLatLng;
  },
  // ################################################################### //
  // ##################### handlers events to control ################## //
  // ################################################################### //

  /**
   * this sends the coordinates to the panel.
   * (cf. this.GPdisplayCoords() into the DOM functions)
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   *
   * @private
   */
  _setCoordinate: function _setCoordinate(oLatLng) {
    // structure
    // L.LatLng
    //     lat: 4.07249425916745
    //     lng: 2.4609375

    // type de systeme : Geographical ou Metric
    var type = this._currentProjectionSystems.type;

    // on recherche la fonction de formatage dans l'unitée demandée
    var format = null;
    var units = this._projectionUnits[type];
    for (var i = 0; i < units.length; i++) {
      if (units[i].code === this._currentProjectionUnits) {
        format = units[i].format;
        break;
      }
    }

    // structure pour les coordonnées en fonctin du type demandé :
    // {x:, y:, unit:} ou {lng:, lat:} ou {lon:, lat:} ou {e:, n:, unit:}...
    var coordinate = {};
    // on projete le point dans le systeme demandé
    var oSrs = this._currentProjectionSystems.crs;
    if (!oSrs) {
      logger.error("crs not found !");
      return;
    }
    coordinate = format(this._project(oLatLng, oSrs));
    if (!coordinate || Object.keys(coordinate).length === 0) {
      return;
    }
    this.GPdisplayCoords(coordinate);
  },
  /**
   * this sends the coordinates to the panel.
   * (cf. this.GPdisplayElevation() into the DOM functions)
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   *
   * @private
   */
  _setElevation: function _setElevation(oLatLng) {
    // gestion du timer de la requete du service d'altitude
    var delay = this.options.altitude.responseDelay;
    var noDataValue = this.options.altitude.noDataValue;
    var noDataValueTolerance = this.options.altitude.noDataValueTolerance;
    this.GPdisplayElevation(oLatLng, delay, noDataValue, noDataValueTolerance);
  },
  /**
   * this method is triggered when the mouse or the map is stopped.
   * (cf. onMouseMove and onMapMove)
   *
   * @param {Object} oLatLng - geographic coordinate (L.LatLng)
   *
   * @private
   */
  onMoveStopped: function onMoveStopped(oLatLng) {
    this._setElevation(oLatLng);
  },
  /**
   * this method is an handler event to control. The event is 'mousemove' on
   * the map. The handler sends the coordinates to the panel.
   * (cf. this.GPdisplayCoords() into the DOM functions)
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMouseMove: function onMouseMove(e) {
    var self = this;
    var oLatLng = e.latlng;
    this._setCoordinate(oLatLng);
    clearTimeout(this._timer);
    this._timer = setTimeout(function () {
      self.onMoveStopped(oLatLng);
    }, this.options.altitude.triggerDelay);
  },
  /**
   * this method is an handler event to control. The event is 'moveend' on
   * the map. The handler sends the coordinates to the panel.
   * (cf. this.GPdisplayCoords() into the DOM functions)
   *
   * @private
   */
  onMapMove: function onMapMove() {
    var self = this;
    var map = this._map;
    var oLatLng = map.getCenter();
    this._setCoordinate(oLatLng);
    clearTimeout(this._timer);
    this._timer = setTimeout(function () {
      self.onMoveStopped(oLatLng);
    }, this.options.altitude.triggerDelay);
  },
  // ################################################################### //
  // ####################### handlers events to dom #################### //
  // ################################################################### //

  /**
   * this method is called by this.GPdisplayCoords() in the dom, and
   * it executes a request to the elevation service.
   *
   * @param {Object} coordinate - {lat:..., lng:...}
   * @param {Function} callback - callback
   *
   * @private
   */
  onRequestAltitude: function onRequestAltitude(coordinate, callback) {
    logger.log("onRequestAltitude");

    // INFORMATION
    // on effectue la requête au service d'altitude...
    // on met en place des callbacks afin de recuperer les resultats ou
    // les messages d'erreurs du service.
    // le resultat est affiché dans une balise du dom.
    // les messages d'erreurs sont affichés sur la console (?)

    if (!coordinate || Object.keys(coordinate).length === 0) {
      return;
    }

    // si on ne veut pas de calcul d'altitude, on ne continue pas !
    if (!this.options.displayAltitude) {
      return;
    }
    logger.log(coordinate);
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.altitude.serviceOptions);

    // ainsi que les coordonnées
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      zonly: true,
      positions: [{
        lon: coordinate.lon || coordinate.lng,
        lat: coordinate.lat
      }]
    });

    // et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      scope: this,
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results && Object.keys(results).length) {
          // var context = this.options.scope;
          // context._setAltidude(results.elevations[0].z);
          callback.call(this, results.elevations[0].z);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        logger.error(error.message);
      }
    });

    // cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle ou la clé "calcul" par défaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      ssl: this.options.ssl
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.getAltitude(options);
  },
  /**
   * this method is called by event 'click' on 'GPshowMousePositionPicto' tag label
   * (cf. this._createShowMousePositionPictoElement),
   * and toggles event 'mousemove' on map.
   * FIXME
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowMousePositionClick: function onShowMousePositionClick(e) {
    logger.log(e);

    // checked : true - panel close
    // checked : false - panel open
    var map = this._map;

    // evenement declenché à l'ouverture/fermeture du panneau,
    // et en fonction du mode : desktop ou tactile !
    if (this._showContainer.checked) {
      this._isDesktop ? map.off("mousemove", this.onMouseMove, this) : map.off("move", this.onMapMove, this);
    } else {
      this._isDesktop ? map.on("mousemove", this.onMouseMove, this) : map.on("move", this.onMapMove, this);
    }

    // on gère l'affichage des panneaux ici...,
    // même si ce n'est pas l'endroit adequate...
    this._setElevationPanel(this.options.displayAltitude);
    this._setCoordinatePanel(this.options.displayCoordinates);
    if (!this.options.displayCoordinates) {
      this._setSettingsPanel(false);
    }
  },
  /**
   * this method is called by event 'click' on input coordinate
   *
   * @param {Boolean} editing - editing mode
   * @private
   */
  onMousePositionEditModeClick: function onMousePositionEditModeClick(editing) {
    if (!this.options.editCoordinates) {
      return;
    }
    if (this._isEditing === editing) {
      return;
    }
    this._isEditing = editing;

    // Affichage des outils, input en ecriture
    this._setEditMode(this._isEditing);
    var map = this._map;
    if (this._isDesktop) {
      this._isEditing ? map.off("mousemove", this.onMouseMove, this) : map.on("mousemove", this.onMouseMove, this);
    } else {
      this._isEditing ? map.off("move", this.onMapMove, this) : map.on("move", this.onMapMove, this);
    }
  },
  /**
   * Convert Coordinate value : km to meters, radians, grades to decimal degrees
   * @param {Number} value - value to convert
   * @param {String} unit - unit
   *
   * @returns {Number} converted value
   * @private
   */
  _convertCoordinate: function _convertCoordinate(value, unit) {
    var result;
    if (unit === "DEC" || unit === "DMS") {
      // DMS est converti en DEC !
      result = value;
    } else if (unit === "M") {
      result = value;
    } else if (unit === "KM") {
      result = value * 1000;
    } else if (unit === "RAD") {
      var rd = (180 / Math.PI).toFixed(20);
      result = (value * rd).toFixed(20);
    } else if (unit === "GON") {
      var d = (9 / 10).toFixed(20);
      result = (value * d).toFixed(20);
    }
    return result;
  },
  /**
   * Validate Extend coordinate
   *
   * @param {String} coordType - Lat or Lon
   * @param {String} value - coordinate
   * @param {Event} e - event
   * @returns {Boolean} value is within extent
   */
  validateExtentCoordinate: function validateExtentCoordinate(coordType, value, e) {
    // FIXME pas de validation...
    if (e !== undefined) {
      return true;
    }
    if (["Lon", "Lat"].indexOf(coordType) === -1) {
      return false;
    }
    var geoBBox = this._currentProjectionSystems.geoBBox;
    if (geoBBox === undefined) {
      return true;
    }
    if (geoBBox) {
      // check if coordinates are in the extent

      var extent = [geoBBox.left, geoBBox.bottom, geoBBox.right, geoBBox.top];
      var unit = this._currentProjectionUnits;

      // on convertit un point..., mais on n'a pas de fonction
      // de conversion comme pour openlayers...
      var oLatLon = this._unproject({
        x: coordType === "Lon" ? this._convertCoordinate(value, unit) : 0,
        y: coordType === "Lat" ? this._convertCoordinate(value, unit) : 0
      });
      if (coordType === "Lon" && (oLatLon.lng < extent[0] || oLatLon.lng > extent[2])) {
        logger.warn("coordinates (lon) out of extent !?");
        return false;
      }
      if (coordType === "Lat" && (oLatLon.lat < extent[1] || oLatLon.lat > extent[3])) {
        logger.warn("coordinates (lat) out of extent !?");
        return false;
      }
    }
    return true;
  },
  /**
   * Get coordinate from inputs and select in decimal degrees
   *
   * @param {String} coordType - "Lon" or "Lat"
   * @returns {String} coordinate
   * @private
   */
  _getCoordinate: function _getCoordinate(coordType) {
    var inputDegrees = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePosition" + coordType + "Degrees"));
    var degrees = inputDegrees.value;
    if (!degrees) {
      return null;
    }
    degrees = degrees.replace(",", ".");
    if (!_Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__["default"].isInteger(degrees)) {
      return null;
    }
    var result = _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__["default"].toInteger(degrees);
    if (result < Number(inputDegrees.dataset.min) || result > Number(inputDegrees.dataset.max)) {
      return null;
    }
    var direction = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePosition" + coordType + "Direction")).value;
    var inputMinutes = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePosition" + coordType + "Minutes"));
    var minutes = inputMinutes.value;
    if (minutes) {
      minutes = minutes.replace(",", ".");
      if (_Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__["default"].isInteger(minutes)) {
        var mins = _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__["default"].toInteger(minutes);
        if (mins >= Number(inputMinutes.dataset.min) && mins <= Number(inputMinutes.dataset.max)) {
          result += mins / 60;
        }
      }
    }
    var inputSeconds = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePosition" + coordType + "Seconds"));
    var seconds = inputSeconds.value;
    if (seconds) {
      seconds = seconds.replace(",", ".");
      var secs = _Common_Utils_MathUtils__WEBPACK_IMPORTED_MODULE_4__["default"].toFloat(seconds);
      if (secs && secs >= Number(inputSeconds.dataset.min) && secs <= Number(inputSeconds.dataset.max)) {
        result += secs / 3600;
      }
    }
    if (direction === "O" || direction === "S") {
      result = -result;
    }
    return result;
  },
  /**
   * locate DMS coordinates on map
   *
   * @private
   */
  _locateDMSCoordinates: function _locateDMSCoordinates() {
    // on est toujours en coordonnées geographiques...
    var oLatLon = {
      lat: this._getCoordinate("Lat"),
      lng: this._getCoordinate("Lon")
    };
    if (!this.validateExtentCoordinate("Lon", oLatLon.lng)) {
      return;
    }
    if (!this.validateExtentCoordinate("Lat", oLatLon.lat)) {
      return;
    }

    // FIXME https://github.com/Leaflet/Leaflet/issues/922
    var map = this._map;
    map.panTo(oLatLon);
  },
  /**
   * locate coordinates on map (not DMS)
   *
   * @private
   */
  _locateCoordinates: function _locateCoordinates() {
    // soit longitude ou soit y
    var lonYDom = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionLon")).value;
    lonYDom = lonYDom.replace(",", ".");
    lonYDom = parseFloat(lonYDom);
    if (isNaN(lonYDom)) {
      return;
    }

    // soit lattitude ou soit x
    var latXDom = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionLat")).value;
    latXDom = latXDom.replace(",", ".");
    latXDom = parseFloat(latXDom);
    if (isNaN(latXDom)) {
      return;
    }
    var lon = null;
    var lat = null;
    var x = null;
    var y = null;
    if (this._currentProjectionType === "Geographical") {
      lon = lonYDom;
      lat = latXDom;
    } else {
      x = latXDom;
      y = lonYDom;
    }
    if (!this.validateExtentCoordinate("Lon", lon || x)) {
      return;
    }
    if (!this.validateExtentCoordinate("Lat", lat || y)) {
      return;
    }
    var unit = this._currentProjectionUnits;
    var oLatLon = this._unproject({
      x: this._convertCoordinate(lon !== null ? lon : x, unit),
      y: this._convertCoordinate(lat !== null ? lat : y, unit)
    });

    // FIXME https://github.com/Leaflet/Leaflet/issues/922
    var map = this._map;
    map.panTo(oLatLon);
  },
  /**
   * locate coordinates on map
   *
   * @method locate
   * @private
   */
  onMousePositionEditModeLocateClick: function onMousePositionEditModeLocateClick() {
    if (!this.options.editCoordinates) {
      return;
    }
    if (!this._isEditing) {
      this.onMousePositionEditModeClick(true);
      return;
    }
    this._currentProjectionUnits === "DMS" ? this._locateDMSCoordinates() : this._locateCoordinates();
  },
  /**
   * this method is called by event 'change' on 'GPmousePositionProjectionSystem'
   * tag select (cf. this._createMousePositionSettingsElement),
   * and selects the system projection.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMousePositionProjectionSystemChange: function onMousePositionProjectionSystemChange(e) {
    logger.log("onMousePositionProjectionSystemChange", e);
    var idx = e.target.selectedIndex; // index
    var value = e.target.options[idx].value; // crs, ex. MERCATOR (optionnel)
    var label = e.target.options[idx].label; // etiquette, ex Géographiques

    logger.log(idx, value, label);
    this._setCurrentSystem(value);
  },
  /**
   * this method selects the current system projection.
   *
   * @param {Object} systemCode - inner code (rank in array _projectionSystems)
   *
   * @private
   */
  _setCurrentSystem: function _setCurrentSystem(systemCode) {
    // si on change de type de systeme, on doit aussi changer le type d'unités !
    var type = null;
    for (var i = 0; i < this._projectionSystems.length; ++i) {
      if (this._projectionSystems[i].code === Number(systemCode)) {
        type = this._projectionSystems[i].type;
        break;
      }
    }
    if (!type) {
      logger.log("system not found in projection systems container");
      return;
    }
    if (type !== this._currentProjectionType) {
      this._setTypeUnitsPanel(type);
    }

    // on enregistre le systeme courrant
    this._currentProjectionSystems = this._projectionSystems[Number(systemCode)];

    // on simule un deplacement en mode tactile pour mettre à jour les
    // resultats
    if (!this._isDesktop) {
      this.onMapMove();
    }
  },
  /**
   * this method is called by event 'mouseover' on 'GPmousePositionProjectionSystem'
   * tag select (cf. this._createMousePositionSettingsElement),
   * and selects the system projection.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMousePositionProjectionSystemMouseOver: function onMousePositionProjectionSystemMouseOver(e) {
    logger.log("onMousePositionProjectionSystemMouseOver", e);
    var map = this._map;
    if (!map) {
      return;
    }

    // clear select
    var systemList = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get(this._addUID("GPmousePositionProjectionSystem"));
    systemList.innerHTML = "";

    // add systems whose extent intersects the map extent
    for (var j = 0; j < this._projectionSystems.length; j++) {
      var proj = this._projectionSystems[j];
      var option = null;
      if (proj.geoBBox) {
        // bboxes intersection test
        if (map.getBounds()._southWest.lng > proj.geoBBox.right || map.getBounds()._southWest.lat > proj.geoBBox.top || map.getBounds()._northEast.lng < proj.geoBBox.left || map.getBounds()._northEast.lat < proj.geoBBox.bottom) {
          if (proj === this._currentProjectionSystems) {
            option = document.createElement("option");
            option.value = proj.code;
            option.text = proj.label || j;
            option.setAttribute("selected", "selected");
            option.setAttribute("disabled", "disabled");
            systemList.appendChild(option);
          }
          continue; // do not intersect
        }
      }
      option = document.createElement("option");
      option.value = proj.code;
      option.text = proj.label || j;
      if (proj === this._currentProjectionSystems) {
        option.setAttribute("selected", "selected");
      }
      systemList.appendChild(option);
    }
  },
  /**
   * this method is called by event 'change' on 'GPmousePositionProjectionUnits'
   * tag select (cf. this._createMousePositionSettingsElement),
   * and selects the units projection.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onMousePositionProjectionUnitsChange: function onMousePositionProjectionUnitsChange(e) {
    logger.log("onMousePositionProjectionUnitsChange", e);
    var idx = e.target.selectedIndex;
    var value = e.target.options[idx].value;
    var label = e.target.options[idx].label;
    logger.log(idx, value, label);
    var oldProjectionUnits = this._currentProjectionUnits;
    var newProjectionUnits = this._currentProjectionUnits = value;
    var newProjectionType = this._currentProjectionType;

    // Mise a jour des elements lebels et unites
    this._resetLabelElements(newProjectionType);
    this._resetUnitElements(newProjectionUnits);

    // mise a jour des inputs pour les coordonnees
    if (oldProjectionUnits === "DMS" || newProjectionUnits === "DMS") {
      this._resetCoordinateElements(this.options.editCoordinates, newProjectionType, newProjectionUnits);
      this._setEditMode(this._isEditing);
    }

    // on simule un deplacement en mode tactile pour mettre à jour les
    // resultats
    if (!this._isDesktop) {
      this.onMapMove();
    }
  },
  // ################################################################### //
  // ###### METHODES PUBLIQUES (INTERFACE AVEC LE CONTROLE) ############ //
  // ################################################################### //

  /**
   * This method is public.
   * It allows to control the execution of a movement.
   *
   * @param {Object} position - position = {lon: , lat: }
   * @param {Number} zoom - zoom
   * @param {Object} options - Zoom/pan options
   */
  moveTo: function moveTo(position, zoom, options) {
    if (!this._showContainer.checked) {
      this._pictoContainer.click();
    }
    var map = this._map;
    if (!map) {
      return;
    }
    this.onMouseMove({
      latlng: position
    });
    map.flyTo(position, zoom || 10, options || {});
  }
});
/* harmony default export */ __webpack_exports__["default"] = (MousePosition);

/***/ }),
/* 111 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
* @module MathUtils
* @alias Gp.MathUtils
* @description
* ...
*
* @example
* modulo();
* decimalToDMS();
* toInteger();
* isInteger();
* toFloat();
*/
var MathUtils = {
  /**
   * Reste de la division euclidienne
   * @function modulo
   * @param {Number} a - divisor
   * @param {Number} b - quotient
   * @returns {Number} Modulo
   */
  modulo: function modulo(a, b) {
    var r = a % b;
    return r * b < 0 ? r + b : r;
  },
  /**
   * Transform degrees, minutes, seconds form decimal degrees -
   * Largely inspired by the private function degreesToStringHDMS from ol/coordinate.js
   *
   * @function decimalToDMS
   * @param {Number} degrees - decimal degrees
   * @param {Array} hemispheres - "NS" ou "EO"
   * @param {Number} numDigits - number of digits for seconds
   * @returns {Object} DMS coordinate
   */
  decimalToDMS: function decimalToDMS(degrees, hemispheres, numDigits) {
    var normalizedDegrees = this.modulo(degrees + 180, 360) - 180;
    var x = Math.abs(3600 * normalizedDegrees);
    var dflPrecision = numDigits || 0;
    var precision = Math.pow(10, dflPrecision);
    var deg = Math.floor(x / 3600);
    var min = Math.floor((x - deg * 3600) / 60);
    var sec = x - deg * 3600 - min * 60;
    sec = Math.ceil(sec * precision) / precision;
    if (sec >= 60) {
      sec = 0;
      min += 1;
    }
    if (min >= 60) {
      min = 0;
      deg += 1;
    }
    var direction = hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);
    return {
      d: deg,
      m: min,
      s: sec,
      direction: direction
    };
  },
  /**
   * Converts string to Integer
   *
   * @function toInteger
   * @param {String} s - string number
   * @param {Numeric} base - between 2 and 36
   * @returns {null|Numeric} result
   */
  toInteger: function toInteger(s, base) {
    var _base = base || 10;
    var n = parseInt(s, _base);
    if (!isNaN(n) && isFinite(n)) {
      return n;
    }
    return null;
  },
  /**
   * check if s represents an integer
   *
   * @function isInteger
   * @param {String} s - string number
   * @returns {Boolean} is integer
   */
  isInteger: function isInteger(s) {
    if (isNaN(s)) {
      return false;
    }
    var v = parseFloat(s);
    return (v | 0) === v;
  },
  /**
   * Converts s to float
   *
   * @function toFloat
   * @param {String} s - string number
   * @returns {null|Numeric} result
   */
  toFloat: function toFloat(s) {
    var n = parseFloat(s);
    if (!isNaN(n) && isFinite(n)) {
      return n;
    }
    return null;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (MathUtils);

/***/ }),
/* 112 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
var MousePositionDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPmousePosition");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################### Methods of main container ##################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing
   *
   * @returns {DOMElement} DOM element
   */
  _createShowMousePositionElement: function _createShowMousePositionElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowMousePosition");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show mouse position control
   * @param {Boolean} isDesktop - specifies if the support is desktop or tactile
   *
   * @returns {DOMElement} DOM element
   */
  _createShowMousePositionPictoElement: function _createShowMousePositionPictoElement(isDesktop) {
    // contexte d'execution
    var self = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowMousePositionPicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowMousePosition");
    label.title = "Afficher les coordonnées du curseur";

    // FIXME detection disponible dans le JS !
    // Detection : test for desktop or tactile
    // var isDesktop = true;
    // var userAgent = window.navigator.userAgent.toLowerCase();
    // if (userAgent.indexOf("iphone") !== -1 ||
    // userAgent.indexOf("ipod") !== -1 ||
    // userAgent.indexOf("ipad") !== -1 ||
    // userAgent.indexOf("android") !== -1 ||
    // userAgent.indexOf("mobile") !== -1 ||
    // userAgent.indexOf("blackberry") !== -1 ||
    // userAgent.indexOf("tablet") !== -1 ||
    // userAgent.indexOf("phone") !== -1 ||
    // userAgent.indexOf("touch") !== -1 ) {
    //     isDesktop = false;
    // }
    // if (userAgent.indexOf("msie") !== -1 ||
    // userAgent.indexOf("trident") !== -1) {
    //     isDesktop = true;
    // }

    // Show map center localisation if panel opened and tactile support
    label.addEventListener("click", function (e) {
      var mapCenterClass = "";
      if (!document.getElementById(self._addUID("GPshowMousePosition")).checked && !isDesktop) {
        mapCenterClass = "GPmapCenterVisible";
      }
      document.getElementById("GPmapCenter").className = mapCenterClass;
      self.onShowMousePositionClick(e);
    });
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowMousePositionOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  /**
   * mouse position panel
   *
   * @returns {DOMElement} DOM element
   */
  _createMousePositionPanelElement: function _createMousePositionPanelElement() {
    var panel = document.createElement("div");
    panel.id = this._addUID("GPmousePositionPanel");
    panel.className = "GPpanel";

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // div.appendChild(this._createMousePositionPanelHeaderElement());
    // div.appendChild(this._createMousePositionPanelBasicElement());
    // div.appendChild(this._createShowMousePositionSettingsElement());
    // div.appendChild(this._createMousePositionSettingsElement());

    return panel;
  },
  /**
   * Map center localisation (tactile use)
   *
   * @returns {DOMElement} container
   */
  _createMapCenter: function _createMapCenter() {
    var div = document.createElement("div");
    div.id = "GPmapCenter";
    div.className = "";
    return div;
  },
  // ################################################################### //
  // ####################### Panel container ########################### //
  // ################################################################### //

  /**
   * @returns {DOMElement} container
   */
  _createMousePositionPanelHeaderElement: function _createMousePositionPanelHeaderElement() {
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var divTitle = document.createElement("div");
    divTitle.className = "GPpanelTitle";
    divTitle.innerHTML = "Coordonnées";
    container.appendChild(divTitle);
    var divClose = document.createElement("div");
    divClose.id = "GPmousePositionPanelClose";
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer le panneau";

    // Link panel close / visibility checkbox
    var self = this;
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPshowMousePositionPicto")).click();
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPshowMousePositionPicto")).click();
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * coordinate panel
   * @param {Boolean} [displayAltitude] - specifies if the altitude panel must be displayed
   * @param {Boolean} [displayCoordinates] - specifies if the coordinates panel must be displayed
   * @param {Boolean} [editCoordinates] - specifies if the coordinates edition is allowed
   * @param {Boolean} [currentProjectionUnits] - specifies if the current projection units
   *
   * FIXME
   * call this._createMousePositionPanelBasicCoordinateElement
   * call this._createMousePositionPanelBasicAltitudeElement
   *
   * @returns {DOMElement} DOM element
   */
  _createMousePositionPanelBasicElement: function _createMousePositionPanelBasicElement(displayAltitude, displayCoordinates, editCoordinates, currentProjectionUnits) {
    // default Values
    displayAltitude = typeof displayAltitude === "undefined" ? true : displayAltitude;
    displayCoordinates = typeof displayCoordinates === "undefined" ? true : displayCoordinates;
    editCoordinates = typeof editCoordinates === "undefined" ? false : editCoordinates;
    var container = document.createElement("div");
    container.id = this._addUID("GPmousePositionBasicPanel");

    // FIXME on devrait decomposer la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    container.appendChild(this._createMousePositionPanelBasicCoordinateElement(displayCoordinates, editCoordinates, currentProjectionUnits));
    container.appendChild(this._createMousePositionPanelEditToolsElement(editCoordinates));
    container.appendChild(this._createMousePositionPanelBasicAltitudeElement(displayAltitude));
    return container;
  },
  /**
   * create coordinate elements
   *
   * @param {String} coordType - ("Lon" ou "Lat")
   * @param {Boolean} [editCoordinates=false] - specifies if the coordinates edition is allowed
   *
   * @returns {Array} list of DOM elements
   */
  _createCoordinateElement: function _createCoordinateElement(coordType, editCoordinates) {
    var context = this;
    if (["Lon", "Lat"].indexOf(coordType) === -1) {
      return [];
    }
    var list = [];
    var input = document.createElement("input");
    input.id = this._addUID("GPmousePosition" + coordType);
    input.title = editCoordinates === true ? "Cliquer pour saisir des coordonnées" : "";
    input.readOnly = true;
    if (editCoordinates) {
      input.addEventListener("click", function () {
        context.onMousePositionEditModeClick(true);
      });
      input.addEventListener("change", function (e) {
        this.classList.remove("error");
        var valid = context.validateExtentCoordinate(coordType, this.value, e);
        valid ? this.classList.remove("error") : this.classList.add("error");
      });
    }
    list.push(input);
    var span = document.createElement("span");
    span.className = "GPmousePositionUnits";
    list.push(span);
    return list;
  },
  /**
   *
   * @param {String} coordType - ("Lon" ou "Lat")
   * @param {Boolean} [editCoordinates=false] - specifies if the coordinates edition is allowed
   *
   * @returns {Array} list of DOM elements
   */
  _createDMSCoordinateElement: function _createDMSCoordinateElement(coordType, editCoordinates) {
    if (["Lon", "Lat"].indexOf(coordType) === -1) {
      return [];
    }
    var context = this;
    var list = [];
    var input = document.createElement("input");
    input.id = this._addUID("GPmousePosition" + coordType + "Degrees");
    input.className = "GPSexagesimal";
    input.setAttribute("name", "degrees");
    input.title = editCoordinates === true ? "Cliquer pour saisir des coordonnées" : "";
    input.readOnly = true;
    input.dataset.min = 0;
    input.dataset.max = coordType === "Lon" ? 180 : 90;
    if (editCoordinates) {
      input.addEventListener("click", function () {
        context.onMousePositionEditModeClick(true);
      });
      input.addEventListener("change", function () {
        this.classList.remove("error");
        var valid = context._checkDMSDegrees(coordType, this);
        valid ? this.classList.remove("error") : this.classList.add("error");
      });
    }
    list.push(input);
    var span = document.createElement("span");
    span.className = "GPmousePositionSexagesimalLabel";
    span.innerHTML = "°";
    list.push(span);
    var input1 = document.createElement("input");
    input1.id = this._addUID("GPmousePosition" + coordType + "Minutes");
    input1.className = "GPSexagesimal";
    input1.setAttribute("name", "minutes");
    input1.title = editCoordinates === true ? "Cliquer pour saisir des coordonnées" : "";
    input1.readOnly = true;
    input1.dataset.min = 0;
    input1.dataset.max = 59;
    if (editCoordinates) {
      input1.addEventListener("click", function () {
        context.onMousePositionEditModeClick(true);
      });
      input1.addEventListener("change", function () {
        this.classList.remove("error");
        var valid = context._checkDMSElement(this);
        valid ? this.classList.remove("error") : this.classList.add("error");
      });
    }
    list.push(input1);
    var span1 = document.createElement("span");
    span1.className = "GPmousePositionSexagesimalLabel";
    span1.innerHTML = "'";
    list.push(span1);
    var input2 = document.createElement("input");
    input2.id = this._addUID("GPmousePosition" + coordType + "Seconds");
    input2.className = "GPSexagesimalsec";
    input2.setAttribute("name", "seconds");
    input2.title = editCoordinates === true ? "Cliquer pour saisir des coordonnées" : "";
    input2.readOnly = true;
    input2.dataset.min = 0;
    input2.dataset.max = 59;
    if (editCoordinates) {
      input2.addEventListener("click", function () {
        context.onMousePositionEditModeClick(true);
      });
      input2.addEventListener("change", function () {
        this.classList.remove("error");
        var valid = context._checkDMSElement(this, true);
        valid ? this.classList.remove("error") : this.classList.add("error");
      });
    }
    list.push(input2);
    var span2 = document.createElement("span");
    span2.className = "GPmousePositionSexagesimalLabel";
    span2.innerHTML = "''";
    list.push(span2);
    var select = document.createElement("select");
    select.id = this._addUID("GPmousePosition" + coordType + "Direction");
    select.className = "GPmousePositionDirection";
    select.setAttribute("name", "direction");
    select.disabled = true;
    var option = document.createElement("option");
    option.value = coordType === "Lon" ? "E" : "N";
    option.innerHTML = coordType === "Lon" ? "E" : "N";
    select.appendChild(option);
    var option1 = document.createElement("option");
    option1.value = coordType === "Lon" ? "O" : "S";
    option1.innerHTML = coordType === "Lon" ? "O" : "S";
    select.appendChild(option1);
    list.push(select);
    return list;
  },
  /**
   * @param {Boolean} [display=false] - specifies if the coordinates panel must be displayed
   * @param {Boolean} [editCoordinates] - specifies if the coordinates edition is allowed
   * @param {Boolean} [currentProjectionUnits] - specifies if the current projection units
   *
   * @returns {DOMElement} container
   */
  _createMousePositionPanelBasicCoordinateElement: function _createMousePositionPanelBasicCoordinateElement(display, editCoordinates, currentProjectionUnits) {
    var div = document.createElement("div");
    div.id = this._addUID("GPmousePositionCoordinate");
    div.style.display = display ? "block" : "none";

    // latitude
    var divLat = document.createElement("div");
    var spanLat = document.createElement("span");
    spanLat.className = "GPmousePositionLabel";
    spanLat.id = this._addUID("GPmousePositionLatLabel");
    spanLat.innerHTML = "Latitude : ";
    divLat.appendChild(spanLat);
    var span = document.createElement("span");
    span.id = this._addUID("GPmousePositionLatCoordinate");
    var arrayCoords;
    if (currentProjectionUnits === "DMS") {
      arrayCoords = this._createDMSCoordinateElement("Lat", editCoordinates);
    } else {
      arrayCoords = this._createCoordinateElement("Lat", editCoordinates);
    }
    for (var i = 0; i < arrayCoords.length; i++) {
      span.appendChild(arrayCoords[i]);
    }
    divLat.appendChild(span);
    div.appendChild(divLat);

    // longitude
    var divLon = document.createElement("div");
    var spanLon = document.createElement("span");
    spanLon.className = "GPmousePositionLabel";
    spanLon.id = this._addUID("GPmousePositionLonLabel");
    spanLon.innerHTML = "Longitude : ";
    divLon.appendChild(spanLon);
    var span1 = document.createElement("span");
    span1.id = this._addUID("GPmousePositionLonCoordinate");
    var arrayCoords1;
    if (currentProjectionUnits === "DMS") {
      arrayCoords1 = this._createDMSCoordinateElement("Lon", editCoordinates);
    } else {
      arrayCoords1 = this._createCoordinateElement("Lon", editCoordinates);
    }
    for (var j = 0; j < arrayCoords1.length; j++) {
      span1.appendChild(arrayCoords1[j]);
    }
    divLon.appendChild(span1);
    div.appendChild(divLon);
    return div;
  },
  /**
   * @param {Boolean} [display=false] - specifies if the altitude panel must be displayed
   *
   * @returns {DOMElement} container
   */
  _createMousePositionPanelBasicAltitudeElement: function _createMousePositionPanelBasicAltitudeElement(display) {
    var div = document.createElement("div");
    div.id = this._addUID("GPmousePositionAltitude");
    div.style.display = display ? "block" : "none";
    var spanLabel = document.createElement("span");
    spanLabel.className = "GPmousePositionLabel";
    spanLabel.innerHTML = "Altitude : ";
    div.appendChild(spanLabel);
    var spanAlt = document.createElement("span");
    spanAlt.className = "GPmousePositionCoords";
    spanAlt.id = this._addUID("GPmousePositionAlt");
    spanAlt.innerHTML = "...";
    div.appendChild(spanAlt);
    var spanUnits = document.createElement("span");
    spanUnits.className = "GPmousePositionAltitudeUnits";
    spanUnits.innerHTML = "m";
    div.appendChild(spanUnits);
    return div;
  },
  /**
   * @param {Boolean} [editCoordinates=false] - specifies if the coordinates edition is allowed
   *
   * @returns {DOMElement} container
   */
  _createMousePositionPanelEditToolsElement: function _createMousePositionPanelEditToolsElement(editCoordinates) {
    var context = this;
    var div = document.createElement("div");
    div.className = "GPmousePositionPanelEditTools";
    div.id = this._addUID("GPmousePositionPanelEditTools");
    if (!editCoordinates) {
      div.style.display = "none";
    }
    var span1 = document.createElement("span");
    span1.className = "GPmousePositionEditTool";
    span1.id = this._addUID("GPmousePositionLocate");
    span1.title = editCoordinates === true ? "Cliquer pour saisir des coordonnées" : "";
    if (editCoordinates) {
      span1.addEventListener("click", function () {
        context.onMousePositionEditModeLocateClick();
      });
    }
    div.appendChild(span1);
    var span2 = document.createElement("span");
    span2.className = "GPmousePositionEditTool";
    span2.id = this._addUID("GPmousePositionCloseEdit");
    span2.title = "Quitter la saisie des coordonnées";
    span2.style.display = "none";
    if (editCoordinates) {
      span2.addEventListener("click", function () {
        context.onMousePositionEditModeClick(false);
      });
    }
    div.appendChild(span2);
    return div;
  },
  // ################################################################### //
  // #################### Settings container ########################### //
  // ################################################################### //

  /**
   * @param {Boolean} [display=false] - specifies if the settings panel must be displayed
   *
   * @returns {DOMElement[]} array containing input and label elements
   */
  _createShowMousePositionSettingsElement: function _createShowMousePositionSettingsElement(display) {
    var list = [];
    var context = this;
    var input = document.createElement("input");
    input.type = "checkbox";
    input.id = this._addUID("GPshowMousePositionSettings");
    var label = document.createElement("label");
    label.id = this._addUID("GPshowMousePositionSettingsPicto");
    label.htmlFor = this._addUID("GPshowMousePositionSettings");
    label.title = "Réglages";
    label.className = "GPshowMoreOptionsImage GPshowMoreOptions GPshowMousePositionSettingsPicto"; // FIXME classname and id ?
    label.style.display = display ? "block" : "none";
    if (label.addEventListener) {
      label.addEventListener("click", function (e) {
        if (typeof context.onShowMousePositionSettingsClick === "function") {
          context.onShowMousePositionSettingsClick(e);
        }
      }, false);
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function (e) {
        if (typeof context.onShowMousePositionSettingsClick === "function") {
          context.onShowMousePositionSettingsClick(e);
        }
      });
    }
    list.push(input);
    list.push(label);
    return list;
  },
  /**
   * settings panel
   * @param {Boolean} [display=true] - specifies if the settings panel must be displayed
   *
   * FIXME
   * don't call this._createMousePositionSettingsSystemsElement
   * don't call this._createMousePositionSettingsUnitsElement
   *
   * @returns {DOMElement} DOM element
   */
  _createMousePositionSettingsElement: function _createMousePositionSettingsElement(display) {
    var container = document.createElement("div");
    container.id = this._addUID("GPmousePositionSettings");
    container.style.display = display === undefined || display ? "block" : "none";
    var span = document.createElement("span");
    span.className = "GPmousePositionSettingsLabel";
    span.innerHTML = "Système de référence";
    container.appendChild(span);

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // FIXME tableau statique !
    // var systems = [
    //     {
    //         code : "GEOGRAPHIC",
    //         label : "Géographique"
    //     },
    //     {
    //         code : "MERCATOR",
    //         label : "Mercator"
    //     },
    //     {
    //         code : "LAMB93",
    //         label : "Lambert 93"
    //     },
    //     {
    //         code : "LAMB2E",
    //         label : "Lambert II étendu"
    //     }
    // ];
    //
    // var selectSystem = this._createMousePositionSettingsSystemsElement(systems);
    //
    // container.appendChild(selectSystem);

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // FIXME tableau statique !
    // var units = [
    //     {
    //         code : "DEC",
    //         label : "degrés décimaux",
    //     },
    //     {
    //         code : "DMS",
    //         label : "degrés sexagésimaux",
    //     },
    //     {
    //         code : "RAD",
    //         label : "radians",
    //     },
    //     {
    //         code : "GON",
    //         label : "grades"
    //     }
    // ];
    //
    // var selectUnits = this._createMousePositionSettingsUnitsElement(units);
    //
    // container.appendChild(selectUnits);

    return container;
  },
  /**
   * @param {Object[]} systems - list of systems
   *
   * @returns {DOMElement} DOM element select
   */
  _createMousePositionSettingsSystemsElement: function _createMousePositionSettingsSystemsElement(systems) {
    // contexte d'execution
    var context = this;
    var selectSystem = document.createElement("select");
    selectSystem.id = this._addUID("GPmousePositionProjectionSystem");
    selectSystem.className = "GPinputSelect GPmousePositionSettingsSelect";
    selectSystem.addEventListener("change", function (e) {
      context.onMousePositionProjectionSystemChange(e);
    });
    selectSystem.addEventListener("mouseover", function (e) {
      // FIXME mettre une condition si target === option
      if (e.target.nodeName !== "OPTION") {
        context.onMousePositionProjectionSystemMouseOver(e);
      }
    });
    for (var i = 0; i < systems.length; i++) {
      var obj = systems[i];
      var option = document.createElement("option");
      option.value = obj.code;
      option.text = obj.label || i;
      // option.label = obj.label;
      selectSystem.appendChild(option);
    }
    return selectSystem;
  },
  /**
   * @param {Object[]} units - list of units
   *
   * @returns {DOMElement} DOM element select
   */
  _createMousePositionSettingsUnitsElement: function _createMousePositionSettingsUnitsElement(units) {
    // contexte d'execution
    var context = this;
    var selectUnits = document.createElement("select");
    selectUnits.id = this._addUID("GPmousePositionProjectionUnits");
    selectUnits.className = "GPinputSelect GPmousePositionSettingsSelect";
    selectUnits.addEventListener("change", function (e) {
      context.onMousePositionProjectionUnitsChange(e);
    });
    for (var j = 0; j < units.length; j++) {
      var obj = units[j];
      var option = document.createElement("option");
      option.value = obj.code ? obj.code : j;
      option.text = obj.label || j;
      // option.label = obj.label;
      selectUnits.appendChild(option);
    }
    return selectUnits;
  },
  /**
   * @param {String} [currentProjectionType="Metric"] - "Geographical" or "Metric"
   */
  _resetLabelElements: function _resetLabelElements(currentProjectionType) {
    // Changement des labels dans le formulaire de saisie
    var spanLat = document.getElementById(this._addUID("GPmousePositionLatLabel"));
    spanLat.innerHTML = currentProjectionType === "Geographical" ? "Latitude :" : "X :";
    var spanLon = document.getElementById(this._addUID("GPmousePositionLonLabel"));
    spanLon.innerHTML = currentProjectionType === "Geographical" ? "Longitude :" : "Y :";
  },
  /**
   * @param {String} currentProjectionUnits - projection units
   */
  _resetUnitElements: function _resetUnitElements(currentProjectionUnits) {
    var value = "";
    if (currentProjectionUnits === "M" || currentProjectionUnits === "KM") {
      value = currentProjectionUnits.toLowerCase();
    }
    var elts = document.getElementsByClassName("GPmousePositionUnits");
    for (var e = 0; e < elts.length; e++) {
      elts[e].innerHTML = value;
    }
  },
  /**
   * @param {Boolean} editCoordinates - edit coordinates option
   * @param {String} currentProjectionType - current projection type
   * @param {String} currentProjectionUnits - current projection unit
   */
  _resetCoordinateElements: function _resetCoordinateElements(editCoordinates, currentProjectionType, currentProjectionUnits) {
    // Suppression de tous les enfants de GPmousePositionLatCoordinate
    var latElt = document.getElementById(this._addUID("GPmousePositionLatCoordinate"));
    while (latElt.firstChild) {
      latElt.removeChild(latElt.firstChild);
    }
    var arrayCoords;
    if (currentProjectionUnits === "DMS") {
      arrayCoords = this._createDMSCoordinateElement("Lat", editCoordinates);
    } else {
      arrayCoords = this._createCoordinateElement("Lat", editCoordinates);
    }
    for (var i = 0; i < arrayCoords.length; i++) {
      latElt.appendChild(arrayCoords[i]);
    }

    // Suppression de tous les enfants de GPmousePositionLonCoordinate
    var lonElt = document.getElementById(this._addUID("GPmousePositionLonCoordinate"));
    while (lonElt.firstChild) {
      lonElt.removeChild(lonElt.firstChild);
    }
    var arrayCoords1;
    if (currentProjectionUnits === "DMS") {
      arrayCoords1 = this._createDMSCoordinateElement("Lon", editCoordinates);
    } else {
      arrayCoords1 = this._createCoordinateElement("Lon", editCoordinates);
    }
    for (var j = 0; j < arrayCoords1.length; j++) {
      lonElt.appendChild(arrayCoords1[j]);
    }

    // FIXME on simule un deplacement ?
    // this.onMapMove();
  },
  /**
   * Set/unset editing mode
   *
   * @param {Boolean} editing - active edit coordinates mode
   */
  _setEditMode: function _setEditMode(editing) {
    var locateElt = document.getElementById(this._addUID("GPmousePositionLocate"));
    locateElt.title = editing ? "Aller à la position ..." : "Cliquer pour saisir des coordonnées";
    var closeEditElt = document.getElementById(this._addUID("GPmousePositionCloseEdit"));
    closeEditElt.style.display = editing ? "inline-block" : "none";
    var selector = "div[id^=" + this._addUID("GPmousePositionCoordinate") + "]";
    var inputs = document.querySelectorAll(selector + " input");
    for (var i = 0; i < inputs.length; i++) {
      inputs[i].readOnly = !editing;
      if (editing) {
        inputs[i].value = "";
        inputs[i].classList.remove("error");
      }
    }
    var selects = document.querySelectorAll(selector + " select");
    for (var j = 0; j < selects.length; j++) {
      selects[j].disabled = !editing;
    }
  },
  /**
   *
   * @param {DOMElement} input - input element
   * @param {Boolean} isFloat - check for float value
   *
   * @returns {Boolean} true if input value is within bounds
   */
  _checkDMSElement: function _checkDMSElement(input, isFloat) {
    var b = isFloat !== undefined;
    var value = input.value;
    if (b) {
      value = value.replace(",", ".");
    }
    if (isNaN(value)) {
      return false;
    }
    var v = parseFloat(value);
    if (!b && (v | 0) !== v) {
      // is it an integer
      return false;
    }
    var min = Number(input.dataset.min);
    var max = Number(input.dataset.max);
    return v >= min && v <= max;
  },
  /**
   * @param {String} coordType - "Lon" or "Lat"
   * @param {DOMElement} input - input element
   *
   * @returns {Boolean} true if input value is within bounds
   */
  _checkDMSDegrees: function _checkDMSDegrees(coordType, input) {
    if (isNaN(input.value)) {
      return false;
    }
    var v = parseFloat(input.value);
    if ((v | 0) !== v) {
      // is it an integer
      return false;
    }
    var min = Number(input.dataset.min);
    var max = Number(input.dataset.max);
    if (v < min || v > max) {
      return false;
    }
    var inputMinutes = document.getElementById(this._addUID("GPmousePosition" + coordType + "Minutes"));
    var inputSeconds = document.getElementById(this._addUID("GPmousePosition" + coordType + "Seconds"));
    if (v >= max) {
      inputMinutes.dataset.max = 0;
      inputSeconds.dataset.max = 0;
    } else {
      inputMinutes.dataset.max = 59;
      inputSeconds.dataset.max = 59.9999;
    }
    return true;
  },
  // ################################################################### //
  // ####################### handlers Event ############################ //
  // ################################################################### //

  /**
   * Function displaying coordinates from cursor position (desktop)
   * or map center (tactile)
   * @param {Object} coordinate - coordinates
   */
  GPdisplayCoords: function GPdisplayCoords(coordinate) {
    // Compute coords in case of cursor position (desktop)
    if (coordinate) {
      var labelLon = document.getElementById(this._addUID("GPmousePositionLonLabel"));
      var labelLat = document.getElementById(this._addUID("GPmousePositionLatLabel"));
      if (coordinate.x || coordinate.y) {
        labelLat.innerHTML = "X : ";
        labelLon.innerHTML = "Y : ";
      } else if (coordinate.e || coordinate.n) {
        labelLat.innerHTML = "E : ";
        labelLon.innerHTML = "N : ";
      } else {
        labelLat.innerHTML = "Latitude : ";
        labelLon.innerHTML = "Longitude : ";
      }
      if (_typeof(coordinate.lat) === "object" && _typeof(coordinate.lng) === "object") {
        var parts = {
          lng: "Lon",
          lat: "Lat"
        };
        var units = ["Degrees", "Minutes", "Seconds"];
        for (var p in parts) {
          for (var u = 0; u < units.length; ++u) {
            var selector = "GPmousePosition" + parts[p] + units[u];
            var elt = document.getElementById(this._addUID(selector));
            var key = units[u].charAt(0).toLowerCase();
            elt.value = coordinate[p][key];
          }
        }
        // directions
        document.getElementById(this._addUID("GPmousePositionLonDirection")).value = coordinate.lng.direction;
        document.getElementById(this._addUID("GPmousePositionLatDirection")).value = coordinate.lat.direction;
      } else {
        var elLat = document.getElementById(this._addUID("GPmousePositionLat"));
        var elLon = document.getElementById(this._addUID("GPmousePositionLon"));
        elLat.value = coordinate.x || coordinate.lat || coordinate.e || "0";
        elLon.value = coordinate.y || coordinate.lng || coordinate.lon || coordinate.n || "0";

        // les unites
        var unit = coordinate.unit === undefined ? "" : coordinate.unit;
        var elements = document.getElementsByClassName("GPmousePositionUnits");
        for (var n = 0; n < elements.length; ++n) {
          elements[n].innerHTML = unit;
        }
      }
    }
  },
  /**
   * Function displaying altitude from cursor position (desktop)
   * or map center (tactile)
   * @param {Object} coordinate - coordinates
   * @param {Number} altitudeTimeoutDelay - when the mouse stop moving, delay before the altitude request is launched
   * @param {Number} noDataValue - the no data value
   * @param {Number} noDataValueTolerance - the no data value tolerance
   */
  GPdisplayElevation: function GPdisplayElevation(coordinate, altitudeTimeoutDelay, noDataValue, noDataValueTolerance) {
    // contexte d'execution
    var self = this;

    // Latency for altitude request
    var altitudeTimeout;
    if (!altitudeTimeoutDelay) {
      altitudeTimeoutDelay = 500;
    }
    clearTimeout(altitudeTimeout);
    document.getElementById(this._addUID("GPmousePositionAlt")).innerHTML = "...";
    if (noDataValue == null) {
      noDataValue = -99999;
    }
    if (noDataValueTolerance == null) {
      noDataValueTolerance = 99980;
    }
    var maxThreshold = noDataValue + noDataValueTolerance;
    var minThreshold = noDataValue - noDataValueTolerance;

    // Compute coords in case of cursor position (desktop)
    if (coordinate) {
      // If no altitude panel, don't call altitude request
      if (document.getElementById(this._addUID("GPmousePositionAltitude"))) {
        altitudeTimeout = setTimeout(function () {
          self.onRequestAltitude(coordinate, function (z) {
            if (minThreshold < z && z < maxThreshold) {
              self.GPresetElevation();
            } else {
              document.getElementById(self._addUID("GPmousePositionAlt")).innerHTML = z;
            }
          });
        }, altitudeTimeoutDelay);
      }
    }
  },
  /**
   * Function reseting altitude value
   */
  GPresetElevation: function GPresetElevation() {
    if (document.getElementById(this._addUID("GPmousePositionAltitude"))) {
      document.getElementById(this._addUID("GPmousePositionAlt")).innerHTML = "---";
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (MousePositionDOM);

/***/ }),
/* 113 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var proj4__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(114);
/* harmony import */ var proj4__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(proj4__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var proj4leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(116);
/* harmony import */ var proj4leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(proj4leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(117);
/* harmony import */ var _EPSG2154__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(118);
/* harmony import */ var _EPSG27572__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(120);
/* harmony import */ var _EPSG4326__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(121);







/** autoload function */
(function () {
  // load all defs into proj4
  _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__["default"].load(proj4__WEBPACK_IMPORTED_MODULE_0___default.a);
})();

/**
 * CRS (Coordinate Reference Systems) Factory to create <a href="http://kartena.github.io/Proj4Leaflet/api/#l-proj-crs" target="_blank">L.Proj.CRS</a> instances.
 *
 * @module CRS
 * @alias L.geoportalCRS
 * @abstract
 * @example
 *  var map = L.Map('divmap', {
 *    crs : L.geoportalCRS.EPSG2154
 *  }).setView();
 *
 *  var lyr = L.geoportalLayer.WMTS(
 *    {
 *      layer : "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO.L93"
 *    },
 *    {
 *      opacity : 1,
 *      transparent : true,
 *      minZoom : 1,
 *      maxZoom : 21
 *      ...
 *    });
 *
 *  lyr.addTo(map); // ou map.addLayer(lyr);
 */
/** @type {L.geoportalCRS} */
var CRS = {
  /**
   * Lambert 93 ("EPSG:2154") CRS definition to be used with Leaflet.
   *
   * @method EPSG2154
   * @static
   * @alias L.geoportalCRS.EPSG2154
   * @returns {EPSG2154} epsg code
   */
  EPSG2154: function EPSG2154() {
    return _EPSG2154__WEBPACK_IMPORTED_MODULE_3__["default"].build();
  },
  /**
   * CRS : Lambert 2 extened
   *
   * @method EPSG27572
   * @static
   * @alias L.geoportalCRS.EPSG27572
   * @returns {EPSG27572} epsg code
   */
  EPSG27572: function EPSG27572() {
    return _EPSG27572__WEBPACK_IMPORTED_MODULE_4__["default"].build();
  },
  /**
   * CRS : EPSG4326
   *
   * @ignore
   * @method EPSG4326
   * @static
   * @alias L.geoportalCRS.EPSG4326
   * @returns {EPSG4326} epsg code
   */
  EPSG4326: function EPSG4326() {
    return _EPSG4326__WEBPACK_IMPORTED_MODULE_5__["default"].build();
  }
};
/* harmony default export */ __webpack_exports__["default"] = (CRS);

/***/ }),
/* 114 */
/***/ (function(module, exports, __webpack_require__) {

/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["proj4"] = __webpack_require__(115);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(52)))

/***/ }),
/* 115 */
/***/ (function(module, exports, __webpack_require__) {

(function (global, factory) {
     true ? module.exports = factory() :
    undefined;
}(this, (function () { 'use strict';

    var globals = function(defs) {
      defs('EPSG:4326', "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees");
      defs('EPSG:4269', "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees");
      defs('EPSG:3857', "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs");

      defs.WGS84 = defs['EPSG:4326'];
      defs['EPSG:3785'] = defs['EPSG:3857']; // maintain backward compat, official code is 3857
      defs.GOOGLE = defs['EPSG:3857'];
      defs['EPSG:900913'] = defs['EPSG:3857'];
      defs['EPSG:102113'] = defs['EPSG:3857'];
    };

    var PJD_3PARAM = 1;
    var PJD_7PARAM = 2;
    var PJD_GRIDSHIFT = 3;
    var PJD_WGS84 = 4; // WGS84 or equivalent
    var PJD_NODATUM = 5; // WGS84 or equivalent
    var SRS_WGS84_SEMIMAJOR = 6378137.0;  // only used in grid shift transforms
    var SRS_WGS84_SEMIMINOR = 6356752.314;  // only used in grid shift transforms
    var SRS_WGS84_ESQUARED = 0.0066943799901413165; // only used in grid shift transforms
    var SEC_TO_RAD = 4.84813681109535993589914102357e-6;
    var HALF_PI = Math.PI/2;
    // ellipoid pj_set_ell.c
    var SIXTH = 0.1666666666666666667;
    /* 1/6 */
    var RA4 = 0.04722222222222222222;
    /* 17/360 */
    var RA6 = 0.02215608465608465608;
    var EPSLN = 1.0e-10;
    // you'd think you could use Number.EPSILON above but that makes
    // Mollweide get into an infinate loop.

    var D2R = 0.01745329251994329577;
    var R2D = 57.29577951308232088;
    var FORTPI = Math.PI/4;
    var TWO_PI = Math.PI * 2;
    // SPI is slightly greater than Math.PI, so values that exceed the -180..180
    // degree range by a tiny amount don't get wrapped. This prevents points that
    // have drifted from their original location along the 180th meridian (due to
    // floating point error) from changing their sign.
    var SPI = 3.14159265359;

    var exports$1 = {};
    exports$1.greenwich = 0.0; //"0dE",
    exports$1.lisbon = -9.131906111111; //"9d07'54.862\"W",
    exports$1.paris = 2.337229166667; //"2d20'14.025\"E",
    exports$1.bogota = -74.080916666667; //"74d04'51.3\"W",
    exports$1.madrid = -3.687938888889; //"3d41'16.58\"W",
    exports$1.rome = 12.452333333333; //"12d27'8.4\"E",
    exports$1.bern = 7.439583333333; //"7d26'22.5\"E",
    exports$1.jakarta = 106.807719444444; //"106d48'27.79\"E",
    exports$1.ferro = -17.666666666667; //"17d40'W",
    exports$1.brussels = 4.367975; //"4d22'4.71\"E",
    exports$1.stockholm = 18.058277777778; //"18d3'29.8\"E",
    exports$1.athens = 23.7163375; //"23d42'58.815\"E",
    exports$1.oslo = 10.722916666667; //"10d43'22.5\"E"

    var units = {
      ft: {to_meter: 0.3048},
      'us-ft': {to_meter: 1200 / 3937}
    };

    var ignoredChar = /[\s_\-\/\(\)]/g;
    function match(obj, key) {
      if (obj[key]) {
        return obj[key];
      }
      var keys = Object.keys(obj);
      var lkey = key.toLowerCase().replace(ignoredChar, '');
      var i = -1;
      var testkey, processedKey;
      while (++i < keys.length) {
        testkey = keys[i];
        processedKey = testkey.toLowerCase().replace(ignoredChar, '');
        if (processedKey === lkey) {
          return obj[testkey];
        }
      }
    }

    var parseProj = function(defData) {
      var self = {};
      var paramObj = defData.split('+').map(function(v) {
        return v.trim();
      }).filter(function(a) {
        return a;
      }).reduce(function(p, a) {
        var split = a.split('=');
        split.push(true);
        p[split[0].toLowerCase()] = split[1];
        return p;
      }, {});
      var paramName, paramVal, paramOutname;
      var params = {
        proj: 'projName',
        datum: 'datumCode',
        rf: function(v) {
          self.rf = parseFloat(v);
        },
        lat_0: function(v) {
          self.lat0 = v * D2R;
        },
        lat_1: function(v) {
          self.lat1 = v * D2R;
        },
        lat_2: function(v) {
          self.lat2 = v * D2R;
        },
        lat_ts: function(v) {
          self.lat_ts = v * D2R;
        },
        lon_0: function(v) {
          self.long0 = v * D2R;
        },
        lon_1: function(v) {
          self.long1 = v * D2R;
        },
        lon_2: function(v) {
          self.long2 = v * D2R;
        },
        alpha: function(v) {
          self.alpha = parseFloat(v) * D2R;
        },
        gamma: function(v) {
          self.rectified_grid_angle = parseFloat(v);
        },
        lonc: function(v) {
          self.longc = v * D2R;
        },
        x_0: function(v) {
          self.x0 = parseFloat(v);
        },
        y_0: function(v) {
          self.y0 = parseFloat(v);
        },
        k_0: function(v) {
          self.k0 = parseFloat(v);
        },
        k: function(v) {
          self.k0 = parseFloat(v);
        },
        a: function(v) {
          self.a = parseFloat(v);
        },
        b: function(v) {
          self.b = parseFloat(v);
        },
        r_a: function() {
          self.R_A = true;
        },
        zone: function(v) {
          self.zone = parseInt(v, 10);
        },
        south: function() {
          self.utmSouth = true;
        },
        towgs84: function(v) {
          self.datum_params = v.split(",").map(function(a) {
            return parseFloat(a);
          });
        },
        to_meter: function(v) {
          self.to_meter = parseFloat(v);
        },
        units: function(v) {
          self.units = v;
          var unit = match(units, v);
          if (unit) {
            self.to_meter = unit.to_meter;
          }
        },
        from_greenwich: function(v) {
          self.from_greenwich = v * D2R;
        },
        pm: function(v) {
          var pm = match(exports$1, v);
          self.from_greenwich = (pm ? pm : parseFloat(v)) * D2R;
        },
        nadgrids: function(v) {
          if (v === '@null') {
            self.datumCode = 'none';
          }
          else {
            self.nadgrids = v;
          }
        },
        axis: function(v) {
          var legalAxis = "ewnsud";
          if (v.length === 3 && legalAxis.indexOf(v.substr(0, 1)) !== -1 && legalAxis.indexOf(v.substr(1, 1)) !== -1 && legalAxis.indexOf(v.substr(2, 1)) !== -1) {
            self.axis = v;
          }
        },
        approx: function() {
          self.approx = true;
        }
      };
      for (paramName in paramObj) {
        paramVal = paramObj[paramName];
        if (paramName in params) {
          paramOutname = params[paramName];
          if (typeof paramOutname === 'function') {
            paramOutname(paramVal);
          }
          else {
            self[paramOutname] = paramVal;
          }
        }
        else {
          self[paramName] = paramVal;
        }
      }
      if(typeof self.datumCode === 'string' && self.datumCode !== "WGS84"){
        self.datumCode = self.datumCode.toLowerCase();
      }
      return self;
    };

    var NEUTRAL = 1;
    var KEYWORD = 2;
    var NUMBER = 3;
    var QUOTED = 4;
    var AFTERQUOTE = 5;
    var ENDED = -1;
    var whitespace = /\s/;
    var latin = /[A-Za-z]/;
    var keyword = /[A-Za-z84]/;
    var endThings = /[,\]]/;
    var digets = /[\d\.E\-\+]/;
    // const ignoredChar = /[\s_\-\/\(\)]/g;
    function Parser(text) {
      if (typeof text !== 'string') {
        throw new Error('not a string');
      }
      this.text = text.trim();
      this.level = 0;
      this.place = 0;
      this.root = null;
      this.stack = [];
      this.currentObject = null;
      this.state = NEUTRAL;
    }
    Parser.prototype.readCharicter = function() {
      var char = this.text[this.place++];
      if (this.state !== QUOTED) {
        while (whitespace.test(char)) {
          if (this.place >= this.text.length) {
            return;
          }
          char = this.text[this.place++];
        }
      }
      switch (this.state) {
        case NEUTRAL:
          return this.neutral(char);
        case KEYWORD:
          return this.keyword(char)
        case QUOTED:
          return this.quoted(char);
        case AFTERQUOTE:
          return this.afterquote(char);
        case NUMBER:
          return this.number(char);
        case ENDED:
          return;
      }
    };
    Parser.prototype.afterquote = function(char) {
      if (char === '"') {
        this.word += '"';
        this.state = QUOTED;
        return;
      }
      if (endThings.test(char)) {
        this.word = this.word.trim();
        this.afterItem(char);
        return;
      }
      throw new Error('havn\'t handled "' +char + '" in afterquote yet, index ' + this.place);
    };
    Parser.prototype.afterItem = function(char) {
      if (char === ',') {
        if (this.word !== null) {
          this.currentObject.push(this.word);
        }
        this.word = null;
        this.state = NEUTRAL;
        return;
      }
      if (char === ']') {
        this.level--;
        if (this.word !== null) {
          this.currentObject.push(this.word);
          this.word = null;
        }
        this.state = NEUTRAL;
        this.currentObject = this.stack.pop();
        if (!this.currentObject) {
          this.state = ENDED;
        }

        return;
      }
    };
    Parser.prototype.number = function(char) {
      if (digets.test(char)) {
        this.word += char;
        return;
      }
      if (endThings.test(char)) {
        this.word = parseFloat(this.word);
        this.afterItem(char);
        return;
      }
      throw new Error('havn\'t handled "' +char + '" in number yet, index ' + this.place);
    };
    Parser.prototype.quoted = function(char) {
      if (char === '"') {
        this.state = AFTERQUOTE;
        return;
      }
      this.word += char;
      return;
    };
    Parser.prototype.keyword = function(char) {
      if (keyword.test(char)) {
        this.word += char;
        return;
      }
      if (char === '[') {
        var newObjects = [];
        newObjects.push(this.word);
        this.level++;
        if (this.root === null) {
          this.root = newObjects;
        } else {
          this.currentObject.push(newObjects);
        }
        this.stack.push(this.currentObject);
        this.currentObject = newObjects;
        this.state = NEUTRAL;
        return;
      }
      if (endThings.test(char)) {
        this.afterItem(char);
        return;
      }
      throw new Error('havn\'t handled "' +char + '" in keyword yet, index ' + this.place);
    };
    Parser.prototype.neutral = function(char) {
      if (latin.test(char)) {
        this.word = char;
        this.state = KEYWORD;
        return;
      }
      if (char === '"') {
        this.word = '';
        this.state = QUOTED;
        return;
      }
      if (digets.test(char)) {
        this.word = char;
        this.state = NUMBER;
        return;
      }
      if (endThings.test(char)) {
        this.afterItem(char);
        return;
      }
      throw new Error('havn\'t handled "' +char + '" in neutral yet, index ' + this.place);
    };
    Parser.prototype.output = function() {
      while (this.place < this.text.length) {
        this.readCharicter();
      }
      if (this.state === ENDED) {
        return this.root;
      }
      throw new Error('unable to parse string "' +this.text + '". State is ' + this.state);
    };

    function parseString(txt) {
      var parser = new Parser(txt);
      return parser.output();
    }

    function mapit(obj, key, value) {
      if (Array.isArray(key)) {
        value.unshift(key);
        key = null;
      }
      var thing = key ? {} : obj;

      var out = value.reduce(function(newObj, item) {
        sExpr(item, newObj);
        return newObj
      }, thing);
      if (key) {
        obj[key] = out;
      }
    }

    function sExpr(v, obj) {
      if (!Array.isArray(v)) {
        obj[v] = true;
        return;
      }
      var key = v.shift();
      if (key === 'PARAMETER') {
        key = v.shift();
      }
      if (v.length === 1) {
        if (Array.isArray(v[0])) {
          obj[key] = {};
          sExpr(v[0], obj[key]);
          return;
        }
        obj[key] = v[0];
        return;
      }
      if (!v.length) {
        obj[key] = true;
        return;
      }
      if (key === 'TOWGS84') {
        obj[key] = v;
        return;
      }
      if (key === 'AXIS') {
        if (!(key in obj)) {
          obj[key] = [];
        }
        obj[key].push(v);
        return;
      }
      if (!Array.isArray(key)) {
        obj[key] = {};
      }

      var i;
      switch (key) {
        case 'UNIT':
        case 'PRIMEM':
        case 'VERT_DATUM':
          obj[key] = {
            name: v[0].toLowerCase(),
            convert: v[1]
          };
          if (v.length === 3) {
            sExpr(v[2], obj[key]);
          }
          return;
        case 'SPHEROID':
        case 'ELLIPSOID':
          obj[key] = {
            name: v[0],
            a: v[1],
            rf: v[2]
          };
          if (v.length === 4) {
            sExpr(v[3], obj[key]);
          }
          return;
        case 'PROJECTEDCRS':
        case 'PROJCRS':
        case 'GEOGCS':
        case 'GEOCCS':
        case 'PROJCS':
        case 'LOCAL_CS':
        case 'GEODCRS':
        case 'GEODETICCRS':
        case 'GEODETICDATUM':
        case 'EDATUM':
        case 'ENGINEERINGDATUM':
        case 'VERT_CS':
        case 'VERTCRS':
        case 'VERTICALCRS':
        case 'COMPD_CS':
        case 'COMPOUNDCRS':
        case 'ENGINEERINGCRS':
        case 'ENGCRS':
        case 'FITTED_CS':
        case 'LOCAL_DATUM':
        case 'DATUM':
          v[0] = ['name', v[0]];
          mapit(obj, key, v);
          return;
        default:
          i = -1;
          while (++i < v.length) {
            if (!Array.isArray(v[i])) {
              return sExpr(v, obj[key]);
            }
          }
          return mapit(obj, key, v);
      }
    }

    var D2R$1 = 0.01745329251994329577;
    function rename(obj, params) {
      var outName = params[0];
      var inName = params[1];
      if (!(outName in obj) && (inName in obj)) {
        obj[outName] = obj[inName];
        if (params.length === 3) {
          obj[outName] = params[2](obj[outName]);
        }
      }
    }

    function d2r(input) {
      return input * D2R$1;
    }

    function cleanWKT(wkt) {
      if (wkt.type === 'GEOGCS') {
        wkt.projName = 'longlat';
      } else if (wkt.type === 'LOCAL_CS') {
        wkt.projName = 'identity';
        wkt.local = true;
      } else {
        if (typeof wkt.PROJECTION === 'object') {
          wkt.projName = Object.keys(wkt.PROJECTION)[0];
        } else {
          wkt.projName = wkt.PROJECTION;
        }
      }
      if (wkt.AXIS) {
        var axisOrder = '';
        for (var i = 0, ii = wkt.AXIS.length; i < ii; ++i) {
          var axis = [wkt.AXIS[i][0].toLowerCase(), wkt.AXIS[i][1].toLowerCase()];
          if (axis[0].indexOf('north') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'north')) {
            axisOrder += 'n';
          } else if (axis[0].indexOf('south') !== -1 || ((axis[0] === 'y' || axis[0] === 'lat') && axis[1] === 'south')) {
            axisOrder += 's';
          } else if (axis[0].indexOf('east') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'east')) {
            axisOrder += 'e';
          } else if (axis[0].indexOf('west') !== -1 || ((axis[0] === 'x' || axis[0] === 'lon') && axis[1] === 'west')) {
            axisOrder += 'w';
          }
        }
        if (axisOrder.length === 2) {
          axisOrder += 'u';
        }
        if (axisOrder.length === 3) {
          wkt.axis = axisOrder;
        }
      }
      if (wkt.UNIT) {
        wkt.units = wkt.UNIT.name.toLowerCase();
        if (wkt.units === 'metre') {
          wkt.units = 'meter';
        }
        if (wkt.UNIT.convert) {
          if (wkt.type === 'GEOGCS') {
            if (wkt.DATUM && wkt.DATUM.SPHEROID) {
              wkt.to_meter = wkt.UNIT.convert*wkt.DATUM.SPHEROID.a;
            }
          } else {
            wkt.to_meter = wkt.UNIT.convert;
          }
        }
      }
      var geogcs = wkt.GEOGCS;
      if (wkt.type === 'GEOGCS') {
        geogcs = wkt;
      }
      if (geogcs) {
        //if(wkt.GEOGCS.PRIMEM&&wkt.GEOGCS.PRIMEM.convert){
        //  wkt.from_greenwich=wkt.GEOGCS.PRIMEM.convert*D2R;
        //}
        if (geogcs.DATUM) {
          wkt.datumCode = geogcs.DATUM.name.toLowerCase();
        } else {
          wkt.datumCode = geogcs.name.toLowerCase();
        }
        if (wkt.datumCode.slice(0, 2) === 'd_') {
          wkt.datumCode = wkt.datumCode.slice(2);
        }
        if (wkt.datumCode === 'new_zealand_geodetic_datum_1949' || wkt.datumCode === 'new_zealand_1949') {
          wkt.datumCode = 'nzgd49';
        }
        if (wkt.datumCode === 'wgs_1984' || wkt.datumCode === 'world_geodetic_system_1984') {
          if (wkt.PROJECTION === 'Mercator_Auxiliary_Sphere') {
            wkt.sphere = true;
          }
          wkt.datumCode = 'wgs84';
        }
        if (wkt.datumCode.slice(-6) === '_ferro') {
          wkt.datumCode = wkt.datumCode.slice(0, - 6);
        }
        if (wkt.datumCode.slice(-8) === '_jakarta') {
          wkt.datumCode = wkt.datumCode.slice(0, - 8);
        }
        if (~wkt.datumCode.indexOf('belge')) {
          wkt.datumCode = 'rnb72';
        }
        if (geogcs.DATUM && geogcs.DATUM.SPHEROID) {
          wkt.ellps = geogcs.DATUM.SPHEROID.name.replace('_19', '').replace(/[Cc]larke\_18/, 'clrk');
          if (wkt.ellps.toLowerCase().slice(0, 13) === 'international') {
            wkt.ellps = 'intl';
          }

          wkt.a = geogcs.DATUM.SPHEROID.a;
          wkt.rf = parseFloat(geogcs.DATUM.SPHEROID.rf, 10);
        }

        if (geogcs.DATUM && geogcs.DATUM.TOWGS84) {
          wkt.datum_params = geogcs.DATUM.TOWGS84;
        }
        if (~wkt.datumCode.indexOf('osgb_1936')) {
          wkt.datumCode = 'osgb36';
        }
        if (~wkt.datumCode.indexOf('osni_1952')) {
          wkt.datumCode = 'osni52';
        }
        if (~wkt.datumCode.indexOf('tm65')
          || ~wkt.datumCode.indexOf('geodetic_datum_of_1965')) {
          wkt.datumCode = 'ire65';
        }
        if (wkt.datumCode === 'ch1903+') {
          wkt.datumCode = 'ch1903';
        }
        if (~wkt.datumCode.indexOf('israel')) {
          wkt.datumCode = 'isr93';
        }
      }
      if (wkt.b && !isFinite(wkt.b)) {
        wkt.b = wkt.a;
      }

      function toMeter(input) {
        var ratio = wkt.to_meter || 1;
        return input * ratio;
      }
      var renamer = function(a) {
        return rename(wkt, a);
      };
      var list = [
        ['standard_parallel_1', 'Standard_Parallel_1'],
        ['standard_parallel_1', 'Latitude of 1st standard parallel'],
        ['standard_parallel_2', 'Standard_Parallel_2'],
        ['standard_parallel_2', 'Latitude of 2nd standard parallel'],
        ['false_easting', 'False_Easting'],
        ['false_easting', 'False easting'],
        ['false-easting', 'Easting at false origin'],
        ['false_northing', 'False_Northing'],
        ['false_northing', 'False northing'],
        ['false_northing', 'Northing at false origin'],
        ['central_meridian', 'Central_Meridian'],
        ['central_meridian', 'Longitude of natural origin'],
        ['central_meridian', 'Longitude of false origin'],
        ['latitude_of_origin', 'Latitude_Of_Origin'],
        ['latitude_of_origin', 'Central_Parallel'],
        ['latitude_of_origin', 'Latitude of natural origin'],
        ['latitude_of_origin', 'Latitude of false origin'],
        ['scale_factor', 'Scale_Factor'],
        ['k0', 'scale_factor'],
        ['latitude_of_center', 'Latitude_Of_Center'],
        ['latitude_of_center', 'Latitude_of_center'],
        ['lat0', 'latitude_of_center', d2r],
        ['longitude_of_center', 'Longitude_Of_Center'],
        ['longitude_of_center', 'Longitude_of_center'],
        ['longc', 'longitude_of_center', d2r],
        ['x0', 'false_easting', toMeter],
        ['y0', 'false_northing', toMeter],
        ['long0', 'central_meridian', d2r],
        ['lat0', 'latitude_of_origin', d2r],
        ['lat0', 'standard_parallel_1', d2r],
        ['lat1', 'standard_parallel_1', d2r],
        ['lat2', 'standard_parallel_2', d2r],
        ['azimuth', 'Azimuth'],
        ['alpha', 'azimuth', d2r],
        ['srsCode', 'name']
      ];
      list.forEach(renamer);
      if (!wkt.long0 && wkt.longc && (wkt.projName === 'Albers_Conic_Equal_Area' || wkt.projName === 'Lambert_Azimuthal_Equal_Area')) {
        wkt.long0 = wkt.longc;
      }
      if (!wkt.lat_ts && wkt.lat1 && (wkt.projName === 'Stereographic_South_Pole' || wkt.projName === 'Polar Stereographic (variant B)')) {
        wkt.lat0 = d2r(wkt.lat1 > 0 ? 90 : -90);
        wkt.lat_ts = wkt.lat1;
      }
    }
    var wkt = function(wkt) {
      var lisp = parseString(wkt);
      var type = lisp.shift();
      var name = lisp.shift();
      lisp.unshift(['name', name]);
      lisp.unshift(['type', type]);
      var obj = {};
      sExpr(lisp, obj);
      cleanWKT(obj);
      return obj;
    };

    function defs(name) {
      /*global console*/
      var that = this;
      if (arguments.length === 2) {
        var def = arguments[1];
        if (typeof def === 'string') {
          if (def.charAt(0) === '+') {
            defs[name] = parseProj(arguments[1]);
          }
          else {
            defs[name] = wkt(arguments[1]);
          }
        } else {
          defs[name] = def;
        }
      }
      else if (arguments.length === 1) {
        if (Array.isArray(name)) {
          return name.map(function(v) {
            if (Array.isArray(v)) {
              defs.apply(that, v);
            }
            else {
              defs(v);
            }
          });
        }
        else if (typeof name === 'string') {
          if (name in defs) {
            return defs[name];
          }
        }
        else if ('EPSG' in name) {
          defs['EPSG:' + name.EPSG] = name;
        }
        else if ('ESRI' in name) {
          defs['ESRI:' + name.ESRI] = name;
        }
        else if ('IAU2000' in name) {
          defs['IAU2000:' + name.IAU2000] = name;
        }
        else {
          console.log(name);
        }
        return;
      }


    }
    globals(defs);

    function testObj(code){
      return typeof code === 'string';
    }
    function testDef(code){
      return code in defs;
    }
    var codeWords = ['PROJECTEDCRS', 'PROJCRS', 'GEOGCS','GEOCCS','PROJCS','LOCAL_CS', 'GEODCRS', 'GEODETICCRS', 'GEODETICDATUM', 'ENGCRS', 'ENGINEERINGCRS'];
    function testWKT(code){
      return codeWords.some(function (word) {
        return code.indexOf(word) > -1;
      });
    }
    var codes = ['3857', '900913', '3785', '102113'];
    function checkMercator(item) {
      var auth = match(item, 'authority');
      if (!auth) {
        return;
      }
      var code = match(auth, 'epsg');
      return code && codes.indexOf(code) > -1;
    }
    function checkProjStr(item) {
      var ext = match(item, 'extension');
      if (!ext) {
        return;
      }
      return match(ext, 'proj4');
    }
    function testProj(code){
      return code[0] === '+';
    }
    function parse(code){
      if (testObj(code)) {
        //check to see if this is a WKT string
        if (testDef(code)) {
          return defs[code];
        }
        if (testWKT(code)) {
          var out = wkt(code);
          // test of spetial case, due to this being a very common and often malformed
          if (checkMercator(out)) {
            return defs['EPSG:3857'];
          }
          var maybeProjStr = checkProjStr(out);
          if (maybeProjStr) {
            return parseProj(maybeProjStr);
          }
          return out;
        }
        if (testProj(code)) {
          return parseProj(code);
        }
      }else{
        return code;
      }
    }

    var extend = function(destination, source) {
      destination = destination || {};
      var value, property;
      if (!source) {
        return destination;
      }
      for (property in source) {
        value = source[property];
        if (value !== undefined) {
          destination[property] = value;
        }
      }
      return destination;
    };

    var msfnz = function(eccent, sinphi, cosphi) {
      var con = eccent * sinphi;
      return cosphi / (Math.sqrt(1 - con * con));
    };

    var sign = function(x) {
      return x<0 ? -1 : 1;
    };

    var adjust_lon = function(x) {
      return (Math.abs(x) <= SPI) ? x : (x - (sign(x) * TWO_PI));
    };

    var tsfnz = function(eccent, phi, sinphi) {
      var con = eccent * sinphi;
      var com = 0.5 * eccent;
      con = Math.pow(((1 - con) / (1 + con)), com);
      return (Math.tan(0.5 * (HALF_PI - phi)) / con);
    };

    var phi2z = function(eccent, ts) {
      var eccnth = 0.5 * eccent;
      var con, dphi;
      var phi = HALF_PI - 2 * Math.atan(ts);
      for (var i = 0; i <= 15; i++) {
        con = eccent * Math.sin(phi);
        dphi = HALF_PI - 2 * Math.atan(ts * (Math.pow(((1 - con) / (1 + con)), eccnth))) - phi;
        phi += dphi;
        if (Math.abs(dphi) <= 0.0000000001) {
          return phi;
        }
      }
      //console.log("phi2z has NoConvergence");
      return -9999;
    };

    function init() {
      var con = this.b / this.a;
      this.es = 1 - con * con;
      if(!('x0' in this)){
        this.x0 = 0;
      }
      if(!('y0' in this)){
        this.y0 = 0;
      }
      this.e = Math.sqrt(this.es);
      if (this.lat_ts) {
        if (this.sphere) {
          this.k0 = Math.cos(this.lat_ts);
        }
        else {
          this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
        }
      }
      else {
        if (!this.k0) {
          if (this.k) {
            this.k0 = this.k;
          }
          else {
            this.k0 = 1;
          }
        }
      }
    }

    /* Mercator forward equations--mapping lat,long to x,y
      --------------------------------------------------*/

    function forward(p) {
      var lon = p.x;
      var lat = p.y;
      // convert to radians
      if (lat * R2D > 90 && lat * R2D < -90 && lon * R2D > 180 && lon * R2D < -180) {
        return null;
      }

      var x, y;
      if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
        return null;
      }
      else {
        if (this.sphere) {
          x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
          y = this.y0 + this.a * this.k0 * Math.log(Math.tan(FORTPI + 0.5 * lat));
        }
        else {
          var sinphi = Math.sin(lat);
          var ts = tsfnz(this.e, lat, sinphi);
          x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
          y = this.y0 - this.a * this.k0 * Math.log(ts);
        }
        p.x = x;
        p.y = y;
        return p;
      }
    }

    /* Mercator inverse equations--mapping x,y to lat/long
      --------------------------------------------------*/
    function inverse(p) {

      var x = p.x - this.x0;
      var y = p.y - this.y0;
      var lon, lat;

      if (this.sphere) {
        lat = HALF_PI - 2 * Math.atan(Math.exp(-y / (this.a * this.k0)));
      }
      else {
        var ts = Math.exp(-y / (this.a * this.k0));
        lat = phi2z(this.e, ts);
        if (lat === -9999) {
          return null;
        }
      }
      lon = adjust_lon(this.long0 + x / (this.a * this.k0));

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$1 = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "merc"];
    var merc = {
      init: init,
      forward: forward,
      inverse: inverse,
      names: names$1
    };

    function init$1() {
      //no-op for longlat
    }

    function identity(pt) {
      return pt;
    }
    var names$2 = ["longlat", "identity"];
    var longlat = {
      init: init$1,
      forward: identity,
      inverse: identity,
      names: names$2
    };

    var projs = [merc, longlat];
    var names = {};
    var projStore = [];

    function add(proj, i) {
      var len = projStore.length;
      if (!proj.names) {
        console.log(i);
        return true;
      }
      projStore[len] = proj;
      proj.names.forEach(function(n) {
        names[n.toLowerCase()] = len;
      });
      return this;
    }

    function get(name) {
      if (!name) {
        return false;
      }
      var n = name.toLowerCase();
      if (typeof names[n] !== 'undefined' && projStore[names[n]]) {
        return projStore[names[n]];
      }
    }

    function start() {
      projs.forEach(add);
    }
    var projections = {
      start: start,
      add: add,
      get: get
    };

    var exports$2 = {};
    exports$2.MERIT = {
      a: 6378137.0,
      rf: 298.257,
      ellipseName: "MERIT 1983"
    };

    exports$2.SGS85 = {
      a: 6378136.0,
      rf: 298.257,
      ellipseName: "Soviet Geodetic System 85"
    };

    exports$2.GRS80 = {
      a: 6378137.0,
      rf: 298.257222101,
      ellipseName: "GRS 1980(IUGG, 1980)"
    };

    exports$2.IAU76 = {
      a: 6378140.0,
      rf: 298.257,
      ellipseName: "IAU 1976"
    };

    exports$2.airy = {
      a: 6377563.396,
      b: 6356256.910,
      ellipseName: "Airy 1830"
    };

    exports$2.APL4 = {
      a: 6378137,
      rf: 298.25,
      ellipseName: "Appl. Physics. 1965"
    };

    exports$2.NWL9D = {
      a: 6378145.0,
      rf: 298.25,
      ellipseName: "Naval Weapons Lab., 1965"
    };

    exports$2.mod_airy = {
      a: 6377340.189,
      b: 6356034.446,
      ellipseName: "Modified Airy"
    };

    exports$2.andrae = {
      a: 6377104.43,
      rf: 300.0,
      ellipseName: "Andrae 1876 (Den., Iclnd.)"
    };

    exports$2.aust_SA = {
      a: 6378160.0,
      rf: 298.25,
      ellipseName: "Australian Natl & S. Amer. 1969"
    };

    exports$2.GRS67 = {
      a: 6378160.0,
      rf: 298.2471674270,
      ellipseName: "GRS 67(IUGG 1967)"
    };

    exports$2.bessel = {
      a: 6377397.155,
      rf: 299.1528128,
      ellipseName: "Bessel 1841"
    };

    exports$2.bess_nam = {
      a: 6377483.865,
      rf: 299.1528128,
      ellipseName: "Bessel 1841 (Namibia)"
    };

    exports$2.clrk66 = {
      a: 6378206.4,
      b: 6356583.8,
      ellipseName: "Clarke 1866"
    };

    exports$2.clrk80 = {
      a: 6378249.145,
      rf: 293.4663,
      ellipseName: "Clarke 1880 mod."
    };

    exports$2.clrk58 = {
      a: 6378293.645208759,
      rf: 294.2606763692654,
      ellipseName: "Clarke 1858"
    };

    exports$2.CPM = {
      a: 6375738.7,
      rf: 334.29,
      ellipseName: "Comm. des Poids et Mesures 1799"
    };

    exports$2.delmbr = {
      a: 6376428.0,
      rf: 311.5,
      ellipseName: "Delambre 1810 (Belgium)"
    };

    exports$2.engelis = {
      a: 6378136.05,
      rf: 298.2566,
      ellipseName: "Engelis 1985"
    };

    exports$2.evrst30 = {
      a: 6377276.345,
      rf: 300.8017,
      ellipseName: "Everest 1830"
    };

    exports$2.evrst48 = {
      a: 6377304.063,
      rf: 300.8017,
      ellipseName: "Everest 1948"
    };

    exports$2.evrst56 = {
      a: 6377301.243,
      rf: 300.8017,
      ellipseName: "Everest 1956"
    };

    exports$2.evrst69 = {
      a: 6377295.664,
      rf: 300.8017,
      ellipseName: "Everest 1969"
    };

    exports$2.evrstSS = {
      a: 6377298.556,
      rf: 300.8017,
      ellipseName: "Everest (Sabah & Sarawak)"
    };

    exports$2.fschr60 = {
      a: 6378166.0,
      rf: 298.3,
      ellipseName: "Fischer (Mercury Datum) 1960"
    };

    exports$2.fschr60m = {
      a: 6378155.0,
      rf: 298.3,
      ellipseName: "Fischer 1960"
    };

    exports$2.fschr68 = {
      a: 6378150.0,
      rf: 298.3,
      ellipseName: "Fischer 1968"
    };

    exports$2.helmert = {
      a: 6378200.0,
      rf: 298.3,
      ellipseName: "Helmert 1906"
    };

    exports$2.hough = {
      a: 6378270.0,
      rf: 297.0,
      ellipseName: "Hough"
    };

    exports$2.intl = {
      a: 6378388.0,
      rf: 297.0,
      ellipseName: "International 1909 (Hayford)"
    };

    exports$2.kaula = {
      a: 6378163.0,
      rf: 298.24,
      ellipseName: "Kaula 1961"
    };

    exports$2.lerch = {
      a: 6378139.0,
      rf: 298.257,
      ellipseName: "Lerch 1979"
    };

    exports$2.mprts = {
      a: 6397300.0,
      rf: 191.0,
      ellipseName: "Maupertius 1738"
    };

    exports$2.new_intl = {
      a: 6378157.5,
      b: 6356772.2,
      ellipseName: "New International 1967"
    };

    exports$2.plessis = {
      a: 6376523.0,
      rf: 6355863.0,
      ellipseName: "Plessis 1817 (France)"
    };

    exports$2.krass = {
      a: 6378245.0,
      rf: 298.3,
      ellipseName: "Krassovsky, 1942"
    };

    exports$2.SEasia = {
      a: 6378155.0,
      b: 6356773.3205,
      ellipseName: "Southeast Asia"
    };

    exports$2.walbeck = {
      a: 6376896.0,
      b: 6355834.8467,
      ellipseName: "Walbeck"
    };

    exports$2.WGS60 = {
      a: 6378165.0,
      rf: 298.3,
      ellipseName: "WGS 60"
    };

    exports$2.WGS66 = {
      a: 6378145.0,
      rf: 298.25,
      ellipseName: "WGS 66"
    };

    exports$2.WGS7 = {
      a: 6378135.0,
      rf: 298.26,
      ellipseName: "WGS 72"
    };

    var WGS84 = exports$2.WGS84 = {
      a: 6378137.0,
      rf: 298.257223563,
      ellipseName: "WGS 84"
    };

    exports$2.sphere = {
      a: 6370997.0,
      b: 6370997.0,
      ellipseName: "Normal Sphere (r=6370997)"
    };

    function eccentricity(a, b, rf, R_A) {
      var a2 = a * a; // used in geocentric
      var b2 = b * b; // used in geocentric
      var es = (a2 - b2) / a2; // e ^ 2
      var e = 0;
      if (R_A) {
        a *= 1 - es * (SIXTH + es * (RA4 + es * RA6));
        a2 = a * a;
        es = 0;
      } else {
        e = Math.sqrt(es); // eccentricity
      }
      var ep2 = (a2 - b2) / b2; // used in geocentric
      return {
        es: es,
        e: e,
        ep2: ep2
      };
    }
    function sphere(a, b, rf, ellps, sphere) {
      if (!a) { // do we have an ellipsoid?
        var ellipse = match(exports$2, ellps);
        if (!ellipse) {
          ellipse = WGS84;
        }
        a = ellipse.a;
        b = ellipse.b;
        rf = ellipse.rf;
      }

      if (rf && !b) {
        b = (1.0 - 1.0 / rf) * a;
      }
      if (rf === 0 || Math.abs(a - b) < EPSLN) {
        sphere = true;
        b = a;
      }
      return {
        a: a,
        b: b,
        rf: rf,
        sphere: sphere
      };
    }

    var exports$3 = {};
    exports$3.wgs84 = {
      towgs84: "0,0,0",
      ellipse: "WGS84",
      datumName: "WGS84"
    };

    exports$3.ch1903 = {
      towgs84: "674.374,15.056,405.346",
      ellipse: "bessel",
      datumName: "swiss"
    };

    exports$3.ggrs87 = {
      towgs84: "-199.87,74.79,246.62",
      ellipse: "GRS80",
      datumName: "Greek_Geodetic_Reference_System_1987"
    };

    exports$3.nad83 = {
      towgs84: "0,0,0",
      ellipse: "GRS80",
      datumName: "North_American_Datum_1983"
    };

    exports$3.nad27 = {
      nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
      ellipse: "clrk66",
      datumName: "North_American_Datum_1927"
    };

    exports$3.potsdam = {
      towgs84: "598.1,73.7,418.2,0.202,0.045,-2.455,6.7",
      ellipse: "bessel",
      datumName: "Potsdam Rauenberg 1950 DHDN"
    };

    exports$3.carthage = {
      towgs84: "-263.0,6.0,431.0",
      ellipse: "clark80",
      datumName: "Carthage 1934 Tunisia"
    };

    exports$3.hermannskogel = {
      towgs84: "577.326,90.129,463.919,5.137,1.474,5.297,2.4232",
      ellipse: "bessel",
      datumName: "Hermannskogel"
    };

    exports$3.osni52 = {
      towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
      ellipse: "airy",
      datumName: "Irish National"
    };

    exports$3.ire65 = {
      towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
      ellipse: "mod_airy",
      datumName: "Ireland 1965"
    };

    exports$3.rassadiran = {
      towgs84: "-133.63,-157.5,-158.62",
      ellipse: "intl",
      datumName: "Rassadiran"
    };

    exports$3.nzgd49 = {
      towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",
      ellipse: "intl",
      datumName: "New Zealand Geodetic Datum 1949"
    };

    exports$3.osgb36 = {
      towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",
      ellipse: "airy",
      datumName: "Airy 1830"
    };

    exports$3.s_jtsk = {
      towgs84: "589,76,480",
      ellipse: 'bessel',
      datumName: 'S-JTSK (Ferro)'
    };

    exports$3.beduaram = {
      towgs84: '-106,-87,188',
      ellipse: 'clrk80',
      datumName: 'Beduaram'
    };

    exports$3.gunung_segara = {
      towgs84: '-403,684,41',
      ellipse: 'bessel',
      datumName: 'Gunung Segara Jakarta'
    };

    exports$3.rnb72 = {
      towgs84: "106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",
      ellipse: "intl",
      datumName: "Reseau National Belge 1972"
    };

    function datum(datumCode, datum_params, a, b, es, ep2, nadgrids) {
      var out = {};

      if (datumCode === undefined || datumCode === 'none') {
        out.datum_type = PJD_NODATUM;
      } else {
        out.datum_type = PJD_WGS84;
      }

      if (datum_params) {
        out.datum_params = datum_params.map(parseFloat);
        if (out.datum_params[0] !== 0 || out.datum_params[1] !== 0 || out.datum_params[2] !== 0) {
          out.datum_type = PJD_3PARAM;
        }
        if (out.datum_params.length > 3) {
          if (out.datum_params[3] !== 0 || out.datum_params[4] !== 0 || out.datum_params[5] !== 0 || out.datum_params[6] !== 0) {
            out.datum_type = PJD_7PARAM;
            out.datum_params[3] *= SEC_TO_RAD;
            out.datum_params[4] *= SEC_TO_RAD;
            out.datum_params[5] *= SEC_TO_RAD;
            out.datum_params[6] = (out.datum_params[6] / 1000000.0) + 1.0;
          }
        }
      }

      if (nadgrids) {
        out.datum_type = PJD_GRIDSHIFT;
        out.grids = nadgrids;
      }
      out.a = a; //datum object also uses these values
      out.b = b;
      out.es = es;
      out.ep2 = ep2;
      return out;
    }

    /**
     * Resources for details of NTv2 file formats:
     * - https://web.archive.org/web/20140127204822if_/http://www.mgs.gov.on.ca:80/stdprodconsume/groups/content/@mgs/@iandit/documents/resourcelist/stel02_047447.pdf
     * - http://mimaka.com/help/gs/html/004_NTV2%20Data%20Format.htm
     */

    var loadedNadgrids = {};

    /**
     * Load a binary NTv2 file (.gsb) to a key that can be used in a proj string like +nadgrids=<key>. Pass the NTv2 file
     * as an ArrayBuffer.
     */
    function nadgrid(key, data) {
      var view = new DataView(data);
      var isLittleEndian = detectLittleEndian(view);
      var header = readHeader(view, isLittleEndian);
      if (header.nSubgrids > 1) {
        console.log('Only single NTv2 subgrids are currently supported, subsequent sub grids are ignored');
      }
      var subgrids = readSubgrids(view, header, isLittleEndian);
      var nadgrid = {header: header, subgrids: subgrids};
      loadedNadgrids[key] = nadgrid;
      return nadgrid;
    }

    /**
     * Given a proj4 value for nadgrids, return an array of loaded grids
     */
    function getNadgrids(nadgrids) {
      // Format details: http://proj.maptools.org/gen_parms.html
      if (nadgrids === undefined) { return null; }
      var grids = nadgrids.split(',');
      return grids.map(parseNadgridString);
    }

    function parseNadgridString(value) {
      if (value.length === 0) {
        return null;
      }
      var optional = value[0] === '@';
      if (optional) {
        value = value.slice(1);
      }
      if (value === 'null') {
        return {name: 'null', mandatory: !optional, grid: null, isNull: true};
      }
      return {
        name: value,
        mandatory: !optional,
        grid: loadedNadgrids[value] || null,
        isNull: false
      };
    }

    function secondsToRadians(seconds) {
      return (seconds / 3600) * Math.PI / 180;
    }

    function detectLittleEndian(view) {
      var nFields = view.getInt32(8, false);
      if (nFields === 11) {
        return false;
      }
      nFields = view.getInt32(8, true);
      if (nFields !== 11) {
        console.warn('Failed to detect nadgrid endian-ness, defaulting to little-endian');
      }
      return true;
    }

    function readHeader(view, isLittleEndian) {
      return {
        nFields: view.getInt32(8, isLittleEndian),
        nSubgridFields: view.getInt32(24, isLittleEndian),
        nSubgrids: view.getInt32(40, isLittleEndian),
        shiftType: decodeString(view, 56, 56 + 8).trim(),
        fromSemiMajorAxis: view.getFloat64(120, isLittleEndian),
        fromSemiMinorAxis: view.getFloat64(136, isLittleEndian),
        toSemiMajorAxis: view.getFloat64(152, isLittleEndian),
        toSemiMinorAxis: view.getFloat64(168, isLittleEndian),
      };
    }

    function decodeString(view, start, end) {
      return String.fromCharCode.apply(null, new Uint8Array(view.buffer.slice(start, end)));
    }

    function readSubgrids(view, header, isLittleEndian) {
      var gridOffset = 176;
      var grids = [];
      for (var i = 0; i < header.nSubgrids; i++) {
        var subHeader = readGridHeader(view, gridOffset, isLittleEndian);
        var nodes = readGridNodes(view, gridOffset, subHeader, isLittleEndian);
        var lngColumnCount = Math.round(
          1 + (subHeader.upperLongitude - subHeader.lowerLongitude) / subHeader.longitudeInterval);
        var latColumnCount = Math.round(
          1 + (subHeader.upperLatitude - subHeader.lowerLatitude) / subHeader.latitudeInterval);
        // Proj4 operates on radians whereas the coordinates are in seconds in the grid
        grids.push({
          ll: [secondsToRadians(subHeader.lowerLongitude), secondsToRadians(subHeader.lowerLatitude)],
          del: [secondsToRadians(subHeader.longitudeInterval), secondsToRadians(subHeader.latitudeInterval)],
          lim: [lngColumnCount, latColumnCount],
          count: subHeader.gridNodeCount,
          cvs: mapNodes(nodes)
        });
      }
      return grids;
    }

    function mapNodes(nodes) {
      return nodes.map(function (r) {return [secondsToRadians(r.longitudeShift), secondsToRadians(r.latitudeShift)];});
    }

    function readGridHeader(view, offset, isLittleEndian) {
      return {
        name: decodeString(view, offset + 8, offset + 16).trim(),
        parent: decodeString(view, offset + 24, offset + 24 + 8).trim(),
        lowerLatitude: view.getFloat64(offset + 72, isLittleEndian),
        upperLatitude: view.getFloat64(offset + 88, isLittleEndian),
        lowerLongitude: view.getFloat64(offset + 104, isLittleEndian),
        upperLongitude: view.getFloat64(offset + 120, isLittleEndian),
        latitudeInterval: view.getFloat64(offset + 136, isLittleEndian),
        longitudeInterval: view.getFloat64(offset + 152, isLittleEndian),
        gridNodeCount: view.getInt32(offset + 168, isLittleEndian)
      };
    }

    function readGridNodes(view, offset, gridHeader, isLittleEndian) {
      var nodesOffset = offset + 176;
      var gridRecordLength = 16;
      var gridShiftRecords = [];
      for (var i = 0; i < gridHeader.gridNodeCount; i++) {
        var record = {
          latitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength, isLittleEndian),
          longitudeShift: view.getFloat32(nodesOffset + i * gridRecordLength + 4, isLittleEndian),
          latitudeAccuracy: view.getFloat32(nodesOffset + i * gridRecordLength + 8, isLittleEndian),
          longitudeAccuracy: view.getFloat32(nodesOffset + i * gridRecordLength + 12, isLittleEndian),
        };
        gridShiftRecords.push(record);
      }
      return gridShiftRecords;
    }

    function Projection(srsCode,callback) {
      if (!(this instanceof Projection)) {
        return new Projection(srsCode);
      }
      callback = callback || function(error){
        if(error){
          throw error;
        }
      };
      var json = parse(srsCode);
      if(typeof json !== 'object'){
        callback(srsCode);
        return;
      }
      var ourProj = Projection.projections.get(json.projName);
      if(!ourProj){
        callback(srsCode);
        return;
      }
      if (json.datumCode && json.datumCode !== 'none') {
        var datumDef = match(exports$3, json.datumCode);
        if (datumDef) {
          json.datum_params = json.datum_params || (datumDef.towgs84 ? datumDef.towgs84.split(',') : null);
          json.ellps = datumDef.ellipse;
          json.datumName = datumDef.datumName ? datumDef.datumName : json.datumCode;
        }
      }
      json.k0 = json.k0 || 1.0;
      json.axis = json.axis || 'enu';
      json.ellps = json.ellps || 'wgs84';
      json.lat1 = json.lat1 || json.lat0; // Lambert_Conformal_Conic_1SP, for example, needs this

      var sphere_ = sphere(json.a, json.b, json.rf, json.ellps, json.sphere);
      var ecc = eccentricity(sphere_.a, sphere_.b, sphere_.rf, json.R_A);
      var nadgrids = getNadgrids(json.nadgrids);
      var datumObj = json.datum || datum(json.datumCode, json.datum_params, sphere_.a, sphere_.b, ecc.es, ecc.ep2,
        nadgrids);

      extend(this, json); // transfer everything over from the projection because we don't know what we'll need
      extend(this, ourProj); // transfer all the methods from the projection

      // copy the 4 things over we calulated in deriveConstants.sphere
      this.a = sphere_.a;
      this.b = sphere_.b;
      this.rf = sphere_.rf;
      this.sphere = sphere_.sphere;

      // copy the 3 things we calculated in deriveConstants.eccentricity
      this.es = ecc.es;
      this.e = ecc.e;
      this.ep2 = ecc.ep2;

      // add in the datum object
      this.datum = datumObj;

      // init the projection
      this.init();

      // legecy callback from back in the day when it went to spatialreference.org
      callback(null, this);

    }
    Projection.projections = projections;
    Projection.projections.start();

    'use strict';
    function compareDatums(source, dest) {
      if (source.datum_type !== dest.datum_type) {
        return false; // false, datums are not equal
      } else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) {
        // the tolerance for es is to ensure that GRS80 and WGS84
        // are considered identical
        return false;
      } else if (source.datum_type === PJD_3PARAM) {
        return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]);
      } else if (source.datum_type === PJD_7PARAM) {
        return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]);
      } else {
        return true; // datums are equal
      }
    } // cs_compare_datums()

    /*
     * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
     * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
     * according to the current ellipsoid parameters.
     *
     *    Latitude  : Geodetic latitude in radians                     (input)
     *    Longitude : Geodetic longitude in radians                    (input)
     *    Height    : Geodetic height, in meters                       (input)
     *    X         : Calculated Geocentric X coordinate, in meters    (output)
     *    Y         : Calculated Geocentric Y coordinate, in meters    (output)
     *    Z         : Calculated Geocentric Z coordinate, in meters    (output)
     *
     */
    function geodeticToGeocentric(p, es, a) {
      var Longitude = p.x;
      var Latitude = p.y;
      var Height = p.z ? p.z : 0; //Z value not always supplied

      var Rn; /*  Earth radius at location  */
      var Sin_Lat; /*  Math.sin(Latitude)  */
      var Sin2_Lat; /*  Square of Math.sin(Latitude)  */
      var Cos_Lat; /*  Math.cos(Latitude)  */

      /*
       ** Don't blow up if Latitude is just a little out of the value
       ** range as it may just be a rounding issue.  Also removed longitude
       ** test, it should be wrapped by Math.cos() and Math.sin().  NFW for PROJ.4, Sep/2001.
       */
      if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
        Latitude = -HALF_PI;
      } else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
        Latitude = HALF_PI;
      } else if (Latitude < -HALF_PI) {
        /* Latitude out of range */
        //..reportError('geocent:lat out of range:' + Latitude);
        return { x: -Infinity, y: -Infinity, z: p.z };
      } else if (Latitude > HALF_PI) {
        /* Latitude out of range */
        return { x: Infinity, y: Infinity, z: p.z };
      }

      if (Longitude > Math.PI) {
        Longitude -= (2 * Math.PI);
      }
      Sin_Lat = Math.sin(Latitude);
      Cos_Lat = Math.cos(Latitude);
      Sin2_Lat = Sin_Lat * Sin_Lat;
      Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat));
      return {
        x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
        y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
        z: ((Rn * (1 - es)) + Height) * Sin_Lat
      };
    } // cs_geodetic_to_geocentric()

    function geocentricToGeodetic(p, es, a, b) {
      /* local defintions and variables */
      /* end-criterium of loop, accuracy of sin(Latitude) */
      var genau = 1e-12;
      var genau2 = (genau * genau);
      var maxiter = 30;

      var P; /* distance between semi-minor axis and location */
      var RR; /* distance between center and location */
      var CT; /* sin of geocentric latitude */
      var ST; /* cos of geocentric latitude */
      var RX;
      var RK;
      var RN; /* Earth radius at location */
      var CPHI0; /* cos of start or old geodetic latitude in iterations */
      var SPHI0; /* sin of start or old geodetic latitude in iterations */
      var CPHI; /* cos of searched geodetic latitude */
      var SPHI; /* sin of searched geodetic latitude */
      var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
      var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */

      var X = p.x;
      var Y = p.y;
      var Z = p.z ? p.z : 0.0; //Z value not always supplied
      var Longitude;
      var Latitude;
      var Height;

      P = Math.sqrt(X * X + Y * Y);
      RR = Math.sqrt(X * X + Y * Y + Z * Z);

      /*      special cases for latitude and longitude */
      if (P / a < genau) {

        /*  special case, if P=0. (X=0., Y=0.) */
        Longitude = 0.0;

        /*  if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
         *  of ellipsoid (=center of mass), Latitude becomes PI/2 */
        if (RR / a < genau) {
          Latitude = HALF_PI;
          Height = -b;
          return {
            x: p.x,
            y: p.y,
            z: p.z
          };
        }
      } else {
        /*  ellipsoidal (geodetic) longitude
         *  interval: -PI < Longitude <= +PI */
        Longitude = Math.atan2(Y, X);
      }

      /* --------------------------------------------------------------
       * Following iterative algorithm was developped by
       * "Institut for Erdmessung", University of Hannover, July 1988.
       * Internet: www.ife.uni-hannover.de
       * Iterative computation of CPHI,SPHI and Height.
       * Iteration of CPHI and SPHI to 10**-12 radian resp.
       * 2*10**-7 arcsec.
       * --------------------------------------------------------------
       */
      CT = Z / RR;
      ST = P / RR;
      RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST);
      CPHI0 = ST * (1.0 - es) * RX;
      SPHI0 = CT * RX;
      iter = 0;

      /* loop to find sin(Latitude) resp. Latitude
       * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
      do {
        iter++;
        RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0);

        /*  ellipsoidal (geodetic) height */
        Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0);

        RK = es * RN / (RN + Height);
        RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST);
        CPHI = ST * (1.0 - RK) * RX;
        SPHI = CT * RX;
        SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
        CPHI0 = CPHI;
        SPHI0 = SPHI;
      }
      while (SDPHI * SDPHI > genau2 && iter < maxiter);

      /*      ellipsoidal (geodetic) latitude */
      Latitude = Math.atan(SPHI / Math.abs(CPHI));
      return {
        x: Longitude,
        y: Latitude,
        z: Height
      };
    } // cs_geocentric_to_geodetic()

    /****************************************************************/
    // pj_geocentic_to_wgs84( p )
    //  p = point to transform in geocentric coordinates (x,y,z)


    /** point object, nothing fancy, just allows values to be
        passed back and forth by reference rather than by value.
        Other point classes may be used as long as they have
        x and y properties, which will get modified in the transform method.
    */
    function geocentricToWgs84(p, datum_type, datum_params) {

      if (datum_type === PJD_3PARAM) {
        // if( x[io] === HUGE_VAL )
        //    continue;
        return {
          x: p.x + datum_params[0],
          y: p.y + datum_params[1],
          z: p.z + datum_params[2],
        };
      } else if (datum_type === PJD_7PARAM) {
        var Dx_BF = datum_params[0];
        var Dy_BF = datum_params[1];
        var Dz_BF = datum_params[2];
        var Rx_BF = datum_params[3];
        var Ry_BF = datum_params[4];
        var Rz_BF = datum_params[5];
        var M_BF = datum_params[6];
        // if( x[io] === HUGE_VAL )
        //    continue;
        return {
          x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
          y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
          z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
        };
      }
    } // cs_geocentric_to_wgs84

    /****************************************************************/
    // pj_geocentic_from_wgs84()
    //  coordinate system definition,
    //  point to transform in geocentric coordinates (x,y,z)
    function geocentricFromWgs84(p, datum_type, datum_params) {

      if (datum_type === PJD_3PARAM) {
        //if( x[io] === HUGE_VAL )
        //    continue;
        return {
          x: p.x - datum_params[0],
          y: p.y - datum_params[1],
          z: p.z - datum_params[2],
        };

      } else if (datum_type === PJD_7PARAM) {
        var Dx_BF = datum_params[0];
        var Dy_BF = datum_params[1];
        var Dz_BF = datum_params[2];
        var Rx_BF = datum_params[3];
        var Ry_BF = datum_params[4];
        var Rz_BF = datum_params[5];
        var M_BF = datum_params[6];
        var x_tmp = (p.x - Dx_BF) / M_BF;
        var y_tmp = (p.y - Dy_BF) / M_BF;
        var z_tmp = (p.z - Dz_BF) / M_BF;
        //if( x[io] === HUGE_VAL )
        //    continue;

        return {
          x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
          y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
          z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
        };
      } //cs_geocentric_from_wgs84()
    }

    function checkParams(type) {
      return (type === PJD_3PARAM || type === PJD_7PARAM);
    }

    var datum_transform = function(source, dest, point) {
      // Short cut if the datums are identical.
      if (compareDatums(source, dest)) {
        return point; // in this case, zero is sucess,
        // whereas cs_compare_datums returns 1 to indicate TRUE
        // confusing, should fix this
      }

      // Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest
      if (source.datum_type === PJD_NODATUM || dest.datum_type === PJD_NODATUM) {
        return point;
      }

      // If this datum requires grid shifts, then apply it to geodetic coordinates.
      var source_a = source.a;
      var source_es = source.es;
      if (source.datum_type === PJD_GRIDSHIFT) {
        var gridShiftCode = applyGridShift(source, false, point);
        if (gridShiftCode !== 0) {
          return undefined;
        }
        source_a = SRS_WGS84_SEMIMAJOR;
        source_es = SRS_WGS84_ESQUARED;
      }

      var dest_a = dest.a;
      var dest_b = dest.b;
      var dest_es = dest.es;
      if (dest.datum_type === PJD_GRIDSHIFT) {
        dest_a = SRS_WGS84_SEMIMAJOR;
        dest_b = SRS_WGS84_SEMIMINOR;
        dest_es = SRS_WGS84_ESQUARED;
      }

      // Do we need to go through geocentric coordinates?
      if (source_es === dest_es && source_a === dest_a && !checkParams(source.datum_type) &&  !checkParams(dest.datum_type)) {
        return point;
      }

      // Convert to geocentric coordinates.
      point = geodeticToGeocentric(point, source_es, source_a);
      // Convert between datums
      if (checkParams(source.datum_type)) {
        point = geocentricToWgs84(point, source.datum_type, source.datum_params);
      }
      if (checkParams(dest.datum_type)) {
        point = geocentricFromWgs84(point, dest.datum_type, dest.datum_params);
      }
      point = geocentricToGeodetic(point, dest_es, dest_a, dest_b);

      if (dest.datum_type === PJD_GRIDSHIFT) {
        var destGridShiftResult = applyGridShift(dest, true, point);
        if (destGridShiftResult !== 0) {
          return undefined;
        }
      }

      return point;
    };

    function applyGridShift(source, inverse, point) {
      if (source.grids === null || source.grids.length === 0) {
        console.log('Grid shift grids not found');
        return -1;
      }
      var input = {x: -point.x, y: point.y};
      var output = {x: Number.NaN, y: Number.NaN};
      var attemptedGrids = [];
      for (var i = 0; i < source.grids.length; i++) {
        var grid = source.grids[i];
        attemptedGrids.push(grid.name);
        if (grid.isNull) {
          output = input;
          break;
        }
        if (grid.grid === null) {
          if (grid.mandatory) {
            console.log("Unable to find mandatory grid '" + grid.name + "'");
            return -1;
          }
          continue;
        }
        var subgrid = grid.grid.subgrids[0];
        // skip tables that don't match our point at all
        var epsilon = (Math.abs(subgrid.del[1]) + Math.abs(subgrid.del[0])) / 10000.0;
        var minX = subgrid.ll[0] - epsilon;
        var minY = subgrid.ll[1] - epsilon;
        var maxX = subgrid.ll[0] + (subgrid.lim[0] - 1) * subgrid.del[0] + epsilon;
        var maxY = subgrid.ll[1] + (subgrid.lim[1] - 1) * subgrid.del[1] + epsilon;
        if (minY > input.y || minX > input.x || maxY < input.y || maxX < input.x ) {
          continue;
        }
        output = applySubgridShift(input, inverse, subgrid);
        if (!isNaN(output.x)) {
          break;
        }
      }
      if (isNaN(output.x)) {
        console.log("Failed to find a grid shift table for location '"+
          -input.x * R2D + " " + input.y * R2D + " tried: '" + attemptedGrids + "'");
        return -1;
      }
      point.x = -output.x;
      point.y = output.y;
      return 0;
    }

    function applySubgridShift(pin, inverse, ct) {
      var val = {x: Number.NaN, y: Number.NaN};
      if (isNaN(pin.x)) { return val; }
      var tb = {x: pin.x, y: pin.y};
      tb.x -= ct.ll[0];
      tb.y -= ct.ll[1];
      tb.x = adjust_lon(tb.x - Math.PI) + Math.PI;
      var t = nadInterpolate(tb, ct);
      if (inverse) {
        if (isNaN(t.x)) {
          return val;
        }
        t.x = tb.x - t.x;
        t.y = tb.y - t.y;
        var i = 9, tol = 1e-12;
        var dif, del;
        do {
          del = nadInterpolate(t, ct);
          if (isNaN(del.x)) {
            console.log("Inverse grid shift iteration failed, presumably at grid edge.  Using first approximation.");
            break;
          }
          dif = {x: tb.x - (del.x + t.x), y: tb.y - (del.y + t.y)};
          t.x += dif.x;
          t.y += dif.y;
        } while (i-- && Math.abs(dif.x) > tol && Math.abs(dif.y) > tol);
        if (i < 0) {
          console.log("Inverse grid shift iterator failed to converge.");
          return val;
        }
        val.x = adjust_lon(t.x + ct.ll[0]);
        val.y = t.y + ct.ll[1];
      } else {
        if (!isNaN(t.x)) {
          val.x = pin.x + t.x;
          val.y = pin.y + t.y;
        }
      }
      return val;
    }

    function nadInterpolate(pin, ct) {
      var t = {x: pin.x / ct.del[0], y: pin.y / ct.del[1]};
      var indx = {x: Math.floor(t.x), y: Math.floor(t.y)};
      var frct = {x: t.x - 1.0 * indx.x, y: t.y - 1.0 * indx.y};
      var val= {x: Number.NaN, y: Number.NaN};
      var inx;
      if (indx.x < 0 || indx.x >= ct.lim[0]) {
        return val;
      }
      if (indx.y < 0 || indx.y >= ct.lim[1]) {
        return val;
      }
      inx = (indx.y * ct.lim[0]) + indx.x;
      var f00 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]};
      inx++;
      var f10= {x: ct.cvs[inx][0], y: ct.cvs[inx][1]};
      inx += ct.lim[0];
      var f11 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]};
      inx--;
      var f01 = {x: ct.cvs[inx][0], y: ct.cvs[inx][1]};
      var m11 = frct.x * frct.y, m10 = frct.x * (1.0 - frct.y),
        m00 = (1.0 - frct.x) * (1.0 - frct.y), m01 = (1.0 - frct.x) * frct.y;
      val.x = (m00 * f00.x + m10 * f10.x + m01 * f01.x + m11 * f11.x);
      val.y = (m00 * f00.y + m10 * f10.y + m01 * f01.y + m11 * f11.y);
      return val;
    }

    var adjust_axis = function(crs, denorm, point) {
      var xin = point.x,
        yin = point.y,
        zin = point.z || 0.0;
      var v, t, i;
      var out = {};
      for (i = 0; i < 3; i++) {
        if (denorm && i === 2 && point.z === undefined) {
          continue;
        }
        if (i === 0) {
          v = xin;
          if ("ew".indexOf(crs.axis[i]) !== -1) {
            t = 'x';
          } else {
            t = 'y';
          }

        }
        else if (i === 1) {
          v = yin;
          if ("ns".indexOf(crs.axis[i]) !== -1) {
            t = 'y';
          } else {
            t = 'x';
          }
        }
        else {
          v = zin;
          t = 'z';
        }
        switch (crs.axis[i]) {
        case 'e':
          out[t] = v;
          break;
        case 'w':
          out[t] = -v;
          break;
        case 'n':
          out[t] = v;
          break;
        case 's':
          out[t] = -v;
          break;
        case 'u':
          if (point[t] !== undefined) {
            out.z = v;
          }
          break;
        case 'd':
          if (point[t] !== undefined) {
            out.z = -v;
          }
          break;
        default:
          //console.log("ERROR: unknow axis ("+crs.axis[i]+") - check definition of "+crs.projName);
          return null;
        }
      }
      return out;
    };

    var toPoint = function (array){
      var out = {
        x: array[0],
        y: array[1]
      };
      if (array.length>2) {
        out.z = array[2];
      }
      if (array.length>3) {
        out.m = array[3];
      }
      return out;
    };

    var checkSanity = function (point) {
      checkCoord(point.x);
      checkCoord(point.y);
    };
    function checkCoord(num) {
      if (typeof Number.isFinite === 'function') {
        if (Number.isFinite(num)) {
          return;
        }
        throw new TypeError('coordinates must be finite numbers');
      }
      if (typeof num !== 'number' || num !== num || !isFinite(num)) {
        throw new TypeError('coordinates must be finite numbers');
      }
    }

    function checkNotWGS(source, dest) {
      return ((source.datum.datum_type === PJD_3PARAM || source.datum.datum_type === PJD_7PARAM) && dest.datumCode !== 'WGS84') || ((dest.datum.datum_type === PJD_3PARAM || dest.datum.datum_type === PJD_7PARAM) && source.datumCode !== 'WGS84');
    }

    function transform(source, dest, point, enforceAxis) {
      var wgs84;
      if (Array.isArray(point)) {
        point = toPoint(point);
      }
      checkSanity(point);
      // Workaround for datum shifts towgs84, if either source or destination projection is not wgs84
      if (source.datum && dest.datum && checkNotWGS(source, dest)) {
        wgs84 = new Projection('WGS84');
        point = transform(source, wgs84, point, enforceAxis);
        source = wgs84;
      }
      // DGR, 2010/11/12
      if (enforceAxis && source.axis !== 'enu') {
        point = adjust_axis(source, false, point);
      }
      // Transform source points to long/lat, if they aren't already.
      if (source.projName === 'longlat') {
        point = {
          x: point.x * D2R,
          y: point.y * D2R,
          z: point.z || 0
        };
      } else {
        if (source.to_meter) {
          point = {
            x: point.x * source.to_meter,
            y: point.y * source.to_meter,
            z: point.z || 0
          };
        }
        point = source.inverse(point); // Convert Cartesian to longlat
        if (!point) {
          return;
        }
      }
      // Adjust for the prime meridian if necessary
      if (source.from_greenwich) {
        point.x += source.from_greenwich;
      }

      // Convert datums if needed, and if possible.
      point = datum_transform(source.datum, dest.datum, point);
      if (!point) {
        return;
      }

      // Adjust for the prime meridian if necessary
      if (dest.from_greenwich) {
        point = {
          x: point.x - dest.from_greenwich,
          y: point.y,
          z: point.z || 0
        };
      }

      if (dest.projName === 'longlat') {
        // convert radians to decimal degrees
        point = {
          x: point.x * R2D,
          y: point.y * R2D,
          z: point.z || 0
        };
      } else { // else project
        point = dest.forward(point);
        if (dest.to_meter) {
          point = {
            x: point.x / dest.to_meter,
            y: point.y / dest.to_meter,
            z: point.z || 0
          };
        }
      }

      // DGR, 2010/11/12
      if (enforceAxis && dest.axis !== 'enu') {
        return adjust_axis(dest, true, point);
      }

      return point;
    }

    var wgs84 = Projection('WGS84');

    function transformer(from, to, coords, enforceAxis) {
      var transformedArray, out, keys;
      if (Array.isArray(coords)) {
        transformedArray = transform(from, to, coords, enforceAxis) || {x: NaN, y: NaN};
        if (coords.length > 2) {
          if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
            if (typeof transformedArray.z === 'number') {
              return [transformedArray.x, transformedArray.y, transformedArray.z].concat(coords.splice(3));
            } else {
              return [transformedArray.x, transformedArray.y, coords[2]].concat(coords.splice(3));
            }
          } else {
            return [transformedArray.x, transformedArray.y].concat(coords.splice(2));
          }
        } else {
          return [transformedArray.x, transformedArray.y];
        }
      } else {
        out = transform(from, to, coords, enforceAxis);
        keys = Object.keys(coords);
        if (keys.length === 2) {
          return out;
        }
        keys.forEach(function (key) {
          if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
            if (key === 'x' || key === 'y' || key === 'z') {
              return;
            }
          } else {
            if (key === 'x' || key === 'y') {
              return;
            }
          }
          out[key] = coords[key];
        });
        return out;
      }
    }

    function checkProj(item) {
      if (item instanceof Projection) {
        return item;
      }
      if (item.oProj) {
        return item.oProj;
      }
      return Projection(item);
    }

    function proj4$1(fromProj, toProj, coord) {
      fromProj = checkProj(fromProj);
      var single = false;
      var obj;
      if (typeof toProj === 'undefined') {
        toProj = fromProj;
        fromProj = wgs84;
        single = true;
      } else if (typeof toProj.x !== 'undefined' || Array.isArray(toProj)) {
        coord = toProj;
        toProj = fromProj;
        fromProj = wgs84;
        single = true;
      }
      toProj = checkProj(toProj);
      if (coord) {
        return transformer(fromProj, toProj, coord);
      } else {
        obj = {
          forward: function (coords, enforceAxis) {
            return transformer(fromProj, toProj, coords, enforceAxis);
          },
          inverse: function (coords, enforceAxis) {
            return transformer(toProj, fromProj, coords, enforceAxis);
          }
        };
        if (single) {
          obj.oProj = toProj;
        }
        return obj;
      }
    }

    /**
     * UTM zones are grouped, and assigned to one of a group of 6
     * sets.
     *
     * {int} @private
     */
    var NUM_100K_SETS = 6;

    /**
     * The column letters (for easting) of the lower left value, per
     * set.
     *
     * {string} @private
     */
    var SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS';

    /**
     * The row letters (for northing) of the lower left value, per
     * set.
     *
     * {string} @private
     */
    var SET_ORIGIN_ROW_LETTERS = 'AFAFAF';

    var A = 65; // A
    var I = 73; // I
    var O = 79; // O
    var V = 86; // V
    var Z = 90; // Z
    var mgrs = {
      forward: forward$1,
      inverse: inverse$1,
      toPoint: toPoint$1
    };
    /**
     * Conversion of lat/lon to MGRS.
     *
     * @param {object} ll Object literal with lat and lon properties on a
     *     WGS84 ellipsoid.
     * @param {int} accuracy Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for
     *      100 m, 2 for 1000 m or 1 for 10000 m). Optional, default is 5.
     * @return {string} the MGRS string for the given location and accuracy.
     */
    function forward$1(ll, accuracy) {
      accuracy = accuracy || 5; // default accuracy 1m
      return encode(LLtoUTM({
        lat: ll[1],
        lon: ll[0]
      }), accuracy);
    }

    /**
     * Conversion of MGRS to lat/lon.
     *
     * @param {string} mgrs MGRS string.
     * @return {array} An array with left (longitude), bottom (latitude), right
     *     (longitude) and top (latitude) values in WGS84, representing the
     *     bounding box for the provided MGRS reference.
     */
    function inverse$1(mgrs) {
      var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
      if (bbox.lat && bbox.lon) {
        return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];
      }
      return [bbox.left, bbox.bottom, bbox.right, bbox.top];
    }

    function toPoint$1(mgrs) {
      var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
      if (bbox.lat && bbox.lon) {
        return [bbox.lon, bbox.lat];
      }
      return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];
    }
    /**
     * Conversion from degrees to radians.
     *
     * @private
     * @param {number} deg the angle in degrees.
     * @return {number} the angle in radians.
     */
    function degToRad(deg) {
      return (deg * (Math.PI / 180.0));
    }

    /**
     * Conversion from radians to degrees.
     *
     * @private
     * @param {number} rad the angle in radians.
     * @return {number} the angle in degrees.
     */
    function radToDeg(rad) {
      return (180.0 * (rad / Math.PI));
    }

    /**
     * Converts a set of Longitude and Latitude co-ordinates to UTM
     * using the WGS84 ellipsoid.
     *
     * @private
     * @param {object} ll Object literal with lat and lon properties
     *     representing the WGS84 coordinate to be converted.
     * @return {object} Object literal containing the UTM value with easting,
     *     northing, zoneNumber and zoneLetter properties, and an optional
     *     accuracy property in digits. Returns null if the conversion failed.
     */
    function LLtoUTM(ll) {
      var Lat = ll.lat;
      var Long = ll.lon;
      var a = 6378137.0; //ellip.radius;
      var eccSquared = 0.00669438; //ellip.eccsq;
      var k0 = 0.9996;
      var LongOrigin;
      var eccPrimeSquared;
      var N, T, C, A, M;
      var LatRad = degToRad(Lat);
      var LongRad = degToRad(Long);
      var LongOriginRad;
      var ZoneNumber;
      // (int)
      ZoneNumber = Math.floor((Long + 180) / 6) + 1;

      //Make sure the longitude 180.00 is in Zone 60
      if (Long === 180) {
        ZoneNumber = 60;
      }

      // Special zone for Norway
      if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) {
        ZoneNumber = 32;
      }

      // Special zones for Svalbard
      if (Lat >= 72.0 && Lat < 84.0) {
        if (Long >= 0.0 && Long < 9.0) {
          ZoneNumber = 31;
        }
        else if (Long >= 9.0 && Long < 21.0) {
          ZoneNumber = 33;
        }
        else if (Long >= 21.0 && Long < 33.0) {
          ZoneNumber = 35;
        }
        else if (Long >= 33.0 && Long < 42.0) {
          ZoneNumber = 37;
        }
      }

      LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin
      // in middle of
      // zone
      LongOriginRad = degToRad(LongOrigin);

      eccPrimeSquared = (eccSquared) / (1 - eccSquared);

      N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad));
      T = Math.tan(LatRad) * Math.tan(LatRad);
      C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);
      A = Math.cos(LatRad) * (LongRad - LongOriginRad);

      M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad));

      var UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0) + 500000.0);

      var UTMNorthing = (k0 * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720.0)));
      if (Lat < 0.0) {
        UTMNorthing += 10000000.0; //10000000 meter offset for
        // southern hemisphere
      }

      return {
        northing: Math.round(UTMNorthing),
        easting: Math.round(UTMEasting),
        zoneNumber: ZoneNumber,
        zoneLetter: getLetterDesignator(Lat)
      };
    }

    /**
     * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience
     * class where the Zone can be specified as a single string eg."60N" which
     * is then broken down into the ZoneNumber and ZoneLetter.
     *
     * @private
     * @param {object} utm An object literal with northing, easting, zoneNumber
     *     and zoneLetter properties. If an optional accuracy property is
     *     provided (in meters), a bounding box will be returned instead of
     *     latitude and longitude.
     * @return {object} An object literal containing either lat and lon values
     *     (if no accuracy was provided), or top, right, bottom and left values
     *     for the bounding box calculated according to the provided accuracy.
     *     Returns null if the conversion failed.
     */
    function UTMtoLL(utm) {

      var UTMNorthing = utm.northing;
      var UTMEasting = utm.easting;
      var zoneLetter = utm.zoneLetter;
      var zoneNumber = utm.zoneNumber;
      // check the ZoneNummber is valid
      if (zoneNumber < 0 || zoneNumber > 60) {
        return null;
      }

      var k0 = 0.9996;
      var a = 6378137.0; //ellip.radius;
      var eccSquared = 0.00669438; //ellip.eccsq;
      var eccPrimeSquared;
      var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
      var N1, T1, C1, R1, D, M;
      var LongOrigin;
      var mu, phi1Rad;

      // remove 500,000 meter offset for longitude
      var x = UTMEasting - 500000.0;
      var y = UTMNorthing;

      // We must know somehow if we are in the Northern or Southern
      // hemisphere, this is the only time we use the letter So even
      // if the Zone letter isn't exactly correct it should indicate
      // the hemisphere correctly
      if (zoneLetter < 'N') {
        y -= 10000000.0; // remove 10,000,000 meter offset used
        // for southern hemisphere
      }

      // There are 60 zones with zone 1 being at West -180 to -174
      LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
      // in middle of
      // zone

      eccPrimeSquared = (eccSquared) / (1 - eccSquared);

      M = y / k0;
      mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));

      phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);
      // double phi1 = ProjMath.radToDeg(phi1Rad);

      N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
      T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
      C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
      R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
      D = x / (N1 * k0);

      var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
      lat = radToDeg(lat);

      var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);
      lon = LongOrigin + radToDeg(lon);

      var result;
      if (utm.accuracy) {
        var topRight = UTMtoLL({
          northing: utm.northing + utm.accuracy,
          easting: utm.easting + utm.accuracy,
          zoneLetter: utm.zoneLetter,
          zoneNumber: utm.zoneNumber
        });
        result = {
          top: topRight.lat,
          right: topRight.lon,
          bottom: lat,
          left: lon
        };
      }
      else {
        result = {
          lat: lat,
          lon: lon
        };
      }
      return result;
    }

    /**
     * Calculates the MGRS letter designator for the given latitude.
     *
     * @private
     * @param {number} lat The latitude in WGS84 to get the letter designator
     *     for.
     * @return {char} The letter designator.
     */
    function getLetterDesignator(lat) {
      //This is here as an error flag to show that the Latitude is
      //outside MGRS limits
      var LetterDesignator = 'Z';

      if ((84 >= lat) && (lat >= 72)) {
        LetterDesignator = 'X';
      }
      else if ((72 > lat) && (lat >= 64)) {
        LetterDesignator = 'W';
      }
      else if ((64 > lat) && (lat >= 56)) {
        LetterDesignator = 'V';
      }
      else if ((56 > lat) && (lat >= 48)) {
        LetterDesignator = 'U';
      }
      else if ((48 > lat) && (lat >= 40)) {
        LetterDesignator = 'T';
      }
      else if ((40 > lat) && (lat >= 32)) {
        LetterDesignator = 'S';
      }
      else if ((32 > lat) && (lat >= 24)) {
        LetterDesignator = 'R';
      }
      else if ((24 > lat) && (lat >= 16)) {
        LetterDesignator = 'Q';
      }
      else if ((16 > lat) && (lat >= 8)) {
        LetterDesignator = 'P';
      }
      else if ((8 > lat) && (lat >= 0)) {
        LetterDesignator = 'N';
      }
      else if ((0 > lat) && (lat >= -8)) {
        LetterDesignator = 'M';
      }
      else if ((-8 > lat) && (lat >= -16)) {
        LetterDesignator = 'L';
      }
      else if ((-16 > lat) && (lat >= -24)) {
        LetterDesignator = 'K';
      }
      else if ((-24 > lat) && (lat >= -32)) {
        LetterDesignator = 'J';
      }
      else if ((-32 > lat) && (lat >= -40)) {
        LetterDesignator = 'H';
      }
      else if ((-40 > lat) && (lat >= -48)) {
        LetterDesignator = 'G';
      }
      else if ((-48 > lat) && (lat >= -56)) {
        LetterDesignator = 'F';
      }
      else if ((-56 > lat) && (lat >= -64)) {
        LetterDesignator = 'E';
      }
      else if ((-64 > lat) && (lat >= -72)) {
        LetterDesignator = 'D';
      }
      else if ((-72 > lat) && (lat >= -80)) {
        LetterDesignator = 'C';
      }
      return LetterDesignator;
    }

    /**
     * Encodes a UTM location as MGRS string.
     *
     * @private
     * @param {object} utm An object literal with easting, northing,
     *     zoneLetter, zoneNumber
     * @param {number} accuracy Accuracy in digits (1-5).
     * @return {string} MGRS string for the given UTM location.
     */
    function encode(utm, accuracy) {
      // prepend with leading zeroes
      var seasting = "00000" + utm.easting,
        snorthing = "00000" + utm.northing;

      return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);
    }

    /**
     * Get the two letter 100k designator for a given UTM easting,
     * northing and zone number value.
     *
     * @private
     * @param {number} easting
     * @param {number} northing
     * @param {number} zoneNumber
     * @return the two letter 100k designator for the given UTM location.
     */
    function get100kID(easting, northing, zoneNumber) {
      var setParm = get100kSetForZone(zoneNumber);
      var setColumn = Math.floor(easting / 100000);
      var setRow = Math.floor(northing / 100000) % 20;
      return getLetter100kID(setColumn, setRow, setParm);
    }

    /**
     * Given a UTM zone number, figure out the MGRS 100K set it is in.
     *
     * @private
     * @param {number} i An UTM zone number.
     * @return {number} the 100k set the UTM zone is in.
     */
    function get100kSetForZone(i) {
      var setParm = i % NUM_100K_SETS;
      if (setParm === 0) {
        setParm = NUM_100K_SETS;
      }

      return setParm;
    }

    /**
     * Get the two-letter MGRS 100k designator given information
     * translated from the UTM northing, easting and zone number.
     *
     * @private
     * @param {number} column the column index as it relates to the MGRS
     *        100k set spreadsheet, created from the UTM easting.
     *        Values are 1-8.
     * @param {number} row the row index as it relates to the MGRS 100k set
     *        spreadsheet, created from the UTM northing value. Values
     *        are from 0-19.
     * @param {number} parm the set block, as it relates to the MGRS 100k set
     *        spreadsheet, created from the UTM zone. Values are from
     *        1-60.
     * @return two letter MGRS 100k code.
     */
    function getLetter100kID(column, row, parm) {
      // colOrigin and rowOrigin are the letters at the origin of the set
      var index = parm - 1;
      var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);
      var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);

      // colInt and rowInt are the letters to build to return
      var colInt = colOrigin + column - 1;
      var rowInt = rowOrigin + row;
      var rollover = false;

      if (colInt > Z) {
        colInt = colInt - Z + A - 1;
        rollover = true;
      }

      if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {
        colInt++;
      }

      if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {
        colInt++;

        if (colInt === I) {
          colInt++;
        }
      }

      if (colInt > Z) {
        colInt = colInt - Z + A - 1;
      }

      if (rowInt > V) {
        rowInt = rowInt - V + A - 1;
        rollover = true;
      }
      else {
        rollover = false;
      }

      if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) {
        rowInt++;
      }

      if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {
        rowInt++;

        if (rowInt === I) {
          rowInt++;
        }
      }

      if (rowInt > V) {
        rowInt = rowInt - V + A - 1;
      }

      var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);
      return twoLetter;
    }

    /**
     * Decode the UTM parameters from a MGRS string.
     *
     * @private
     * @param {string} mgrsString an UPPERCASE coordinate string is expected.
     * @return {object} An object literal with easting, northing, zoneLetter,
     *     zoneNumber and accuracy (in meters) properties.
     */
    function decode(mgrsString) {

      if (mgrsString && mgrsString.length === 0) {
        throw ("MGRSPoint coverting from nothing");
      }

      var length = mgrsString.length;

      var hunK = null;
      var sb = "";
      var testChar;
      var i = 0;

      // get Zone number
      while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {
        if (i >= 2) {
          throw ("MGRSPoint bad conversion from: " + mgrsString);
        }
        sb += testChar;
        i++;
      }

      var zoneNumber = parseInt(sb, 10);

      if (i === 0 || i + 3 > length) {
        // A good MGRS string has to be 4-5 digits long,
        // ##AAA/#AAA at least.
        throw ("MGRSPoint bad conversion from: " + mgrsString);
      }

      var zoneLetter = mgrsString.charAt(i++);

      // Should we check the zone letter here? Why not.
      if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') {
        throw ("MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString);
      }

      hunK = mgrsString.substring(i, i += 2);

      var set = get100kSetForZone(zoneNumber);

      var east100k = getEastingFromChar(hunK.charAt(0), set);
      var north100k = getNorthingFromChar(hunK.charAt(1), set);

      // We have a bug where the northing may be 2000000 too low.
      // How
      // do we know when to roll over?

      while (north100k < getMinNorthing(zoneLetter)) {
        north100k += 2000000;
      }

      // calculate the char index for easting/northing separator
      var remainder = length - i;

      if (remainder % 2 !== 0) {
        throw ("MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString);
      }

      var sep = remainder / 2;

      var sepEasting = 0.0;
      var sepNorthing = 0.0;
      var accuracyBonus, sepEastingString, sepNorthingString, easting, northing;
      if (sep > 0) {
        accuracyBonus = 100000.0 / Math.pow(10, sep);
        sepEastingString = mgrsString.substring(i, i + sep);
        sepEasting = parseFloat(sepEastingString) * accuracyBonus;
        sepNorthingString = mgrsString.substring(i + sep);
        sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;
      }

      easting = sepEasting + east100k;
      northing = sepNorthing + north100k;

      return {
        easting: easting,
        northing: northing,
        zoneLetter: zoneLetter,
        zoneNumber: zoneNumber,
        accuracy: accuracyBonus
      };
    }

    /**
     * Given the first letter from a two-letter MGRS 100k zone, and given the
     * MGRS table set for the zone number, figure out the easting value that
     * should be added to the other, secondary easting value.
     *
     * @private
     * @param {char} e The first letter from a two-letter MGRS 100´k zone.
     * @param {number} set The MGRS table set for the zone number.
     * @return {number} The easting value for the given letter and set.
     */
    function getEastingFromChar(e, set) {
      // colOrigin is the letter at the origin of the set for the
      // column
      var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1);
      var eastingValue = 100000.0;
      var rewindMarker = false;

      while (curCol !== e.charCodeAt(0)) {
        curCol++;
        if (curCol === I) {
          curCol++;
        }
        if (curCol === O) {
          curCol++;
        }
        if (curCol > Z) {
          if (rewindMarker) {
            throw ("Bad character: " + e);
          }
          curCol = A;
          rewindMarker = true;
        }
        eastingValue += 100000.0;
      }

      return eastingValue;
    }

    /**
     * Given the second letter from a two-letter MGRS 100k zone, and given the
     * MGRS table set for the zone number, figure out the northing value that
     * should be added to the other, secondary northing value. You have to
     * remember that Northings are determined from the equator, and the vertical
     * cycle of letters mean a 2000000 additional northing meters. This happens
     * approx. every 18 degrees of latitude. This method does *NOT* count any
     * additional northings. You have to figure out how many 2000000 meters need
     * to be added for the zone letter of the MGRS coordinate.
     *
     * @private
     * @param {char} n Second letter of the MGRS 100k zone
     * @param {number} set The MGRS table set number, which is dependent on the
     *     UTM zone number.
     * @return {number} The northing value for the given letter and set.
     */
    function getNorthingFromChar(n, set) {

      if (n > 'V') {
        throw ("MGRSPoint given invalid Northing " + n);
      }

      // rowOrigin is the letter at the origin of the set for the
      // column
      var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1);
      var northingValue = 0.0;
      var rewindMarker = false;

      while (curRow !== n.charCodeAt(0)) {
        curRow++;
        if (curRow === I) {
          curRow++;
        }
        if (curRow === O) {
          curRow++;
        }
        // fixing a bug making whole application hang in this loop
        // when 'n' is a wrong character
        if (curRow > V) {
          if (rewindMarker) { // making sure that this loop ends
            throw ("Bad character: " + n);
          }
          curRow = A;
          rewindMarker = true;
        }
        northingValue += 100000.0;
      }

      return northingValue;
    }

    /**
     * The function getMinNorthing returns the minimum northing value of a MGRS
     * zone.
     *
     * Ported from Geotrans' c Lattitude_Band_Value structure table.
     *
     * @private
     * @param {char} zoneLetter The MGRS zone to get the min northing for.
     * @return {number}
     */
    function getMinNorthing(zoneLetter) {
      var northing;
      switch (zoneLetter) {
      case 'C':
        northing = 1100000.0;
        break;
      case 'D':
        northing = 2000000.0;
        break;
      case 'E':
        northing = 2800000.0;
        break;
      case 'F':
        northing = 3700000.0;
        break;
      case 'G':
        northing = 4600000.0;
        break;
      case 'H':
        northing = 5500000.0;
        break;
      case 'J':
        northing = 6400000.0;
        break;
      case 'K':
        northing = 7300000.0;
        break;
      case 'L':
        northing = 8200000.0;
        break;
      case 'M':
        northing = 9100000.0;
        break;
      case 'N':
        northing = 0.0;
        break;
      case 'P':
        northing = 800000.0;
        break;
      case 'Q':
        northing = 1700000.0;
        break;
      case 'R':
        northing = 2600000.0;
        break;
      case 'S':
        northing = 3500000.0;
        break;
      case 'T':
        northing = 4400000.0;
        break;
      case 'U':
        northing = 5300000.0;
        break;
      case 'V':
        northing = 6200000.0;
        break;
      case 'W':
        northing = 7000000.0;
        break;
      case 'X':
        northing = 7900000.0;
        break;
      default:
        northing = -1.0;
      }
      if (northing >= 0.0) {
        return northing;
      }
      else {
        throw ("Invalid zone letter: " + zoneLetter);
      }

    }

    function Point(x, y, z) {
      if (!(this instanceof Point)) {
        return new Point(x, y, z);
      }
      if (Array.isArray(x)) {
        this.x = x[0];
        this.y = x[1];
        this.z = x[2] || 0.0;
      } else if(typeof x === 'object') {
        this.x = x.x;
        this.y = x.y;
        this.z = x.z || 0.0;
      } else if (typeof x === 'string' && typeof y === 'undefined') {
        var coords = x.split(',');
        this.x = parseFloat(coords[0], 10);
        this.y = parseFloat(coords[1], 10);
        this.z = parseFloat(coords[2], 10) || 0.0;
      } else {
        this.x = x;
        this.y = y;
        this.z = z || 0.0;
      }
      console.warn('proj4.Point will be removed in version 3, use proj4.toPoint');
    }

    Point.fromMGRS = function(mgrsStr) {
      return new Point(toPoint$1(mgrsStr));
    };
    Point.prototype.toMGRS = function(accuracy) {
      return forward$1([this.x, this.y], accuracy);
    };

    var C00 = 1;
    var C02 = 0.25;
    var C04 = 0.046875;
    var C06 = 0.01953125;
    var C08 = 0.01068115234375;
    var C22 = 0.75;
    var C44 = 0.46875;
    var C46 = 0.01302083333333333333;
    var C48 = 0.00712076822916666666;
    var C66 = 0.36458333333333333333;
    var C68 = 0.00569661458333333333;
    var C88 = 0.3076171875;

    var pj_enfn = function(es) {
      var en = [];
      en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08)));
      en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08)));
      var t = es * es;
      en[2] = t * (C44 - es * (C46 + es * C48));
      t *= es;
      en[3] = t * (C66 - es * C68);
      en[4] = t * es * C88;
      return en;
    };

    var pj_mlfn = function(phi, sphi, cphi, en) {
      cphi *= sphi;
      sphi *= sphi;
      return (en[0] * phi - cphi * (en[1] + sphi * (en[2] + sphi * (en[3] + sphi * en[4]))));
    };

    var MAX_ITER = 20;

    var pj_inv_mlfn = function(arg, es, en) {
      var k = 1 / (1 - es);
      var phi = arg;
      for (var i = MAX_ITER; i; --i) { /* rarely goes over 2 iterations */
        var s = Math.sin(phi);
        var t = 1 - es * s * s;
        //t = this.pj_mlfn(phi, s, Math.cos(phi), en) - arg;
        //phi -= t * (t * Math.sqrt(t)) * k;
        t = (pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
        phi -= t;
        if (Math.abs(t) < EPSLN) {
          return phi;
        }
      }
      //..reportError("cass:pj_inv_mlfn: Convergence error");
      return phi;
    };

    // Heavily based on this tmerc projection implementation
    // https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js

    function init$2() {
      this.x0 = this.x0 !== undefined ? this.x0 : 0;
      this.y0 = this.y0 !== undefined ? this.y0 : 0;
      this.long0 = this.long0 !== undefined ? this.long0 : 0;
      this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;

      if (this.es) {
        this.en = pj_enfn(this.es);
        this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
      }
    }

    /**
        Transverse Mercator Forward  - long/lat to x/y
        long/lat in radians
      */
    function forward$2(p) {
      var lon = p.x;
      var lat = p.y;

      var delta_lon = adjust_lon(lon - this.long0);
      var con;
      var x, y;
      var sin_phi = Math.sin(lat);
      var cos_phi = Math.cos(lat);

      if (!this.es) {
        var b = cos_phi * Math.sin(delta_lon);

        if ((Math.abs(Math.abs(b) - 1)) < EPSLN) {
          return (93);
        }
        else {
          x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0;
          y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2));
          b = Math.abs(y);

          if (b >= 1) {
            if ((b - 1) > EPSLN) {
              return (93);
            }
            else {
              y = 0;
            }
          }
          else {
            y = Math.acos(y);
          }

          if (lat < 0) {
            y = -y;
          }

          y = this.a * this.k0 * (y - this.lat0) + this.y0;
        }
      }
      else {
        var al = cos_phi * delta_lon;
        var als = Math.pow(al, 2);
        var c = this.ep2 * Math.pow(cos_phi, 2);
        var cs = Math.pow(c, 2);
        var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0;
        var t = Math.pow(tq, 2);
        var ts = Math.pow(t, 2);
        con = 1 - this.es * Math.pow(sin_phi, 2);
        al = al / Math.sqrt(con);
        var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en);

        x = this.a * (this.k0 * al * (1 +
          als / 6 * (1 - t + c +
          als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c +
          als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) +
          this.x0;

        y = this.a * (this.k0 * (ml - this.ml0 +
          sin_phi * delta_lon * al / 2 * (1 +
          als / 12 * (5 - t + 9 * c + 4 * cs +
          als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c +
          als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) +
          this.y0;
      }

      p.x = x;
      p.y = y;

      return p;
    }

    /**
        Transverse Mercator Inverse  -  x/y to long/lat
      */
    function inverse$2(p) {
      var con, phi;
      var lat, lon;
      var x = (p.x - this.x0) * (1 / this.a);
      var y = (p.y - this.y0) * (1 / this.a);

      if (!this.es) {
        var f = Math.exp(x / this.k0);
        var g = 0.5 * (f - 1 / f);
        var temp = this.lat0 + y / this.k0;
        var h = Math.cos(temp);
        con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2)));
        lat = Math.asin(con);

        if (y < 0) {
          lat = -lat;
        }

        if ((g === 0) && (h === 0)) {
          lon = 0;
        }
        else {
          lon = adjust_lon(Math.atan2(g, h) + this.long0);
        }
      }
      else { // ellipsoidal form
        con = this.ml0 + y / this.k0;
        phi = pj_inv_mlfn(con, this.es, this.en);

        if (Math.abs(phi) < HALF_PI) {
          var sin_phi = Math.sin(phi);
          var cos_phi = Math.cos(phi);
          var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0;
          var c = this.ep2 * Math.pow(cos_phi, 2);
          var cs = Math.pow(c, 2);
          var t = Math.pow(tan_phi, 2);
          var ts = Math.pow(t, 2);
          con = 1 - this.es * Math.pow(sin_phi, 2);
          var d = x * Math.sqrt(con) / this.k0;
          var ds = Math.pow(d, 2);
          con = con * tan_phi;

          lat = phi - (con * ds / (1 - this.es)) * 0.5 * (1 -
            ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs -
            ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c -
            ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t))));

          lon = adjust_lon(this.long0 + (d * (1 -
            ds / 6 * (1 + 2 * t + c -
            ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c -
            ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi));
        }
        else {
          lat = HALF_PI * sign(y);
          lon = 0;
        }
      }

      p.x = lon;
      p.y = lat;

      return p;
    }

    var names$3 = ["Fast_Transverse_Mercator", "Fast Transverse Mercator"];
    var tmerc = {
      init: init$2,
      forward: forward$2,
      inverse: inverse$2,
      names: names$3
    };

    var sinh = function(x) {
      var r = Math.exp(x);
      r = (r - 1 / r) / 2;
      return r;
    };

    var hypot = function(x, y) {
      x = Math.abs(x);
      y = Math.abs(y);
      var a = Math.max(x, y);
      var b = Math.min(x, y) / (a ? a : 1);

      return a * Math.sqrt(1 + Math.pow(b, 2));
    };

    var log1py = function(x) {
      var y = 1 + x;
      var z = y - 1;

      return z === 0 ? x : x * Math.log(y) / z;
    };

    var asinhy = function(x) {
      var y = Math.abs(x);
      y = log1py(y * (1 + y / (hypot(1, y) + 1)));

      return x < 0 ? -y : y;
    };

    var gatg = function(pp, B) {
      var cos_2B = 2 * Math.cos(2 * B);
      var i = pp.length - 1;
      var h1 = pp[i];
      var h2 = 0;
      var h;

      while (--i >= 0) {
        h = -h2 + cos_2B * h1 + pp[i];
        h2 = h1;
        h1 = h;
      }

      return (B + h * Math.sin(2 * B));
    };

    var clens = function(pp, arg_r) {
      var r = 2 * Math.cos(arg_r);
      var i = pp.length - 1;
      var hr1 = pp[i];
      var hr2 = 0;
      var hr;

      while (--i >= 0) {
        hr = -hr2 + r * hr1 + pp[i];
        hr2 = hr1;
        hr1 = hr;
      }

      return Math.sin(arg_r) * hr;
    };

    var cosh = function(x) {
      var r = Math.exp(x);
      r = (r + 1 / r) / 2;
      return r;
    };

    var clens_cmplx = function(pp, arg_r, arg_i) {
      var sin_arg_r = Math.sin(arg_r);
      var cos_arg_r = Math.cos(arg_r);
      var sinh_arg_i = sinh(arg_i);
      var cosh_arg_i = cosh(arg_i);
      var r = 2 * cos_arg_r * cosh_arg_i;
      var i = -2 * sin_arg_r * sinh_arg_i;
      var j = pp.length - 1;
      var hr = pp[j];
      var hi1 = 0;
      var hr1 = 0;
      var hi = 0;
      var hr2;
      var hi2;

      while (--j >= 0) {
        hr2 = hr1;
        hi2 = hi1;
        hr1 = hr;
        hi1 = hi;
        hr = -hr2 + r * hr1 - i * hi1 + pp[j];
        hi = -hi2 + i * hr1 + r * hi1;
      }

      r = sin_arg_r * cosh_arg_i;
      i = cos_arg_r * sinh_arg_i;

      return [r * hr - i * hi, r * hi + i * hr];
    };

    // Heavily based on this etmerc projection implementation
    // https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/etmerc.js

    function init$3() {
      if (!this.approx && (isNaN(this.es) || this.es <= 0)) {
        throw new Error('Incorrect elliptical usage. Try using the +approx option in the proj string, or PROJECTION["Fast_Transverse_Mercator"] in the WKT.');
      }
      if (this.approx) {
        // When '+approx' is set, use tmerc instead
        tmerc.init.apply(this);
        this.forward = tmerc.forward;
        this.inverse = tmerc.inverse;
      }

      this.x0 = this.x0 !== undefined ? this.x0 : 0;
      this.y0 = this.y0 !== undefined ? this.y0 : 0;
      this.long0 = this.long0 !== undefined ? this.long0 : 0;
      this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;

      this.cgb = [];
      this.cbg = [];
      this.utg = [];
      this.gtu = [];

      var f = this.es / (1 + Math.sqrt(1 - this.es));
      var n = f / (2 - f);
      var np = n;

      this.cgb[0] = n * (2 + n * (-2 / 3 + n * (-2 + n * (116 / 45 + n * (26 / 45 + n * (-2854 / 675 ))))));
      this.cbg[0] = n * (-2 + n * ( 2 / 3 + n * ( 4 / 3 + n * (-82 / 45 + n * (32 / 45 + n * (4642 / 4725))))));

      np = np * n;
      this.cgb[1] = np * (7 / 3 + n * (-8 / 5 + n * (-227 / 45 + n * (2704 / 315 + n * (2323 / 945)))));
      this.cbg[1] = np * (5 / 3 + n * (-16 / 15 + n * ( -13 / 9 + n * (904 / 315 + n * (-1522 / 945)))));

      np = np * n;
      this.cgb[2] = np * (56 / 15 + n * (-136 / 35 + n * (-1262 / 105 + n * (73814 / 2835))));
      this.cbg[2] = np * (-26 / 15 + n * (34 / 21 + n * (8 / 5 + n * (-12686 / 2835))));

      np = np * n;
      this.cgb[3] = np * (4279 / 630 + n * (-332 / 35 + n * (-399572 / 14175)));
      this.cbg[3] = np * (1237 / 630 + n * (-12 / 5 + n * ( -24832 / 14175)));

      np = np * n;
      this.cgb[4] = np * (4174 / 315 + n * (-144838 / 6237));
      this.cbg[4] = np * (-734 / 315 + n * (109598 / 31185));

      np = np * n;
      this.cgb[5] = np * (601676 / 22275);
      this.cbg[5] = np * (444337 / 155925);

      np = Math.pow(n, 2);
      this.Qn = this.k0 / (1 + n) * (1 + np * (1 / 4 + np * (1 / 64 + np / 256)));

      this.utg[0] = n * (-0.5 + n * ( 2 / 3 + n * (-37 / 96 + n * ( 1 / 360 + n * (81 / 512 + n * (-96199 / 604800))))));
      this.gtu[0] = n * (0.5 + n * (-2 / 3 + n * (5 / 16 + n * (41 / 180 + n * (-127 / 288 + n * (7891 / 37800))))));

      this.utg[1] = np * (-1 / 48 + n * (-1 / 15 + n * (437 / 1440 + n * (-46 / 105 + n * (1118711 / 3870720)))));
      this.gtu[1] = np * (13 / 48 + n * (-3 / 5 + n * (557 / 1440 + n * (281 / 630 + n * (-1983433 / 1935360)))));

      np = np * n;
      this.utg[2] = np * (-17 / 480 + n * (37 / 840 + n * (209 / 4480 + n * (-5569 / 90720 ))));
      this.gtu[2] = np * (61 / 240 + n * (-103 / 140 + n * (15061 / 26880 + n * (167603 / 181440))));

      np = np * n;
      this.utg[3] = np * (-4397 / 161280 + n * (11 / 504 + n * (830251 / 7257600)));
      this.gtu[3] = np * (49561 / 161280 + n * (-179 / 168 + n * (6601661 / 7257600)));

      np = np * n;
      this.utg[4] = np * (-4583 / 161280 + n * (108847 / 3991680));
      this.gtu[4] = np * (34729 / 80640 + n * (-3418889 / 1995840));

      np = np * n;
      this.utg[5] = np * (-20648693 / 638668800);
      this.gtu[5] = np * (212378941 / 319334400);

      var Z = gatg(this.cbg, this.lat0);
      this.Zb = -this.Qn * (Z + clens(this.gtu, 2 * Z));
    }

    function forward$3(p) {
      var Ce = adjust_lon(p.x - this.long0);
      var Cn = p.y;

      Cn = gatg(this.cbg, Cn);
      var sin_Cn = Math.sin(Cn);
      var cos_Cn = Math.cos(Cn);
      var sin_Ce = Math.sin(Ce);
      var cos_Ce = Math.cos(Ce);

      Cn = Math.atan2(sin_Cn, cos_Ce * cos_Cn);
      Ce = Math.atan2(sin_Ce * cos_Cn, hypot(sin_Cn, cos_Cn * cos_Ce));
      Ce = asinhy(Math.tan(Ce));

      var tmp = clens_cmplx(this.gtu, 2 * Cn, 2 * Ce);

      Cn = Cn + tmp[0];
      Ce = Ce + tmp[1];

      var x;
      var y;

      if (Math.abs(Ce) <= 2.623395162778) {
        x = this.a * (this.Qn * Ce) + this.x0;
        y = this.a * (this.Qn * Cn + this.Zb) + this.y0;
      }
      else {
        x = Infinity;
        y = Infinity;
      }

      p.x = x;
      p.y = y;

      return p;
    }

    function inverse$3(p) {
      var Ce = (p.x - this.x0) * (1 / this.a);
      var Cn = (p.y - this.y0) * (1 / this.a);

      Cn = (Cn - this.Zb) / this.Qn;
      Ce = Ce / this.Qn;

      var lon;
      var lat;

      if (Math.abs(Ce) <= 2.623395162778) {
        var tmp = clens_cmplx(this.utg, 2 * Cn, 2 * Ce);

        Cn = Cn + tmp[0];
        Ce = Ce + tmp[1];
        Ce = Math.atan(sinh(Ce));

        var sin_Cn = Math.sin(Cn);
        var cos_Cn = Math.cos(Cn);
        var sin_Ce = Math.sin(Ce);
        var cos_Ce = Math.cos(Ce);

        Cn = Math.atan2(sin_Cn * cos_Ce, hypot(sin_Ce, cos_Ce * cos_Cn));
        Ce = Math.atan2(sin_Ce, cos_Ce * cos_Cn);

        lon = adjust_lon(Ce + this.long0);
        lat = gatg(this.cgb, Cn);
      }
      else {
        lon = Infinity;
        lat = Infinity;
      }

      p.x = lon;
      p.y = lat;

      return p;
    }

    var names$4 = ["Extended_Transverse_Mercator", "Extended Transverse Mercator", "etmerc", "Transverse_Mercator", "Transverse Mercator", "tmerc"];
    var etmerc = {
      init: init$3,
      forward: forward$3,
      inverse: inverse$3,
      names: names$4
    };

    var adjust_zone = function(zone, lon) {
      if (zone === undefined) {
        zone = Math.floor((adjust_lon(lon) + Math.PI) * 30 / Math.PI) + 1;

        if (zone < 0) {
          return 0;
        } else if (zone > 60) {
          return 60;
        }
      }
      return zone;
    };

    var dependsOn = 'etmerc';
    function init$4() {
      var zone = adjust_zone(this.zone, this.long0);
      if (zone === undefined) {
        throw new Error('unknown utm zone');
      }
      this.lat0 = 0;
      this.long0 =  ((6 * Math.abs(zone)) - 183) * D2R;
      this.x0 = 500000;
      this.y0 = this.utmSouth ? 10000000 : 0;
      this.k0 = 0.9996;

      etmerc.init.apply(this);
      this.forward = etmerc.forward;
      this.inverse = etmerc.inverse;
    }

    var names$5 = ["Universal Transverse Mercator System", "utm"];
    var utm = {
      init: init$4,
      names: names$5,
      dependsOn: dependsOn
    };

    var srat = function(esinp, exp) {
      return (Math.pow((1 - esinp) / (1 + esinp), exp));
    };

    var MAX_ITER$1 = 20;
    function init$6() {
      var sphi = Math.sin(this.lat0);
      var cphi = Math.cos(this.lat0);
      cphi *= cphi;
      this.rc = Math.sqrt(1 - this.es) / (1 - this.es * sphi * sphi);
      this.C = Math.sqrt(1 + this.es * cphi * cphi / (1 - this.es));
      this.phic0 = Math.asin(sphi / this.C);
      this.ratexp = 0.5 * this.C * this.e;
      this.K = Math.tan(0.5 * this.phic0 + FORTPI) / (Math.pow(Math.tan(0.5 * this.lat0 + FORTPI), this.C) * srat(this.e * sphi, this.ratexp));
    }

    function forward$5(p) {
      var lon = p.x;
      var lat = p.y;

      p.y = 2 * Math.atan(this.K * Math.pow(Math.tan(0.5 * lat + FORTPI), this.C) * srat(this.e * Math.sin(lat), this.ratexp)) - HALF_PI;
      p.x = this.C * lon;
      return p;
    }

    function inverse$5(p) {
      var DEL_TOL = 1e-14;
      var lon = p.x / this.C;
      var lat = p.y;
      var num = Math.pow(Math.tan(0.5 * lat + FORTPI) / this.K, 1 / this.C);
      for (var i = MAX_ITER$1; i > 0; --i) {
        lat = 2 * Math.atan(num * srat(this.e * Math.sin(p.y), - 0.5 * this.e)) - HALF_PI;
        if (Math.abs(lat - p.y) < DEL_TOL) {
          break;
        }
        p.y = lat;
      }
      /* convergence failed */
      if (!i) {
        return null;
      }
      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$7 = ["gauss"];
    var gauss = {
      init: init$6,
      forward: forward$5,
      inverse: inverse$5,
      names: names$7
    };

    function init$5() {
      gauss.init.apply(this);
      if (!this.rc) {
        return;
      }
      this.sinc0 = Math.sin(this.phic0);
      this.cosc0 = Math.cos(this.phic0);
      this.R2 = 2 * this.rc;
      if (!this.title) {
        this.title = "Oblique Stereographic Alternative";
      }
    }

    function forward$4(p) {
      var sinc, cosc, cosl, k;
      p.x = adjust_lon(p.x - this.long0);
      gauss.forward.apply(this, [p]);
      sinc = Math.sin(p.y);
      cosc = Math.cos(p.y);
      cosl = Math.cos(p.x);
      k = this.k0 * this.R2 / (1 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
      p.x = k * cosc * Math.sin(p.x);
      p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
      p.x = this.a * p.x + this.x0;
      p.y = this.a * p.y + this.y0;
      return p;
    }

    function inverse$4(p) {
      var sinc, cosc, lon, lat, rho;
      p.x = (p.x - this.x0) / this.a;
      p.y = (p.y - this.y0) / this.a;

      p.x /= this.k0;
      p.y /= this.k0;
      if ((rho = Math.sqrt(p.x * p.x + p.y * p.y))) {
        var c = 2 * Math.atan2(rho, this.R2);
        sinc = Math.sin(c);
        cosc = Math.cos(c);
        lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
        lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
      }
      else {
        lat = this.phic0;
        lon = 0;
      }

      p.x = lon;
      p.y = lat;
      gauss.inverse.apply(this, [p]);
      p.x = adjust_lon(p.x + this.long0);
      return p;
    }

    var names$6 = ["Stereographic_North_Pole", "Oblique_Stereographic", "Polar_Stereographic", "sterea","Oblique Stereographic Alternative","Double_Stereographic"];
    var sterea = {
      init: init$5,
      forward: forward$4,
      inverse: inverse$4,
      names: names$6
    };

    function ssfn_(phit, sinphi, eccen) {
      sinphi *= eccen;
      return (Math.tan(0.5 * (HALF_PI + phit)) * Math.pow((1 - sinphi) / (1 + sinphi), 0.5 * eccen));
    }

    function init$7() {
      this.coslat0 = Math.cos(this.lat0);
      this.sinlat0 = Math.sin(this.lat0);
      if (this.sphere) {
        if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
          this.k0 = 0.5 * (1 + sign(this.lat0) * Math.sin(this.lat_ts));
        }
      }
      else {
        if (Math.abs(this.coslat0) <= EPSLN) {
          if (this.lat0 > 0) {
            //North pole
            //trace('stere:north pole');
            this.con = 1;
          }
          else {
            //South pole
            //trace('stere:south pole');
            this.con = -1;
          }
        }
        this.cons = Math.sqrt(Math.pow(1 + this.e, 1 + this.e) * Math.pow(1 - this.e, 1 - this.e));
        if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
          this.k0 = 0.5 * this.cons * msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)) / tsfnz(this.e, this.con * this.lat_ts, this.con * Math.sin(this.lat_ts));
        }
        this.ms1 = msfnz(this.e, this.sinlat0, this.coslat0);
        this.X0 = 2 * Math.atan(this.ssfn_(this.lat0, this.sinlat0, this.e)) - HALF_PI;
        this.cosX0 = Math.cos(this.X0);
        this.sinX0 = Math.sin(this.X0);
      }
    }

    // Stereographic forward equations--mapping lat,long to x,y
    function forward$6(p) {
      var lon = p.x;
      var lat = p.y;
      var sinlat = Math.sin(lat);
      var coslat = Math.cos(lat);
      var A, X, sinX, cosX, ts, rh;
      var dlon = adjust_lon(lon - this.long0);

      if (Math.abs(Math.abs(lon - this.long0) - Math.PI) <= EPSLN && Math.abs(lat + this.lat0) <= EPSLN) {
        //case of the origine point
        //trace('stere:this is the origin point');
        p.x = NaN;
        p.y = NaN;
        return p;
      }
      if (this.sphere) {
        //trace('stere:sphere case');
        A = 2 * this.k0 / (1 + this.sinlat0 * sinlat + this.coslat0 * coslat * Math.cos(dlon));
        p.x = this.a * A * coslat * Math.sin(dlon) + this.x0;
        p.y = this.a * A * (this.coslat0 * sinlat - this.sinlat0 * coslat * Math.cos(dlon)) + this.y0;
        return p;
      }
      else {
        X = 2 * Math.atan(this.ssfn_(lat, sinlat, this.e)) - HALF_PI;
        cosX = Math.cos(X);
        sinX = Math.sin(X);
        if (Math.abs(this.coslat0) <= EPSLN) {
          ts = tsfnz(this.e, lat * this.con, this.con * sinlat);
          rh = 2 * this.a * this.k0 * ts / this.cons;
          p.x = this.x0 + rh * Math.sin(lon - this.long0);
          p.y = this.y0 - this.con * rh * Math.cos(lon - this.long0);
          //trace(p.toString());
          return p;
        }
        else if (Math.abs(this.sinlat0) < EPSLN) {
          //Eq
          //trace('stere:equateur');
          A = 2 * this.a * this.k0 / (1 + cosX * Math.cos(dlon));
          p.y = A * sinX;
        }
        else {
          //other case
          //trace('stere:normal case');
          A = 2 * this.a * this.k0 * this.ms1 / (this.cosX0 * (1 + this.sinX0 * sinX + this.cosX0 * cosX * Math.cos(dlon)));
          p.y = A * (this.cosX0 * sinX - this.sinX0 * cosX * Math.cos(dlon)) + this.y0;
        }
        p.x = A * cosX * Math.sin(dlon) + this.x0;
      }
      //trace(p.toString());
      return p;
    }

    //* Stereographic inverse equations--mapping x,y to lat/long
    function inverse$6(p) {
      p.x -= this.x0;
      p.y -= this.y0;
      var lon, lat, ts, ce, Chi;
      var rh = Math.sqrt(p.x * p.x + p.y * p.y);
      if (this.sphere) {
        var c = 2 * Math.atan(rh / (2 * this.a * this.k0));
        lon = this.long0;
        lat = this.lat0;
        if (rh <= EPSLN) {
          p.x = lon;
          p.y = lat;
          return p;
        }
        lat = Math.asin(Math.cos(c) * this.sinlat0 + p.y * Math.sin(c) * this.coslat0 / rh);
        if (Math.abs(this.coslat0) < EPSLN) {
          if (this.lat0 > 0) {
            lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
          }
          else {
            lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
          }
        }
        else {
          lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(c), rh * this.coslat0 * Math.cos(c) - p.y * this.sinlat0 * Math.sin(c)));
        }
        p.x = lon;
        p.y = lat;
        return p;
      }
      else {
        if (Math.abs(this.coslat0) <= EPSLN) {
          if (rh <= EPSLN) {
            lat = this.lat0;
            lon = this.long0;
            p.x = lon;
            p.y = lat;
            //trace(p.toString());
            return p;
          }
          p.x *= this.con;
          p.y *= this.con;
          ts = rh * this.cons / (2 * this.a * this.k0);
          lat = this.con * phi2z(this.e, ts);
          lon = this.con * adjust_lon(this.con * this.long0 + Math.atan2(p.x, - 1 * p.y));
        }
        else {
          ce = 2 * Math.atan(rh * this.cosX0 / (2 * this.a * this.k0 * this.ms1));
          lon = this.long0;
          if (rh <= EPSLN) {
            Chi = this.X0;
          }
          else {
            Chi = Math.asin(Math.cos(ce) * this.sinX0 + p.y * Math.sin(ce) * this.cosX0 / rh);
            lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(ce), rh * this.cosX0 * Math.cos(ce) - p.y * this.sinX0 * Math.sin(ce)));
          }
          lat = -1 * phi2z(this.e, Math.tan(0.5 * (HALF_PI + Chi)));
        }
      }
      p.x = lon;
      p.y = lat;

      //trace(p.toString());
      return p;

    }

    var names$8 = ["stere", "Stereographic_South_Pole", "Polar Stereographic (variant B)"];
    var stere = {
      init: init$7,
      forward: forward$6,
      inverse: inverse$6,
      names: names$8,
      ssfn_: ssfn_
    };

    /*
      references:
        Formules et constantes pour le Calcul pour la
        projection cylindrique conforme à axe oblique et pour la transformation entre
        des systèmes de référence.
        http://www.swisstopo.admin.ch/internet/swisstopo/fr/home/topics/survey/sys/refsys/switzerland.parsysrelated1.31216.downloadList.77004.DownloadFile.tmp/swissprojectionfr.pdf
      */

    function init$8() {
      var phy0 = this.lat0;
      this.lambda0 = this.long0;
      var sinPhy0 = Math.sin(phy0);
      var semiMajorAxis = this.a;
      var invF = this.rf;
      var flattening = 1 / invF;
      var e2 = 2 * flattening - Math.pow(flattening, 2);
      var e = this.e = Math.sqrt(e2);
      this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2));
      this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4));
      this.b0 = Math.asin(sinPhy0 / this.alpha);
      var k1 = Math.log(Math.tan(Math.PI / 4 + this.b0 / 2));
      var k2 = Math.log(Math.tan(Math.PI / 4 + phy0 / 2));
      var k3 = Math.log((1 + e * sinPhy0) / (1 - e * sinPhy0));
      this.K = k1 - this.alpha * k2 + this.alpha * e / 2 * k3;
    }

    function forward$7(p) {
      var Sa1 = Math.log(Math.tan(Math.PI / 4 - p.y / 2));
      var Sa2 = this.e / 2 * Math.log((1 + this.e * Math.sin(p.y)) / (1 - this.e * Math.sin(p.y)));
      var S = -this.alpha * (Sa1 + Sa2) + this.K;

      // spheric latitude
      var b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);

      // spheric longitude
      var I = this.alpha * (p.x - this.lambda0);

      // psoeudo equatorial rotation
      var rotI = Math.atan(Math.sin(I) / (Math.sin(this.b0) * Math.tan(b) + Math.cos(this.b0) * Math.cos(I)));

      var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) - Math.sin(this.b0) * Math.cos(b) * Math.cos(I));

      p.y = this.R / 2 * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB))) + this.y0;
      p.x = this.R * rotI + this.x0;
      return p;
    }

    function inverse$7(p) {
      var Y = p.x - this.x0;
      var X = p.y - this.y0;

      var rotI = Y / this.R;
      var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4);

      var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB) + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI));
      var I = Math.atan(Math.sin(rotI) / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0) * Math.tan(rotB)));

      var lambda = this.lambda0 + I / this.alpha;

      var S = 0;
      var phy = b;
      var prevPhy = -1000;
      var iteration = 0;
      while (Math.abs(phy - prevPhy) > 0.0000001) {
        if (++iteration > 20) {
          //...reportError("omercFwdInfinity");
          return;
        }
        //S = Math.log(Math.tan(Math.PI / 4 + phy / 2));
        S = 1 / this.alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - this.K) + this.e * Math.log(Math.tan(Math.PI / 4 + Math.asin(this.e * Math.sin(phy)) / 2));
        prevPhy = phy;
        phy = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
      }

      p.x = lambda;
      p.y = phy;
      return p;
    }

    var names$9 = ["somerc"];
    var somerc = {
      init: init$8,
      forward: forward$7,
      inverse: inverse$7,
      names: names$9
    };

    var TOL = 1e-7;

    function isTypeA(P) {
      var typeAProjections = ['Hotine_Oblique_Mercator','Hotine_Oblique_Mercator_Azimuth_Natural_Origin'];
      var projectionName = typeof P.PROJECTION === "object" ? Object.keys(P.PROJECTION)[0] : P.PROJECTION;
      
      return 'no_uoff' in P || 'no_off' in P || typeAProjections.indexOf(projectionName) !== -1;
    }


    /* Initialize the Oblique Mercator  projection
        ------------------------------------------*/
    function init$9() {  
      var con, com, cosph0, D, F, H, L, sinph0, p, J, gamma = 0,
        gamma0, lamc = 0, lam1 = 0, lam2 = 0, phi1 = 0, phi2 = 0, alpha_c = 0;
      
      // only Type A uses the no_off or no_uoff property
      // https://github.com/OSGeo/proj.4/issues/104
      this.no_off = isTypeA(this);
      this.no_rot = 'no_rot' in this;
      
      var alp = false;
      if ("alpha" in this) {
        alp = true;
      }

      var gam = false;
      if ("rectified_grid_angle" in this) {
        gam = true;
      }

      if (alp) {
        alpha_c = this.alpha;
      }
      
      if (gam) {
        gamma = (this.rectified_grid_angle * D2R);
      }
      
      if (alp || gam) {
        lamc = this.longc;
      } else {
        lam1 = this.long1;
        phi1 = this.lat1;
        lam2 = this.long2;
        phi2 = this.lat2;
        
        if (Math.abs(phi1 - phi2) <= TOL || (con = Math.abs(phi1)) <= TOL ||
            Math.abs(con - HALF_PI) <= TOL || Math.abs(Math.abs(this.lat0) - HALF_PI) <= TOL ||
            Math.abs(Math.abs(phi2) - HALF_PI) <= TOL) {
          throw new Error();
        }
      }
      
      var one_es = 1.0 - this.es;
      com = Math.sqrt(one_es);
      
      if (Math.abs(this.lat0) > EPSLN) {
        sinph0 = Math.sin(this.lat0);
        cosph0 = Math.cos(this.lat0);
        con = 1 - this.es * sinph0 * sinph0;
        this.B = cosph0 * cosph0;
        this.B = Math.sqrt(1 + this.es * this.B * this.B / one_es);
        this.A = this.B * this.k0 * com / con;
        D = this.B * com / (cosph0 * Math.sqrt(con));
        F = D * D -1;
        
        if (F <= 0) {
          F = 0;
        } else {
          F = Math.sqrt(F);
          if (this.lat0 < 0) {
            F = -F;
          }
        }
        
        this.E = F += D;
        this.E *= Math.pow(tsfnz(this.e, this.lat0, sinph0), this.B);
      } else {
        this.B = 1 / com;
        this.A = this.k0;
        this.E = D = F = 1;
      }
      
      if (alp || gam) {
        if (alp) {
          gamma0 = Math.asin(Math.sin(alpha_c) / D);
          if (!gam) {
            gamma = alpha_c;
          }
        } else {
          gamma0 = gamma;
          alpha_c = Math.asin(D * Math.sin(gamma0));
        }
        this.lam0 = lamc - Math.asin(0.5 * (F - 1 / F) * Math.tan(gamma0)) / this.B;
      } else {
        H = Math.pow(tsfnz(this.e, phi1, Math.sin(phi1)), this.B);
        L = Math.pow(tsfnz(this.e, phi2, Math.sin(phi2)), this.B);
        F = this.E / H;
        p = (L - H) / (L + H);
        J = this.E * this.E;
        J = (J - L * H) / (J + L * H);
        con = lam1 - lam2;
        
        if (con < -Math.pi) {
          lam2 -=TWO_PI;
        } else if (con > Math.pi) {
          lam2 += TWO_PI;
        }
        
        this.lam0 = adjust_lon(0.5 * (lam1 + lam2) - Math.atan(J * Math.tan(0.5 * this.B * (lam1 - lam2)) / p) / this.B);
        gamma0 = Math.atan(2 * Math.sin(this.B * adjust_lon(lam1 - this.lam0)) / (F - 1 / F));
        gamma = alpha_c = Math.asin(D * Math.sin(gamma0));
      }
      
      this.singam = Math.sin(gamma0);
      this.cosgam = Math.cos(gamma0);
      this.sinrot = Math.sin(gamma);
      this.cosrot = Math.cos(gamma);
      
      this.rB = 1 / this.B;
      this.ArB = this.A * this.rB;
      this.BrA = 1 / this.ArB;
      if (this.no_off) {
        this.u_0 = 0;
      } else {
        this.u_0 = Math.abs(this.ArB * Math.atan(Math.sqrt(D * D - 1) / Math.cos(alpha_c)));
        
        if (this.lat0 < 0) {
          this.u_0 = - this.u_0;
        }  
      }
        
      F = 0.5 * gamma0;
      this.v_pole_n = this.ArB * Math.log(Math.tan(FORTPI - F));
      this.v_pole_s = this.ArB * Math.log(Math.tan(FORTPI + F));
    }


    /* Oblique Mercator forward equations--mapping lat,long to x,y
        ----------------------------------------------------------*/
    function forward$8(p) {
      var coords = {};
      var S, T, U, V, W, temp, u, v;
      p.x = p.x - this.lam0;
      
      if (Math.abs(Math.abs(p.y) - HALF_PI) > EPSLN) {
        W = this.E / Math.pow(tsfnz(this.e, p.y, Math.sin(p.y)), this.B);
        
        temp = 1 / W;
        S = 0.5 * (W - temp);
        T = 0.5 * (W + temp);
        V = Math.sin(this.B * p.x);
        U = (S * this.singam - V * this.cosgam) / T;
            
        if (Math.abs(Math.abs(U) - 1.0) < EPSLN) {
          throw new Error();
        }
        
        v = 0.5 * this.ArB * Math.log((1 - U)/(1 + U));
        temp = Math.cos(this.B * p.x);
        
        if (Math.abs(temp) < TOL) {
          u = this.A * p.x;
        } else {
          u = this.ArB * Math.atan2((S * this.cosgam + V * this.singam), temp);
        }    
      } else {
        v = p.y > 0 ? this.v_pole_n : this.v_pole_s;
        u = this.ArB * p.y;
      }
         
      if (this.no_rot) {
        coords.x = u;
        coords.y = v;
      } else {
        u -= this.u_0;
        coords.x = v * this.cosrot + u * this.sinrot;
        coords.y = u * this.cosrot - v * this.sinrot;
      }
      
      coords.x = (this.a * coords.x + this.x0);
      coords.y = (this.a * coords.y + this.y0);
      
      return coords;
    }

    function inverse$8(p) {
      var u, v, Qp, Sp, Tp, Vp, Up;
      var coords = {};
      
      p.x = (p.x - this.x0) * (1.0 / this.a);
      p.y = (p.y - this.y0) * (1.0 / this.a);

      if (this.no_rot) {
        v = p.y;
        u = p.x;
      } else {
        v = p.x * this.cosrot - p.y * this.sinrot;
        u = p.y * this.cosrot + p.x * this.sinrot + this.u_0;
      }
      
      Qp = Math.exp(-this.BrA * v);
      Sp = 0.5 * (Qp - 1 / Qp);
      Tp = 0.5 * (Qp + 1 / Qp);
      Vp = Math.sin(this.BrA * u);
      Up = (Vp * this.cosgam + Sp * this.singam) / Tp;
      
      if (Math.abs(Math.abs(Up) - 1) < EPSLN) {
        coords.x = 0;
        coords.y = Up < 0 ? -HALF_PI : HALF_PI;
      } else {
        coords.y = this.E / Math.sqrt((1 + Up) / (1 - Up));
        coords.y = phi2z(this.e, Math.pow(coords.y, 1 / this.B));
        
        if (coords.y === Infinity) {
          throw new Error();
        }
            
        coords.x = -this.rB * Math.atan2((Sp * this.cosgam - Vp * this.singam), Math.cos(this.BrA * u));
      }
      
      coords.x += this.lam0;
      
      return coords;
    }

    var names$10 = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "Oblique_Mercator", "omerc"];
    var omerc = {
      init: init$9,
      forward: forward$8,
      inverse: inverse$8,
      names: names$10
    };

    function init$10() {
      
      //double lat0;                    /* the reference latitude               */
      //double long0;                   /* the reference longitude              */
      //double lat1;                    /* first standard parallel              */
      //double lat2;                    /* second standard parallel             */
      //double r_maj;                   /* major axis                           */
      //double r_min;                   /* minor axis                           */
      //double false_east;              /* x offset in meters                   */
      //double false_north;             /* y offset in meters                   */
      
      //the above value can be set with proj4.defs
      //example: proj4.defs("EPSG:2154","+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");

      if (!this.lat2) {
        this.lat2 = this.lat1;
      } //if lat2 is not defined
      if (!this.k0) {
        this.k0 = 1;
      }
      this.x0 = this.x0 || 0;
      this.y0 = this.y0 || 0;
      // Standard Parallels cannot be equal and on opposite sides of the equator
      if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
        return;
      }

      var temp = this.b / this.a;
      this.e = Math.sqrt(1 - temp * temp);

      var sin1 = Math.sin(this.lat1);
      var cos1 = Math.cos(this.lat1);
      var ms1 = msfnz(this.e, sin1, cos1);
      var ts1 = tsfnz(this.e, this.lat1, sin1);

      var sin2 = Math.sin(this.lat2);
      var cos2 = Math.cos(this.lat2);
      var ms2 = msfnz(this.e, sin2, cos2);
      var ts2 = tsfnz(this.e, this.lat2, sin2);

      var ts0 = tsfnz(this.e, this.lat0, Math.sin(this.lat0));

      if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
        this.ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2);
      }
      else {
        this.ns = sin1;
      }
      if (isNaN(this.ns)) {
        this.ns = sin1;
      }
      this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
      this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
      if (!this.title) {
        this.title = "Lambert Conformal Conic";
      }
    }

    // Lambert Conformal conic forward equations--mapping lat,long to x,y
    // -----------------------------------------------------------------
    function forward$9(p) {

      var lon = p.x;
      var lat = p.y;

      // singular cases :
      if (Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) {
        lat = sign(lat) * (HALF_PI - 2 * EPSLN);
      }

      var con = Math.abs(Math.abs(lat) - HALF_PI);
      var ts, rh1;
      if (con > EPSLN) {
        ts = tsfnz(this.e, lat, Math.sin(lat));
        rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
      }
      else {
        con = lat * this.ns;
        if (con <= 0) {
          return null;
        }
        rh1 = 0;
      }
      var theta = this.ns * adjust_lon(lon - this.long0);
      p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
      p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;

      return p;
    }

    // Lambert Conformal Conic inverse equations--mapping x,y to lat/long
    // -----------------------------------------------------------------
    function inverse$9(p) {

      var rh1, con, ts;
      var lat, lon;
      var x = (p.x - this.x0) / this.k0;
      var y = (this.rh - (p.y - this.y0) / this.k0);
      if (this.ns > 0) {
        rh1 = Math.sqrt(x * x + y * y);
        con = 1;
      }
      else {
        rh1 = -Math.sqrt(x * x + y * y);
        con = -1;
      }
      var theta = 0;
      if (rh1 !== 0) {
        theta = Math.atan2((con * x), (con * y));
      }
      if ((rh1 !== 0) || (this.ns > 0)) {
        con = 1 / this.ns;
        ts = Math.pow((rh1 / (this.a * this.f0)), con);
        lat = phi2z(this.e, ts);
        if (lat === -9999) {
          return null;
        }
      }
      else {
        lat = -HALF_PI;
      }
      lon = adjust_lon(theta / this.ns + this.long0);

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$11 = [
      "Lambert Tangential Conformal Conic Projection",
      "Lambert_Conformal_Conic",
      "Lambert_Conformal_Conic_1SP",
      "Lambert_Conformal_Conic_2SP",
      "lcc"
    ];

    var lcc = {
      init: init$10,
      forward: forward$9,
      inverse: inverse$9,
      names: names$11
    };

    function init$11() {
      this.a = 6377397.155;
      this.es = 0.006674372230614;
      this.e = Math.sqrt(this.es);
      if (!this.lat0) {
        this.lat0 = 0.863937979737193;
      }
      if (!this.long0) {
        this.long0 = 0.7417649320975901 - 0.308341501185665;
      }
      /* if scale not set default to 0.9999 */
      if (!this.k0) {
        this.k0 = 0.9999;
      }
      this.s45 = 0.785398163397448; /* 45 */
      this.s90 = 2 * this.s45;
      this.fi0 = this.lat0;
      this.e2 = this.es;
      this.e = Math.sqrt(this.e2);
      this.alfa = Math.sqrt(1 + (this.e2 * Math.pow(Math.cos(this.fi0), 4)) / (1 - this.e2));
      this.uq = 1.04216856380474;
      this.u0 = Math.asin(Math.sin(this.fi0) / this.alfa);
      this.g = Math.pow((1 + this.e * Math.sin(this.fi0)) / (1 - this.e * Math.sin(this.fi0)), this.alfa * this.e / 2);
      this.k = Math.tan(this.u0 / 2 + this.s45) / Math.pow(Math.tan(this.fi0 / 2 + this.s45), this.alfa) * this.g;
      this.k1 = this.k0;
      this.n0 = this.a * Math.sqrt(1 - this.e2) / (1 - this.e2 * Math.pow(Math.sin(this.fi0), 2));
      this.s0 = 1.37008346281555;
      this.n = Math.sin(this.s0);
      this.ro0 = this.k1 * this.n0 / Math.tan(this.s0);
      this.ad = this.s90 - this.uq;
    }

    /* ellipsoid */
    /* calculate xy from lat/lon */
    /* Constants, identical to inverse transform function */
    function forward$10(p) {
      var gfi, u, deltav, s, d, eps, ro;
      var lon = p.x;
      var lat = p.y;
      var delta_lon = adjust_lon(lon - this.long0);
      /* Transformation */
      gfi = Math.pow(((1 + this.e * Math.sin(lat)) / (1 - this.e * Math.sin(lat))), (this.alfa * this.e / 2));
      u = 2 * (Math.atan(this.k * Math.pow(Math.tan(lat / 2 + this.s45), this.alfa) / gfi) - this.s45);
      deltav = -delta_lon * this.alfa;
      s = Math.asin(Math.cos(this.ad) * Math.sin(u) + Math.sin(this.ad) * Math.cos(u) * Math.cos(deltav));
      d = Math.asin(Math.cos(u) * Math.sin(deltav) / Math.cos(s));
      eps = this.n * d;
      ro = this.ro0 * Math.pow(Math.tan(this.s0 / 2 + this.s45), this.n) / Math.pow(Math.tan(s / 2 + this.s45), this.n);
      p.y = ro * Math.cos(eps) / 1;
      p.x = ro * Math.sin(eps) / 1;

      if (!this.czech) {
        p.y *= -1;
        p.x *= -1;
      }
      return (p);
    }

    /* calculate lat/lon from xy */
    function inverse$10(p) {
      var u, deltav, s, d, eps, ro, fi1;
      var ok;

      /* Transformation */
      /* revert y, x*/
      var tmp = p.x;
      p.x = p.y;
      p.y = tmp;
      if (!this.czech) {
        p.y *= -1;
        p.x *= -1;
      }
      ro = Math.sqrt(p.x * p.x + p.y * p.y);
      eps = Math.atan2(p.y, p.x);
      d = eps / Math.sin(this.s0);
      s = 2 * (Math.atan(Math.pow(this.ro0 / ro, 1 / this.n) * Math.tan(this.s0 / 2 + this.s45)) - this.s45);
      u = Math.asin(Math.cos(this.ad) * Math.sin(s) - Math.sin(this.ad) * Math.cos(s) * Math.cos(d));
      deltav = Math.asin(Math.cos(s) * Math.sin(d) / Math.cos(u));
      p.x = this.long0 - deltav / this.alfa;
      fi1 = u;
      ok = 0;
      var iter = 0;
      do {
        p.y = 2 * (Math.atan(Math.pow(this.k, - 1 / this.alfa) * Math.pow(Math.tan(u / 2 + this.s45), 1 / this.alfa) * Math.pow((1 + this.e * Math.sin(fi1)) / (1 - this.e * Math.sin(fi1)), this.e / 2)) - this.s45);
        if (Math.abs(fi1 - p.y) < 0.0000000001) {
          ok = 1;
        }
        fi1 = p.y;
        iter += 1;
      } while (ok === 0 && iter < 15);
      if (iter >= 15) {
        return null;
      }

      return (p);
    }

    var names$12 = ["Krovak", "krovak"];
    var krovak = {
      init: init$11,
      forward: forward$10,
      inverse: inverse$10,
      names: names$12
    };

    var mlfn = function(e0, e1, e2, e3, phi) {
      return (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi));
    };

    var e0fn = function(x) {
      return (1 - 0.25 * x * (1 + x / 16 * (3 + 1.25 * x)));
    };

    var e1fn = function(x) {
      return (0.375 * x * (1 + 0.25 * x * (1 + 0.46875 * x)));
    };

    var e2fn = function(x) {
      return (0.05859375 * x * x * (1 + 0.75 * x));
    };

    var e3fn = function(x) {
      return (x * x * x * (35 / 3072));
    };

    var gN = function(a, e, sinphi) {
      var temp = e * sinphi;
      return a / Math.sqrt(1 - temp * temp);
    };

    var adjust_lat = function(x) {
      return (Math.abs(x) < HALF_PI) ? x : (x - (sign(x) * Math.PI));
    };

    var imlfn = function(ml, e0, e1, e2, e3) {
      var phi;
      var dphi;

      phi = ml / e0;
      for (var i = 0; i < 15; i++) {
        dphi = (ml - (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi))) / (e0 - 2 * e1 * Math.cos(2 * phi) + 4 * e2 * Math.cos(4 * phi) - 6 * e3 * Math.cos(6 * phi));
        phi += dphi;
        if (Math.abs(dphi) <= 0.0000000001) {
          return phi;
        }
      }

      //..reportError("IMLFN-CONV:Latitude failed to converge after 15 iterations");
      return NaN;
    };

    function init$12() {
      if (!this.sphere) {
        this.e0 = e0fn(this.es);
        this.e1 = e1fn(this.es);
        this.e2 = e2fn(this.es);
        this.e3 = e3fn(this.es);
        this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
      }
    }

    /* Cassini forward equations--mapping lat,long to x,y
      -----------------------------------------------------------------------*/
    function forward$11(p) {

      /* Forward equations
          -----------------*/
      var x, y;
      var lam = p.x;
      var phi = p.y;
      lam = adjust_lon(lam - this.long0);

      if (this.sphere) {
        x = this.a * Math.asin(Math.cos(phi) * Math.sin(lam));
        y = this.a * (Math.atan2(Math.tan(phi), Math.cos(lam)) - this.lat0);
      }
      else {
        //ellipsoid
        var sinphi = Math.sin(phi);
        var cosphi = Math.cos(phi);
        var nl = gN(this.a, this.e, sinphi);
        var tl = Math.tan(phi) * Math.tan(phi);
        var al = lam * Math.cos(phi);
        var asq = al * al;
        var cl = this.es * cosphi * cosphi / (1 - this.es);
        var ml = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);

        x = nl * al * (1 - asq * tl * (1 / 6 - (8 - tl + 8 * cl) * asq / 120));
        y = ml - this.ml0 + nl * sinphi / cosphi * asq * (0.5 + (5 - tl + 6 * cl) * asq / 24);


      }

      p.x = x + this.x0;
      p.y = y + this.y0;
      return p;
    }

    /* Inverse equations
      -----------------*/
    function inverse$11(p) {
      p.x -= this.x0;
      p.y -= this.y0;
      var x = p.x / this.a;
      var y = p.y / this.a;
      var phi, lam;

      if (this.sphere) {
        var dd = y + this.lat0;
        phi = Math.asin(Math.sin(dd) * Math.cos(x));
        lam = Math.atan2(Math.tan(x), Math.cos(dd));
      }
      else {
        /* ellipsoid */
        var ml1 = this.ml0 / this.a + y;
        var phi1 = imlfn(ml1, this.e0, this.e1, this.e2, this.e3);
        if (Math.abs(Math.abs(phi1) - HALF_PI) <= EPSLN) {
          p.x = this.long0;
          p.y = HALF_PI;
          if (y < 0) {
            p.y *= -1;
          }
          return p;
        }
        var nl1 = gN(this.a, this.e, Math.sin(phi1));

        var rl1 = nl1 * nl1 * nl1 / this.a / this.a * (1 - this.es);
        var tl1 = Math.pow(Math.tan(phi1), 2);
        var dl = x * this.a / nl1;
        var dsq = dl * dl;
        phi = phi1 - nl1 * Math.tan(phi1) / rl1 * dl * dl * (0.5 - (1 + 3 * tl1) * dl * dl / 24);
        lam = dl * (1 - dsq * (tl1 / 3 + (1 + 3 * tl1) * tl1 * dsq / 15)) / Math.cos(phi1);

      }

      p.x = adjust_lon(lam + this.long0);
      p.y = adjust_lat(phi);
      return p;

    }

    var names$13 = ["Cassini", "Cassini_Soldner", "cass"];
    var cass = {
      init: init$12,
      forward: forward$11,
      inverse: inverse$11,
      names: names$13
    };

    var qsfnz = function(eccent, sinphi) {
      var con;
      if (eccent > 1.0e-7) {
        con = eccent * sinphi;
        return ((1 - eccent * eccent) * (sinphi / (1 - con * con) - (0.5 / eccent) * Math.log((1 - con) / (1 + con))));
      }
      else {
        return (2 * sinphi);
      }
    };

    /*
      reference
        "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
        The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
      */

    var S_POLE = 1;

    var N_POLE = 2;
    var EQUIT = 3;
    var OBLIQ = 4;

    /* Initialize the Lambert Azimuthal Equal Area projection
      ------------------------------------------------------*/
    function init$13() {
      var t = Math.abs(this.lat0);
      if (Math.abs(t - HALF_PI) < EPSLN) {
        this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE;
      }
      else if (Math.abs(t) < EPSLN) {
        this.mode = this.EQUIT;
      }
      else {
        this.mode = this.OBLIQ;
      }
      if (this.es > 0) {
        var sinphi;

        this.qp = qsfnz(this.e, 1);
        this.mmf = 0.5 / (1 - this.es);
        this.apa = authset(this.es);
        switch (this.mode) {
        case this.N_POLE:
          this.dd = 1;
          break;
        case this.S_POLE:
          this.dd = 1;
          break;
        case this.EQUIT:
          this.rq = Math.sqrt(0.5 * this.qp);
          this.dd = 1 / this.rq;
          this.xmf = 1;
          this.ymf = 0.5 * this.qp;
          break;
        case this.OBLIQ:
          this.rq = Math.sqrt(0.5 * this.qp);
          sinphi = Math.sin(this.lat0);
          this.sinb1 = qsfnz(this.e, sinphi) / this.qp;
          this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1);
          this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1);
          this.ymf = (this.xmf = this.rq) / this.dd;
          this.xmf *= this.dd;
          break;
        }
      }
      else {
        if (this.mode === this.OBLIQ) {
          this.sinph0 = Math.sin(this.lat0);
          this.cosph0 = Math.cos(this.lat0);
        }
      }
    }

    /* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
      -----------------------------------------------------------------------*/
    function forward$12(p) {

      /* Forward equations
          -----------------*/
      var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi;
      var lam = p.x;
      var phi = p.y;

      lam = adjust_lon(lam - this.long0);
      if (this.sphere) {
        sinphi = Math.sin(phi);
        cosphi = Math.cos(phi);
        coslam = Math.cos(lam);
        if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
          y = (this.mode === this.EQUIT) ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
          if (y <= EPSLN) {
            return null;
          }
          y = Math.sqrt(2 / y);
          x = y * cosphi * Math.sin(lam);
          y *= (this.mode === this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
        }
        else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
          if (this.mode === this.N_POLE) {
            coslam = -coslam;
          }
          if (Math.abs(phi + this.lat0) < EPSLN) {
            return null;
          }
          y = FORTPI - phi * 0.5;
          y = 2 * ((this.mode === this.S_POLE) ? Math.cos(y) : Math.sin(y));
          x = y * Math.sin(lam);
          y *= coslam;
        }
      }
      else {
        sinb = 0;
        cosb = 0;
        b = 0;
        coslam = Math.cos(lam);
        sinlam = Math.sin(lam);
        sinphi = Math.sin(phi);
        q = qsfnz(this.e, sinphi);
        if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
          sinb = q / this.qp;
          cosb = Math.sqrt(1 - sinb * sinb);
        }
        switch (this.mode) {
        case this.OBLIQ:
          b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
          break;
        case this.EQUIT:
          b = 1 + cosb * coslam;
          break;
        case this.N_POLE:
          b = HALF_PI + phi;
          q = this.qp - q;
          break;
        case this.S_POLE:
          b = phi - HALF_PI;
          q = this.qp + q;
          break;
        }
        if (Math.abs(b) < EPSLN) {
          return null;
        }
        switch (this.mode) {
        case this.OBLIQ:
        case this.EQUIT:
          b = Math.sqrt(2 / b);
          if (this.mode === this.OBLIQ) {
            y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
          }
          else {
            y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf;
          }
          x = this.xmf * b * cosb * sinlam;
          break;
        case this.N_POLE:
        case this.S_POLE:
          if (q >= 0) {
            x = (b = Math.sqrt(q)) * sinlam;
            y = coslam * ((this.mode === this.S_POLE) ? b : -b);
          }
          else {
            x = y = 0;
          }
          break;
        }
      }

      p.x = this.a * x + this.x0;
      p.y = this.a * y + this.y0;
      return p;
    }

    /* Inverse equations
      -----------------*/
    function inverse$12(p) {
      p.x -= this.x0;
      p.y -= this.y0;
      var x = p.x / this.a;
      var y = p.y / this.a;
      var lam, phi, cCe, sCe, q, rho, ab;
      if (this.sphere) {
        var cosz = 0,
          rh, sinz = 0;

        rh = Math.sqrt(x * x + y * y);
        phi = rh * 0.5;
        if (phi > 1) {
          return null;
        }
        phi = 2 * Math.asin(phi);
        if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
          sinz = Math.sin(phi);
          cosz = Math.cos(phi);
        }
        switch (this.mode) {
        case this.EQUIT:
          phi = (Math.abs(rh) <= EPSLN) ? 0 : Math.asin(y * sinz / rh);
          x *= sinz;
          y = cosz * rh;
          break;
        case this.OBLIQ:
          phi = (Math.abs(rh) <= EPSLN) ? this.lat0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh);
          x *= sinz * this.cosph0;
          y = (cosz - Math.sin(phi) * this.sinph0) * rh;
          break;
        case this.N_POLE:
          y = -y;
          phi = HALF_PI - phi;
          break;
        case this.S_POLE:
          phi -= HALF_PI;
          break;
        }
        lam = (y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ)) ? 0 : Math.atan2(x, y);
      }
      else {
        ab = 0;
        if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
          x /= this.dd;
          y *= this.dd;
          rho = Math.sqrt(x * x + y * y);
          if (rho < EPSLN) {
            p.x = this.long0;
            p.y = this.lat0;
            return p;
          }
          sCe = 2 * Math.asin(0.5 * rho / this.rq);
          cCe = Math.cos(sCe);
          x *= (sCe = Math.sin(sCe));
          if (this.mode === this.OBLIQ) {
            ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho;
            q = this.qp * ab;
            y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
          }
          else {
            ab = y * sCe / rho;
            q = this.qp * ab;
            y = rho * cCe;
          }
        }
        else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
          if (this.mode === this.N_POLE) {
            y = -y;
          }
          q = (x * x + y * y);
          if (!q) {
            p.x = this.long0;
            p.y = this.lat0;
            return p;
          }
          ab = 1 - q / this.qp;
          if (this.mode === this.S_POLE) {
            ab = -ab;
          }
        }
        lam = Math.atan2(x, y);
        phi = authlat(Math.asin(ab), this.apa);
      }

      p.x = adjust_lon(this.long0 + lam);
      p.y = phi;
      return p;
    }

    /* determine latitude from authalic latitude */
    var P00 = 0.33333333333333333333;

    var P01 = 0.17222222222222222222;
    var P02 = 0.10257936507936507936;
    var P10 = 0.06388888888888888888;
    var P11 = 0.06640211640211640211;
    var P20 = 0.01641501294219154443;

    function authset(es) {
      var t;
      var APA = [];
      APA[0] = es * P00;
      t = es * es;
      APA[0] += t * P01;
      APA[1] = t * P10;
      t *= es;
      APA[0] += t * P02;
      APA[1] += t * P11;
      APA[2] = t * P20;
      return APA;
    }

    function authlat(beta, APA) {
      var t = beta + beta;
      return (beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t));
    }

    var names$14 = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"];
    var laea = {
      init: init$13,
      forward: forward$12,
      inverse: inverse$12,
      names: names$14,
      S_POLE: S_POLE,
      N_POLE: N_POLE,
      EQUIT: EQUIT,
      OBLIQ: OBLIQ
    };

    var asinz = function(x) {
      if (Math.abs(x) > 1) {
        x = (x > 1) ? 1 : -1;
      }
      return Math.asin(x);
    };

    function init$14() {

      if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
        return;
      }
      this.temp = this.b / this.a;
      this.es = 1 - Math.pow(this.temp, 2);
      this.e3 = Math.sqrt(this.es);

      this.sin_po = Math.sin(this.lat1);
      this.cos_po = Math.cos(this.lat1);
      this.t1 = this.sin_po;
      this.con = this.sin_po;
      this.ms1 = msfnz(this.e3, this.sin_po, this.cos_po);
      this.qs1 = qsfnz(this.e3, this.sin_po, this.cos_po);

      this.sin_po = Math.sin(this.lat2);
      this.cos_po = Math.cos(this.lat2);
      this.t2 = this.sin_po;
      this.ms2 = msfnz(this.e3, this.sin_po, this.cos_po);
      this.qs2 = qsfnz(this.e3, this.sin_po, this.cos_po);

      this.sin_po = Math.sin(this.lat0);
      this.cos_po = Math.cos(this.lat0);
      this.t3 = this.sin_po;
      this.qs0 = qsfnz(this.e3, this.sin_po, this.cos_po);

      if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
        this.ns0 = (this.ms1 * this.ms1 - this.ms2 * this.ms2) / (this.qs2 - this.qs1);
      }
      else {
        this.ns0 = this.con;
      }
      this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
      this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0) / this.ns0;
    }

    /* Albers Conical Equal Area forward equations--mapping lat,long to x,y
      -------------------------------------------------------------------*/
    function forward$13(p) {

      var lon = p.x;
      var lat = p.y;

      this.sin_phi = Math.sin(lat);
      this.cos_phi = Math.cos(lat);

      var qs = qsfnz(this.e3, this.sin_phi, this.cos_phi);
      var rh1 = this.a * Math.sqrt(this.c - this.ns0 * qs) / this.ns0;
      var theta = this.ns0 * adjust_lon(lon - this.long0);
      var x = rh1 * Math.sin(theta) + this.x0;
      var y = this.rh - rh1 * Math.cos(theta) + this.y0;

      p.x = x;
      p.y = y;
      return p;
    }

    function inverse$13(p) {
      var rh1, qs, con, theta, lon, lat;

      p.x -= this.x0;
      p.y = this.rh - p.y + this.y0;
      if (this.ns0 >= 0) {
        rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
        con = 1;
      }
      else {
        rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
        con = -1;
      }
      theta = 0;
      if (rh1 !== 0) {
        theta = Math.atan2(con * p.x, con * p.y);
      }
      con = rh1 * this.ns0 / this.a;
      if (this.sphere) {
        lat = Math.asin((this.c - con * con) / (2 * this.ns0));
      }
      else {
        qs = (this.c - con * con) / this.ns0;
        lat = this.phi1z(this.e3, qs);
      }

      lon = adjust_lon(theta / this.ns0 + this.long0);
      p.x = lon;
      p.y = lat;
      return p;
    }

    /* Function to compute phi1, the latitude for the inverse of the
       Albers Conical Equal-Area projection.
    -------------------------------------------*/
    function phi1z(eccent, qs) {
      var sinphi, cosphi, con, com, dphi;
      var phi = asinz(0.5 * qs);
      if (eccent < EPSLN) {
        return phi;
      }

      var eccnts = eccent * eccent;
      for (var i = 1; i <= 25; i++) {
        sinphi = Math.sin(phi);
        cosphi = Math.cos(phi);
        con = eccent * sinphi;
        com = 1 - con * con;
        dphi = 0.5 * com * com / cosphi * (qs / (1 - eccnts) - sinphi / com + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
        phi = phi + dphi;
        if (Math.abs(dphi) <= 1e-7) {
          return phi;
        }
      }
      return null;
    }

    var names$15 = ["Albers_Conic_Equal_Area", "Albers", "aea"];
    var aea = {
      init: init$14,
      forward: forward$13,
      inverse: inverse$13,
      names: names$15,
      phi1z: phi1z
    };

    /*
      reference:
        Wolfram Mathworld "Gnomonic Projection"
        http://mathworld.wolfram.com/GnomonicProjection.html
        Accessed: 12th November 2009
      */
    function init$15() {

      /* Place parameters in static storage for common use
          -------------------------------------------------*/
      this.sin_p14 = Math.sin(this.lat0);
      this.cos_p14 = Math.cos(this.lat0);
      // Approximation for projecting points to the horizon (infinity)
      this.infinity_dist = 1000 * this.a;
      this.rc = 1;
    }

    /* Gnomonic forward equations--mapping lat,long to x,y
        ---------------------------------------------------*/
    function forward$14(p) {
      var sinphi, cosphi; /* sin and cos value        */
      var dlon; /* delta longitude value      */
      var coslon; /* cos of longitude        */
      var ksp; /* scale factor          */
      var g;
      var x, y;
      var lon = p.x;
      var lat = p.y;
      /* Forward equations
          -----------------*/
      dlon = adjust_lon(lon - this.long0);

      sinphi = Math.sin(lat);
      cosphi = Math.cos(lat);

      coslon = Math.cos(dlon);
      g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
      ksp = 1;
      if ((g > 0) || (Math.abs(g) <= EPSLN)) {
        x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g;
        y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g;
      }
      else {

        // Point is in the opposing hemisphere and is unprojectable
        // We still need to return a reasonable point, so we project
        // to infinity, on a bearing
        // equivalent to the northern hemisphere equivalent
        // This is a reasonable approximation for short shapes and lines that
        // straddle the horizon.

        x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon);
        y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);

      }
      p.x = x;
      p.y = y;
      return p;
    }

    function inverse$14(p) {
      var rh; /* Rho */
      var sinc, cosc;
      var c;
      var lon, lat;

      /* Inverse equations
          -----------------*/
      p.x = (p.x - this.x0) / this.a;
      p.y = (p.y - this.y0) / this.a;

      p.x /= this.k0;
      p.y /= this.k0;

      if ((rh = Math.sqrt(p.x * p.x + p.y * p.y))) {
        c = Math.atan2(rh, this.rc);
        sinc = Math.sin(c);
        cosc = Math.cos(c);

        lat = asinz(cosc * this.sin_p14 + (p.y * sinc * this.cos_p14) / rh);
        lon = Math.atan2(p.x * sinc, rh * this.cos_p14 * cosc - p.y * this.sin_p14 * sinc);
        lon = adjust_lon(this.long0 + lon);
      }
      else {
        lat = this.phic0;
        lon = 0;
      }

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$16 = ["gnom"];
    var gnom = {
      init: init$15,
      forward: forward$14,
      inverse: inverse$14,
      names: names$16
    };

    var iqsfnz = function(eccent, q) {
      var temp = 1 - (1 - eccent * eccent) / (2 * eccent) * Math.log((1 - eccent) / (1 + eccent));
      if (Math.abs(Math.abs(q) - temp) < 1.0E-6) {
        if (q < 0) {
          return (-1 * HALF_PI);
        }
        else {
          return HALF_PI;
        }
      }
      //var phi = 0.5* q/(1-eccent*eccent);
      var phi = Math.asin(0.5 * q);
      var dphi;
      var sin_phi;
      var cos_phi;
      var con;
      for (var i = 0; i < 30; i++) {
        sin_phi = Math.sin(phi);
        cos_phi = Math.cos(phi);
        con = eccent * sin_phi;
        dphi = Math.pow(1 - con * con, 2) / (2 * cos_phi) * (q / (1 - eccent * eccent) - sin_phi / (1 - con * con) + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
        phi += dphi;
        if (Math.abs(dphi) <= 0.0000000001) {
          return phi;
        }
      }

      //console.log("IQSFN-CONV:Latitude failed to converge after 30 iterations");
      return NaN;
    };

    /*
      reference:
        "Cartographic Projection Procedures for the UNIX Environment-
        A User's Manual" by Gerald I. Evenden,
        USGS Open File Report 90-284and Release 4 Interim Reports (2003)
    */
    function init$16() {
      //no-op
      if (!this.sphere) {
        this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
      }
    }

    /* Cylindrical Equal Area forward equations--mapping lat,long to x,y
        ------------------------------------------------------------*/
    function forward$15(p) {
      var lon = p.x;
      var lat = p.y;
      var x, y;
      /* Forward equations
          -----------------*/
      var dlon = adjust_lon(lon - this.long0);
      if (this.sphere) {
        x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
        y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts);
      }
      else {
        var qs = qsfnz(this.e, Math.sin(lat));
        x = this.x0 + this.a * this.k0 * dlon;
        y = this.y0 + this.a * qs * 0.5 / this.k0;
      }

      p.x = x;
      p.y = y;
      return p;
    }

    /* Cylindrical Equal Area inverse equations--mapping x,y to lat/long
        ------------------------------------------------------------*/
    function inverse$15(p) {
      p.x -= this.x0;
      p.y -= this.y0;
      var lon, lat;

      if (this.sphere) {
        lon = adjust_lon(this.long0 + (p.x / this.a) / Math.cos(this.lat_ts));
        lat = Math.asin((p.y / this.a) * Math.cos(this.lat_ts));
      }
      else {
        lat = iqsfnz(this.e, 2 * p.y * this.k0 / this.a);
        lon = adjust_lon(this.long0 + p.x / (this.a * this.k0));
      }

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$17 = ["cea"];
    var cea = {
      init: init$16,
      forward: forward$15,
      inverse: inverse$15,
      names: names$17
    };

    function init$17() {

      this.x0 = this.x0 || 0;
      this.y0 = this.y0 || 0;
      this.lat0 = this.lat0 || 0;
      this.long0 = this.long0 || 0;
      this.lat_ts = this.lat_ts || 0;
      this.title = this.title || "Equidistant Cylindrical (Plate Carre)";

      this.rc = Math.cos(this.lat_ts);
    }

    // forward equations--mapping lat,long to x,y
    // -----------------------------------------------------------------
    function forward$16(p) {

      var lon = p.x;
      var lat = p.y;

      var dlon = adjust_lon(lon - this.long0);
      var dlat = adjust_lat(lat - this.lat0);
      p.x = this.x0 + (this.a * dlon * this.rc);
      p.y = this.y0 + (this.a * dlat);
      return p;
    }

    // inverse equations--mapping x,y to lat/long
    // -----------------------------------------------------------------
    function inverse$16(p) {

      var x = p.x;
      var y = p.y;

      p.x = adjust_lon(this.long0 + ((x - this.x0) / (this.a * this.rc)));
      p.y = adjust_lat(this.lat0 + ((y - this.y0) / (this.a)));
      return p;
    }

    var names$18 = ["Equirectangular", "Equidistant_Cylindrical", "eqc"];
    var eqc = {
      init: init$17,
      forward: forward$16,
      inverse: inverse$16,
      names: names$18
    };

    var MAX_ITER$2 = 20;

    function init$18() {
      /* Place parameters in static storage for common use
          -------------------------------------------------*/
      this.temp = this.b / this.a;
      this.es = 1 - Math.pow(this.temp, 2); // devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles
      this.e = Math.sqrt(this.es);
      this.e0 = e0fn(this.es);
      this.e1 = e1fn(this.es);
      this.e2 = e2fn(this.es);
      this.e3 = e3fn(this.es);
      this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); //si que des zeros le calcul ne se fait pas
    }

    /* Polyconic forward equations--mapping lat,long to x,y
        ---------------------------------------------------*/
    function forward$17(p) {
      var lon = p.x;
      var lat = p.y;
      var x, y, el;
      var dlon = adjust_lon(lon - this.long0);
      el = dlon * Math.sin(lat);
      if (this.sphere) {
        if (Math.abs(lat) <= EPSLN) {
          x = this.a * dlon;
          y = -1 * this.a * this.lat0;
        }
        else {
          x = this.a * Math.sin(el) / Math.tan(lat);
          y = this.a * (adjust_lat(lat - this.lat0) + (1 - Math.cos(el)) / Math.tan(lat));
        }
      }
      else {
        if (Math.abs(lat) <= EPSLN) {
          x = this.a * dlon;
          y = -1 * this.ml0;
        }
        else {
          var nl = gN(this.a, this.e, Math.sin(lat)) / Math.tan(lat);
          x = nl * Math.sin(el);
          y = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, lat) - this.ml0 + nl * (1 - Math.cos(el));
        }

      }
      p.x = x + this.x0;
      p.y = y + this.y0;
      return p;
    }

    /* Inverse equations
      -----------------*/
    function inverse$17(p) {
      var lon, lat, x, y, i;
      var al, bl;
      var phi, dphi;
      x = p.x - this.x0;
      y = p.y - this.y0;

      if (this.sphere) {
        if (Math.abs(y + this.a * this.lat0) <= EPSLN) {
          lon = adjust_lon(x / this.a + this.long0);
          lat = 0;
        }
        else {
          al = this.lat0 + y / this.a;
          bl = x * x / this.a / this.a + al * al;
          phi = al;
          var tanphi;
          for (i = MAX_ITER$2; i; --i) {
            tanphi = Math.tan(phi);
            dphi = -1 * (al * (phi * tanphi + 1) - phi - 0.5 * (phi * phi + bl) * tanphi) / ((phi - al) / tanphi - 1);
            phi += dphi;
            if (Math.abs(dphi) <= EPSLN) {
              lat = phi;
              break;
            }
          }
          lon = adjust_lon(this.long0 + (Math.asin(x * Math.tan(phi) / this.a)) / Math.sin(lat));
        }
      }
      else {
        if (Math.abs(y + this.ml0) <= EPSLN) {
          lat = 0;
          lon = adjust_lon(this.long0 + x / this.a);
        }
        else {

          al = (this.ml0 + y) / this.a;
          bl = x * x / this.a / this.a + al * al;
          phi = al;
          var cl, mln, mlnp, ma;
          var con;
          for (i = MAX_ITER$2; i; --i) {
            con = this.e * Math.sin(phi);
            cl = Math.sqrt(1 - con * con) * Math.tan(phi);
            mln = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
            mlnp = this.e0 - 2 * this.e1 * Math.cos(2 * phi) + 4 * this.e2 * Math.cos(4 * phi) - 6 * this.e3 * Math.cos(6 * phi);
            ma = mln / this.a;
            dphi = (al * (cl * ma + 1) - ma - 0.5 * cl * (ma * ma + bl)) / (this.es * Math.sin(2 * phi) * (ma * ma + bl - 2 * al * ma) / (4 * cl) + (al - ma) * (cl * mlnp - 2 / Math.sin(2 * phi)) - mlnp);
            phi -= dphi;
            if (Math.abs(dphi) <= EPSLN) {
              lat = phi;
              break;
            }
          }

          //lat=phi4z(this.e,this.e0,this.e1,this.e2,this.e3,al,bl,0,0);
          cl = Math.sqrt(1 - this.es * Math.pow(Math.sin(lat), 2)) * Math.tan(lat);
          lon = adjust_lon(this.long0 + Math.asin(x * cl / this.a) / Math.sin(lat));
        }
      }

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$19 = ["Polyconic", "poly"];
    var poly = {
      init: init$18,
      forward: forward$17,
      inverse: inverse$17,
      names: names$19
    };

    /*
      reference
        Department of Land and Survey Technical Circular 1973/32
          http://www.linz.govt.nz/docs/miscellaneous/nz-map-definition.pdf
        OSG Technical Report 4.1
          http://www.linz.govt.nz/docs/miscellaneous/nzmg.pdf
      */

    /**
     * iterations: Number of iterations to refine inverse transform.
     *     0 -> km accuracy
     *     1 -> m accuracy -- suitable for most mapping applications
     *     2 -> mm accuracy
     */


    function init$19() {
      this.A = [];
      this.A[1] = 0.6399175073;
      this.A[2] = -0.1358797613;
      this.A[3] = 0.063294409;
      this.A[4] = -0.02526853;
      this.A[5] = 0.0117879;
      this.A[6] = -0.0055161;
      this.A[7] = 0.0026906;
      this.A[8] = -0.001333;
      this.A[9] = 0.00067;
      this.A[10] = -0.00034;

      this.B_re = [];
      this.B_im = [];
      this.B_re[1] = 0.7557853228;
      this.B_im[1] = 0;
      this.B_re[2] = 0.249204646;
      this.B_im[2] = 0.003371507;
      this.B_re[3] = -0.001541739;
      this.B_im[3] = 0.041058560;
      this.B_re[4] = -0.10162907;
      this.B_im[4] = 0.01727609;
      this.B_re[5] = -0.26623489;
      this.B_im[5] = -0.36249218;
      this.B_re[6] = -0.6870983;
      this.B_im[6] = -1.1651967;

      this.C_re = [];
      this.C_im = [];
      this.C_re[1] = 1.3231270439;
      this.C_im[1] = 0;
      this.C_re[2] = -0.577245789;
      this.C_im[2] = -0.007809598;
      this.C_re[3] = 0.508307513;
      this.C_im[3] = -0.112208952;
      this.C_re[4] = -0.15094762;
      this.C_im[4] = 0.18200602;
      this.C_re[5] = 1.01418179;
      this.C_im[5] = 1.64497696;
      this.C_re[6] = 1.9660549;
      this.C_im[6] = 2.5127645;

      this.D = [];
      this.D[1] = 1.5627014243;
      this.D[2] = 0.5185406398;
      this.D[3] = -0.03333098;
      this.D[4] = -0.1052906;
      this.D[5] = -0.0368594;
      this.D[6] = 0.007317;
      this.D[7] = 0.01220;
      this.D[8] = 0.00394;
      this.D[9] = -0.0013;
    }

    /**
        New Zealand Map Grid Forward  - long/lat to x/y
        long/lat in radians
      */
    function forward$18(p) {
      var n;
      var lon = p.x;
      var lat = p.y;

      var delta_lat = lat - this.lat0;
      var delta_lon = lon - this.long0;

      // 1. Calculate d_phi and d_psi    ...                          // and d_lambda
      // For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians.
      var d_phi = delta_lat / SEC_TO_RAD * 1E-5;
      var d_lambda = delta_lon;
      var d_phi_n = 1; // d_phi^0

      var d_psi = 0;
      for (n = 1; n <= 10; n++) {
        d_phi_n = d_phi_n * d_phi;
        d_psi = d_psi + this.A[n] * d_phi_n;
      }

      // 2. Calculate theta
      var th_re = d_psi;
      var th_im = d_lambda;

      // 3. Calculate z
      var th_n_re = 1;
      var th_n_im = 0; // theta^0
      var th_n_re1;
      var th_n_im1;

      var z_re = 0;
      var z_im = 0;
      for (n = 1; n <= 6; n++) {
        th_n_re1 = th_n_re * th_re - th_n_im * th_im;
        th_n_im1 = th_n_im * th_re + th_n_re * th_im;
        th_n_re = th_n_re1;
        th_n_im = th_n_im1;
        z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im;
        z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im;
      }

      // 4. Calculate easting and northing
      p.x = (z_im * this.a) + this.x0;
      p.y = (z_re * this.a) + this.y0;

      return p;
    }

    /**
        New Zealand Map Grid Inverse  -  x/y to long/lat
      */
    function inverse$18(p) {
      var n;
      var x = p.x;
      var y = p.y;

      var delta_x = x - this.x0;
      var delta_y = y - this.y0;

      // 1. Calculate z
      var z_re = delta_y / this.a;
      var z_im = delta_x / this.a;

      // 2a. Calculate theta - first approximation gives km accuracy
      var z_n_re = 1;
      var z_n_im = 0; // z^0
      var z_n_re1;
      var z_n_im1;

      var th_re = 0;
      var th_im = 0;
      for (n = 1; n <= 6; n++) {
        z_n_re1 = z_n_re * z_re - z_n_im * z_im;
        z_n_im1 = z_n_im * z_re + z_n_re * z_im;
        z_n_re = z_n_re1;
        z_n_im = z_n_im1;
        th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im;
        th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im;
      }

      // 2b. Iterate to refine the accuracy of the calculation
      //        0 iterations gives km accuracy
      //        1 iteration gives m accuracy -- good enough for most mapping applications
      //        2 iterations bives mm accuracy
      for (var i = 0; i < this.iterations; i++) {
        var th_n_re = th_re;
        var th_n_im = th_im;
        var th_n_re1;
        var th_n_im1;

        var num_re = z_re;
        var num_im = z_im;
        for (n = 2; n <= 6; n++) {
          th_n_re1 = th_n_re * th_re - th_n_im * th_im;
          th_n_im1 = th_n_im * th_re + th_n_re * th_im;
          th_n_re = th_n_re1;
          th_n_im = th_n_im1;
          num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
          num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
        }

        th_n_re = 1;
        th_n_im = 0;
        var den_re = this.B_re[1];
        var den_im = this.B_im[1];
        for (n = 2; n <= 6; n++) {
          th_n_re1 = th_n_re * th_re - th_n_im * th_im;
          th_n_im1 = th_n_im * th_re + th_n_re * th_im;
          th_n_re = th_n_re1;
          th_n_im = th_n_im1;
          den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
          den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
        }

        // Complex division
        var den2 = den_re * den_re + den_im * den_im;
        th_re = (num_re * den_re + num_im * den_im) / den2;
        th_im = (num_im * den_re - num_re * den_im) / den2;
      }

      // 3. Calculate d_phi              ...                                    // and d_lambda
      var d_psi = th_re;
      var d_lambda = th_im;
      var d_psi_n = 1; // d_psi^0

      var d_phi = 0;
      for (n = 1; n <= 9; n++) {
        d_psi_n = d_psi_n * d_psi;
        d_phi = d_phi + this.D[n] * d_psi_n;
      }

      // 4. Calculate latitude and longitude
      // d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians.
      var lat = this.lat0 + (d_phi * SEC_TO_RAD * 1E5);
      var lon = this.long0 + d_lambda;

      p.x = lon;
      p.y = lat;

      return p;
    }

    var names$20 = ["New_Zealand_Map_Grid", "nzmg"];
    var nzmg = {
      init: init$19,
      forward: forward$18,
      inverse: inverse$18,
      names: names$20
    };

    /*
      reference
        "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
        The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
      */


    /* Initialize the Miller Cylindrical projection
      -------------------------------------------*/
    function init$20() {
      //no-op
    }

    /* Miller Cylindrical forward equations--mapping lat,long to x,y
        ------------------------------------------------------------*/
    function forward$19(p) {
      var lon = p.x;
      var lat = p.y;
      /* Forward equations
          -----------------*/
      var dlon = adjust_lon(lon - this.long0);
      var x = this.x0 + this.a * dlon;
      var y = this.y0 + this.a * Math.log(Math.tan((Math.PI / 4) + (lat / 2.5))) * 1.25;

      p.x = x;
      p.y = y;
      return p;
    }

    /* Miller Cylindrical inverse equations--mapping x,y to lat/long
        ------------------------------------------------------------*/
    function inverse$19(p) {
      p.x -= this.x0;
      p.y -= this.y0;

      var lon = adjust_lon(this.long0 + p.x / this.a);
      var lat = 2.5 * (Math.atan(Math.exp(0.8 * p.y / this.a)) - Math.PI / 4);

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$21 = ["Miller_Cylindrical", "mill"];
    var mill = {
      init: init$20,
      forward: forward$19,
      inverse: inverse$19,
      names: names$21
    };

    var MAX_ITER$3 = 20;
    function init$21() {
      /* Place parameters in static storage for common use
        -------------------------------------------------*/


      if (!this.sphere) {
        this.en = pj_enfn(this.es);
      }
      else {
        this.n = 1;
        this.m = 0;
        this.es = 0;
        this.C_y = Math.sqrt((this.m + 1) / this.n);
        this.C_x = this.C_y / (this.m + 1);
      }

    }

    /* Sinusoidal forward equations--mapping lat,long to x,y
      -----------------------------------------------------*/
    function forward$20(p) {
      var x, y;
      var lon = p.x;
      var lat = p.y;
      /* Forward equations
        -----------------*/
      lon = adjust_lon(lon - this.long0);

      if (this.sphere) {
        if (!this.m) {
          lat = this.n !== 1 ? Math.asin(this.n * Math.sin(lat)) : lat;
        }
        else {
          var k = this.n * Math.sin(lat);
          for (var i = MAX_ITER$3; i; --i) {
            var V = (this.m * lat + Math.sin(lat) - k) / (this.m + Math.cos(lat));
            lat -= V;
            if (Math.abs(V) < EPSLN) {
              break;
            }
          }
        }
        x = this.a * this.C_x * lon * (this.m + Math.cos(lat));
        y = this.a * this.C_y * lat;

      }
      else {

        var s = Math.sin(lat);
        var c = Math.cos(lat);
        y = this.a * pj_mlfn(lat, s, c, this.en);
        x = this.a * lon * c / Math.sqrt(1 - this.es * s * s);
      }

      p.x = x;
      p.y = y;
      return p;
    }

    function inverse$20(p) {
      var lat, temp, lon, s;

      p.x -= this.x0;
      lon = p.x / this.a;
      p.y -= this.y0;
      lat = p.y / this.a;

      if (this.sphere) {
        lat /= this.C_y;
        lon = lon / (this.C_x * (this.m + Math.cos(lat)));
        if (this.m) {
          lat = asinz((this.m * lat + Math.sin(lat)) / this.n);
        }
        else if (this.n !== 1) {
          lat = asinz(Math.sin(lat) / this.n);
        }
        lon = adjust_lon(lon + this.long0);
        lat = adjust_lat(lat);
      }
      else {
        lat = pj_inv_mlfn(p.y / this.a, this.es, this.en);
        s = Math.abs(lat);
        if (s < HALF_PI) {
          s = Math.sin(lat);
          temp = this.long0 + p.x * Math.sqrt(1 - this.es * s * s) / (this.a * Math.cos(lat));
          //temp = this.long0 + p.x / (this.a * Math.cos(lat));
          lon = adjust_lon(temp);
        }
        else if ((s - EPSLN) < HALF_PI) {
          lon = this.long0;
        }
      }
      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$22 = ["Sinusoidal", "sinu"];
    var sinu = {
      init: init$21,
      forward: forward$20,
      inverse: inverse$20,
      names: names$22
    };

    function init$22() {}
    /* Mollweide forward equations--mapping lat,long to x,y
        ----------------------------------------------------*/
    function forward$21(p) {

      /* Forward equations
          -----------------*/
      var lon = p.x;
      var lat = p.y;

      var delta_lon = adjust_lon(lon - this.long0);
      var theta = lat;
      var con = Math.PI * Math.sin(lat);

      /* Iterate using the Newton-Raphson method to find theta
          -----------------------------------------------------*/
      while (true) {
        var delta_theta = -(theta + Math.sin(theta) - con) / (1 + Math.cos(theta));
        theta += delta_theta;
        if (Math.abs(delta_theta) < EPSLN) {
          break;
        }
      }
      theta /= 2;

      /* If the latitude is 90 deg, force the x coordinate to be "0 + false easting"
           this is done here because of precision problems with "cos(theta)"
           --------------------------------------------------------------------------*/
      if (Math.PI / 2 - Math.abs(lat) < EPSLN) {
        delta_lon = 0;
      }
      var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0;
      var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0;

      p.x = x;
      p.y = y;
      return p;
    }

    function inverse$21(p) {
      var theta;
      var arg;

      /* Inverse equations
          -----------------*/
      p.x -= this.x0;
      p.y -= this.y0;
      arg = p.y / (1.4142135623731 * this.a);

      /* Because of division by zero problems, 'arg' can not be 1.  Therefore
           a number very close to one is used instead.
           -------------------------------------------------------------------*/
      if (Math.abs(arg) > 0.999999999999) {
        arg = 0.999999999999;
      }
      theta = Math.asin(arg);
      var lon = adjust_lon(this.long0 + (p.x / (0.900316316158 * this.a * Math.cos(theta))));
      if (lon < (-Math.PI)) {
        lon = -Math.PI;
      }
      if (lon > Math.PI) {
        lon = Math.PI;
      }
      arg = (2 * theta + Math.sin(2 * theta)) / Math.PI;
      if (Math.abs(arg) > 1) {
        arg = 1;
      }
      var lat = Math.asin(arg);

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$23 = ["Mollweide", "moll"];
    var moll = {
      init: init$22,
      forward: forward$21,
      inverse: inverse$21,
      names: names$23
    };

    function init$23() {

      /* Place parameters in static storage for common use
          -------------------------------------------------*/
      // Standard Parallels cannot be equal and on opposite sides of the equator
      if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
        return;
      }
      this.lat2 = this.lat2 || this.lat1;
      this.temp = this.b / this.a;
      this.es = 1 - Math.pow(this.temp, 2);
      this.e = Math.sqrt(this.es);
      this.e0 = e0fn(this.es);
      this.e1 = e1fn(this.es);
      this.e2 = e2fn(this.es);
      this.e3 = e3fn(this.es);

      this.sinphi = Math.sin(this.lat1);
      this.cosphi = Math.cos(this.lat1);

      this.ms1 = msfnz(this.e, this.sinphi, this.cosphi);
      this.ml1 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat1);

      if (Math.abs(this.lat1 - this.lat2) < EPSLN) {
        this.ns = this.sinphi;
      }
      else {
        this.sinphi = Math.sin(this.lat2);
        this.cosphi = Math.cos(this.lat2);
        this.ms2 = msfnz(this.e, this.sinphi, this.cosphi);
        this.ml2 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
        this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
      }
      this.g = this.ml1 + this.ms1 / this.ns;
      this.ml0 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
      this.rh = this.a * (this.g - this.ml0);
    }

    /* Equidistant Conic forward equations--mapping lat,long to x,y
      -----------------------------------------------------------*/
    function forward$22(p) {
      var lon = p.x;
      var lat = p.y;
      var rh1;

      /* Forward equations
          -----------------*/
      if (this.sphere) {
        rh1 = this.a * (this.g - lat);
      }
      else {
        var ml = mlfn(this.e0, this.e1, this.e2, this.e3, lat);
        rh1 = this.a * (this.g - ml);
      }
      var theta = this.ns * adjust_lon(lon - this.long0);
      var x = this.x0 + rh1 * Math.sin(theta);
      var y = this.y0 + this.rh - rh1 * Math.cos(theta);
      p.x = x;
      p.y = y;
      return p;
    }

    /* Inverse equations
      -----------------*/
    function inverse$22(p) {
      p.x -= this.x0;
      p.y = this.rh - p.y + this.y0;
      var con, rh1, lat, lon;
      if (this.ns >= 0) {
        rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
        con = 1;
      }
      else {
        rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
        con = -1;
      }
      var theta = 0;
      if (rh1 !== 0) {
        theta = Math.atan2(con * p.x, con * p.y);
      }

      if (this.sphere) {
        lon = adjust_lon(this.long0 + theta / this.ns);
        lat = adjust_lat(this.g - rh1 / this.a);
        p.x = lon;
        p.y = lat;
        return p;
      }
      else {
        var ml = this.g - rh1 / this.a;
        lat = imlfn(ml, this.e0, this.e1, this.e2, this.e3);
        lon = adjust_lon(this.long0 + theta / this.ns);
        p.x = lon;
        p.y = lat;
        return p;
      }

    }

    var names$24 = ["Equidistant_Conic", "eqdc"];
    var eqdc = {
      init: init$23,
      forward: forward$22,
      inverse: inverse$22,
      names: names$24
    };

    /* Initialize the Van Der Grinten projection
      ----------------------------------------*/
    function init$24() {
      //this.R = 6370997; //Radius of earth
      this.R = this.a;
    }

    function forward$23(p) {

      var lon = p.x;
      var lat = p.y;

      /* Forward equations
        -----------------*/
      var dlon = adjust_lon(lon - this.long0);
      var x, y;

      if (Math.abs(lat) <= EPSLN) {
        x = this.x0 + this.R * dlon;
        y = this.y0;
      }
      var theta = asinz(2 * Math.abs(lat / Math.PI));
      if ((Math.abs(dlon) <= EPSLN) || (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN)) {
        x = this.x0;
        if (lat >= 0) {
          y = this.y0 + Math.PI * this.R * Math.tan(0.5 * theta);
        }
        else {
          y = this.y0 + Math.PI * this.R * -Math.tan(0.5 * theta);
        }
        //  return(OK);
      }
      var al = 0.5 * Math.abs((Math.PI / dlon) - (dlon / Math.PI));
      var asq = al * al;
      var sinth = Math.sin(theta);
      var costh = Math.cos(theta);

      var g = costh / (sinth + costh - 1);
      var gsq = g * g;
      var m = g * (2 / sinth - 1);
      var msq = m * m;
      var con = Math.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
      if (dlon < 0) {
        con = -con;
      }
      x = this.x0 + con;
      //con = Math.abs(con / (Math.PI * this.R));
      var q = asq + g;
      con = Math.PI * this.R * (m * q - al * Math.sqrt((msq + asq) * (asq + 1) - q * q)) / (msq + asq);
      if (lat >= 0) {
        //y = this.y0 + Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
        y = this.y0 + con;
      }
      else {
        //y = this.y0 - Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
        y = this.y0 - con;
      }
      p.x = x;
      p.y = y;
      return p;
    }

    /* Van Der Grinten inverse equations--mapping x,y to lat/long
      ---------------------------------------------------------*/
    function inverse$23(p) {
      var lon, lat;
      var xx, yy, xys, c1, c2, c3;
      var a1;
      var m1;
      var con;
      var th1;
      var d;

      /* inverse equations
        -----------------*/
      p.x -= this.x0;
      p.y -= this.y0;
      con = Math.PI * this.R;
      xx = p.x / con;
      yy = p.y / con;
      xys = xx * xx + yy * yy;
      c1 = -Math.abs(yy) * (1 + xys);
      c2 = c1 - 2 * yy * yy + xx * xx;
      c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys;
      d = yy * yy / c3 + (2 * c2 * c2 * c2 / c3 / c3 / c3 - 9 * c1 * c2 / c3 / c3) / 27;
      a1 = (c1 - c2 * c2 / 3 / c3) / c3;
      m1 = 2 * Math.sqrt(-a1 / 3);
      con = ((3 * d) / a1) / m1;
      if (Math.abs(con) > 1) {
        if (con >= 0) {
          con = 1;
        }
        else {
          con = -1;
        }
      }
      th1 = Math.acos(con) / 3;
      if (p.y >= 0) {
        lat = (-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
      }
      else {
        lat = -(-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
      }

      if (Math.abs(xx) < EPSLN) {
        lon = this.long0;
      }
      else {
        lon = adjust_lon(this.long0 + Math.PI * (xys - 1 + Math.sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys)) / 2 / xx);
      }

      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$25 = ["Van_der_Grinten_I", "VanDerGrinten", "vandg"];
    var vandg = {
      init: init$24,
      forward: forward$23,
      inverse: inverse$23,
      names: names$25
    };

    function init$25() {
      this.sin_p12 = Math.sin(this.lat0);
      this.cos_p12 = Math.cos(this.lat0);
    }

    function forward$24(p) {
      var lon = p.x;
      var lat = p.y;
      var sinphi = Math.sin(p.y);
      var cosphi = Math.cos(p.y);
      var dlon = adjust_lon(lon - this.long0);
      var e0, e1, e2, e3, Mlp, Ml, tanphi, Nl1, Nl, psi, Az, G, H, GH, Hs, c, kp, cos_c, s, s2, s3, s4, s5;
      if (this.sphere) {
        if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
          //North Pole case
          p.x = this.x0 + this.a * (HALF_PI - lat) * Math.sin(dlon);
          p.y = this.y0 - this.a * (HALF_PI - lat) * Math.cos(dlon);
          return p;
        }
        else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
          //South Pole case
          p.x = this.x0 + this.a * (HALF_PI + lat) * Math.sin(dlon);
          p.y = this.y0 + this.a * (HALF_PI + lat) * Math.cos(dlon);
          return p;
        }
        else {
          //default case
          cos_c = this.sin_p12 * sinphi + this.cos_p12 * cosphi * Math.cos(dlon);
          c = Math.acos(cos_c);
          kp = c ? c / Math.sin(c) : 1;
          p.x = this.x0 + this.a * kp * cosphi * Math.sin(dlon);
          p.y = this.y0 + this.a * kp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * Math.cos(dlon));
          return p;
        }
      }
      else {
        e0 = e0fn(this.es);
        e1 = e1fn(this.es);
        e2 = e2fn(this.es);
        e3 = e3fn(this.es);
        if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
          //North Pole case
          Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
          Ml = this.a * mlfn(e0, e1, e2, e3, lat);
          p.x = this.x0 + (Mlp - Ml) * Math.sin(dlon);
          p.y = this.y0 - (Mlp - Ml) * Math.cos(dlon);
          return p;
        }
        else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
          //South Pole case
          Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
          Ml = this.a * mlfn(e0, e1, e2, e3, lat);
          p.x = this.x0 + (Mlp + Ml) * Math.sin(dlon);
          p.y = this.y0 + (Mlp + Ml) * Math.cos(dlon);
          return p;
        }
        else {
          //Default case
          tanphi = sinphi / cosphi;
          Nl1 = gN(this.a, this.e, this.sin_p12);
          Nl = gN(this.a, this.e, sinphi);
          psi = Math.atan((1 - this.es) * tanphi + this.es * Nl1 * this.sin_p12 / (Nl * cosphi));
          Az = Math.atan2(Math.sin(dlon), this.cos_p12 * Math.tan(psi) - this.sin_p12 * Math.cos(dlon));
          if (Az === 0) {
            s = Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
          }
          else if (Math.abs(Math.abs(Az) - Math.PI) <= EPSLN) {
            s = -Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
          }
          else {
            s = Math.asin(Math.sin(dlon) * Math.cos(psi) / Math.sin(Az));
          }
          G = this.e * this.sin_p12 / Math.sqrt(1 - this.es);
          H = this.e * this.cos_p12 * Math.cos(Az) / Math.sqrt(1 - this.es);
          GH = G * H;
          Hs = H * H;
          s2 = s * s;
          s3 = s2 * s;
          s4 = s3 * s;
          s5 = s4 * s;
          c = Nl1 * s * (1 - s2 * Hs * (1 - Hs) / 6 + s3 / 8 * GH * (1 - 2 * Hs) + s4 / 120 * (Hs * (4 - 7 * Hs) - 3 * G * G * (1 - 7 * Hs)) - s5 / 48 * GH);
          p.x = this.x0 + c * Math.sin(Az);
          p.y = this.y0 + c * Math.cos(Az);
          return p;
        }
      }


    }

    function inverse$24(p) {
      p.x -= this.x0;
      p.y -= this.y0;
      var rh, z, sinz, cosz, lon, lat, con, e0, e1, e2, e3, Mlp, M, N1, psi, Az, cosAz, tmp, A, B, D, Ee, F, sinpsi;
      if (this.sphere) {
        rh = Math.sqrt(p.x * p.x + p.y * p.y);
        if (rh > (2 * HALF_PI * this.a)) {
          return;
        }
        z = rh / this.a;

        sinz = Math.sin(z);
        cosz = Math.cos(z);

        lon = this.long0;
        if (Math.abs(rh) <= EPSLN) {
          lat = this.lat0;
        }
        else {
          lat = asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh);
          con = Math.abs(this.lat0) - HALF_PI;
          if (Math.abs(con) <= EPSLN) {
            if (this.lat0 >= 0) {
              lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
            }
            else {
              lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
            }
          }
          else {
            /*con = cosz - this.sin_p12 * Math.sin(lat);
            if ((Math.abs(con) < EPSLN) && (Math.abs(p.x) < EPSLN)) {
              //no-op, just keep the lon value as is
            } else {
              var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh));
              lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh)));
            }*/
            lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p12 * cosz - p.y * this.sin_p12 * sinz));
          }
        }

        p.x = lon;
        p.y = lat;
        return p;
      }
      else {
        e0 = e0fn(this.es);
        e1 = e1fn(this.es);
        e2 = e2fn(this.es);
        e3 = e3fn(this.es);
        if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
          //North pole case
          Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
          rh = Math.sqrt(p.x * p.x + p.y * p.y);
          M = Mlp - rh;
          lat = imlfn(M / this.a, e0, e1, e2, e3);
          lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
          p.x = lon;
          p.y = lat;
          return p;
        }
        else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
          //South pole case
          Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
          rh = Math.sqrt(p.x * p.x + p.y * p.y);
          M = rh - Mlp;

          lat = imlfn(M / this.a, e0, e1, e2, e3);
          lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
          p.x = lon;
          p.y = lat;
          return p;
        }
        else {
          //default case
          rh = Math.sqrt(p.x * p.x + p.y * p.y);
          Az = Math.atan2(p.x, p.y);
          N1 = gN(this.a, this.e, this.sin_p12);
          cosAz = Math.cos(Az);
          tmp = this.e * this.cos_p12 * cosAz;
          A = -tmp * tmp / (1 - this.es);
          B = 3 * this.es * (1 - A) * this.sin_p12 * this.cos_p12 * cosAz / (1 - this.es);
          D = rh / N1;
          Ee = D - A * (1 + A) * Math.pow(D, 3) / 6 - B * (1 + 3 * A) * Math.pow(D, 4) / 24;
          F = 1 - A * Ee * Ee / 2 - D * Ee * Ee * Ee / 6;
          psi = Math.asin(this.sin_p12 * Math.cos(Ee) + this.cos_p12 * Math.sin(Ee) * cosAz);
          lon = adjust_lon(this.long0 + Math.asin(Math.sin(Az) * Math.sin(Ee) / Math.cos(psi)));
          sinpsi = Math.sin(psi);
          lat = Math.atan2((sinpsi - this.es * F * this.sin_p12) * Math.tan(psi), sinpsi * (1 - this.es));
          p.x = lon;
          p.y = lat;
          return p;
        }
      }

    }

    var names$26 = ["Azimuthal_Equidistant", "aeqd"];
    var aeqd = {
      init: init$25,
      forward: forward$24,
      inverse: inverse$24,
      names: names$26
    };

    function init$26() {
      //double temp;      /* temporary variable    */

      /* Place parameters in static storage for common use
          -------------------------------------------------*/
      this.sin_p14 = Math.sin(this.lat0);
      this.cos_p14 = Math.cos(this.lat0);
    }

    /* Orthographic forward equations--mapping lat,long to x,y
        ---------------------------------------------------*/
    function forward$25(p) {
      var sinphi, cosphi; /* sin and cos value        */
      var dlon; /* delta longitude value      */
      var coslon; /* cos of longitude        */
      var ksp; /* scale factor          */
      var g, x, y;
      var lon = p.x;
      var lat = p.y;
      /* Forward equations
          -----------------*/
      dlon = adjust_lon(lon - this.long0);

      sinphi = Math.sin(lat);
      cosphi = Math.cos(lat);

      coslon = Math.cos(dlon);
      g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
      ksp = 1;
      if ((g > 0) || (Math.abs(g) <= EPSLN)) {
        x = this.a * ksp * cosphi * Math.sin(dlon);
        y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
      }
      p.x = x;
      p.y = y;
      return p;
    }

    function inverse$25(p) {
      var rh; /* height above ellipsoid      */
      var z; /* angle          */
      var sinz, cosz; /* sin of z and cos of z      */
      var con;
      var lon, lat;
      /* Inverse equations
          -----------------*/
      p.x -= this.x0;
      p.y -= this.y0;
      rh = Math.sqrt(p.x * p.x + p.y * p.y);
      z = asinz(rh / this.a);

      sinz = Math.sin(z);
      cosz = Math.cos(z);

      lon = this.long0;
      if (Math.abs(rh) <= EPSLN) {
        lat = this.lat0;
        p.x = lon;
        p.y = lat;
        return p;
      }
      lat = asinz(cosz * this.sin_p14 + (p.y * sinz * this.cos_p14) / rh);
      con = Math.abs(this.lat0) - HALF_PI;
      if (Math.abs(con) <= EPSLN) {
        if (this.lat0 >= 0) {
          lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
        }
        else {
          lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
        }
        p.x = lon;
        p.y = lat;
        return p;
      }
      lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz), rh * this.cos_p14 * cosz - p.y * this.sin_p14 * sinz));
      p.x = lon;
      p.y = lat;
      return p;
    }

    var names$27 = ["ortho"];
    var ortho = {
      init: init$26,
      forward: forward$25,
      inverse: inverse$25,
      names: names$27
    };

    // QSC projection rewritten from the original PROJ4
    // https://github.com/OSGeo/proj.4/blob/master/src/PJ_qsc.c

    /* constants */
    var FACE_ENUM = {
        FRONT: 1,
        RIGHT: 2,
        BACK: 3,
        LEFT: 4,
        TOP: 5,
        BOTTOM: 6
    };

    var AREA_ENUM = {
        AREA_0: 1,
        AREA_1: 2,
        AREA_2: 3,
        AREA_3: 4
    };

    function init$27() {

      this.x0 = this.x0 || 0;
      this.y0 = this.y0 || 0;
      this.lat0 = this.lat0 || 0;
      this.long0 = this.long0 || 0;
      this.lat_ts = this.lat_ts || 0;
      this.title = this.title || "Quadrilateralized Spherical Cube";

      /* Determine the cube face from the center of projection. */
      if (this.lat0 >= HALF_PI - FORTPI / 2.0) {
        this.face = FACE_ENUM.TOP;
      } else if (this.lat0 <= -(HALF_PI - FORTPI / 2.0)) {
        this.face = FACE_ENUM.BOTTOM;
      } else if (Math.abs(this.long0) <= FORTPI) {
        this.face = FACE_ENUM.FRONT;
      } else if (Math.abs(this.long0) <= HALF_PI + FORTPI) {
        this.face = this.long0 > 0.0 ? FACE_ENUM.RIGHT : FACE_ENUM.LEFT;
      } else {
        this.face = FACE_ENUM.BACK;
      }

      /* Fill in useful values for the ellipsoid <-> sphere shift
       * described in [LK12]. */
      if (this.es !== 0) {
        this.one_minus_f = 1 - (this.a - this.b) / this.a;
        this.one_minus_f_squared = this.one_minus_f * this.one_minus_f;
      }
    }

    // QSC forward equations--mapping lat,long to x,y
    // -----------------------------------------------------------------
    function forward$26(p) {
      var xy = {x: 0, y: 0};
      var lat, lon;
      var theta, phi;
      var t, mu;
      /* nu; */
      var area = {value: 0};

      // move lon according to projection's lon
      p.x -= this.long0;

      /* Convert the geodetic latitude to a geocentric latitude.
       * This corresponds to the shift from the ellipsoid to the sphere
       * described in [LK12]. */
      if (this.es !== 0) {//if (P->es != 0) {
        lat = Math.atan(this.one_minus_f_squared * Math.tan(p.y));
      } else {
        lat = p.y;
      }

      /* Convert the input lat, lon into theta, phi as used by QSC.
       * This depends on the cube face and the area on it.
       * For the top and bottom face, we can compute theta and phi
       * directly from phi, lam. For the other faces, we must use
       * unit sphere cartesian coordinates as an intermediate step. */
      lon = p.x; //lon = lp.lam;
      if (this.face === FACE_ENUM.TOP) {
        phi = HALF_PI - lat;
        if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
          area.value = AREA_ENUM.AREA_0;
          theta = lon - HALF_PI;
        } else if (lon > HALF_PI + FORTPI || lon <= -(HALF_PI + FORTPI)) {
          area.value = AREA_ENUM.AREA_1;
          theta = (lon > 0.0 ? lon - SPI : lon + SPI);
        } else if (lon > -(HALF_PI + FORTPI) && lon <= -FORTPI) {
          area.value = AREA_ENUM.AREA_2;
          theta = lon + HALF_PI;
        } else {
          area.value = AREA_ENUM.AREA_3;
          theta = lon;
        }
      } else if (this.face === FACE_ENUM.BOTTOM) {
        phi = HALF_PI + lat;
        if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
          area.value = AREA_ENUM.AREA_0;
          theta = -lon + HALF_PI;
        } else if (lon < FORTPI && lon >= -FORTPI) {
          area.value = AREA_ENUM.AREA_1;
          theta = -lon;
        } else if (lon < -FORTPI && lon >= -(HALF_PI + FORTPI)) {
          area.value = AREA_ENUM.AREA_2;
          theta = -lon - HALF_PI;
        } else {
          area.value = AREA_ENUM.AREA_3;
          theta = (lon > 0.0 ? -lon + SPI : -lon - SPI);
        }
      } else {
        var q, r, s;
        var sinlat, coslat;
        var sinlon, coslon;

        if (this.face === FACE_ENUM.RIGHT) {
          lon = qsc_shift_lon_origin(lon, +HALF_PI);
        } else if (this.face === FACE_ENUM.BACK) {
          lon = qsc_shift_lon_origin(lon, +SPI);
        } else if (this.face === FACE_ENUM.LEFT) {
          lon = qsc_shift_lon_origin(lon, -HALF_PI);
        }
        sinlat = Math.sin(lat);
        coslat = Math.cos(lat);
        sinlon = Math.sin(lon);
        coslon = Math.cos(lon);
        q = coslat * coslon;
        r = coslat * sinlon;
        s = sinlat;

        if (this.face === FACE_ENUM.FRONT) {
          phi = Math.acos(q);
          theta = qsc_fwd_equat_face_theta(phi, s, r, area);
        } else if (this.face === FACE_ENUM.RIGHT) {
          phi = Math.acos(r);
          theta = qsc_fwd_equat_face_theta(phi, s, -q, area);
        } else if (this.face === FACE_ENUM.BACK) {
          phi = Math.acos(-q);
          theta = qsc_fwd_equat_face_theta(phi, s, -r, area);
        } else if (this.face === FACE_ENUM.LEFT) {
          phi = Math.acos(-r);
          theta = qsc_fwd_equat_face_theta(phi, s, q, area);
        } else {
          /* Impossible */
          phi = theta = 0;
          area.value = AREA_ENUM.AREA_0;
        }
      }

      /* Compute mu and nu for the area of definition.
       * For mu, see Eq. (3-21) in [OL76], but note the typos:
       * compare with Eq. (3-14). For nu, see Eq. (3-38). */
      mu = Math.atan((12 / SPI) * (theta + Math.acos(Math.sin(theta) * Math.cos(FORTPI)) - HALF_PI));
      t = Math.sqrt((1 - Math.cos(phi)) / (Math.cos(mu) * Math.cos(mu)) / (1 - Math.cos(Math.atan(1 / Math.cos(theta)))));

      /* Apply the result to the real area. */
      if (area.value === AREA_ENUM.AREA_1) {
        mu += HALF_PI;
      } else if (area.value === AREA_ENUM.AREA_2) {
        mu += SPI;
      } else if (area.value === AREA_ENUM.AREA_3) {
        mu += 1.5 * SPI;
      }

      /* Now compute x, y from mu and nu */
      xy.x = t * Math.cos(mu);
      xy.y = t * Math.sin(mu);
      xy.x = xy.x * this.a + this.x0;
      xy.y = xy.y * this.a + this.y0;

      p.x = xy.x;
      p.y = xy.y;
      return p;
    }

    // QSC inverse equations--mapping x,y to lat/long
    // -----------------------------------------------------------------
    function inverse$26(p) {
      var lp = {lam: 0, phi: 0};
      var mu, nu, cosmu, tannu;
      var tantheta, theta, cosphi, phi;
      var t;
      var area = {value: 0};

      /* de-offset */
      p.x = (p.x - this.x0) / this.a;
      p.y = (p.y - this.y0) / this.a;

      /* Convert the input x, y to the mu and nu angles as used by QSC.
       * This depends on the area of the cube face. */
      nu = Math.atan(Math.sqrt(p.x * p.x + p.y * p.y));
      mu = Math.atan2(p.y, p.x);
      if (p.x >= 0.0 && p.x >= Math.abs(p.y)) {
        area.value = AREA_ENUM.AREA_0;
      } else if (p.y >= 0.0 && p.y >= Math.abs(p.x)) {
        area.value = AREA_ENUM.AREA_1;
        mu -= HALF_PI;
      } else if (p.x < 0.0 && -p.x >= Math.abs(p.y)) {
        area.value = AREA_ENUM.AREA_2;
        mu = (mu < 0.0 ? mu + SPI : mu - SPI);
      } else {
        area.value = AREA_ENUM.AREA_3;
        mu += HALF_PI;
      }

      /* Compute phi and theta for the area of definition.
       * The inverse projection is not described in the original paper, but some
       * good hints can be found here (as of 2011-12-14):
       * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302
       * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */
      t = (SPI / 12) * Math.tan(mu);
      tantheta = Math.sin(t) / (Math.cos(t) - (1 / Math.sqrt(2)));
      theta = Math.atan(tantheta);
      cosmu = Math.cos(mu);
      tannu = Math.tan(nu);
      cosphi = 1 - cosmu * cosmu * tannu * tannu * (1 - Math.cos(Math.atan(1 / Math.cos(theta))));
      if (cosphi < -1) {
        cosphi = -1;
      } else if (cosphi > +1) {
        cosphi = +1;
      }

      /* Apply the result to the real area on the cube face.
       * For the top and bottom face, we can compute phi and lam directly.
       * For the other faces, we must use unit sphere cartesian coordinates
       * as an intermediate step. */
      if (this.face === FACE_ENUM.TOP) {
        phi = Math.acos(cosphi);
        lp.phi = HALF_PI - phi;
        if (area.value === AREA_ENUM.AREA_0) {
          lp.lam = theta + HALF_PI;
        } else if (area.value === AREA_ENUM.AREA_1) {
          lp.lam = (theta < 0.0 ? theta + SPI : theta - SPI);
        } else if (area.value === AREA_ENUM.AREA_2) {
          lp.lam = theta - HALF_PI;
        } else /* area.value == AREA_ENUM.AREA_3 */ {
          lp.lam = theta;
        }
      } else if (this.face === FACE_ENUM.BOTTOM) {
        phi = Math.acos(cosphi);
        lp.phi = phi - HALF_PI;
        if (area.value === AREA_ENUM.AREA_0) {
          lp.lam = -theta + HALF_PI;
        } else if (area.value === AREA_ENUM.AREA_1) {
          lp.lam = -theta;
        } else if (area.value === AREA_ENUM.AREA_2) {
          lp.lam = -theta - HALF_PI;
        } else /* area.value == AREA_ENUM.AREA_3 */ {
          lp.lam = (theta < 0.0 ? -theta - SPI : -theta + SPI);
        }
      } else {
        /* Compute phi and lam via cartesian unit sphere coordinates. */
        var q, r, s;
        q = cosphi;
        t = q * q;
        if (t >= 1) {
          s = 0;
        } else {
          s = Math.sqrt(1 - t) * Math.sin(theta);
        }
        t += s * s;
        if (t >= 1) {
          r = 0;
        } else {
          r = Math.sqrt(1 - t);
        }
        /* Rotate q,r,s into the correct area. */
        if (area.value === AREA_ENUM.AREA_1) {
          t = r;
          r = -s;
          s = t;
        } else if (area.value === AREA_ENUM.AREA_2) {
          r = -r;
          s = -s;
        } else if (area.value === AREA_ENUM.AREA_3) {
          t = r;
          r = s;
          s = -t;
        }
        /* Rotate q,r,s into the correct cube face. */
        if (this.face === FACE_ENUM.RIGHT) {
          t = q;
          q = -r;
          r = t;
        } else if (this.face === FACE_ENUM.BACK) {
          q = -q;
          r = -r;
        } else if (this.face === FACE_ENUM.LEFT) {
          t = q;
          q = r;
          r = -t;
        }
        /* Now compute phi and lam from the unit sphere coordinates. */
        lp.phi = Math.acos(-s) - HALF_PI;
        lp.lam = Math.atan2(r, q);
        if (this.face === FACE_ENUM.RIGHT) {
          lp.lam = qsc_shift_lon_origin(lp.lam, -HALF_PI);
        } else if (this.face === FACE_ENUM.BACK) {
          lp.lam = qsc_shift_lon_origin(lp.lam, -SPI);
        } else if (this.face === FACE_ENUM.LEFT) {
          lp.lam = qsc_shift_lon_origin(lp.lam, +HALF_PI);
        }
      }

      /* Apply the shift from the sphere to the ellipsoid as described
       * in [LK12]. */
      if (this.es !== 0) {
        var invert_sign;
        var tanphi, xa;
        invert_sign = (lp.phi < 0 ? 1 : 0);
        tanphi = Math.tan(lp.phi);
        xa = this.b / Math.sqrt(tanphi * tanphi + this.one_minus_f_squared);
        lp.phi = Math.atan(Math.sqrt(this.a * this.a - xa * xa) / (this.one_minus_f * xa));
        if (invert_sign) {
          lp.phi = -lp.phi;
        }
      }

      lp.lam += this.long0;
      p.x = lp.lam;
      p.y = lp.phi;
      return p;
    }

    /* Helper function for forward projection: compute the theta angle
     * and determine the area number. */
    function qsc_fwd_equat_face_theta(phi, y, x, area) {
      var theta;
      if (phi < EPSLN) {
        area.value = AREA_ENUM.AREA_0;
        theta = 0.0;
      } else {
        theta = Math.atan2(y, x);
        if (Math.abs(theta) <= FORTPI) {
          area.value = AREA_ENUM.AREA_0;
        } else if (theta > FORTPI && theta <= HALF_PI + FORTPI) {
          area.value = AREA_ENUM.AREA_1;
          theta -= HALF_PI;
        } else if (theta > HALF_PI + FORTPI || theta <= -(HALF_PI + FORTPI)) {
          area.value = AREA_ENUM.AREA_2;
          theta = (theta >= 0.0 ? theta - SPI : theta + SPI);
        } else {
          area.value = AREA_ENUM.AREA_3;
          theta += HALF_PI;
        }
      }
      return theta;
    }

    /* Helper function: shift the longitude. */
    function qsc_shift_lon_origin(lon, offset) {
      var slon = lon + offset;
      if (slon < -SPI) {
        slon += TWO_PI;
      } else if (slon > +SPI) {
        slon -= TWO_PI;
      }
      return slon;
    }

    var names$28 = ["Quadrilateralized Spherical Cube", "Quadrilateralized_Spherical_Cube", "qsc"];
    var qsc = {
      init: init$27,
      forward: forward$26,
      inverse: inverse$26,
      names: names$28
    };

    // Robinson projection
    // Based on https://github.com/OSGeo/proj.4/blob/master/src/PJ_robin.c
    // Polynomial coeficients from http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039

    var COEFS_X = [
        [1.0000, 2.2199e-17, -7.15515e-05, 3.1103e-06],
        [0.9986, -0.000482243, -2.4897e-05, -1.3309e-06],
        [0.9954, -0.00083103, -4.48605e-05, -9.86701e-07],
        [0.9900, -0.00135364, -5.9661e-05, 3.6777e-06],
        [0.9822, -0.00167442, -4.49547e-06, -5.72411e-06],
        [0.9730, -0.00214868, -9.03571e-05, 1.8736e-08],
        [0.9600, -0.00305085, -9.00761e-05, 1.64917e-06],
        [0.9427, -0.00382792, -6.53386e-05, -2.6154e-06],
        [0.9216, -0.00467746, -0.00010457, 4.81243e-06],
        [0.8962, -0.00536223, -3.23831e-05, -5.43432e-06],
        [0.8679, -0.00609363, -0.000113898, 3.32484e-06],
        [0.8350, -0.00698325, -6.40253e-05, 9.34959e-07],
        [0.7986, -0.00755338, -5.00009e-05, 9.35324e-07],
        [0.7597, -0.00798324, -3.5971e-05, -2.27626e-06],
        [0.7186, -0.00851367, -7.01149e-05, -8.6303e-06],
        [0.6732, -0.00986209, -0.000199569, 1.91974e-05],
        [0.6213, -0.010418, 8.83923e-05, 6.24051e-06],
        [0.5722, -0.00906601, 0.000182, 6.24051e-06],
        [0.5322, -0.00677797, 0.000275608, 6.24051e-06]
    ];

    var COEFS_Y = [
        [-5.20417e-18, 0.0124, 1.21431e-18, -8.45284e-11],
        [0.0620, 0.0124, -1.26793e-09, 4.22642e-10],
        [0.1240, 0.0124, 5.07171e-09, -1.60604e-09],
        [0.1860, 0.0123999, -1.90189e-08, 6.00152e-09],
        [0.2480, 0.0124002, 7.10039e-08, -2.24e-08],
        [0.3100, 0.0123992, -2.64997e-07, 8.35986e-08],
        [0.3720, 0.0124029, 9.88983e-07, -3.11994e-07],
        [0.4340, 0.0123893, -3.69093e-06, -4.35621e-07],
        [0.4958, 0.0123198, -1.02252e-05, -3.45523e-07],
        [0.5571, 0.0121916, -1.54081e-05, -5.82288e-07],
        [0.6176, 0.0119938, -2.41424e-05, -5.25327e-07],
        [0.6769, 0.011713, -3.20223e-05, -5.16405e-07],
        [0.7346, 0.0113541, -3.97684e-05, -6.09052e-07],
        [0.7903, 0.0109107, -4.89042e-05, -1.04739e-06],
        [0.8435, 0.0103431, -6.4615e-05, -1.40374e-09],
        [0.8936, 0.00969686, -6.4636e-05, -8.547e-06],
        [0.9394, 0.00840947, -0.000192841, -4.2106e-06],
        [0.9761, 0.00616527, -0.000256, -4.2106e-06],
        [1.0000, 0.00328947, -0.000319159, -4.2106e-06]
    ];

    var FXC = 0.8487;
    var FYC = 1.3523;
    var C1 = R2D/5; // rad to 5-degree interval
    var RC1 = 1/C1;
    var NODES = 18;

    var poly3_val = function(coefs, x) {
        return coefs[0] + x * (coefs[1] + x * (coefs[2] + x * coefs[3]));
    };

    var poly3_der = function(coefs, x) {
        return coefs[1] + x * (2 * coefs[2] + x * 3 * coefs[3]);
    };

    function newton_rapshon(f_df, start, max_err, iters) {
        var x = start;
        for (; iters; --iters) {
            var upd = f_df(x);
            x -= upd;
            if (Math.abs(upd) < max_err) {
                break;
            }
        }
        return x;
    }

    function init$28() {
        this.x0 = this.x0 || 0;
        this.y0 = this.y0 || 0;
        this.long0 = this.long0 || 0;
        this.es = 0;
        this.title = this.title || "Robinson";
    }

    function forward$27(ll) {
        var lon = adjust_lon(ll.x - this.long0);

        var dphi = Math.abs(ll.y);
        var i = Math.floor(dphi * C1);
        if (i < 0) {
            i = 0;
        } else if (i >= NODES) {
            i = NODES - 1;
        }
        dphi = R2D * (dphi - RC1 * i);
        var xy = {
            x: poly3_val(COEFS_X[i], dphi) * lon,
            y: poly3_val(COEFS_Y[i], dphi)
        };
        if (ll.y < 0) {
            xy.y = -xy.y;
        }

        xy.x = xy.x * this.a * FXC + this.x0;
        xy.y = xy.y * this.a * FYC + this.y0;
        return xy;
    }

    function inverse$27(xy) {
        var ll = {
            x: (xy.x - this.x0) / (this.a * FXC),
            y: Math.abs(xy.y - this.y0) / (this.a * FYC)
        };

        if (ll.y >= 1) { // pathologic case
            ll.x /= COEFS_X[NODES][0];
            ll.y = xy.y < 0 ? -HALF_PI : HALF_PI;
        } else {
            // find table interval
            var i = Math.floor(ll.y * NODES);
            if (i < 0) {
                i = 0;
            } else if (i >= NODES) {
                i = NODES - 1;
            }
            for (;;) {
                if (COEFS_Y[i][0] > ll.y) {
                    --i;
                } else if (COEFS_Y[i+1][0] <= ll.y) {
                    ++i;
                } else {
                    break;
                }
            }
            // linear interpolation in 5 degree interval
            var coefs = COEFS_Y[i];
            var t = 5 * (ll.y - coefs[0]) / (COEFS_Y[i+1][0] - coefs[0]);
            // find t so that poly3_val(coefs, t) = ll.y
            t = newton_rapshon(function(x) {
                return (poly3_val(coefs, x) - ll.y) / poly3_der(coefs, x);
            }, t, EPSLN, 100);

            ll.x /= poly3_val(COEFS_X[i], t);
            ll.y = (5 * i + t) * D2R;
            if (xy.y < 0) {
                ll.y = -ll.y;
            }
        }

        ll.x = adjust_lon(ll.x + this.long0);
        return ll;
    }

    var names$29 = ["Robinson", "robin"];
    var robin = {
      init: init$28,
      forward: forward$27,
      inverse: inverse$27,
      names: names$29
    };

    function init$29() {
        this.name = 'geocent';

    }

    function forward$28(p) {
        var point = geodeticToGeocentric(p, this.es, this.a);
        return point;
    }

    function inverse$28(p) {
        var point = geocentricToGeodetic(p, this.es, this.a, this.b);
        return point;
    }

    var names$30 = ["Geocentric", 'geocentric', "geocent", "Geocent"];
    var geocent = {
        init: init$29,
        forward: forward$28,
        inverse: inverse$28,
        names: names$30
    };

    var mode = {
      N_POLE: 0,
      S_POLE: 1,
      EQUIT: 2,
      OBLIQ: 3
    };

    var params = {
      h:     { def: 100000, num: true },           // default is Karman line, no default in PROJ.7
      azi:   { def: 0, num: true, degrees: true }, // default is North
      tilt:  { def: 0, num: true, degrees: true }, // default is Nadir
      long0: { def: 0, num: true },                // default is Greenwich, conversion to rad is automatic
      lat0:  { def: 0, num: true }                 // default is Equator, conversion to rad is automatic
    };

    function init$30() {
      Object.keys(params).forEach(function (p) {
        if (typeof this[p] === "undefined") {
          this[p] = params[p].def;
        } else if (params[p].num && isNaN(this[p])) {
          throw new Error("Invalid parameter value, must be numeric " + p + " = " + this[p]);
        } else if (params[p].num) {
          this[p] = parseFloat(this[p]);
        }
        if (params[p].degrees) {
          this[p] = this[p] * D2R;
        }
      }.bind(this));

      if (Math.abs((Math.abs(this.lat0) - HALF_PI)) < EPSLN) {
        this.mode = this.lat0 < 0 ? mode.S_POLE : mode.N_POLE;
      } else if (Math.abs(this.lat0) < EPSLN) {
        this.mode = mode.EQUIT;
      } else {
        this.mode = mode.OBLIQ;
        this.sinph0 = Math.sin(this.lat0);
        this.cosph0 = Math.cos(this.lat0);
      }

      this.pn1 = this.h / this.a;  // Normalize relative to the Earth's radius

      if (this.pn1 <= 0 || this.pn1 > 1e10) {
        throw new Error("Invalid height");
      }
      
      this.p = 1 + this.pn1;
      this.rp = 1 / this.p;
      this.h1 = 1 / this.pn1;
      this.pfact = (this.p + 1) * this.h1;
      this.es = 0;

      var omega = this.tilt;
      var gamma = this.azi;
      this.cg = Math.cos(gamma);
      this.sg = Math.sin(gamma);
      this.cw = Math.cos(omega);
      this.sw = Math.sin(omega);
    }

    function forward$29(p) {
      p.x -= this.long0;
      var sinphi = Math.sin(p.y);
      var cosphi = Math.cos(p.y);
      var coslam = Math.cos(p.x);
      var x, y;
      switch (this.mode) {
        case mode.OBLIQ:
          y = this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
          break;
        case mode.EQUIT:
          y = cosphi * coslam;
          break;
        case mode.S_POLE:
          y = -sinphi;
          break;
        case mode.N_POLE:
          y = sinphi;
          break;
      }
      y = this.pn1 / (this.p - y);
      x = y * cosphi * Math.sin(p.x);

      switch (this.mode) {
        case mode.OBLIQ:
          y *= this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
          break;
        case mode.EQUIT:
          y *= sinphi;
          break;
        case mode.N_POLE:
          y *= -(cosphi * coslam);
          break;
        case mode.S_POLE:
          y *= cosphi * coslam;
          break;
      }

      // Tilt 
      var yt, ba;
      yt = y * this.cg + x * this.sg;
      ba = 1 / (yt * this.sw * this.h1 + this.cw);
      x = (x * this.cg - y * this.sg) * this.cw * ba;
      y = yt * ba;

      p.x = x * this.a;
      p.y = y * this.a;
      return p;
    }

    function inverse$29(p) {
      p.x /= this.a;
      p.y /= this.a;
      var r = { x: p.x, y: p.y };

      // Un-Tilt
      var bm, bq, yt;
      yt = 1 / (this.pn1 - p.y * this.sw);
      bm = this.pn1 * p.x * yt;
      bq = this.pn1 * p.y * this.cw * yt;
      p.x = bm * this.cg + bq * this.sg;
      p.y = bq * this.cg - bm * this.sg;

      var rh = hypot(p.x, p.y);
      if (Math.abs(rh) < EPSLN) {
        r.x = 0;
        r.y = p.y;
      } else {
        var cosz, sinz;
        sinz = 1 - rh * rh * this.pfact;
        sinz = (this.p - Math.sqrt(sinz)) / (this.pn1 / rh + rh / this.pn1);
        cosz = Math.sqrt(1 - sinz * sinz);
        switch (this.mode) {
          case mode.OBLIQ:
            r.y = Math.asin(cosz * this.sinph0 + p.y * sinz * this.cosph0 / rh);
            p.y = (cosz - this.sinph0 * Math.sin(r.y)) * rh;
            p.x *= sinz * this.cosph0;
            break;
          case mode.EQUIT:
            r.y = Math.asin(p.y * sinz / rh);
            p.y = cosz * rh;
            p.x *= sinz;
            break;
          case mode.N_POLE:
            r.y = Math.asin(cosz);
            p.y = -p.y;
            break;
          case mode.S_POLE:
            r.y = -Math.asin(cosz);
            break;
        }
        r.x = Math.atan2(p.x, p.y);
      }

      p.x = r.x + this.long0;
      p.y = r.y;
      return p;
    }

    var names$31 = ["Tilted_Perspective", "tpers"];
    var tpers = {
      init: init$30,
      forward: forward$29,
      inverse: inverse$29,
      names: names$31
    };

    var includedProjections = function(proj4){
      proj4.Proj.projections.add(tmerc);
      proj4.Proj.projections.add(etmerc);
      proj4.Proj.projections.add(utm);
      proj4.Proj.projections.add(sterea);
      proj4.Proj.projections.add(stere);
      proj4.Proj.projections.add(somerc);
      proj4.Proj.projections.add(omerc);
      proj4.Proj.projections.add(lcc);
      proj4.Proj.projections.add(krovak);
      proj4.Proj.projections.add(cass);
      proj4.Proj.projections.add(laea);
      proj4.Proj.projections.add(aea);
      proj4.Proj.projections.add(gnom);
      proj4.Proj.projections.add(cea);
      proj4.Proj.projections.add(eqc);
      proj4.Proj.projections.add(poly);
      proj4.Proj.projections.add(nzmg);
      proj4.Proj.projections.add(mill);
      proj4.Proj.projections.add(sinu);
      proj4.Proj.projections.add(moll);
      proj4.Proj.projections.add(eqdc);
      proj4.Proj.projections.add(vandg);
      proj4.Proj.projections.add(aeqd);
      proj4.Proj.projections.add(ortho);
      proj4.Proj.projections.add(qsc);
      proj4.Proj.projections.add(robin);
      proj4.Proj.projections.add(geocent);
      proj4.Proj.projections.add(tpers);
    };

    proj4$1.defaultDatum = 'WGS84'; //default datum
    proj4$1.Proj = Projection;
    proj4$1.WGS84 = new proj4$1.Proj('WGS84');
    proj4$1.Point = Point;
    proj4$1.toPoint = toPoint;
    proj4$1.defs = defs;
    proj4$1.nadgrid = nadgrid;
    proj4$1.transform = transform;
    proj4$1.mgrs = mgrs;
    proj4$1.version = '2.7.5';
    includedProjections(proj4$1);

    return proj4$1;

})));


/***/ }),
/* 116 */
/***/ (function(module, exports, __webpack_require__) {

var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (factory) {
	var L, proj4;
	if (true) {
		// AMD
		!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(2), __webpack_require__(114)], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
				__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
				(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
	} else {}
}(function (L, proj4) {
	if (proj4.__esModule && proj4.default) {
		// If proj4 was bundled as an ES6 module, unwrap it to get
		// to the actual main proj4 object.
		// See discussion in https://github.com/kartena/Proj4Leaflet/pull/147
		proj4 = proj4.default;
	}
 
	L.Proj = {};

	L.Proj._isProj4Obj = function(a) {
		return (typeof a.inverse !== 'undefined' &&
			typeof a.forward !== 'undefined');
	};

	L.Proj.Projection = L.Class.extend({
		initialize: function(code, def, bounds) {
			var isP4 = L.Proj._isProj4Obj(code);
			this._proj = isP4 ? code : this._projFromCodeDef(code, def);
			this.bounds = isP4 ? def : bounds;
		},

		project: function (latlng) {
			var point = this._proj.forward([latlng.lng, latlng.lat]);
			return new L.Point(point[0], point[1]);
		},

		unproject: function (point, unbounded) {
			var point2 = this._proj.inverse([point.x, point.y]);
			return new L.LatLng(point2[1], point2[0], unbounded);
		},

		_projFromCodeDef: function(code, def) {
			if (def) {
				proj4.defs(code, def);
			} else if (proj4.defs[code] === undefined) {
				var urn = code.split(':');
				if (urn.length > 3) {
					code = urn[urn.length - 3] + ':' + urn[urn.length - 1];
				}
				if (proj4.defs[code] === undefined) {
					throw 'No projection definition for code ' + code;
				}
			}

			return proj4(code);
		}
	});

	L.Proj.CRS = L.Class.extend({
		includes: L.CRS,

		options: {
			transformation: new L.Transformation(1, 0, -1, 0)
		},

		initialize: function(a, b, c) {
			var code,
			    proj,
			    def,
			    options;

			if (L.Proj._isProj4Obj(a)) {
				proj = a;
				code = proj.srsCode;
				options = b || {};

				this.projection = new L.Proj.Projection(proj, options.bounds);
			} else {
				code = a;
				def = b;
				options = c || {};
				this.projection = new L.Proj.Projection(code, def, options.bounds);
			}

			L.Util.setOptions(this, options);
			this.code = code;
			this.transformation = this.options.transformation;

			if (this.options.origin) {
				this.transformation =
					new L.Transformation(1, -this.options.origin[0],
						-1, this.options.origin[1]);
			}

			if (this.options.scales) {
				this._scales = this.options.scales;
			} else if (this.options.resolutions) {
				this._scales = [];
				for (var i = this.options.resolutions.length - 1; i >= 0; i--) {
					if (this.options.resolutions[i]) {
						this._scales[i] = 1 / this.options.resolutions[i];
					}
				}
			}

			this.infinite = !this.options.bounds;

		},

		scale: function(zoom) {
			var iZoom = Math.floor(zoom),
				baseScale,
				nextScale,
				scaleDiff,
				zDiff;
			if (zoom === iZoom) {
				return this._scales[zoom];
			} else {
				// Non-integer zoom, interpolate
				baseScale = this._scales[iZoom];
				nextScale = this._scales[iZoom + 1];
				scaleDiff = nextScale - baseScale;
				zDiff = (zoom - iZoom);
				return baseScale + scaleDiff * zDiff;
			}
		},

		zoom: function(scale) {
			// Find closest number in this._scales, down
			var downScale = this._closestElement(this._scales, scale),
				downZoom = this._scales.indexOf(downScale),
				nextScale,
				nextZoom,
				scaleDiff;
			// Check if scale is downScale => return array index
			if (scale === downScale) {
				return downZoom;
			}
			if (downScale === undefined) {
				return -Infinity;
			}
			// Interpolate
			nextZoom = downZoom + 1;
			nextScale = this._scales[nextZoom];
			if (nextScale === undefined) {
				return Infinity;
			}
			scaleDiff = nextScale - downScale;
			return (scale - downScale) / scaleDiff + downZoom;
		},

		distance: L.CRS.Earth.distance,

		R: L.CRS.Earth.R,

		/* Get the closest lowest element in an array */
		_closestElement: function(array, element) {
			var low;
			for (var i = array.length; i--;) {
				if (array[i] <= element && (low === undefined || low < array[i])) {
					low = array[i];
				}
			}
			return low;
		}
	});

	L.Proj.GeoJSON = L.GeoJSON.extend({
		initialize: function(geojson, options) {
			this._callLevel = 0;
			L.GeoJSON.prototype.initialize.call(this, geojson, options);
		},

		addData: function(geojson) {
			var crs;

			if (geojson) {
				if (geojson.crs && geojson.crs.type === 'name') {
					crs = new L.Proj.CRS(geojson.crs.properties.name);
				} else if (geojson.crs && geojson.crs.type) {
					crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code);
				}

				if (crs !== undefined) {
					this.options.coordsToLatLng = function(coords) {
						var point = L.point(coords[0], coords[1]);
						return crs.projection.unproject(point);
					};
				}
			}

			// Base class' addData might call us recursively, but
			// CRS shouldn't be cleared in that case, since CRS applies
			// to the whole GeoJSON, inluding sub-features.
			this._callLevel++;
			try {
				L.GeoJSON.prototype.addData.call(this, geojson);
			} finally {
				this._callLevel--;
				if (this._callLevel === 0) {
					delete this.options.coordsToLatLng;
				}
			}
		}
	});

	L.Proj.geoJson = function(geojson, options) {
		return new L.Proj.GeoJSON(geojson, options);
	};

	L.Proj.ImageOverlay = L.ImageOverlay.extend({
		initialize: function (url, bounds, options) {
			L.ImageOverlay.prototype.initialize.call(this, url, null, options);
			this._projectedBounds = bounds;
		},

		// Danger ahead: Overriding internal methods in Leaflet.
		// Decided to do this rather than making a copy of L.ImageOverlay
		// and doing very tiny modifications to it.
		// Future will tell if this was wise or not.
		_animateZoom: function (event) {
			var scale = this._map.getZoomScale(event.zoom);
			var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y);
			var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center);

			L.DomUtil.setTransform(this._image, offset, scale);
		},

		_reset: function () {
			var zoom = this._map.getZoom();
			var pixelOrigin = this._map.getPixelOrigin();
			var bounds = L.bounds(
				this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin),
				this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin)
			);
			var size = bounds.getSize();

			L.DomUtil.setPosition(this._image, bounds.min);
			this._image.style.width = size.x + 'px';
			this._image.style.height = size.y + 'px';
		},

		_projectedToNewLayerPoint: function (point, zoom, center) {
			var viewHalf = this._map.getSize()._divideBy(2);
			var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round();
			var topLeft = newTopLeft.add(this._map._getMapPanePos());

			return this._transform(point, zoom)._subtract(topLeft);
		},

		_transform: function (point, zoom) {
			var crs = this._map.options.crs;
			var transformation = crs.transformation;
			var scale = crs.scale(zoom);

			return transformation.transform(point, scale);
		}
	});

	L.Proj.imageOverlay = function (url, bounds, options) {
		return new L.Proj.ImageOverlay(url, bounds, options);
	};

	return L.Proj;
}));


/***/ }),
/* 117 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * @module Register
 * @alias [private] Register
 * @description
 * Register definition for IGNF, and EPSG CRS.
 *
 * @example
 * Gp.Register.IGNF.AMST63
 *   // return : "+title=Amsterdam 1963 +proj=geocent +towgs84=109.753,-528.133,-362.244,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs"
 * Gp.Register.get("IGNF:AMST63")
 *   // same as Gp.Register.IGNF.AMST63
 */
var Register = {
  /**
   * instance already loaded into proj4
   */
  isLoaded: false,
  /**
   * get the definition for a code
   *
   * @function get
   * @param {String} name - ie. EPSG:2154 (Lambert)
   * @returns {Object} definition
   * @example
   * Register.get("EPSG:2154");
   * // "+title=RGF93 / Lambert-93 +proj=lcc +lat_1=49 ..."
   */
  get: function get(name) {
    if (name === "" || name === null || typeof name === "undefined") {
      return;
    }
    var s = name.split(":");
    if (s.length !== 2) {
      return;
    }
    var _register = s[0];
    var _code = s[1];
    if (!this.hasOwnProperty(_register)) {
      return;
    }
    if (!this[_register].hasOwnProperty(_code)) {
      return;
    }
    return this[_register][_code];
  },
  /**
   * does projection code exist ?
   *
   * @function exist
   * @param {String} name - ie. EPSG:2154 (Lambert)
   * @returns {Boolean} true/false
   * @example
   * Register.exist("EPSG:2154"); // true
   */
  exist: function exist(name) {
    if (name === "" || name === null || typeof name === "undefined") {
      return false;
    }
    var s = name.split(":");
    if (s.length !== 2) {
      return false;
    }
    var _register = s[0];
    var _code = s[1];
    if (!this.hasOwnProperty(_register)) {
      return false;
    }
    if (!this[_register].hasOwnProperty(_code)) {
      return false;
    }
    return true;
  },
  /**
   * load all defs to proj4
   * @function load
   * @param {Object} Proj4 - proj4 instance
   */
  load: function load(Proj4) {
    // un flag pour savoir si le chargement est déjà realisé
    // (car ceci peut être couteux !)
    if (!this.isLoaded) {
      var registers = ["IGNF",
      // exception lors du register IGNF ?
      "EPSG", "CRS"];
      for (var i = 0; i < registers.length; i++) {
        var _register = registers[i];
        var codes = this[_register];
        for (var _code in codes) {
          if (codes.hasOwnProperty(_code)) {
            var name = _register + ":" + _code;
            Proj4.defs(name, this.get(name));
            // on enlève la dependance à OpenLayers...
            // la fonction register est donc à appeller afin d'enregistrer
            // les definitions dans OpenLayers :
            //  import { get } from "ol/proj";
            //  import proj4 from "proj4";
            //  import { register } from "ol/proj/proj4";
            //      Register.load();
            //      // Make projections defined in proj4 (with proj4.defs()) available in OpenLayers.
            //      // see ol/proj/proj4.register (https://openlayers.org/en/latest/apidoc/module-ol_proj_proj4.html)
            //      register(proj4);
            //      console.log(get("CRS:84").getCode()); // "CRS:84"
          }
        }
      }
      /** ts-syntax */
      this.isLoaded = true;
    }
  },
  /**
   * load defs by default to proj4
   *
   * include into proj4 :
   * - WGS84
   * - ['EPSG:4326']
   * - ['EPSG:3785'], ['EPSG:3857'], GOOGLE, ['EPSG:900913'], ['EPSG:102113']
   * +
   * - ["EPSG:2154"], ["EPSG:27571"],  ["EPSG:27572"],  ["EPSG:27573"],  ["EPSG:2757"],
   * - ["CRS:84"],
   * - ["IGNF:LAMB93"],
   * - ["IGNF:LAMBE"], ["IGNF:LAMB1"],  ["IGNF:LAMB2"],  ["IGNF:LAMB3"],  ["IGNF:LAMB4"],
   * - ["IGNF:RGF93G"],
   * - ["IGNF:WGS84G"]
   *
   * @function loadByDefault
   * @param {Object} Proj4 - proj4 instance
   */
  loadByDefault: function loadByDefault(Proj4) {
    // la liste de projections par defaut...
    var registers = {
      EPSG: {
        2154: Register["EPSG"]["2154"],
        27571: Register["EPSG"]["27571"],
        27572: Register["EPSG"]["27572"],
        27573: Register["EPSG"]["27573"],
        27574: Register["EPSG"]["27574"]
      },
      CRS: {
        84: Register["CRS"]["84"]
      },
      IGNF: {
        LAMB93: Register["IGNF"]["LAMB93"],
        LAMBE: Register["IGNF"]["LAMBE"],
        LAMB1: Register["IGNF"]["LAMB1"],
        LAMB2: Register["IGNF"]["LAMB2"],
        LAMB3: Register["IGNF"]["LAMB3"],
        LAMB4: Register["IGNF"]["LAMB4"],
        RGF93G: Register["IGNF"]["RGF93G"],
        WGS84G: Register["IGNF"]["WGS84G"]
      }
    };
    for (var register in registers) {
      if (registers.hasOwnProperty(register)) {
        var codes = registers[register];
        for (var code in codes) {
          if (codes.hasOwnProperty(code)) {
            var name = register + ":" + code;
            Proj4.defs(name, codes[code]);
          }
        }
      }
    }
  },
  /**
   * load only a def to proj4
   *
   * @function loadByName
   * @param {Object} Proj4 - proj4 instance
   * @param {String} name - ie. EPSG:2154 (Lambert)
   * @returns {Boolean} true/false
   */
  loadByName: function loadByName(Proj4, name) {
    if (!this.exist(name)) {
      return false;
    }
    try {
      Proj4.defs(name, this.get(name));
    } catch (e) {
      // FIXME message !?
      return false;
    }
    return true;
  },
  /**
   * definitions EPSG
   * @enum
   */
  EPSG: {
    4978: "+proj=geocent +datum=WGS84 +units=m +no_defs ",
    3857: "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs",
    3785: "+title=WGS 84 / Pseudo-Mercator (deprecated) +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs",
    4149: "+title=CH1903 +proj=longlat +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +no_defs ",
    4150: "+title=CH1903plus +proj=longlat +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +no_defs ",
    4151: "+title=CHTRF95 +proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4171: "+title=RGF93 +proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4230: "+title=ED50 +proj=longlat +ellps=intl +no_defs ",
    4235: "+title=Guyane Francaise +proj=longlat +ellps=intl +no_defs ",
    4258: "+title=ETRS89 +proj=longlat +ellps=GRS80 +no_defs ",
    4275: "+title=NTF +proj=longlat +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +no_defs ",
    4322: "+title=WGS 72 +proj=longlat +ellps=WGS72 +no_defs ",
    4326: "+title=WGS 84 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ",
    4467: "+proj=utm +zone=21 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    4470: "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4471: "+proj=utm +zone=38 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    4474: "+proj=utm +zone=38 +south +ellps=intl +towgs84=-382,-59,-262,0,0,0,0 +units=m +no_defs ",
    4558: "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4559: "+proj=utm +zone=20 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    4621: "+title=Fort Marigot +proj=longlat +ellps=intl +towgs84=137,248,-430,0,0,0,0 +no_defs ",
    4622: "+title=Guadeloupe 1948 +proj=longlat +ellps=intl +no_defs ",
    4623: "+title=CSG67 +proj=longlat +ellps=intl +towgs84=-186,230,110,0,0,0,0 +no_defs ",
    4624: "+title=RGFG95 +proj=longlat +ellps=GRS80 +towgs84=2,2,-2,0,0,0,0 +no_defs ",
    4625: "+title=Martinique 1938 +proj=longlat +ellps=intl +no_defs ",
    4626: "+title=Reunion 1947 +proj=longlat +ellps=intl +no_defs ",
    4627: "+title=RGR92 +proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4628: "+title=Tahiti 52 +proj=longlat +ellps=intl +towgs84=162,117,154,0,0,0,0 +no_defs ",
    4629: "+title=Tahaa 54 +proj=longlat +ellps=intl +no_defs ",
    4630: "+title=IGN72 Nuku Hiva +proj=longlat +ellps=intl +no_defs ",
    4632: "+title=Combani 1950 +proj=longlat +ellps=intl +towgs84=-382,-59,-262,0,0,0,0 +no_defs ",
    4633: "+title=IGN56 Lifou +proj=longlat +ellps=intl +no_defs ",
    4634: "+title=IGN72 Grand Terre +proj=longlat +ellps=intl +no_defs ",
    4637: "+title=Perroud 1950 +proj=longlat +ellps=intl +towgs84=325,154,172,0,0,0,0 +no_defs ",
    4638: "+title=Saint Pierre et Miquelon 1950 +proj=longlat +ellps=clrk66 +towgs84=30,430,368,0,0,0,0 +no_defs ",
    4640: "+title=RRAF 1991 +proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4641: "+title=IGN53 Mare +proj=longlat +ellps=intl +no_defs ",
    4645: "+title=RGNC 1991 +proj=longlat +ellps=intl +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4687: "+proj=longlat +ellps=GRS80 +no_defs ",
    4662: "+title=IGN72 Grande Terre +proj=longlat +ellps=intl +no_defs ",
    4689: "+title=IGN63 Hiva Oa +proj=longlat +ellps=intl +no_defs ",
    4690: "+title=Tahiti 79 +proj=longlat +ellps=intl +no_defs ",
    4691: "+title=Moorea 87 +proj=longlat +ellps=intl +towgs84=215.525,149.593,176.229,-3.2624,-1.692,-1.1571,10.4773 +no_defs ",
    4692: "+title=Maupiti 83 +proj=longlat +ellps=intl +towgs84=217.037,86.959,23.956,0,0,0,0 +no_defs ",
    4698: "+title=IGN 1962 Kerguelen +proj=longlat +ellps=intl +towgs84=145,-187,103,0,0,0,0 +no_defs ",
    4749: "+title=RGNC91-93 +proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs ",
    4750: "+title=ST87 Ouvea +proj=longlat +ellps=WGS84 +towgs84=-56.263,16.136,-22.856,0,0,0,0 +no_defs ",
    4807: "+title=NTF (Paris) +proj=longlat +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +no_defs ",
    2056: "+title=CH1903+ / LV95 +proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs ",
    2154: "+title=RGF93 / Lambert-93 +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    2213: "+title=ETRS89 / TM 30 NE +proj=tmerc +lat_0=0 +lon_0=30 +k=0.9996 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs ",
    2969: "+title=Fort Marigot / UTM zone 20N +proj=utm +zone=20 +ellps=intl +towgs84=137,248,-430,0,0,0,0 +units=m +no_defs ",
    2970: "+title=Guadeloupe 1948 / UTM zone 20N +proj=utm +zone=20 +ellps=intl +units=m +no_defs ",
    2971: "+title=CSG67 / UTM zone 22N +proj=utm +zone=22 +ellps=intl +towgs84=-186,230,110,0,0,0,0 +units=m +no_defs ",
    2972: "+title=RGFG95 / UTM zone 22N +proj=utm +zone=22 +ellps=GRS80 +towgs84=2,2,-2,0,0,0,0 +units=m +no_defs ",
    2973: "+title=Martinique 1938 / UTM zone 20N +proj=utm +zone=20 +ellps=intl +units=m +no_defs ",
    2975: "+title=RGR92 / UTM zone 40S +proj=utm +zone=40 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    2976: "+title=Tahiti 52 / UTM zone 6S +proj=utm +zone=6 +south +ellps=intl +towgs84=162,117,154,0,0,0,0 +units=m +no_defs ",
    2977: "+title=Tahaa 54 / UTM zone 5S +proj=utm +zone=5 +south +ellps=intl +units=m +no_defs ",
    2978: "+title=IGN72 Nuku Hiva / UTM zone 7S +proj=utm +zone=7 +south +ellps=intl +units=m +no_defs ",
    2980: "+title=Combani 1950 / UTM zone 38S +proj=utm +zone=38 +south +ellps=intl +towgs84=-382,-59,-262,0,0,0,0 +units=m +no_defs ",
    2981: "+title=IGN56 Lifou / UTM zone 58S +proj=utm +zone=58 +south +ellps=intl +units=m +no_defs ",
    2982: "+title=IGN72 Grand Terre / UTM zone 58S (deprecated) +proj=utm +zone=58 +south +ellps=intl +units=m +no_defs ",
    2984: "+title=RGNC 1991 / Lambert New Caledonia (deprecated) +proj=lcc +lat_1=-20.66666666666667 +lat_2=-22.33333333333333 +lat_0=-21.5 +lon_0=166 +x_0=400000 +y_0=300000 +ellps=intl +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    2986: "+title=Terre Adelie 1950 +proj=stere +towgs84=324.9120,153.2820,172.0260 +a=6378388.0000 +rf=297.0000000000000 +lat_0=-90.000000000 +lon_0=140.000000000 +lat_ts=-67.000000000 +k=0.96027295 +x_0=300000.000 +y_0=-2299363.482 +units=m +no_defs",
    2987: "+title=Saint Pierre et Miquelon 1950 / UTM zone 21N +proj=utm +zone=21 +ellps=clrk66 +towgs84=30,430,368,0,0,0,0 +units=m +no_defs ",
    2989: "+title=RRAF 1991 / UTM zone 20N +proj=utm +zone=20 +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    2990: "+title=Reunion 1947 / TM Reunion (deprecated) +proj=tmerc +lat_0=-21.11666666666667 +lon_0=55.53333333333333 +k=1 +x_0=50000 +y_0=160000 +ellps=intl +units=m +no_defs ",
    2995: "+title=IGN53 Mare / UTM zone 58S +proj=utm +zone=58 +south +ellps=intl +units=m +no_defs ",
    3038: "+proj=utm +zone=26 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3039: "+proj=utm +zone=27 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3040: "+proj=utm +zone=28 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3041: "+proj=utm +zone=29 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 3042 : "+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 3043 : "+proj=utm +zone=31 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 3044 : "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3045: "+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3046: "+proj=utm +zone=34 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3047: "+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3048: "+proj=utm +zone=36 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3049: "+proj=utm +zone=37 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3050: "+proj=utm +zone=38 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3051: "+proj=utm +zone=39 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3034: "+title=ETRS89 / ETRS-LCC +proj=lcc +lat_1=35 +lat_2=65 +lat_0=52 +lon_0=10 +x_0=4000000 +y_0=2800000 +ellps=GRS80 +units=m +no_defs ",
    3035: "+title=ETRS89 / ETRS-LAEA +proj=laea +lat_0=52 +lon_0=10 +x_0=4321000 +y_0=3210000 +ellps=GRS80 +units=m +no_defs ",
    3042: "+title=ETRS89 / ETRS-TM30 +proj=utm +zone=30 +ellps=GRS80 +units=m +no_defs ",
    3043: "+title=ETRS89 / ETRS-TM31 +proj=utm +zone=31 +ellps=GRS80 +units=m +no_defs ",
    3044: "+title=ETRS89 / ETRS-TM32 +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs ",
    25828: "+proj=utm +zone=28 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25829: "+proj=utm +zone=29 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 25830 : "+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 25831 : "+proj=utm +zone=31 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    // 25832 : "+proj=utm +zone=32 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25833: "+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25834: "+proj=utm +zone=34 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25835: "+proj=utm +zone=35 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25836: "+proj=utm +zone=36 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25837: "+proj=utm +zone=37 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    25838: "+proj=utm +zone=38 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3060: "+title=IGN72 Grande Terre / UTM zone 58S +proj=utm +zone=58 +south +ellps=intl +units=m +no_defs ",
    3163: "+title=RGNC91-93 / Lambert New Caledonia +proj=lcc +lat_1=-20.66666666666667 +lat_2=-22.33333333333333 +lat_0=-21.5 +lon_0=166 +x_0=400000 +y_0=300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3164: "+title=ST87 Ouvea / UTM zone 58S +proj=utm +zone=58 +south +ellps=WGS84 +towgs84=-56.263,16.136,-22.856,0,0,0,0 +units=m +no_defs ",
    3165: "+title=NEA74 Noumea / Noumea Lambert +proj=lcc +lat_1=-22.24469175 +lat_2=-22.29469175 +lat_0=-22.26969175 +lon_0=166.44242575 +x_0=0.66 +y_0=1.02 +ellps=intl +units=m +no_defs ",
    3166: "+title=NEA74 Noumea / Noumea Lambert 2 +proj=lcc +lat_1=-22.24472222222222 +lat_2=-22.29472222222222 +lat_0=-22.26972222222222 +lon_0=166.4425 +x_0=8.313000000000001 +y_0=-2.354 +ellps=intl +units=m +no_defs ",
    3169: "+title=RGNC91-93 / UTM zone 57S +proj=utm +zone=57 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3170: "+title=RGNC91-93 / UTM zone 58S +proj=utm +zone=58 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3171: "+title=RGNC91-93 / UTM zone 59S +proj=utm +zone=59 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs ",
    3172: "+title=IGN53 Mare / UTM zone 59S +proj=utm +zone=59 +south +ellps=intl +units=m +no_defs ",
    3296: "+title=RGPF / UTM zone 5S +proj=utm +zone=5 +south +ellps=GRS80 +units=m +no_defs ",
    3297: "+title=RGPF / UTM zone 6S +proj=utm +zone=6 +south +ellps=GRS80 +units=m +no_defs ",
    3298: "+title=RGPF / UTM zone 7S +proj=utm +zone=7 +south +ellps=GRS80 +units=m +no_defs ",
    3299: "+title=RGPF / UTM zone 8S +proj=utm +zone=8 +south +ellps=GRS80 +units=m +no_defs ",
    3302: "+title=IGN63 Hiva Oa / UTM zone 7S +proj=utm +zone=7 +south +ellps=intl +units=m +no_defs ",
    3303: "+title=Fatu Iva 72 / UTM zone 7S +proj=utm +zone=7 +south +ellps=intl +towgs84=347.103,1078.12,2623.92,-33.8875,70.6773,-9.3943,186.074 +units=m +no_defs ",
    3304: "+title=Tahiti 79 / UTM zone 6S +proj=utm +zone=6 +south +ellps=intl +units=m +no_defs ",
    3305: "+title=Moorea 87 / UTM zone 6S +proj=utm +zone=6 +south +ellps=intl +towgs84=215.525,149.593,176.229,-3.2624,-1.692,-1.1571,10.4773 +units=m +no_defs ",
    3306: "+title=Maupiti 83 / UTM zone 5S +proj=utm +zone=5 +south +ellps=intl +towgs84=217.037,86.959,23.956,0,0,0,0 +units=m +no_defs ",
    3312: "+title=CSG67 / UTM zone 21N +proj=utm +zone=21 +ellps=intl +towgs84=-186,230,110,0,0,0,0 +units=m +no_defs ",
    3313: "+title=RGFG95 / UTM zone 21N +proj=utm +zone=21 +ellps=GRS80 +towgs84=2,2,-2,0,0,0,0 +units=m +no_defs ",
    3336: "+title=IGN 1962 Kerguelen / UTM zone 42S +proj=utm +zone=42 +south +ellps=intl +towgs84=145,-187,103,0,0,0,0 +units=m +no_defs ",
    3395: "+title=WGS 84 / World Mercator +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    3727: "+title=Reunion 1947 / TM Reunion +proj=tmerc +lat_0=-21.11666666666667 +lon_0=55.53333333333333 +k=1 +x_0=160000 +y_0=50000 +ellps=intl +units=m +no_defs ",
    21781: "+title=CH1903 / LV03 +proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +x_0=600000 +y_0=200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 +units=m +no_defs ",
    25830: "+title=ETRS89 / UTM zone 30N +proj=utm +zone=30 +ellps=GRS80 +units=m +no_defs ",
    25831: "+title=ETRS89 / UTM zone 31N +proj=utm +zone=31 +ellps=GRS80 +units=m +no_defs ",
    25832: "+title=ETRS89 / UTM zone 32N +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs ",
    27561: "+title=NTF (Paris) / Lambert Nord France +proj=lcc +lat_1=49.50000000000001 +lat_0=49.50000000000001 +lon_0=0 +k_0=0.999877341 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27562: "+title=NTF (Paris) / Lambert Centre France +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27563: "+title=NTF (Paris) / Lambert Sud France +proj=lcc +lat_1=44.10000000000001 +lat_0=44.10000000000001 +lon_0=0 +k_0=0.9998774990000001 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27564: "+title=NTF (Paris) / Lambert Corse +proj=lcc +lat_1=42.16500000000001 +lat_0=42.16500000000001 +lon_0=0 +k_0=0.9999447100000001 +x_0=234.358 +y_0=185861.369 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27571: "+title=NTF (Paris) / Lambert zone I +proj=lcc +lat_1=49.50000000000001 +lat_0=49.50000000000001 +lon_0=0 +k_0=0.999877341 +x_0=600000 +y_0=1200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27572: "+title=NTF (Paris) / Lambert zone II +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=2200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27573: "+title=NTF (Paris) / Lambert zone III +proj=lcc +lat_1=44.10000000000001 +lat_0=44.10000000000001 +lon_0=0 +k_0=0.9998774990000001 +x_0=600000 +y_0=3200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27574: "+title=NTF (Paris) / Lambert zone IV +proj=lcc +lat_1=42.16500000000001 +lat_0=42.16500000000001 +lon_0=0 +k_0=0.9999447100000001 +x_0=234.358 +y_0=4185861.369 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27581: "+title=NTF (Paris) / France I (deprecated) +proj=lcc +lat_1=49.50000000000001 +lat_0=49.50000000000001 +lon_0=0 +k_0=0.999877341 +x_0=600000 +y_0=1200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27582: "+title=NTF (Paris) / France II (deprecated) +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=2200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27583: "+title=NTF (Paris) / France III (deprecated) +proj=lcc +lat_1=44.10000000000001 +lat_0=44.10000000000001 +lon_0=0 +k_0=0.9998774990000001 +x_0=600000 +y_0=3200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27584: "+title=NTF (Paris) / France IV (deprecated) +proj=lcc +lat_1=42.16500000000001 +lat_0=42.16500000000001 +lon_0=0 +k_0=0.9999447100000001 +x_0=234.358 +y_0=4185861.369 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27591: "+title=NTF (Paris) / Nord France (deprecated) +proj=lcc +lat_1=49.50000000000001 +lat_0=49.50000000000001 +lon_0=0 +k_0=0.999877341 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27592: "+title=NTF (Paris) / Centre France (deprecated) +proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27593: "+title=NTF (Paris) / Sud France (deprecated) +proj=lcc +lat_1=44.10000000000001 +lat_0=44.10000000000001 +lon_0=0 +k_0=0.9998774990000001 +x_0=600000 +y_0=200000 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    27594: "+title=NTF (Paris) / Corse (deprecated) +proj=lcc +lat_1=42.16500000000001 +lat_0=42.16500000000001 +lon_0=0 +k_0=0.9999447100000001 +x_0=234.358 +y_0=185861.369 +a=6378249.2 +b=6356515 +towgs84=-168,-60,320,0,0,0,0 +pm=paris +units=m +no_defs ",
    32601: "+proj=utm +zone=1 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32602: "+proj=utm +zone=2 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32603: "+proj=utm +zone=3 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32604: "+proj=utm +zone=4 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32605: "+proj=utm +zone=5 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32606: "+proj=utm +zone=6 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32607: "+proj=utm +zone=7 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32608: "+proj=utm +zone=8 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32609: "+proj=utm +zone=9 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32610: "+proj=utm +zone=10 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32611: "+proj=utm +zone=11 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32612: "+proj=utm +zone=12 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32613: "+proj=utm +zone=13 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32614: "+proj=utm +zone=14 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32615: "+proj=utm +zone=15 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32616: "+proj=utm +zone=16 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32617: "+proj=utm +zone=17 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32618: "+proj=utm +zone=18 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32619: "+proj=utm +zone=19 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32620: "+proj=utm +zone=20 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32621: "+proj=utm +zone=21 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32622: "+proj=utm +zone=22 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32623: "+proj=utm +zone=23 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32624: "+proj=utm +zone=24 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32625: "+proj=utm +zone=25 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32626: "+proj=utm +zone=26 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32627: "+proj=utm +zone=27 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32628: "+proj=utm +zone=28 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32629: "+proj=utm +zone=29 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32630: "+proj=utm +zone=30 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32631: "+proj=utm +zone=31 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32632: "+proj=utm +zone=32 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32633: "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32634: "+proj=utm +zone=34 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32635: "+proj=utm +zone=35 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32636: "+proj=utm +zone=36 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32637: "+proj=utm +zone=37 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32638: "+proj=utm +zone=38 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32639: "+proj=utm +zone=39 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32640: "+proj=utm +zone=40 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32641: "+proj=utm +zone=41 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32642: "+proj=utm +zone=42 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32643: "+proj=utm +zone=43 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32644: "+proj=utm +zone=44 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32645: "+proj=utm +zone=45 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32646: "+proj=utm +zone=46 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32647: "+proj=utm +zone=47 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32648: "+proj=utm +zone=48 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32649: "+proj=utm +zone=49 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32650: "+proj=utm +zone=50 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32651: "+proj=utm +zone=51 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32652: "+proj=utm +zone=52 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32653: "+proj=utm +zone=53 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32654: "+proj=utm +zone=54 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32655: "+proj=utm +zone=55 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32656: "+proj=utm +zone=56 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32657: "+proj=utm +zone=57 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32658: "+proj=utm +zone=58 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32659: "+proj=utm +zone=59 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32660: "+proj=utm +zone=60 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32661: "+proj=stere +lat_0=90 +lat_ts=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32662: "+title=WGS 84 / Plate Carree +proj=eqc +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32701: "+proj=utm +zone=1 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32702: "+proj=utm +zone=2 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32703: "+proj=utm +zone=3 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32704: "+proj=utm +zone=4 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32705: "+proj=utm +zone=5 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32706: "+proj=utm +zone=6 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32707: "+proj=utm +zone=7 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32708: "+proj=utm +zone=8 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32709: "+proj=utm +zone=9 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32710: "+proj=utm +zone=10 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32711: "+proj=utm +zone=11 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32712: "+proj=utm +zone=12 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32713: "+proj=utm +zone=13 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32714: "+proj=utm +zone=14 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32715: "+proj=utm +zone=15 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32716: "+proj=utm +zone=16 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32717: "+proj=utm +zone=17 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32718: "+proj=utm +zone=18 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32719: "+proj=utm +zone=19 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32720: "+proj=utm +zone=20 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32721: "+proj=utm +zone=21 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32722: "+proj=utm +zone=22 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32723: "+proj=utm +zone=23 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32724: "+proj=utm +zone=24 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32725: "+proj=utm +zone=25 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32726: "+proj=utm +zone=26 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32727: "+proj=utm +zone=27 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32728: "+proj=utm +zone=28 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32729: "+proj=utm +zone=29 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32730: "+proj=utm +zone=30 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32731: "+proj=utm +zone=31 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32732: "+proj=utm +zone=32 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32733: "+proj=utm +zone=33 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32734: "+proj=utm +zone=34 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32735: "+proj=utm +zone=35 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32736: "+proj=utm +zone=36 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32737: "+proj=utm +zone=37 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32738: "+proj=utm +zone=38 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32739: "+proj=utm +zone=39 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32740: "+proj=utm +zone=40 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32741: "+proj=utm +zone=41 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32742: "+proj=utm +zone=42 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32743: "+proj=utm +zone=43 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32744: "+proj=utm +zone=44 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32745: "+proj=utm +zone=45 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32746: "+proj=utm +zone=46 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32747: "+proj=utm +zone=47 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32748: "+proj=utm +zone=48 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32749: "+proj=utm +zone=49 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32750: "+proj=utm +zone=50 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32751: "+proj=utm +zone=51 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32752: "+proj=utm +zone=52 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32753: "+proj=utm +zone=53 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32754: "+proj=utm +zone=54 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32755: "+proj=utm +zone=55 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32756: "+proj=utm +zone=56 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32757: "+proj=utm +zone=57 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32758: "+proj=utm +zone=58 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32759: "+proj=utm +zone=59 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32760: "+proj=utm +zone=60 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    32761: "+proj=stere +lat_0=-90 +lat_ts=-90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ",
    310024802: "+title=Geoportail - France metropolitaine +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=46.500000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310915814: "+title=Geoportail - Antilles francaises +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=15.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310486805: "+title=Geoportail - Guyane +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=4.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310700806: "+title=Geoportail - Reunion et dependances +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-21.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310702807: "+title=Geoportail - Mayotte +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-12.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310706808: "+title=Geoportail - Saint-Pierre et Miquelon +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=47.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310547809: "+title=Geoportail - Nouvelle-Caledonie +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-22.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310642810: "+title=Geoportail - Wallis et Futuna +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.000000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-14.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310032811: "+title=Geoportail - Polynesie francaise +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-15.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310642812: "+title=Geoportail - Kerguelen +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-49.500000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310642801: "+title=Geoportail - Crozet +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-46.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310642813: "+title=Geoportail - Amsterdam et Saint-Paul +proj=eqc +nadgrids=null +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-38.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    310642901: "+title=Geoportail - Monde +proj=mill +towgs84=0.0000,0.0000,0.0000,0.0000,0.0000,0.0000,0.000000 +a=6378137.0000 +rf=298.2572221010000 +lon_0=0.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    5489: "+title=RGAF09 geographiques (dms) +proj=longlat +nadgrids=@null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137 +rf=298.257222101 +units=m +no_defs",
    5490: "+title=RGAF09 UTM Nord Fuseau 20 +proj=tmerc +nadgrids=@null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137 +rf=298.257222101 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs"
  },
  /**
   * definitions CRS
   * @enum
   */
  CRS: {
    84: "+title=WGS 84 longitude-latitude +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs "
  },
  /**
   * definitions IGNF
   * @enum
   */
  IGNF: {
    AMST63: "+title=Amsterdam 1963 +proj=geocent +towgs84=109.753,-528.133,-362.244,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    CROZ63: "+title=Crozet 1963 +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    CSG67: "+title=Guyane CSG67 +proj=geocent +towgs84=-193.0660,236.9930,105.4470,0.4814,-0.8074,0.1276,1.564900 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    ED50: "+title=ED50 +proj=geocent +towgs84=-84.0000,-97.0000,-117.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    ETRS89: "+title=Systeme de reference terrestre Europeen (1989) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    GUAD48: "+title=Guadeloupe Ste Anne +proj=geocent +towgs84=-472.2900,-5.6300,-304.1200,0.4362,-0.8374,0.2563,1.898400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    GUADFM49: "+title=Guadeloupe Fort Marigot +proj=geocent +towgs84=136.5960,248.1480,-429.7890 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    IGN63: "+title=IGN 1963 (Hiva Oa, Tahuata, Mohotani) +proj=geocent +towgs84=410.7210,55.0490,80.7460,-2.5779,-2.3514,-0.6664,17.331100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    IGN72: "+title=IGN 1972 Grande-Terre / Ile des Pins +proj=geocent +towgs84=-11.6400,-348.6000,291.6800 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    KERG62CAR: "+title=Kerguelen - K0 +proj=geocent +towgs84=144.8990,-186.7700,100.9230 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MART38: "+title=Martinique Fort-Desaix +proj=geocent +towgs84=126.9260,547.9390,130.4090,-2.7867,5.1612,-0.8584,13.822650 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MAYO50: "+title=Mayotte Combani +proj=geocent +towgs84=-599.9280,-275.5520,-195.6650,-0.0835,-0.4715,0.0602,49.281400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MOOREA87: "+title=Moorea 1987 +proj=geocent +towgs84=215.9820,149.5930,176.2290,3.2624,1.6920,1.1571,10.477300 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    NTF: "+title=Nouvelle Triangulation Francaise +proj=geocent +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +units=m +no_defs",
    NUKU72: "+title=IGN 1972 Nuku Hiva +proj=geocent +towgs84=165.7320,216.7200,180.5050,-0.6434,-0.4512,-0.0791,7.420400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    REUN47: "+title=Reunion 1947 +proj=geocent +towgs84=789.5240,-626.4860,-89.9040,0.6006,76.7946,-10.5788,-32.324100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    RGF93: "+title=Reseau geodesique francais 1993 +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGFG95: "+title=Reseau geodesique francais de Guyane 1995 +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGM04: "+title=RGM04 (Reseau Geodesique de Mayotte 2004) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGNC: "+title=Reseau Geodesique de Nouvelle-Caledonie +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGPF: "+title=RGPF (Reseau Geodesique de Polynesie Francaise) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGR92: "+title=Reseau geodesique Reunion 1992 +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGSPM06: "+title=Reseau Geodesique Saint-Pierre-et-Miquelon (2006) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGTAAF07: "+title=Reseau Geodesique des TAAF (2007) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RRAF91: "+title=RRAF 1991 (Reseau de Reference des Antilles Francaises) +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    STPL69: "+title=Saint-Paul 1969 +proj=geocent +towgs84=225.571,-346.608,-46.567,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    STPM50: "+title=St Pierre et Miquelon 1950 +proj=geocent +towgs84=-95.5930,573.7630,173.4420,-0.9602,1.2510,-1.3918,42.626500 +a=6378206.4000 +rf=294.9786982000000 +units=m +no_defs",
    TAHAA: "+title=Raiatea - Tahaa 51-54 (Tahaa, Base Terme Est) +proj=geocent +towgs84=72.4380,345.9180,79.4860,-1.6045,-0.8823,-0.5565,1.374600 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    TAHI79: "+title=IGN79 (Tahiti) Iles de la Societe +proj=geocent +towgs84=221.5250,152.9480,176.7680,2.3847,1.3896,0.8770,11.474100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    TERA50: "+title=Pointe Geologie - Perroud 1950 +proj=geocent +towgs84=324.9120,153.2820,172.0260 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    WALL78: "+title=Wallis-Uvea 1978 (MOP78) +proj=geocent +towgs84=253.0000,-133.0000,-127.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    WGS72: "+title=World Geodetic System 1972 +proj=geocent +towgs84=0.0000,12.0000,6.0000 +a=6378135.0000 +rf=298.2600000000000 +units=m +no_defs",
    WGS84: "+title=World Geodetic System 1984 +proj=geocent +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    AMST63GEO: "+title=Amsterdam 1963 +proj=longlat +towgs84=109.753,-528.133,-362.244,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    CROZ63GEO: "+title=Crozet 1963 +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    CSG67GEO: "+title=Guyane CSG67 +proj=longlat +towgs84=-193.0660,236.9930,105.4470,0.4814,-0.8074,0.1276,1.564900 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    ED50G: "+title=ED50 +proj=longlat +towgs84=-84.0000,-97.0000,-117.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    GUAD48GEO: "+title=Guadeloupe Ste Anne +proj=longlat +towgs84=-472.2900,-5.6300,-304.1200,0.4362,-0.8374,0.2563,1.898400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    GUADFM49GEO: "+title=Guadeloupe Fort Marigot +proj=longlat +towgs84=136.5960,248.1480,-429.7890 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    IGN63GEO: "+title=IGN 1963 (Hiva Oa, Tahuata, Mohotani) +proj=longlat +towgs84=410.7210,55.0490,80.7460,-2.5779,-2.3514,-0.6664,17.331100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    IGN72GEO: "+title=IGN 1972 Grande-Terre / Ile des Pins +proj=longlat +towgs84=-11.6400,-348.6000,291.6800 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    KERG62GEO: "+title=Kerguelen - K0 +proj=longlat +towgs84=144.8990,-186.7700,100.9230 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MART38GEO: "+title=Martinique Fort-Desaix +proj=longlat +towgs84=126.9260,547.9390,130.4090,-2.7867,5.1612,-0.8584,13.822650 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MAYO50GEO: "+title=Mayotte Combani +proj=longlat +towgs84=-599.9280,-275.5520,-195.6650,-0.0835,-0.4715,0.0602,49.281400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    MOOREA87GEO: "+title=Moorea 1987 +proj=longlat +towgs84=215.9820,149.5930,176.2290,3.2624,1.6920,1.1571,10.477300 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    NTFG: "+title=Nouvelle Triangulation Francaise Greenwich degres sexagesimaux +proj=longlat +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +units=m +no_defs",
    NTFP: "+title=Nouvelle Triangulation Francaise Paris grades +proj=longlat +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +units=m +no_defs",
    NUKU72GEO: "+title=IGN 1972 Nuku Hiva +proj=longlat +towgs84=165.7320,216.7200,180.5050,-0.6434,-0.4512,-0.0791,7.420400 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    REUN47GEO: "+title=Reunion 1947 +proj=longlat +towgs84=789.5240,-626.4860,-89.9040,0.6006,76.7946,-10.5788,-32.324100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    RGF93G: "+title=Reseau geodesique francais 1993 +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGFG95GEO: "+title=Reseau geodesique francais de Guyane 1995 +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGM04GEO: "+title=RGM04 (Reseau Geodesique de Mayotte 2004) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGNCGEO: "+title=Reseau Geodesique de Nouvelle-Caledonie +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGPFGEO: "+title=RGPF (Reseau Geodesique de Polynesie Francaise) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGR92GEO: "+title=Reseau geodesique de la Reunion 1992 +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGSPM06GEO: "+title=Saint-Pierre-et-Miquelon (2006) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    RGTAAF07G: "+title=Reseau Geodesique des TAAF (2007) (dms) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    STPL69GEO: "+title=Saint-Paul 1969 +proj=longlat +towgs84=225.571,-346.608,-46.567,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    STPM50GEO: "+title=St Pierre et Miquelon 1950  +proj=longlat +towgs84=-95.5930,573.7630,173.4420,-0.9602,1.2510,-1.3918,42.626500 +a=6378206.4000 +rf=294.9786982000000 +units=m +no_defs",
    TAHAAGEO: "+title=Raiatea - Tahaa 51-54 (Tahaa, Base Terme Est) +proj=longlat +towgs84=72.4380,345.9180,79.4860,-1.6045,-0.8823,-0.5565,1.374600 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    TAHI79GEO: "+title=IGN79 (Tahiti) Iles de la Societe +proj=longlat +towgs84=221.5250,152.9480,176.7680,2.3847,1.3896,0.8770,11.474100 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    TERA50G: "+title=Pointe Geologie - Perroud 1950 +proj=longlat +towgs84=324.9120,153.2820,172.0260 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    WALL78GEO: "+title=Wallis - Uvea 1978 (MOP78) +proj=longlat +towgs84=253.0000,-133.0000,-127.0000 +a=6378388.0000 +rf=297.0000000000000 +units=m +no_defs",
    WGS72G: "+title=WGS72 +proj=longlat +towgs84=0.0000,12.0000,6.0000 +a=6378135.0000 +rf=298.2600000000000 +units=m +no_defs",
    WGS84G: "+title=World Geodetic System 1984 +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    WGS84RRAFGEO: "+title=Reseau de reference des Antilles francaises (1988-1991) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    XGEO: "+title=Systeme CIO-BIH +proj=longlat +towgs84=0.0000,0.0000,0.5000,0.0000,0.0000,0.0140,-0.100000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    AMST63UTM43S: "+title=Amsterdam 1963 UTM fuseau 43 Sud +proj=tmerc +towgs84=109.753,-528.133,-362.244,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=75.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    CROZ63UTM39S: "+title=Crozet 1963 +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=51.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    CSG67UTM21: "+title=Guyane CSG67 UTM fuseau 21 +proj=tmerc +towgs84=-193.0660,236.9930,105.4470,0.4814,-0.8074,0.1276,1.564900 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-57.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    CSG67UTM22: "+title=Guyane CSG67 UTM fuseau 22 +proj=tmerc +towgs84=-193.0660,236.9930,105.4470,0.4814,-0.8074,0.1276,1.564900 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-51.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALANF: "+title=Geoportail - Antilles francaises +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=15.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALASP: "+title=Geoportail - Amsterdam et Saint-Paul +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-38.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALCRZ: "+title=Geoportail - Crozet +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-46.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALFXX: "+title=Geoportail - France metropolitaine +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=46.500000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALGUF: "+title=Geoportail - Guyane +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=4.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALKER: "+title=Geoportail - Kerguelen +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-49.500000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALMYT: "+title=Geoportail - Mayotte +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-12.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALNCL: "+title=Geoportail - Nouvelle-Caledonie +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-22.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALPYF: "+title=Geoportail - Polynesie francaise +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-15.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALREU: "+title=Geoportail - Reunion et dependances +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-21.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALSPM: "+title=Geoportail - Saint-Pierre et Miquelon +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=47.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GEOPORTALWLF: "+title=Geoportail - Wallis et Futuna +proj=eqc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=0.000000000 +lat_ts=-14.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    GUAD48UTM20: "+title=Guadeloupe Ste Anne +proj=tmerc +towgs84=-472.2900,-5.6300,-304.1200,0.4362,-0.8374,0.2563,1.898400 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    GUADFM49U20: "+title=Guadeloupe Fort Marigot  +proj=tmerc +towgs84=136.5960,248.1480,-429.7890 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    IGN63UTM7S: "+title=IGN 1963 - Hiva Oa, Tahuata, Mohotani - UTM fuseau 7 Sud +proj=tmerc +towgs84=410.7210,55.0490,80.7460,-2.5779,-2.3514,-0.6664,17.331100 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-141.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    IGN72UTM58S: "+title=IGN 1972 - UTM fuseau 58 Sud +proj=tmerc +towgs84=-11.6400,-348.6000,291.6800 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=165.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    KERG62UTM42S: "+title=Kerguelen 1962 +proj=tmerc +towgs84=144.8990,-186.7700,100.9230 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=69.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    LAMB1: "+title=Lambert I +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=49.500000000 +lon_0=0.000000000 +k_0=0.99987734 +lat_1=49.500000000 +x_0=600000.000 +y_0=200000.000 +units=m +no_defs",
    LAMB1C: "+title=Lambert I Carto +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=49.500000000 +lon_0=0.000000000 +k_0=0.99987734 +lat_1=49.500000000 +x_0=600000.000 +y_0=1200000.000 +units=m +no_defs",
    LAMB2: "+title=Lambert II +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=46.800000000 +lon_0=0.000000000 +k_0=0.99987742 +lat_1=46.800000000 +x_0=600000.000 +y_0=200000.000 +units=m +no_defs",
    LAMB2C: "+title=Lambert II Carto +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=46.800000000 +lon_0=0.000000000 +k_0=0.99987742 +lat_1=46.800000000 +x_0=600000.000 +y_0=2200000.000 +units=m +no_defs",
    LAMB3: "+title=Lambert III +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=44.100000000 +lon_0=0.000000000 +k_0=0.99987750 +lat_1=44.100000000 +x_0=600000.000 +y_0=200000.000 +units=m +no_defs",
    LAMB3C: "+title=Lambert III Carto +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=44.100000000 +lon_0=0.000000000 +k_0=0.99987750 +lat_1=44.100000000 +x_0=600000.000 +y_0=3200000.000 +units=m +no_defs",
    LAMB4: "+title=Lambert IV +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=42.165000000 +lon_0=0.000000000 +k_0=0.99994471 +lat_1=42.165000000 +x_0=234.358 +y_0=185861.369 +units=m +no_defs",
    LAMB4C: "+title=Lambert IV Carto +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=42.165000000 +lon_0=0.000000000 +k_0=0.99994471 +lat_1=42.165000000 +x_0=234.358 +y_0=4185861.369 +units=m +no_defs",
    LAMB93: "+title=Lambert 93 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=46.500000000 +lon_0=3.000000000 +lat_1=44.000000000 +lat_2=49.000000000 +x_0=700000.000 +y_0=6600000.000 +units=m +no_defs",
    RGF93CC42: "+title=Lambert conique conforme Zone 1 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=42.000000000 +lon_0=3.000000000 +lat_1=41.200000000 +lat_2=42.800000000 +x_0=1700000.000 +y_0=1200000.000 +units=m +no_defs",
    RGF93CC43: "+title=Lambert conique conforme Zone 2 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=43.000000000 +lon_0=3.000000000 +lat_1=42.200000000 +lat_2=43.800000000 +x_0=1700000.000 +y_0=2200000.000 +units=m +no_defs",
    RGF93CC44: "+title=Lambert conique conforme Zone 3 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=44.000000000 +lon_0=3.000000000 +lat_1=43.200000000 +lat_2=44.800000000 +x_0=1700000.000 +y_0=3200000.000 +units=m +no_defs",
    RGF93CC45: "+title=Lambert conique conforme Zone 4 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=45.000000000 +lon_0=3.000000000 +lat_1=44.200000000 +lat_2=45.800000000 +x_0=1700000.000 +y_0=4200000.000 +units=m +no_defs",
    RGF93CC46: "+title=Lambert conique conforme Zone 5 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=46.000000000 +lon_0=3.000000000 +lat_1=45.200000000 +lat_2=46.800000000 +x_0=1700000.000 +y_0=5200000.000 +units=m +no_defs",
    RGF93CC47: "+title=Lambert conique conforme Zone 6 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=47.000000000 +lon_0=3.000000000 +lat_1=46.200000000 +lat_2=47.800000000 +x_0=1700000.000 +y_0=6200000.000 +units=m +no_defs",
    RGF93CC48: "+title=Lambert conique conforme Zone 7 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=48.000000000 +lon_0=3.000000000 +lat_1=47.200000000 +lat_2=48.800000000 +x_0=1700000.000 +y_0=7200000.000 +units=m +no_defs",
    RGF93CC49: "+title=Lambert conique conforme Zone 8 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=49.000000000 +lon_0=3.000000000 +lat_1=48.200000000 +lat_2=49.800000000 +x_0=1700000.000 +y_0=8200000.000 +units=m +no_defs",
    RGF93CC50: "+title=Lambert conique conforme Zone 9 +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=50.000000000 +lon_0=3.000000000 +lat_1=49.200000000 +lat_2=50.800000000 +x_0=1700000.000 +y_0=9200000.000 +units=m +no_defs",
    LAMBE: "+title=Lambert II etendu +proj=lcc +nadgrids=ntf_r93.gsb,null +wktext +towgs84=-168.0000,-60.0000,320.0000 +a=6378249.2000 +rf=293.4660210000000 +pm=2.337229167 +lat_0=46.800000000 +lon_0=0.000000000 +k_0=0.99987742 +lat_1=46.800000000 +x_0=600000.000 +y_0=2200000.000 +units=m +no_defs",
    MART38UTM20: "+title=Martinique Fort-Desaix +proj=tmerc +towgs84=126.9260,547.9390,130.4090,-2.7867,5.1612,-0.8584,13.822650 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    MAYO50UTM38S: "+title=Mayotte Combani +proj=tmerc +towgs84=-599.9280,-275.5520,-195.6650,-0.0835,-0.4715,0.0602,49.281400 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=45.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    MILLER: "+title=Geoportail - Monde +proj=mill +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lon_0=0.000000000 +x_0=0.000 +y_0=0.000 +units=m +no_defs",
    MOOREA87U6S: "+title=Moorea 1987 - UTM fuseau 6 Sud +proj=tmerc +towgs84=215.9820,149.5930,176.2290,3.2624,1.6920,1.1571,10.477300 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-147.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    NUKU72U7S: "+title=IGN 1972 Nuku Hiva - UTM fuseau 7 Sud +proj=tmerc +towgs84=165.7320,216.7200,180.5050,-0.6434,-0.4512,-0.0791,7.420400 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-141.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    // REUN47GAUSSL : "+title=Reunion Gauss Laborde +proj=gstmerc +towgs84=789.5240,-626.4860,-89.9040,0.6006,76.7946,-10.5788,-32.324100 +a=6378388.0000 +rf=297.0000000000000 +lat_0=-21.116666667 +lon_0=55.533333333 +k_0=1.00000000 +x_0=160000.000 +y_0=50000.000 +units=m +no_defs",
    RGM04UTM38S: "+title=UTM fuseau 38 Sud (Reseau Geodesique de Mayotte 2004) +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=45.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGNCUTM57S: "+title=Reseau Geodesique de Nouvelle-Caledonie - UTM fuseau 57 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=159.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGNCUTM58S: "+title=Reseau Geodesique de Nouvelle-Caledonie - UTM fuseau 58 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=165.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGNCUTM59S: "+title=Reseau Geodesique de Nouvelle-Caledonie - UTM fuseau 59 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=171.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGPFUTM5S: "+title=RGPF - UTM fuseau 5 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-153.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGPFUTM6S: "+title=RGPF - UTM fuseau 6 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-147.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGPFUTM7S: "+title=RGPF - UTM fuseau 7 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-141.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGR92UTM40S: "+title=RGR92 UTM fuseau 40 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=57.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    RGSPM06U21: "+title=Saint-Pierre-et-Miquelon (2006) UTM Fuseau 21 Nord +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-57.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    STPL69UTM43S: "+title=Saint-Paul 1969 UTM fuseau 43 Sud +proj=tmerc +towgs84=225.571,-346.608,-46.567,0,0,0,0 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=75.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    STPM50UTM21: "+title=St Pierre et Miquelon 1950 +proj=tmerc +towgs84=-95.5930,573.7630,173.4420,-0.9602,1.2510,-1.3918,42.626500 +a=6378206.4000 +rf=294.9786982000000 +lat_0=0.000000000 +lon_0=-57.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    TAHAAUTM05S: "+title=Tahaa 1951 +proj=tmerc +towgs84=72.4380,345.9180,79.4860,-1.6045,-0.8823,-0.5565,1.374600 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-153.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    TAHI51UTM06S: "+title=Tahiti-Terme Nord UTM fuseau 6 Sud +proj=tmerc +towgs84=162.0000,117.0000,154.0000 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-147.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    TAHI79UTM6S: "+title=Tahiti 1979 +proj=tmerc +towgs84=221.5250,152.9480,176.7680,2.3847,1.3896,0.8770,11.474100 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-147.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    TERA50STEREO: "+title=Terre Adelie 1950 +proj=stere +towgs84=324.9120,153.2820,172.0260 +a=6378388.0000 +rf=297.0000000000000 +lat_0=-90.000000000 +lon_0=140.000000000 +lat_ts=-67 +k=0.96027295 +x_0=300000.000 +y_0=-2299363.482 +units=m +no_defs",
    UTM01SW84: "+title=World Geodetic System 1984 UTM fuseau 01 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-177.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    UTM20W84GUAD: "+title=World Geodetic System 1984 UTM fuseau 20 Nord-Guadeloupe +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM20W84MART: "+title=World Geodetic System 1984 UTM fuseau 20 Nord-Martinique +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-63.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM22RGFG95: "+title=RGFG95 UTM fuseau 22 Nord-Guyane +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-51.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM39SW84: "+title=World Geodetic System 1984 UTM fuseau 39 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=51.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    UTM42SW84: "+title=World Geodetic System 1984 UTM fuseau 42 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=69.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    UTM43SW84: "+title=World Geodetic System 1984 UTM fuseau 43 Sud +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=75.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    WALL78UTM1S: "+title=Wallis-Uvea 1978 (MOP78) UTM 1 SUD +proj=tmerc +towgs84=253.0000,-133.0000,-127.0000 +a=6378388.0000 +rf=297.0000000000000 +lat_0=0.000000000 +lon_0=-177.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=10000000.000 +units=m +no_defs",
    ETRS89GEO: "+title=ETRS89 geographiques (dms) +proj=longlat +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +units=m +no_defs",
    ETRS89LAEA: "+title=ETRS89 Lambert Azimutal Equal Area +proj=laea +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=52.000000000 +lon_0=10.000000000 +x_0=4321000.000 +y_0=3210000.000 +units=m +no_defs",
    ETRS89LCC: "+title=ETRS89 Lambert Conformal Conic +proj=lcc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=52.000000000 +lon_0=9.999999995 +lat_1=35.000000000 +lat_2=65.000000000 +x_0=4000000.000 +y_0=2800000.000 +units=m +no_defs",
    UTM26ETRS89: "+title=Europe - de 30d a 24d Ouest +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-27.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM27ETRS89: "+title=Europe - de 24d a 18d Ouest +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-21.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM28ETRS89: "+title=Europe - de 18d a 12d Ouest +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-15.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM29ETRS89: "+title=Europe - de 12d a 6d Ouest +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-9.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM30ETRS89: "+title=Europe - de -6d a 0d Ouest +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=-3.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM31ETRS89: "+title=Europe - de 0d a 6d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=3.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM32ETRS89: "+title=Europe - de 6d a 12d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=9.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM33ETRS89: "+title=Europe - de 12d a 18d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=15.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM34ETRS89: "+title=Europe - de 18d a 24d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=21.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM35ETRS89: "+title=Europe - de 24d a 30d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=27.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM36ETRS89: "+title=Europe - de 30d a 36d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=33.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM37ETRS89: "+title=Europe - de 36d a 42d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=39.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs",
    UTM38ETRS89: "+title=Europe - de 42d a 48d Est +proj=tmerc +nadgrids=null +wktext +towgs84=0.0000,0.0000,0.0000 +a=6378137.0000 +rf=298.2572221010000 +lat_0=0.000000000 +lon_0=45.000000000 +k_0=0.99960000 +x_0=500000.000 +y_0=0.000 +units=m +no_defs"
  }
};
/* harmony default export */ __webpack_exports__["default"] = (Register);

/***/ }),
/* 118 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(119);
/* harmony import */ var _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(117);




/**
 * @classdesc
 *
 * Leaflet Lambert 93 (EPSG:2154) <a href="http://leafletjs.com/reference.html#icrs" target="_blank">ICRS compatible</a> definition.
 *
 * @module
 * @alias L.geoportalCRS.EPSG2154
 * @example
 *  var map = L.Map('divmap', {
 *    crs : L.geoportalCRS.EPSG2154
 *  }).setView();
 *  var lyr = L.geoportalLayer.WMTS(
 *    {
 *      layer : "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO.L93"
 *    });
 *
 *  lyr.addTo(map); // ou map.addLayer(lyr);
 */
/** @type {L.geoportalCRS.EPSG2154} */
var EPSG2154 = {
  /**
   * instance
   *
   * @private
   */
  instance: null,
  /**
   * execution
   *
   * @returns {Object} instance
   * @private
   */
  build: function build() {
    // singleton
    if (!this.instance) {
      var crs = new leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Proj.CRS("EPSG:2154", _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__["default"].get("EPSG:2154"), {
        resolutions: this._getResolutions(),
        origin: this._getOrigin()
      });
      this.instance = crs;
    }
    return this.instance;
  },
  /**
   * resolutions
   *
   * @returns {Number[]} resolutions
   * @private
   */
  _getResolutions: function _getResolutions() {
    var resolutions = [];
    // resolutions issues de la configuration
    if (_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].isConfigLoaded()) {
      var o = _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].configuration.getTMSConf("LAMB93_5cm");
      resolutions = o.nativeResolutions;
    }
    if (resolutions.length) {
      return resolutions;
    }

    // resolution par defaut
    return [104579.22454989408, 52277.53235379051, 26135.487078595408, 13066.891381800004, 6533.228604113456, 3266.5595244626675, 1633.2660045974187, 816.6295549860224, 408.31391467683596, 204.15674151090204, 102.07831678324082, 51.0391448966112, 25.519569074269395, 12.759783693647506, 6.379891635966491, 3.18994576530532, 1.5949728694977277, 0.7974864315474559, 0.398743214900604, 0.19937160727567999, 0.099685803696052, 0.049842901818919996];
  },
  /**
   * origine
   *
   * @returns {Number[]} origin
   * @private
   */
  _getOrigin: function _getOrigin() {
    return [0, 12000000];
  }
};
/* harmony default export */ __webpack_exports__["default"] = (EPSG2154);

/***/ }),
/* 119 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/**
 * @module Config
 * @alias [private] Config
 * @description
 * ...
 *
 * @example
 * isConfigLoaded();
 */
var Config = {
  /**
   * Config
   *
   * @public
   * @type {Object}
   */
  configuration: {},
  /**
   * Check if the configuration is loaded
   *
   * @returns {Boolean} True if Config is loaded, false otherwise
   */
  isConfigLoaded: function isConfigLoaded() {
    // config already loaded !
    if (this.configuration && Object.keys(this.configuration).length !== 0) {
      return true;
    }
    var scope = typeof window !== "undefined" ? window : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : {};
    if (scope.Gp && scope.Gp.Config && scope.Gp.Config.layers && Object.keys(scope.Gp.Config.layers).length !== 0) {
      /** ts-syntax */this.configuration = scope.Gp.Config;
      return true;
    }
    return false;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (Config);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(52)))

/***/ }),
/* 120 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(119);
/* harmony import */ var _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(117);




/**
 *
 * Projection Lambert 2 étendu
 *
 * @module
 * @alias L.geoportalCRS.EPSG27572
 * @example
 *  var map = L.Map('divmap', {
 *    crs : L.geoportalCRS.EPSG27572
 *  }).setView();
 *  var lyr = L.geoportalLayer.WMTS(
 *    {
 *      layer : "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO.L93",
 *      apiKey : "wqxljfvklsdhvlfkjqfmlq787645"
 *    },
 *    {
 *      attribution : "test for layer ORTHOIMAGERY",
 *      opacity : 1,
 *      transparent : true,
 *      minZoom : 1,
 *      maxZoom : 21
 *      ...
 *    });
 *
 *  lyr.addTo(map); // ou map.addLayer(lyr);
 */
/** @type {L.geoportalCRS.EPSG27572} */
var EPSG27572 = {
  /**
   * instance
   *
   * @private
   */
  instance: null,
  /**
   * execution
   *
   * @returns {Object} instance
   * @private
   */
  build: function build() {
    // singleton
    if (!this.instance) {
      var crs = new leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Proj.CRS("EPSG:27572", _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__["default"].get("EPSG:27572"), {
        resolutions: this._getResolutions(),
        origin: this._getOrigin()
      });
      this.instance = crs;
    }
    return this.instance;
  },
  /**
   * resolutions
   *
   * @returns {Number[]} resolutions
   * @private
   */
  _getResolutions: function _getResolutions() {
    var resolutions = [];
    // resolutions issues de la configuration
    if (_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].isConfigLoaded()) {
      var o = _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].configuration.getTMSConf("LAMB2E");
      if (o && Object.keys(o).length) {
        resolutions = o.nativeResolutions;
      }
    }
    if (resolutions.length) {
      return resolutions;
    }

    // FIXME resolution par defaut ???
    return [104579.22454989408, 52277.53235379051, 26135.487078595408, 13066.891381800004, 6533.228604113456, 3266.5595244626675, 1633.2660045974187, 816.6295549860224, 408.31391467683596, 204.15674151090204, 102.07831678324082, 51.0391448966112, 25.519569074269395, 12.759783693647506, 6.379891635966491, 3.18994576530532, 1.5949728694977277, 0.7974864315474559, 0.398743214900604, 0.19937160727567999, 0.099685803696052, 0.049842901818919996];
  },
  /**
   * origine
   *
   * @returns {Number[]} origin
   * @private
   */
  _getOrigin: function _getOrigin() {
    return [0, 12000000];
  }
};
/* harmony default export */ __webpack_exports__["default"] = (EPSG27572);

/***/ }),
/* 121 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(119);
/* harmony import */ var _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(117);




// FIXME prototype
// il ne fonctionne pas car les bbox ne sont pas bien formatées !?
//   > BBOX=xmin,ymin,xmax,ymax --> conversion en EPSG --> BBOX=ymin,xmin,ymax,xmax
// cf. methode L.TileLayer.WMS.getTileUrl()
//   > inversion des coordonnées si crs = L.CRS.EPSG4326
// il faudrait donc surcharger cette methode afin qu'elle prenne en compte la condition suivante :
//   > crs.code = "EPSG:4326"

/**
 * Projection Geographic (EPSG:4326)
 * (PROTOTYPE)
 *
 * @ignore
 * @module
 * @alias L.geoportalCRS.EPSG2154
 * @returns {L.Proj.CRS}
 * @example
 *  var map = L.Map('divmap', {
 *    crs : L.geoportalCRS.EPSG4326 // ou L.CRS.EPSG4326
 *  }).setView();
 *  var lyr = L.geoportalLayer.WMTS(
 *    {
 *      layer : "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO",
 *      apiKey : "wqxljfvklsdhvlfkjqfmlq787645"
 *    },
 *    {
 *      attribution : "test for layer ORTHOIMAGERY",
 *      opacity : 1,
 *      transparent : true,
 *      minZoom : 1,
 *      maxZoom : 21
 *      ...
 *    });
 *
 *  lyr.addTo(map); // ou map.addLayer(lyr);
 */
/** @type {L.geoportalCRS.EPSG4326} */
var EPSG4326 = {
  /**
   * instance
   *
   * @private
   */
  instance: null,
  /**
   * execution
   *
   * @returns {Object} instance
   * @private
   */
  build: function build() {
    // singleton
    if (!this.instance) {
      var crs = new leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Proj.CRS("EPSG:4326", _Common_Utils_Register__WEBPACK_IMPORTED_MODULE_2__["default"].get("EPSG:4326"), {
        resolutions: this._getResolutions(),
        origin: [-180, 90] // ???
      });
      this.instance = crs;
    }
    return this.instance;
  },
  /**
   * resolutions
   *
   * @returns {Number[]} resolutions
   * @private
   */
  _getResolutions: function _getResolutions() {
    var resolutions = [];
    // resolutions issues de la configuration
    if (_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].isConfigLoaded()) {
      var o = _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].configuration.getTMSConf("WGS84G");
      resolutions = o.nativeResolutions;
    }
    if (resolutions.length) {
      return resolutions;
    }
    return [1.40625, 0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625, 0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625, 0.0006866455078125, 0.00034332275390625, 0.000171661376953126, 0.0000858306884765628, 0.0000429153442382813, 0.0000214576721191407, 0.0000107288360595703, 0.00000536441802978517, 0.00000268220901489259, 0.0000013411045074463, 0.000000670552253723145, 0.00000033527612686157];
  },
  /**
   * origine
   *
   * @private
   */
  _getOrigin: function _getOrigin() {}
};
/* harmony default export */ __webpack_exports__["default"] = (EPSG4326);

/***/ }),
/* 122 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var leaflet_draw__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(123);
/* harmony import */ var leaflet_draw__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(leaflet_draw__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(37);
/* harmony import */ var _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(108);
/* harmony import */ var _Common_Controls_ReverseGeocodingDOM__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(124);







var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__["default"].getLogger("reversegeocoding");

/**
 * @classdesc
 *
 * Leaflet Control Class to find locations by clicking on a map using <a href="https://geoservices.ign.fr/documentation/geoservices/geocodage-inverse.html" target="_blank">reverse geocoding service</a> of the Geoportal platform.
 *
 * Use {@link module :Controls.ReverseGeocode L.geoportalControl.ReverseGeocode()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.ReverseGeocode
 */
var ReverseGeocoding = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends L.geoportalControl.ReverseGeocode.prototype */{
  includes: _Common_Controls_ReverseGeocodingDOM__WEBPACK_IMPORTED_MODULE_6__["default"],
  /**
   * options by default
   *
   * @private
   */
  options: {
    position: "bottomleft",
    collapsed: true,
    resources: ["StreetAddress", "PositionOfInterest", "CadastralParcel"],
    delimitations: ["Point", "Circle", "Extent"],
    reverseGeocodeOptions: {}
  },
  /**
   * @constructor ReverseGeocode
   * @param {Object} options - ReverseGeocoding control options
   * @param {String}  [options.apiKey] - API key for services call (reverse geocode service). The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {String}  [options.position] - position of component into the map, 'topleft' by default
   * @param {Boolean} [options.collapsed] - Specify if widget has to be collapsed (true) or not (false) on map loading. Default is true.
   * @param {Array}  [options.resources] - resources for geocoding, by default : ["StreetAddress", "PositionOfInterest","CadastralParcel"]
   * @param {Array}  [options.delimitations] - delimitations for reverse geocoding, by default : ["Point", "Circle", "Extent"]
   * @param {Object}  [options.reverseGeocodeOptions] - reverse geocode service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~ReverseGeocode Gp.Services.reverseGeocode()} to know all reverse geocode options.
   * @example
   *  var reverse = L.geoportalControl.ReverseGeocode({
   *      collapsed : false,
   *      position : "topright",
   *      resources : ["StreetAddress", "PositionOfInterest","CadastralParcel"],
   *      delimitations : ["Point", "Circle"],
   *      reverseGeocodeOptions : {}
   *  });
   * reverse.on("reverse:onclickresult", function (e) {
   *   console.log(e.data):
   * });
   * @private
   */
  initialize: function initialize(options) {
    // on merge les options avec celles par defaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(this.options, options);

    // check input options format (resources and delimitations arrays)
    this._checkInputOptions();

    /** uuid */
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__["default"].generate();

    // Type de géocodage sélectionné (StreetAddress, PositionOfInterest, ...)
    this._currentGeocodingType = null;
    this._initGeocodingType();

    // Type de délimitation à utiliser pour la requête + pour sélection sur la containerDistance
    this._currentGeocodingDelimitation = null;
    this._initGeocodingDelimitation();

    // ################################################################## //
    // ################### Elements principaux du DOM ################### //

    // containers principaux
    this._showReverseGeocodingContainer = null;
    // header panel
    this._panelHeaderContainer = null;
    this._panelTitleContainer = null;
    this._returnPictoContainer = null;
    // form
    this._formContainer = null;
    // results
    this._resultsContainer = null;
    this._resultsListContainer = null;
    // waiting
    this._waitingContainer = null;

    // ###################################################################### //
    // ################### informations des points saisis ################### //

    // couche vectorielle dans laquelle seront saisis les points (features ci-dessus)
    this._inputFeaturesLayer = null;
    this._inputResultsLayer = null;
    this._lastIdLayer = 0;
    this._currentIdLayer = 0;
    // interaction avec la carte (de type "Point", "Circle" ou "Polygon")
    this._currentFeature = null;

    // #################################################################### //
    // ################### informations pour la requête ################### //

    // geometrie de recherche du géocodage inverse qui sera envoyée dans la requête
    this._requestGeom = null;

    // pour savoir si un calcul est en cours ou non
    this._waiting = false;
    // timer pour cacher la patience après un certain temps
    this._timer = null;

    // #################################################################### //
    // #################### informations des résultats #################### //

    this._reverseGeocodingLocations = [];
  },
  /**
   * this method is called by this.addTo(map) when the control is added on the map
   * and fills variable 'this._container = this.onAdd(map)',
   * and create events on map.
   *
   * @param {Object} map - the map
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  onAdd: function onAdd(map) {
    // initialisation du DOM du composant
    var container = this._container = this._initLayout();

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    if (map) {
      // lors de l'ajout à la map, on active la saisie du point,
      // mais seulement si le widget est ouvert
      if (!this.options.collapsed) {
        this._activateMapInteraction(map);
      }
    }
    return container;
  },
  /**
   * this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @param {Object} map - the map
   *
   * @private
   */
  onRemove: function onRemove(map) {
    this._clearLocations();
    this._clearLocationsFeature(map);
    this._clearInputRequest();

    // on supprime l'éventuelle précédente interaction
    this._removeMapInteraction(map);
  },
  // ################################################################### //
  // ##################### init component ############################## //
  // ################################################################### //

  /**
   * this method is called by this.initialize()
   * and makes sure input options are correctly formated
   *
   * @private
   */
  _checkInputOptions: function _checkInputOptions() {
    var i;
    // on vérifie le tableau des resources
    if (this.options.resources) {
      var resources = this.options.resources;
      // on vérifie que la liste des ressources de geocodage est bien un tableau
      if (Array.isArray(resources)) {
        var resourcesList = ["StreetAddress", "PositionOfInterest", "CadastralParcel", "Administratif"];
        for (i = 0; i < resources.length; i++) {
          if (resourcesList.indexOf(resources[i]) === -1) {
            // si la resource n'est pas référencée, on l'enlève
            // resources.splice(i, 1);
            logger.log("[ReverseGeocoding] options.resources : " + resources[i] + " is not a resource for reverse geocode");
          }
        }
      } else {
        logger.log("[ReverseGeocoding] 'options.resources' parameter should be an array");
        resources = null;
      }
    }
    // et le tableau des délimitations
    if (this.options.delimitations) {
      var delimitations = this.options.delimitations;
      // on vérifie que la liste des delimitations est bien un tableau
      if (Array.isArray(delimitations)) {
        var delimitationsList = ["Circle", "Point", "Extent"];
        for (i = 0; i < delimitations.length; i++) {
          if (delimitationsList.indexOf(delimitations[i]) === -1) {
            // si la delimitations n'est pas référencée, on l'enlève
            // resources.splice(i, 1);
            logger.log("[ReverseGeocoding] options.delimitations : " + delimitations[i] + " is not a delimitation for reverse geocode");
          }
        }
      } else {
        logger.log("[ReverseGeocoding] 'options.delimitations' parameter should be an array");
        delimitations = null;
      }
    }
  },
  /**
   * this method is called by this.initialize() and initialize geocoding type (=resource)
   * ("StreetAddress", "PositionOfInterest", "CadastralParcel")
   *
   * @private
   */
  _initGeocodingType: function _initGeocodingType() {
    // Type de géocodage selectionné
    this._currentGeocodingType = "StreetAddress"; // par defaut

    // par defaut
    var resources = this.options.resources;
    if (!resources || resources.length === 0) {
      this.options.resources = ["StreetAddress", "PositionOfInterest", "CadastralParcel"];
    }

    // options utilisateur
    if (Array.isArray(resources) && resources.length) {
      // récupération du type par défaut
      if (resources[0] === "StreetAddress" || resources[0] === "PositionOfInterest" || resources[0] === "CadastralParcel") {
        this._currentGeocodingType = resources[0];
      }
    }

    // si l'utilisateur a spécifié au moins une ressource dans le service, on surcharge les options du widget
    var serviceOptions = this.options.reverseGeocodeOptions;
    if (serviceOptions.filterOptions && Array.isArray(serviceOptions.filterOptions.type) && serviceOptions.filterOptions.type.length !== 0) {
      this._currentGeocodingType = serviceOptions.filterOptions.type[0];
    }
  },
  /**
   * this method is called by this.initialize() and initialize geocoding delimitation
   * ("Point", "Circle", "Extent")
   *
   * @private
   */
  _initGeocodingDelimitation: function _initGeocodingDelimitation() {
    // Type de délimitation selectionné
    this._currentGeocodingDelimitation = "Point"; // par defaut

    // par defaut
    var delimitations = this.options.delimitations;
    if (!delimitations || delimitations.length === 0) {
      this.options.delimitations = ["Point", "Circle", "Extent"];
    }

    // options utilisateur
    if (Array.isArray(delimitations) && delimitations.length) {
      var d = delimitations[0].toLowerCase();
      if (d === "point" || d === "circle" || d === "extent") {
        this._currentGeocodingDelimitation = delimitations[0];
      }
    }
  },
  // ################################################################### //
  // ######################## methods handle dom ####################### //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  _initLayout: function _initLayout() {
    // create main container
    var container = this._createMainContainerElement();

    // create show ReverseGeocoding element
    var inputShow = this._showReverseGeocodingContainer = this._createShowReverseGeocodingElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (!this.options.collapsed) {
      inputShow.checked = true;
    }

    // create ReverseGeocoding picto
    var picto = this._createShowReverseGeocodingPictoElement();
    container.appendChild(picto);

    // panel
    var reverseGeocodingPanel = this._createReverseGeocodingPanelElement();

    // header
    var panelHeader = this._panelHeaderContainer = this._createReverseGeocodingPanelHeaderElement();
    // return picto (hidden at start)
    var returnPicto = this._returnPictoContainer = this._createReverseGeocodingPanelReturnPictoElement();
    panelHeader.appendChild(returnPicto);
    // pane title
    var panelTitle = this._panelTitleContainer = this._createReverseGeocodingPanelTitleElement();
    panelHeader.appendChild(panelTitle);
    // close picto
    var closeDiv = this._createReverseGeocodingPanelCloseElement();
    panelHeader.appendChild(closeDiv);
    reverseGeocodingPanel.appendChild(panelHeader);

    // form
    var reverseGeocodingForm = this._formContainer = this._createReverseGeocodingPanelFormElement();
    // choices element
    reverseGeocodingForm.appendChild(this._createReverseGeocodingFormModeChoiceGeocodingTypeElement(this.options.resources));
    reverseGeocodingForm.appendChild(this._createReverseGeocodingFormModeChoiceGeocodingDelimitationElement(this.options.delimitations));

    // submit (bouton "Chercher")
    var submit = this._createReverseGeocodingSubmitFormElement();
    reverseGeocodingForm.appendChild(submit);
    reverseGeocodingPanel.appendChild(reverseGeocodingForm);

    // waiting
    var waiting = this._waitingContainer = this._createReverseGeocodingWaitingElement();
    reverseGeocodingPanel.appendChild(waiting);

    // results (dans le panel)
    var resultsPanel = this._resultsContainer = this._createReverseGeocodingResultsPanelElement();
    var reverseGeocodingResultsList = this._resultsListContainer = this._createReverseGeocodingResultsListElement();
    resultsPanel.appendChild(reverseGeocodingResultsList);
    reverseGeocodingPanel.appendChild(resultsPanel);
    container.appendChild(reverseGeocodingPanel);
    logger.log(container);
    return container;
  },
  // ################################################################### //
  // ################### Map interactions management ################### //
  // ################################################################### //

  /**
   * this method is called by this.onAdd,
   * or by this.onShowReverseGeocodingClick,
   * and calls method corresponding to current delimitation, if widget is not collapsed.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activateMapInteraction: function _activateMapInteraction(map) {
    logger.info("_activateMapInteraction()");

    // Creation de la couche vectorielle sur laquelle on va dessiner
    if (this._inputFeaturesLayer === null) {
      this._inputFeaturesLayer = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.FeatureGroup();
      map.addLayer(this._inputFeaturesLayer);
      var self = this;
      /* evenement sur la carte lors d'une saisie,
      on y ajoute le layer, et on y stocke les coordonnées */
      map.on("draw:created", function (e) {
        var layer = e.layer;
        var type = e.layerType;
        logger.trace("draw:created");

        // TODO
        // comment mettre en place un icone dynamiquement ?
        // if (type === "marker") {}

        self._setFeaturePosition(layer, type);
        self._currentIdLayer = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.stamp(layer);
        self._setFeatureLayer(layer);
      });

      /* evenements */
      map.on("draw:drawstart", function () {
        logger.trace("draw:drawstart");
        self._removeFeatureLayer(self._lastIdLayer);
        self._lastIdLayer = self._currentIdLayer;
      });

      /* evenements */
      map.on("draw:drawstop", function () {
        logger.trace("draw:drawstop");
      });
    }

    // Création de l'interaction de dessin, selon le type de délimitation sélectionné
    var delimitation = this._currentGeocodingDelimitation.toLowerCase();
    switch (delimitation) {
      case "point":
        this._activatePointInteraction(map);
        break;
      case "circle":
        this._activateCircleInteraction(map);
        break;
      case "extent":
        this._activateBoxInteraction(map);
        break;
      default:
        break;
    }
  },
  /**
   * remove draw interaction from map (if exists)
   *
   * @param {Object} map - control map.
   * @private
   */
  _removeMapInteraction: function _removeMapInteraction(map) {
    if (!map) {
      return;
    }
    if (this._inputFeaturesLayer !== null) {
      map.off("draw:created");
      map.off("draw:drawstart");
      map.off("draw:drawstop");
      map.removeLayer(this._inputFeaturesLayer);
      this._inputFeaturesLayer = null;
    }
    this._lastIdLayer = this._currentIdLayer = 0;

    // FIXME delete this._currentFeature ?
    if (this._currentFeature) {
      this._currentFeature.disable();
    }
  },
  /**
   * TODO this method is called by this._activateMapInteraction,
   * and creates map point drawing interaction.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activatePointInteraction: function _activatePointInteraction(map) {
    logger.info("_activatePointInteraction()");
    if (this._currentFeature) {
      this._currentFeature.disable();
    }

    // on modifie le tooltip du marker
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.drawLocal.draw.handlers.marker.tooltip.start = "click map to place search point";

    // TODO styles des icones
    var markerOptions = {
      // icon : par defaut...
      repeatMode: true
    };
    this._currentFeature = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Draw.Marker(map, markerOptions);
    this._currentFeature.enable();
  },
  /**
   * TODO this method is called by this._activateMapInteraction,
   * and creates map circle drawing interaction.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activateCircleInteraction: function _activateCircleInteraction(map) {
    logger.info("_activateCircleInteraction()");
    if (this._currentFeature) {
      this._currentFeature.disable();
    }
    var circleOptions = {
      repeatMode: true
    }; // TODO styles

    this._currentFeature = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Draw.Circle(map, circleOptions);
    this._currentFeature.enable();
  },
  /**
   * TODO this method is called by this._activateMapInteraction,
   * and creates map box drawing interaction.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activateBoxInteraction: function _activateBoxInteraction(map) {
    logger.info("_activateBoxInteraction()");
    if (this._currentFeature) {
      this._currentFeature.disable();
    }
    var rectangleOptions = {
      repeatMode: true
    }; // TODO styles

    this._currentFeature = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Draw.Rectangle(map, rectangleOptions);
    this._currentFeature.enable();
  },
  /**
   * set current position of feature
   *
   * @param {Object} layer - layer
   * @param {String} type - type
   *
   * @private
   */
  _setFeaturePosition: function _setFeaturePosition(layer, type) {
    // on transmet toujours des coordonnées au service en EPSG:4326
    var oLatLng = null;
    if (type === "marker") {
      oLatLng = layer.getLatLng();
      this._requestGeom = {
        type: "Point",
        coordinates: [oLatLng.lng, oLatLng.lat]
      };
    } else if (type === "circle") {
      oLatLng = layer.getLatLng();
      this._requestGeom = {
        type: "Circle",
        coordinates: [oLatLng.lng, oLatLng.lat],
        radius: layer.getRadius()
      };
    } else if (type === "rectangle") {
      oLatLng = layer.getBounds();
      this._requestGeom = {
        type: "Polygon",
        coordinates: [[[oLatLng.getNorthWest().lng, oLatLng.getNorthWest().lat], [oLatLng.getSouthWest().lng, oLatLng.getSouthWest().lat], [oLatLng.getSouthEast().lng, oLatLng.getSouthEast().lat], [oLatLng.getNorthEast().lng, oLatLng.getNorthEast().lat], [oLatLng.getNorthWest().lng, oLatLng.getNorthWest().lat]]]
      };
    } else {
      logger.warn("type geometric not defined !?");
    }
    logger.log(oLatLng);
  },
  /**
   * set current layer of feature
   *
   * @param {Object} layer - layer
   *
   * @private
   */
  _setFeatureLayer: function _setFeatureLayer(layer) {
    if (!this._inputFeaturesLayer) {
      return;
    }
    this._inputFeaturesLayer.addLayer(layer);
  },
  /**
   * remove layer feature from group
   * @param {Integer} id - id
   *
   * @private
   */
  _removeFeatureLayer: function _removeFeatureLayer(id) {
    if (!this._inputFeaturesLayer) {
      return;
    }
    if (id === 0) {
      return;
    }
    if (!id) {
      this._inputFeaturesLayer.clearLayers();
    } else {
      this._inputFeaturesLayer.removeLayer(id);
    }
  },
  // ################################################################### //
  // ##################### Reverse Geocoding request ################### //
  // ################################################################### //

  /**
   * this methode is called by this.onReverseGeocodingSubmit method,
   * it generates and sends reverse geocode request, then displays results
   * @param {Object} settings - settings
   *
   * @private
   */
  _reverseGeocodingRequest: function _reverseGeocodingRequest(settings) {
    // retrait de l'interaction sur la map pendant l'attente (et l'affichage des résultats)
    var map = this._map;
    this._removeMapInteraction(map);

    // on construit les options pour la requête
    var options = {};
    // on surcharge avec les options utilisateur
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.reverseGeocodeOptions);
    // la recherche et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);
    // options par defaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: this.options.apiKey,
      // maximumResponses : 25, // on peut la surcharger !
      timeOut: 30000,
      protocol: "XHR"
    });

    // on récupère d'éventuels filtres
    if (this._requestGeom.type.toLowerCase() === "circle") {
      // FIXME : a confirmer !
      if (this._requestGeom.radius > 1000) {
        logger.log("INFO : initial circle radius (" + this._requestGeom.radius + ") limited to 1000m.");
        this._requestGeom.radius = 1000;
      }
      options.searchGeometry = this._requestGeom;
    } else if (this._requestGeom.type.toLowerCase() === "polygon") {
      options.searchGeometry = this._requestGeom;
    } else if (this._requestGeom.type.toLowerCase() === "point") {
      if (this._currentGeocodingType === "StreetAddress") {
        options.searchGeometry = {
          type: "Circle",
          radius: 50,
          coordinates: this._requestGeom.coordinates
        };
        options.maximumResponses = 1;
      } else {
        options.searchGeometry = this._requestGeom;
      }
    }
    logger.log("reverseGeocode request options : ", options);

    // affichage d'une patience pendant l'attente
    this._displayWaitingContainer();

    // envoi de la requête
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.reverseGeocode(options);
  },
  // ################################################################### //
  // ############################# results list ######################## //
  // ################################################################### //

  /**
   * this method is called by this._reverseGeocodingRequest() (in case of reverse geocode success)
   * and display results : in both container list and map
   *
   * @param {Array} locations - array of geocoded locations (reverse geocode results)
   * @private
   */
  _displayGeocodedLocations: function _displayGeocodedLocations(locations) {
    var map = this._map;

    // 1. on vide les résultats précédents
    this._clearLocations();
    this._clearLocationsFeature(map);
    this._reverseGeocodingLocations = locations;
    if (!locations || locations.length === 0) {
      this._clearInputRequest(); // FIXME pas sûr que se soit le bon endroit...
      return;
    }

    // 2. cache de la patience et du formulaire
    this._formContainer.className = "GPreverseGeocodingComponentHidden";
    this._hideWaitingContainer();

    // affichage de la div des résultats (et changement du titre)
    this._panelTitleContainer.innerHTML = "Résultats de la recherche";
    this._returnPictoContainer.className = "";
    this._resultsContainer.className = "GPpanel";

    // 3. ajout de la liste des résultats dans le container des resultats
    this._fillGeocodedLocationListContainer(locations);

    // 4. affichage des résultats sur la carte (+ zoom ?)
    this._displayGeocodedLocationsOnMap(locations);

    // on zoom sur l'emprise des markers
    map.fitBounds(this._inputResultsLayer.getBounds());
  },
  /**
   * this method is called by this._displayGeocodedLocations()
   * and fills the container with results list
   *
   * @param {Array} locations - array of geocoded locations (reverse geocode results)
   * @private
   */
  _fillGeocodedLocationListContainer: function _fillGeocodedLocationListContainer(locations) {
    //  ajout de la liste des résultats dans le container des resultats
    for (var i = 0; i < locations.length; i++) {
      var location = locations[i];
      logger.log(location);
      // on récupère la description à afficher dans la liste
      var locationDescription = this._fillGeocodedLocationDescription(location);
      // on ajoute chaque résutat à la liste
      if (locationDescription.length !== 0) {
        this._createReverseGeocodingResultElement(locationDescription, i);
      }
    }
  },
  /**
   * this method is called by this._fillGeocodedLocationListContainer()
   * and fills location description (String), depending on matchType
   *
   * @param {Object} location - geocoded location (from reverse geocode results)
   * @returns {String} locationDescription - geocoded location description to be displayed
   * @private
   */
  _fillGeocodedLocationDescription: function _fillGeocodedLocationDescription(location) {
    if (!location || !location.placeAttributes) {
      return;
    }
    var attr = location.placeAttributes;
    var locationDescription = "";
    // on sélectionne les infos à afficher selon le type
    switch (location.type) {
      case "StreetAddress":
        if (attr.street) {
          locationDescription += attr.housenumber ? attr.housenumber + " " : "";
          locationDescription += attr.street + ", ";
        }
        locationDescription += attr.postcode + " " + attr.city;
        break;
      case "PositionOfInterest":
        locationDescription += attr.toponym;
        if (attr.postcode.length === 1) {
          locationDescription += ", " + attr.postcode[0];
        }
        locationDescription += " (" + attr.category.join(",") + ")";
        break;
      case "CadastralParcel":
        locationDescription += attr.id;
        locationDescription += attr.city ? " (" + attr.city + ")" : "";
        break;
      default:
        locationDescription += attr.city ? attr.city : "";
        break;
    }
    ;
    return locationDescription;
  },
  // ################################################################### //
  // ######################## map results (markers) #################### //
  // ################################################################### //

  /**
   * this method is called by this._displayGeocodedLocations()
   * and display locations in map (markers)
   *
   * @param {Object} locations - geocoded locations (reverse geocode result)
   * @private
   */
  _displayGeocodedLocationsOnMap: function _displayGeocodedLocationsOnMap(locations) {
    var map = this._map;
    var self = this;

    // function set style Highlight for results
    function _setHighLight(e) {
      var layer = e.target;
      layer.setIcon(new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_5__["default"]("red"));
      var div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("ReverseGeocodedLocation_" + layer.options.id + "-" + self._uid);
      leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.addClass(div, "GPreverseGeocodedLocationHighlight");
      div.scrollIntoView(false);
    }

    // function reset style Highlight for results
    function _resetHighLight(e) {
      var layer = e.target;
      layer.setIcon(new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_5__["default"]("green"));
      var div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("ReverseGeocodedLocation_" + layer.options.id + "-" + self._uid);
      leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.removeClass(div, "GPreverseGeocodedLocationHighlight");
    }

    // création de la couche où seront ajoutés les résultats
    this._inputResultsLayer = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.FeatureGroup();
    map.addLayer(this._inputResultsLayer);

    // ajout de chaque résultat à la couche (marker)
    for (var i = 0; i < locations.length; i++) {
      var location = locations[i];
      if (!location) {
        continue;
      }
      var options = {
        id: i,
        icon: new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_5__["default"]("green"),
        riseOnHover: true,
        draggable: false,
        clickable: true,
        zIndexOffset: 1000,
        data: location
      };
      var _marker = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.marker(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(location.position), options);

      // creation du contenu de la popup
      var popupContent = "<ul>";
      var attributes = location.placeAttributes;
      for (var attr in attributes) {
        if (attributes.hasOwnProperty(attr)) {
          if (attr !== "trueGeometry" && attr !== "extraFields" && attr !== "houseNumberInfos" && attr !== "_count") {
            popupContent += "<li>";
            popupContent += "<span class=\"gp-attname-others-span\">" + attr.toUpperCase() + " : </span>";
            popupContent += attributes[attr];
            popupContent += " </li>";
          }
        }
      }
      popupContent += " </ul>";
      _marker.bindPopup(popupContent);

      /** evenement mouseover sur le marker */
      _marker.on("mouseover", _setHighLight);

      /** evenement mouseout sur le marker */
      _marker.on("mouseout", _resetHighLight);
      _marker.on("click", function (e) {
        /**
         * event triggered when an element of the results is clicked for geocoding
         *
         * @event reverse:onclickresult
        */
        self.fire("reverse:onclickresult", {
          data: e.target.options.data
        });
      });
      this._inputResultsLayer.addLayer(_marker);
    }
  },
  // ################################################################### //
  // ####################### handlers events to dom #################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on 'GPshowReverseGeocodingPicto' tag label
   * (cf. ReverseGeocodingDOM._createShowReverseGeocodingPictoElement), and it cleans the component
   * when it's closed.
   *
   * @private
   */
  onShowReverseGeocodingClick: function onShowReverseGeocodingClick() {
    var map = this._map;

    // interactions declenchées à l'ouverture/fermeture du panneau
    if (this._showReverseGeocodingContainer.checked) {
      this._removeMapInteraction(map);
    } else {
      if (!this._waiting && !this._reverseGeocodingLocations.length) {
        this._activateMapInteraction(map);
      }
    }
  },
  /**
   * this method is called by event 'change' on 'GPreverseGeocodingCode' tag select
   * (cf. ReverseGeocodingDOM._createReverseGeocodingFormModeChoiceGeocodingTypeElement).
   * this value is saved as a parameter for reverseGeocode service.
   *
   * @param {Object} e - HTMLElement
   * @private
   */
  onReverseGeocodingTypeChange: function onReverseGeocodingTypeChange(e) {
    var idx = e.target.selectedIndex;
    var value = e.target.options[idx].value;
    if (!value) {
      return;
    }
    logger.log(value);
    this._currentGeocodingType = value;
  },
  /**
   * this method is called by event 'change' on 'GPreverseGeocodingCode' tag select
   * (cf. ReverseGeocodingDOM._createReverseGeocodingFormModeChoiceGeocodingDelimitationElement).
   * this value is saved as a parameter for reverseGeocode service.
   *
   * @param {Object} e - HTMLElement
   * @private
   */
  onReverseGeocodingDelimitationChange: function onReverseGeocodingDelimitationChange(e) {
    var idx = e.target.selectedIndex;
    var value = e.target.options[idx].value;
    if (!value) {
      return;
    }
    logger.log(value);
    this._currentGeocodingDelimitation = value;

    // on supprime l'interaction précédente,
    // ainsi que les géométries et valeurs stockées (filtres, position)
    this._clearInputRequest();

    // on met à jour l'interaction de la map en fonction de la nouvelle délimitation
    var map = this._map;

    // on supprime l'éventuelle précédente interaction
    this._removeMapInteraction(map);
    // on crée une nouvelle interaction
    this._activateMapInteraction(map);
  },
  /**
   * TODO this method is called by event 'click' on 'GPreverseGeocodingReturnPicto' div
   * (cf. ReverseGeocodingDOM._createReverseGeocodingPanelReturnPictoElement),
   * and clear geocoded location (from both list container and map)
   *
   * @private
   */
  onGPreverseGeocodingReturnPictoClick: function onGPreverseGeocodingReturnPictoClick() {
    var map = this._map;

    // suppression des résultats précédents
    this._clearLocations();
    this._clearLocationsFeature(map);

    // on efface les points qui ont pu être saisis précédemment
    this._clearInputRequest();

    // et on réactive l'interaction sur la map
    this._activateMapInteraction(map);
  },
  /**
   * TODO this methode is called by event 'submit' on reverseGeocoding form ('GPreverseGeocodingForm')
   * (cf. ReverseGeocodingDOM._createReverseGeocodingPanelFormElement),
   * it checks reverse geocode mandatory parameters,
   * then call this._reverseGeocodingRequest() to generate and send request
   *
   * @private
   */
  onReverseGeocodingSubmit: function onReverseGeocodingSubmit() {
    // le paramètre position est obligatoire
    if (!this._requestGeom) {
      logger.log("missing search geometry");
      return;
    }
    var map = this._map;
    var self = this;
    this._reverseGeocodingRequest({
      index: self._currentGeocodingType,
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results) {
          var locations = results.locations;
          self._displayGeocodedLocations(locations);
          self._hideWaitingContainer();

          // et on réactive l'interaction sur la map
          if (locations.length === 0) self._activateMapInteraction(map);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        self._hideWaitingContainer();

        // suppression d'éventuels résultats précédents
        self._clearLocations();
        self._clearLocationsFeature(map);

        // on efface les points qui ont été saisis précédemment
        self._clearInputRequest();

        // et on réactive l'interaction sur la map
        self._activateMapInteraction(map);
        logger.log(error.message);
      }
    });
  },
  /**
   * TODO this method is called by event 'click' on 'ReverseGeocodedLocation_' div
   * (cf. ReverseGeocodingDOM._createReverseGeocodingResultElement),
   * and zoom to location ?
   * TODO
   *
   * @param {Object} e - HTMLElement
   * @private
   */
  onReverseGeocodingResultClick: function onReverseGeocodingResultClick(e) {
    // récupération de l'id du résultat survolé
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__["default"].index(e.target.id);
    if (!this._inputResultsLayer) {
      return;
    }
    this._inputResultsLayer.eachLayer(function (layer) {
      if (layer.options.id === parseInt(idx, 10)) {
        layer.fire("click");
      }
    });
  },
  /**
   * TODO this method is called by event 'mouseover' on 'ReverseGeocodedLocation_' div
   * (cf. ReverseGeocodingDOM._createReverseGeocodingResultElement),
   * and changes style of matching marker on map (selected)
   *
   * @param {Object} e - HTMLElement
   * @private
   */
  onReverseGeocodingResultMouseOver: function onReverseGeocodingResultMouseOver(e) {
    // récupération de l'id du résultat survolé
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__["default"].index(e.target.id);

    // on passe le texte en gras
    if (e.target.classList) {
      e.target.classList.add("GPreverseGeocodedLocationHighlight");
    }
    if (!this._inputResultsLayer) {
      return;
    }
    this._inputResultsLayer.eachLayer(function (layer) {
      if (layer.options.id === parseInt(idx, 10)) {
        layer.fire("mouseover");
      }
    });
  },
  /**
   * TODO this method is called by event 'mouseout' on 'ReverseGeocodedLocation_' div
   * (cf. ReverseGeocodingDOM._createReverseGeocodingResultElement),
   * and changes style of matching marker on map (default)
   *
   * @param {Object} e - HTMLElement
   * @private
   */
  onReverseGeocodingResultMouseOut: function onReverseGeocodingResultMouseOut(e) {
    // récupération de l'id du résultat survolé
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__["default"].index(e.target.id);

    // on repasse le texte en style normal
    if (e.target.classList) {
      e.target.classList.remove("GPreverseGeocodedLocationHighlight");
    }
    if (!this._inputResultsLayer) {
      return;
    }
    this._inputResultsLayer.eachLayer(function (layer) {
      if (layer.options.id === parseInt(idx, 10)) {
        layer.fire("mouseout");
      }
    });
  },
  // ################################################################### //
  // ################################ clean ############################ //
  // ################################################################### //

  /**
   * TODO this method clears previous location results
   *
   * @private
   */
  _clearLocations: function _clearLocations() {
    this._reverseGeocodingLocations = [];
    // on vide le container avec la liste des résultats
    if (this._resultsListContainer) {
      while (this._resultsListContainer.firstChild) {
        this._resultsListContainer.removeChild(this._resultsListContainer.firstChild);
      }
    }
  },
  /**
   * TODO this method clears previous location results marker
   * @param {Object} map - the map
   *
   * @private
   */
  _clearLocationsFeature: function _clearLocationsFeature(map) {
    // suppression des anciens resultats
    if (this._inputResultsLayer !== null) {
      map.removeLayer(this._inputResultsLayer);
      this._inputResultsLayer = null;
    }
  },
  /**
   * TODO this method clears previous input features (features, position and filters)
   *
   * @private
   */
  _clearInputRequest: function _clearInputRequest() {
    // on supprime les valeurs stockées (filtres, position)
    this._requestPosition = null;
    this._requestCircleFilter = null;
    this._requestBboxFilter = null;
  },
  // ################################################################### //
  // ############################ Patience ############################# //
  // ################################################################### //

  /**
   * this method displays waiting container and sets a timeout
   *
   * @private
   */
  _displayWaitingContainer: function _displayWaitingContainer() {
    this._waitingContainer.className = "GPreverseGeocodingCalcWaitingContainerVisible";
    this._waiting = true;

    // mise en place d'un timeout pour réinitialiser le panel (cacher la patience)
    // si on est toujours en attente (si la requête est bloquée par exemple)
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
    var context = this;
    this._timer = setTimeout(function () {
      if (context._waiting === true) {
        context._hideWaitingContainer();
      } else {
        if (context._timer) {
          clearTimeout(context._timer);
        }
      }
    }, 16000);
  },
  /**
   * this method hides waiting container and clears timeout
   *
   * @private
   */
  _hideWaitingContainer: function _hideWaitingContainer() {
    if (this._waiting) {
      this._waitingContainer.className = "GPreverseGeocodingCalcWaitingContainerHidden";
      this._waiting = false;
      clearTimeout(this._timer);
      this._timer = null;
    }
  }
});

/** mix in L.Evented into control */
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.extend(ReverseGeocoding.prototype, leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Evented.prototype);
/* harmony default export */ __webpack_exports__["default"] = (ReverseGeocoding);

/***/ }),
/* 123 */
/***/ (function(module, exports) {

/*
 Leaflet.draw 1.0.4, a plugin that adds drawing and editing tools to Leaflet powered maps.
 (c) 2012-2017, Jacob Toye, Jon West, Smartrak, Leaflet

 https://github.com/Leaflet/Leaflet.draw
 http://leafletjs.com
 */
(function (window, document, undefined) {/**
 * Leaflet.draw assumes that you have already included the Leaflet library.
 */
L.drawVersion = "1.0.4";
/**
 * @class L.Draw
 * @aka Draw
 *
 *
 * To add the draw toolbar set the option drawControl: true in the map options.
 *
 * @example
 * ```js
 *      var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13);
 *
 *      L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
 *          attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
 *      }).addTo(map);
 * ```
 *
 * ### Adding the edit toolbar
 * To use the edit toolbar you must initialise the Leaflet.draw control and manually add it to the map.
 *
 * ```js
 *      var map = L.map('map').setView([51.505, -0.09], 13);
 *
 *      L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
 *          attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
 *      }).addTo(map);
 *
 *      // FeatureGroup is to store editable layers
 *      var drawnItems = new L.FeatureGroup();
 *      map.addLayer(drawnItems);
 *
 *      var drawControl = new L.Control.Draw({
 *          edit: {
 *              featureGroup: drawnItems
 *          }
 *      });
 *      map.addControl(drawControl);
 * ```
 *
 * The key here is the featureGroup option. This tells the plugin which FeatureGroup contains the layers that
 * should be editable. The featureGroup can contain 0 or more features with geometry types Point, LineString, and Polygon.
 * Leaflet.draw does not work with multigeometry features such as MultiPoint, MultiLineString, MultiPolygon,
 * or GeometryCollection. If you need to add multigeometry features to the draw plugin, convert them to a
 * FeatureCollection of non-multigeometries (Points, LineStrings, or Polygons).
 */
L.Draw = {};

/**
 * @class L.drawLocal
 * @aka L.drawLocal
 *
 * The core toolbar class of the API — it is used to create the toolbar ui
 *
 * @example
 * ```js
 *      var modifiedDraw = L.drawLocal.extend({
 *          draw: {
 *              toolbar: {
 *                  buttons: {
 *                      polygon: 'Draw an awesome polygon'
 *                  }
 *              }
 *          }
 *      });
 * ```
 *
 * The default state for the control is the draw toolbar just below the zoom control.
 *  This will allow map users to draw vectors and markers.
 *  **Please note the edit toolbar is not enabled by default.**
 */
L.drawLocal = {
	// format: {
	// 	numeric: {
	// 		delimiters: {
	// 			thousands: ',',
	// 			decimal: '.'
	// 		}
	// 	}
	// },
	draw: {
		toolbar: {
			// #TODO: this should be reorganized where actions are nested in actions
			// ex: actions.undo  or actions.cancel
			actions: {
				title: 'Cancel drawing',
				text: 'Cancel'
			},
			finish: {
				title: 'Finish drawing',
				text: 'Finish'
			},
			undo: {
				title: 'Delete last point drawn',
				text: 'Delete last point'
			},
			buttons: {
				polyline: 'Draw a polyline',
				polygon: 'Draw a polygon',
				rectangle: 'Draw a rectangle',
				circle: 'Draw a circle',
				marker: 'Draw a marker',
				circlemarker: 'Draw a circlemarker'
			}
		},
		handlers: {
			circle: {
				tooltip: {
					start: 'Click and drag to draw circle.'
				},
				radius: 'Radius'
			},
			circlemarker: {
				tooltip: {
					start: 'Click map to place circle marker.'
				}
			},
			marker: {
				tooltip: {
					start: 'Click map to place marker.'
				}
			},
			polygon: {
				tooltip: {
					start: 'Click to start drawing shape.',
					cont: 'Click to continue drawing shape.',
					end: 'Click first point to close this shape.'
				}
			},
			polyline: {
				error: '<strong>Error:</strong> shape edges cannot cross!',
				tooltip: {
					start: 'Click to start drawing line.',
					cont: 'Click to continue drawing line.',
					end: 'Click last point to finish line.'
				}
			},
			rectangle: {
				tooltip: {
					start: 'Click and drag to draw rectangle.'
				}
			},
			simpleshape: {
				tooltip: {
					end: 'Release mouse to finish drawing.'
				}
			}
		}
	},
	edit: {
		toolbar: {
			actions: {
				save: {
					title: 'Save changes',
					text: 'Save'
				},
				cancel: {
					title: 'Cancel editing, discards all changes',
					text: 'Cancel'
				},
				clearAll: {
					title: 'Clear all layers',
					text: 'Clear All'
				}
			},
			buttons: {
				edit: 'Edit layers',
				editDisabled: 'No layers to edit',
				remove: 'Delete layers',
				removeDisabled: 'No layers to delete'
			}
		},
		handlers: {
			edit: {
				tooltip: {
					text: 'Drag handles or markers to edit features.',
					subtext: 'Click cancel to undo changes.'
				}
			},
			remove: {
				tooltip: {
					text: 'Click on a feature to remove.'
				}
			}
		}
	}
};



/**
 * ### Events
 * Once you have successfully added the Leaflet.draw plugin to your map you will want to respond to the different
 * actions users can initiate. The following events will be triggered on the map:
 *
 * @class L.Draw.Event
 * @aka Draw.Event
 *
 * Use `L.Draw.Event.EVENTNAME` constants to ensure events are correct.
 *
 * @example
 * ```js
 * map.on(L.Draw.Event.CREATED; function (e) {
 *    var type = e.layerType,
 *        layer = e.layer;
 *
 *    if (type === 'marker') {
 *        // Do marker specific actions
 *    }
 *
 *    // Do whatever else you need to. (save to db; add to map etc)
 *    map.addLayer(layer);
 *});
 * ```
 */
L.Draw.Event = {};
/**
 * @event draw:created: PolyLine; Polygon; Rectangle; Circle; Marker | String
 *
 * Layer that was just created.
 * The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
 * Triggered when a new vector or marker has been created.
 *
 */
L.Draw.Event.CREATED = 'draw:created';

/**
 * @event draw:edited: LayerGroup
 *
 * List of all layers just edited on the map.
 *
 *
 * Triggered when layers in the FeatureGroup; initialised with the plugin; have been edited and saved.
 *
 * @example
 * ```js
 *      map.on('draw:edited', function (e) {
     *          var layers = e.layers;
     *          layers.eachLayer(function (layer) {
     *              //do whatever you want; most likely save back to db
     *          });
     *      });
 * ```
 */
L.Draw.Event.EDITED = 'draw:edited';

/**
 * @event draw:deleted: LayerGroup
 *
 * List of all layers just removed from the map.
 *
 * Triggered when layers have been removed (and saved) from the FeatureGroup.
 */
L.Draw.Event.DELETED = 'draw:deleted';

/**
 * @event draw:drawstart: String
 *
 * The type of layer this is. One of:`polyline`; `polygon`; `rectangle`; `circle`; `marker`
 *
 * Triggered when the user has chosen to draw a particular vector or marker.
 */
L.Draw.Event.DRAWSTART = 'draw:drawstart';

/**
 * @event draw:drawstop: String
 *
 * The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
 *
 * Triggered when the user has finished a particular vector or marker.
 */

L.Draw.Event.DRAWSTOP = 'draw:drawstop';

/**
 * @event draw:drawvertex: LayerGroup
 *
 * List of all layers just being added from the map.
 *
 * Triggered when a vertex is created on a polyline or polygon.
 */
L.Draw.Event.DRAWVERTEX = 'draw:drawvertex';

/**
 * @event draw:editstart: String
 *
 * The type of edit this is. One of: `edit`
 *
 * Triggered when the user starts edit mode by clicking the edit tool button.
 */

L.Draw.Event.EDITSTART = 'draw:editstart';

/**
 * @event draw:editmove: ILayer
 *
 *  Layer that was just moved.
 *
 * Triggered as the user moves a rectangle; circle or marker.
 */
L.Draw.Event.EDITMOVE = 'draw:editmove';

/**
 * @event draw:editresize: ILayer
 *
 * Layer that was just moved.
 *
 * Triggered as the user resizes a rectangle or circle.
 */
L.Draw.Event.EDITRESIZE = 'draw:editresize';

/**
 * @event draw:editvertex: LayerGroup
 *
 * List of all layers just being edited from the map.
 *
 * Triggered when a vertex is edited on a polyline or polygon.
 */
L.Draw.Event.EDITVERTEX = 'draw:editvertex';

/**
 * @event draw:editstop: String
 *
 * The type of edit this is. One of: `edit`
 *
 * Triggered when the user has finshed editing (edit mode) and saves edits.
 */
L.Draw.Event.EDITSTOP = 'draw:editstop';

/**
 * @event draw:deletestart: String
 *
 * The type of edit this is. One of: `remove`
 *
 * Triggered when the user starts remove mode by clicking the remove tool button.
 */
L.Draw.Event.DELETESTART = 'draw:deletestart';

/**
 * @event draw:deletestop: String
 *
 * The type of edit this is. One of: `remove`
 *
 * Triggered when the user has finished removing shapes (remove mode) and saves.
 */
L.Draw.Event.DELETESTOP = 'draw:deletestop';

/**
 * @event draw:toolbaropened: String
 *
 * Triggered when a toolbar is opened.
 */
L.Draw.Event.TOOLBAROPENED = 'draw:toolbaropened';

/**
 * @event draw:toolbarclosed: String
 *
 * Triggered when a toolbar is closed.
 */
L.Draw.Event.TOOLBARCLOSED = 'draw:toolbarclosed';

/**
 * @event draw:markercontext: String
 *
 * Triggered when a marker is right clicked.
 */
L.Draw.Event.MARKERCONTEXT = 'draw:markercontext';


L.Draw = L.Draw || {};

/**
 * @class L.Draw.Feature
 * @aka Draw.Feature
 */
L.Draw.Feature = L.Handler.extend({

	// @method initialize(): void
	initialize: function (map, options) {
		this._map = map;
		this._container = map._container;
		this._overlayPane = map._panes.overlayPane;
		this._popupPane = map._panes.popupPane;

		// Merge default shapeOptions options with custom shapeOptions
		if (options && options.shapeOptions) {
			options.shapeOptions = L.Util.extend({}, this.options.shapeOptions, options.shapeOptions);
		}
		L.setOptions(this, options);

		var version = L.version.split('.');
		//If Version is >= 1.2.0
		if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
			L.Draw.Feature.include(L.Evented.prototype);
		} else {
			L.Draw.Feature.include(L.Mixin.Events);
		}
	},

	// @method enable(): void
	// Enables this handler
	enable: function () {
		if (this._enabled) {
			return;
		}

		L.Handler.prototype.enable.call(this);

		this.fire('enabled', {handler: this.type});

		this._map.fire(L.Draw.Event.DRAWSTART, {layerType: this.type});
	},

	// @method disable(): void
	disable: function () {
		if (!this._enabled) {
			return;
		}

		L.Handler.prototype.disable.call(this);

		this._map.fire(L.Draw.Event.DRAWSTOP, {layerType: this.type});

		this.fire('disabled', {handler: this.type});
	},

	// @method addHooks(): void
	// Add's event listeners to this handler
	addHooks: function () {
		var map = this._map;

		if (map) {
			L.DomUtil.disableTextSelection();

			map.getContainer().focus();

			this._tooltip = new L.Draw.Tooltip(this._map);

			L.DomEvent.on(this._container, 'keyup', this._cancelDrawing, this);
		}
	},

	// @method removeHooks(): void
	// Removes event listeners from this handler
	removeHooks: function () {
		if (this._map) {
			L.DomUtil.enableTextSelection();

			this._tooltip.dispose();
			this._tooltip = null;

			L.DomEvent.off(this._container, 'keyup', this._cancelDrawing, this);
		}
	},

	// @method setOptions(object): void
	// Sets new options to this handler
	setOptions: function (options) {
		L.setOptions(this, options);
	},

	_fireCreatedEvent: function (layer) {
		this._map.fire(L.Draw.Event.CREATED, {layer: layer, layerType: this.type});
	},

	// Cancel drawing when the escape key is pressed
	_cancelDrawing: function (e) {
		if (e.keyCode === 27) {
			this._map.fire('draw:canceled', {layerType: this.type});
			this.disable();
		}
	}
});



/**
 * @class L.Draw.Polyline
 * @aka Draw.Polyline
 * @inherits L.Draw.Feature
 */
L.Draw.Polyline = L.Draw.Feature.extend({
	statics: {
		TYPE: 'polyline'
	},

	Poly: L.Polyline,

	options: {
		allowIntersection: true,
		repeatMode: false,
		drawError: {
			color: '#b00b00',
			timeout: 2500
		},
		icon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon'
		}),
		touchIcon: new L.DivIcon({
			iconSize: new L.Point(20, 20),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
		}),
		guidelineDistance: 20,
		maxGuideLineLength: 4000,
		shapeOptions: {
			stroke: true,
			color: '#3388ff',
			weight: 4,
			opacity: 0.5,
			fill: false,
			clickable: true
		},
		metric: true, // Whether to use the metric measurement system or imperial
		feet: true, // When not metric, to use feet instead of yards for display.
		nautic: false, // When not metric, not feet use nautic mile for display
		showLength: true, // Whether to display distance in the tooltip
		zIndexOffset: 2000, // This should be > than the highest z-index any map layers
		factor: 1, // To change distance calculation
		maxPoints: 0 // Once this number of points are placed, finish shape
	},

	// @method initialize(): void
	initialize: function (map, options) {
		// if touch, switch to touch icon
		if (L.Browser.touch) {
			this.options.icon = this.options.touchIcon;
		}

		// Need to set this here to ensure the correct message is used.
		this.options.drawError.message = L.drawLocal.draw.handlers.polyline.error;

		// Merge default drawError options with custom options
		if (options && options.drawError) {
			options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
		}

		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.Polyline.TYPE;

		L.Draw.Feature.prototype.initialize.call(this, map, options);
	},

	// @method addHooks(): void
	// Add listener hooks to this handler
	addHooks: function () {
		L.Draw.Feature.prototype.addHooks.call(this);
		if (this._map) {
			this._markers = [];

			this._markerGroup = new L.LayerGroup();
			this._map.addLayer(this._markerGroup);

			this._poly = new L.Polyline([], this.options.shapeOptions);

			this._tooltip.updateContent(this._getTooltipText());

			// Make a transparent marker that will used to catch click events. These click
			// events will create the vertices. We need to do this so we can ensure that
			// we can create vertices over other map layers (markers, vector layers). We
			// also do not want to trigger any click handlers of objects we are clicking on
			// while drawing.
			if (!this._mouseMarker) {
				this._mouseMarker = L.marker(this._map.getCenter(), {
					icon: L.divIcon({
						className: 'leaflet-mouse-marker',
						iconAnchor: [20, 20],
						iconSize: [40, 40]
					}),
					opacity: 0,
					zIndexOffset: this.options.zIndexOffset
				});
			}

			this._mouseMarker
				.on('mouseout', this._onMouseOut, this)
				.on('mousemove', this._onMouseMove, this) // Necessary to prevent 0.8 stutter
				.on('mousedown', this._onMouseDown, this)
				.on('mouseup', this._onMouseUp, this) // Necessary for 0.8 compatibility
				.addTo(this._map);

			this._map
				.on('mouseup', this._onMouseUp, this) // Necessary for 0.7 compatibility
				.on('mousemove', this._onMouseMove, this)
				.on('zoomlevelschange', this._onZoomEnd, this)
				.on('touchstart', this._onTouch, this)
				.on('zoomend', this._onZoomEnd, this);

		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler.
	removeHooks: function () {
		L.Draw.Feature.prototype.removeHooks.call(this);

		this._clearHideErrorTimeout();

		this._cleanUpShape();

		// remove markers from map
		this._map.removeLayer(this._markerGroup);
		delete this._markerGroup;
		delete this._markers;

		this._map.removeLayer(this._poly);
		delete this._poly;

		this._mouseMarker
			.off('mousedown', this._onMouseDown, this)
			.off('mouseout', this._onMouseOut, this)
			.off('mouseup', this._onMouseUp, this)
			.off('mousemove', this._onMouseMove, this);
		this._map.removeLayer(this._mouseMarker);
		delete this._mouseMarker;

		// clean up DOM
		this._clearGuides();

		this._map
			.off('mouseup', this._onMouseUp, this)
			.off('mousemove', this._onMouseMove, this)
			.off('zoomlevelschange', this._onZoomEnd, this)
			.off('zoomend', this._onZoomEnd, this)
			.off('touchstart', this._onTouch, this)
			.off('click', this._onTouch, this);
	},

	// @method deleteLastVertex(): void
	// Remove the last vertex from the polyline, removes polyline from map if only one point exists.
	deleteLastVertex: function () {
		if (this._markers.length <= 1) {
			return;
		}

		var lastMarker = this._markers.pop(),
			poly = this._poly,
			// Replaces .spliceLatLngs()
			latlngs = poly.getLatLngs(),
			latlng = latlngs.splice(-1, 1)[0];
		this._poly.setLatLngs(latlngs);

		this._markerGroup.removeLayer(lastMarker);

		if (poly.getLatLngs().length < 2) {
			this._map.removeLayer(poly);
		}

		this._vertexChanged(latlng, false);
	},

	// @method addVertex(): void
	// Add a vertex to the end of the polyline
	addVertex: function (latlng) {
		var markersLength = this._markers.length;
		// markersLength must be greater than or equal to 2 before intersections can occur
		if (markersLength >= 2 && !this.options.allowIntersection && this._poly.newLatLngIntersects(latlng)) {
			this._showErrorTooltip();
			return;
		}
		else if (this._errorShown) {
			this._hideErrorTooltip();
		}

		this._markers.push(this._createMarker(latlng));

		this._poly.addLatLng(latlng);

		if (this._poly.getLatLngs().length === 2) {
			this._map.addLayer(this._poly);
		}

		this._vertexChanged(latlng, true);
	},

	// @method completeShape(): void
	// Closes the polyline between the first and last points
	completeShape: function () {
		if (this._markers.length <= 1 || !this._shapeIsValid()) {
			return;
		}

		this._fireCreatedEvent();
		this.disable();

		if (this.options.repeatMode) {
			this.enable();
		}
	},

	_finishShape: function () {
		var latlngs = this._poly._defaultShape ? this._poly._defaultShape() : this._poly.getLatLngs();
		var intersects = this._poly.newLatLngIntersects(latlngs[latlngs.length - 1]);

		if ((!this.options.allowIntersection && intersects) || !this._shapeIsValid()) {
			this._showErrorTooltip();
			return;
		}

		this._fireCreatedEvent();
		this.disable();
		if (this.options.repeatMode) {
			this.enable();
		}
	},

	// Called to verify the shape is valid when the user tries to finish it
	// Return false if the shape is not valid
	_shapeIsValid: function () {
		return true;
	},

	_onZoomEnd: function () {
		if (this._markers !== null) {
			this._updateGuide();
		}
	},

	_onMouseMove: function (e) {
		var newPos = this._map.mouseEventToLayerPoint(e.originalEvent);
		var latlng = this._map.layerPointToLatLng(newPos);

		// Save latlng
		// should this be moved to _updateGuide() ?
		this._currentLatLng = latlng;

		this._updateTooltip(latlng);

		// Update the guide line
		this._updateGuide(newPos);

		// Update the mouse marker position
		this._mouseMarker.setLatLng(latlng);

		L.DomEvent.preventDefault(e.originalEvent);
	},

	_vertexChanged: function (latlng, added) {
		this._map.fire(L.Draw.Event.DRAWVERTEX, {layers: this._markerGroup});
		this._updateFinishHandler();

		this._updateRunningMeasure(latlng, added);

		this._clearGuides();

		this._updateTooltip();
	},

	_onMouseDown: function (e) {
		if (!this._clickHandled && !this._touchHandled && !this._disableMarkers) {
			this._onMouseMove(e);
			this._clickHandled = true;
			this._disableNewMarkers();
			var originalEvent = e.originalEvent;
			var clientX = originalEvent.clientX;
			var clientY = originalEvent.clientY;
			this._startPoint.call(this, clientX, clientY);
		}
	},

	_startPoint: function (clientX, clientY) {
		this._mouseDownOrigin = L.point(clientX, clientY);
	},

	_onMouseUp: function (e) {
		var originalEvent = e.originalEvent;
		var clientX = originalEvent.clientX;
		var clientY = originalEvent.clientY;
		this._endPoint.call(this, clientX, clientY, e);
		this._clickHandled = null;
	},

	_endPoint: function (clientX, clientY, e) {
		if (this._mouseDownOrigin) {
			var dragCheckDistance = L.point(clientX, clientY)
				.distanceTo(this._mouseDownOrigin);
			var lastPtDistance = this._calculateFinishDistance(e.latlng);
			if (this.options.maxPoints > 1 && this.options.maxPoints == this._markers.length + 1) {
				this.addVertex(e.latlng);
				this._finishShape();
			} else if (lastPtDistance < 10 && L.Browser.touch) {
				this._finishShape();
			} else if (Math.abs(dragCheckDistance) < 9 * (window.devicePixelRatio || 1)) {
				this.addVertex(e.latlng);
			}
			this._enableNewMarkers(); // after a short pause, enable new markers
		}
		this._mouseDownOrigin = null;
	},

	// ontouch prevented by clickHandled flag because some browsers fire both click/touch events,
	// causing unwanted behavior
	_onTouch: function (e) {
		var originalEvent = e.originalEvent;
		var clientX;
		var clientY;
		if (originalEvent.touches && originalEvent.touches[0] && !this._clickHandled && !this._touchHandled && !this._disableMarkers) {
			clientX = originalEvent.touches[0].clientX;
			clientY = originalEvent.touches[0].clientY;
			this._disableNewMarkers();
			this._touchHandled = true;
			this._startPoint.call(this, clientX, clientY);
			this._endPoint.call(this, clientX, clientY, e);
			this._touchHandled = null;
		}
		this._clickHandled = null;
	},

	_onMouseOut: function () {
		if (this._tooltip) {
			this._tooltip._onMouseOut.call(this._tooltip);
		}
	},

	// calculate if we are currently within close enough distance
	// of the closing point (first point for shapes, last point for lines)
	// this is semi-ugly code but the only reliable way i found to get the job done
	// note: calculating point.distanceTo between mouseDownOrigin and last marker did NOT work
	_calculateFinishDistance: function (potentialLatLng) {
		var lastPtDistance;
		if (this._markers.length > 0) {
			var finishMarker;
			if (this.type === L.Draw.Polyline.TYPE) {
				finishMarker = this._markers[this._markers.length - 1];
			} else if (this.type === L.Draw.Polygon.TYPE) {
				finishMarker = this._markers[0];
			} else {
				return Infinity;
			}
			var lastMarkerPoint = this._map.latLngToContainerPoint(finishMarker.getLatLng()),
				potentialMarker = new L.Marker(potentialLatLng, {
					icon: this.options.icon,
					zIndexOffset: this.options.zIndexOffset * 2
				});
			var potentialMarkerPint = this._map.latLngToContainerPoint(potentialMarker.getLatLng());
			lastPtDistance = lastMarkerPoint.distanceTo(potentialMarkerPint);
		} else {
			lastPtDistance = Infinity;
		}
		return lastPtDistance;
	},

	_updateFinishHandler: function () {
		var markerCount = this._markers.length;
		// The last marker should have a click handler to close the polyline
		if (markerCount > 1) {
			this._markers[markerCount - 1].on('click', this._finishShape, this);
		}

		// Remove the old marker click handler (as only the last point should close the polyline)
		if (markerCount > 2) {
			this._markers[markerCount - 2].off('click', this._finishShape, this);
		}
	},

	_createMarker: function (latlng) {
		var marker = new L.Marker(latlng, {
			icon: this.options.icon,
			zIndexOffset: this.options.zIndexOffset * 2
		});

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_updateGuide: function (newPos) {
		var markerCount = this._markers ? this._markers.length : 0;

		if (markerCount > 0) {
			newPos = newPos || this._map.latLngToLayerPoint(this._currentLatLng);

			// draw the guide line
			this._clearGuides();
			this._drawGuide(
				this._map.latLngToLayerPoint(this._markers[markerCount - 1].getLatLng()),
				newPos
			);
		}
	},

	_updateTooltip: function (latLng) {
		var text = this._getTooltipText();

		if (latLng) {
			this._tooltip.updatePosition(latLng);
		}

		if (!this._errorShown) {
			this._tooltip.updateContent(text);
		}
	},

	_drawGuide: function (pointA, pointB) {
		var length = Math.floor(Math.sqrt(Math.pow((pointB.x - pointA.x), 2) + Math.pow((pointB.y - pointA.y), 2))),
			guidelineDistance = this.options.guidelineDistance,
			maxGuideLineLength = this.options.maxGuideLineLength,
			// Only draw a guideline with a max length
			i = length > maxGuideLineLength ? length - maxGuideLineLength : guidelineDistance,
			fraction,
			dashPoint,
			dash;

		//create the guides container if we haven't yet
		if (!this._guidesContainer) {
			this._guidesContainer = L.DomUtil.create('div', 'leaflet-draw-guides', this._overlayPane);
		}

		//draw a dash every GuildeLineDistance
		for (; i < length; i += this.options.guidelineDistance) {
			//work out fraction along line we are
			fraction = i / length;

			//calculate new x,y point
			dashPoint = {
				x: Math.floor((pointA.x * (1 - fraction)) + (fraction * pointB.x)),
				y: Math.floor((pointA.y * (1 - fraction)) + (fraction * pointB.y))
			};

			//add guide dash to guide container
			dash = L.DomUtil.create('div', 'leaflet-draw-guide-dash', this._guidesContainer);
			dash.style.backgroundColor =
				!this._errorShown ? this.options.shapeOptions.color : this.options.drawError.color;

			L.DomUtil.setPosition(dash, dashPoint);
		}
	},

	_updateGuideColor: function (color) {
		if (this._guidesContainer) {
			for (var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) {
				this._guidesContainer.childNodes[i].style.backgroundColor = color;
			}
		}
	},

	// removes all child elements (guide dashes) from the guides container
	_clearGuides: function () {
		if (this._guidesContainer) {
			while (this._guidesContainer.firstChild) {
				this._guidesContainer.removeChild(this._guidesContainer.firstChild);
			}
		}
	},

	_getTooltipText: function () {
		var showLength = this.options.showLength,
			labelText, distanceStr;
		if (this._markers.length === 0) {
			labelText = {
				text: L.drawLocal.draw.handlers.polyline.tooltip.start
			};
		} else {
			distanceStr = showLength ? this._getMeasurementString() : '';

			if (this._markers.length === 1) {
				labelText = {
					text: L.drawLocal.draw.handlers.polyline.tooltip.cont,
					subtext: distanceStr
				};
			} else {
				labelText = {
					text: L.drawLocal.draw.handlers.polyline.tooltip.end,
					subtext: distanceStr
				};
			}
		}
		return labelText;
	},

	_updateRunningMeasure: function (latlng, added) {
		var markersLength = this._markers.length,
			previousMarkerIndex, distance;

		if (this._markers.length === 1) {
			this._measurementRunningTotal = 0;
		} else {
			previousMarkerIndex = markersLength - (added ? 2 : 1);

			// Calculate the distance based on the version
			if (L.GeometryUtil.isVersion07x()) {
				distance = latlng.distanceTo(this._markers[previousMarkerIndex].getLatLng()) * (this.options.factor || 1);
			} else {
				distance = this._map.distance(latlng, this._markers[previousMarkerIndex].getLatLng()) * (this.options.factor || 1);
			}

			this._measurementRunningTotal += distance * (added ? 1 : -1);
		}
	},

	_getMeasurementString: function () {
		var currentLatLng = this._currentLatLng,
			previousLatLng = this._markers[this._markers.length - 1].getLatLng(),
			distance;

		// Calculate the distance from the last fixed point to the mouse position based on the version
		if (L.GeometryUtil.isVersion07x()) {
			distance = previousLatLng && currentLatLng && currentLatLng.distanceTo ? this._measurementRunningTotal + currentLatLng.distanceTo(previousLatLng) * (this.options.factor || 1) : this._measurementRunningTotal || 0;
		} else {
			distance = previousLatLng && currentLatLng ? this._measurementRunningTotal + this._map.distance(currentLatLng, previousLatLng) * (this.options.factor || 1) : this._measurementRunningTotal || 0;
		}

		return L.GeometryUtil.readableDistance(distance, this.options.metric, this.options.feet, this.options.nautic, this.options.precision);
	},

	_showErrorTooltip: function () {
		this._errorShown = true;

		// Update tooltip
		this._tooltip
			.showAsError()
			.updateContent({text: this.options.drawError.message});

		// Update shape
		this._updateGuideColor(this.options.drawError.color);
		this._poly.setStyle({color: this.options.drawError.color});

		// Hide the error after 2 seconds
		this._clearHideErrorTimeout();
		this._hideErrorTimeout = setTimeout(L.Util.bind(this._hideErrorTooltip, this), this.options.drawError.timeout);
	},

	_hideErrorTooltip: function () {
		this._errorShown = false;

		this._clearHideErrorTimeout();

		// Revert tooltip
		this._tooltip
			.removeError()
			.updateContent(this._getTooltipText());

		// Revert shape
		this._updateGuideColor(this.options.shapeOptions.color);
		this._poly.setStyle({color: this.options.shapeOptions.color});
	},

	_clearHideErrorTimeout: function () {
		if (this._hideErrorTimeout) {
			clearTimeout(this._hideErrorTimeout);
			this._hideErrorTimeout = null;
		}
	},

	// disable new markers temporarily;
	// this is to prevent duplicated touch/click events in some browsers
	_disableNewMarkers: function () {
		this._disableMarkers = true;
	},

	// see _disableNewMarkers
	_enableNewMarkers: function () {
		setTimeout(function () {
			this._disableMarkers = false;
		}.bind(this), 50);
	},

	_cleanUpShape: function () {
		if (this._markers.length > 1) {
			this._markers[this._markers.length - 1].off('click', this._finishShape, this);
		}
	},

	_fireCreatedEvent: function () {
		var poly = new this.Poly(this._poly.getLatLngs(), this.options.shapeOptions);
		L.Draw.Feature.prototype._fireCreatedEvent.call(this, poly);
	}
});



/**
 * @class L.Draw.Polygon
 * @aka Draw.Polygon
 * @inherits L.Draw.Polyline
 */
L.Draw.Polygon = L.Draw.Polyline.extend({
	statics: {
		TYPE: 'polygon'
	},

	Poly: L.Polygon,

	options: {
		showArea: false,
		showLength: false,
		shapeOptions: {
			stroke: true,
			color: '#3388ff',
			weight: 4,
			opacity: 0.5,
			fill: true,
			fillColor: null, //same as color by default
			fillOpacity: 0.2,
			clickable: true
		},
		// Whether to use the metric measurement system (truthy) or not (falsy).
		// Also defines the units to use for the metric system as an array of
		// strings (e.g. `['ha', 'm']`).
		metric: true,
		feet: true, // When not metric, to use feet instead of yards for display.
		nautic: false, // When not metric, not feet use nautic mile for display
		// Defines the precision for each type of unit (e.g. {km: 2, ft: 0}
		precision: {}
	},

	// @method initialize(): void
	initialize: function (map, options) {
		L.Draw.Polyline.prototype.initialize.call(this, map, options);

		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.Polygon.TYPE;
	},

	_updateFinishHandler: function () {
		var markerCount = this._markers.length;

		// The first marker should have a click handler to close the polygon
		if (markerCount === 1) {
			this._markers[0].on('click', this._finishShape, this);
		}

		// Add and update the double click handler
		if (markerCount > 2) {
			this._markers[markerCount - 1].on('dblclick', this._finishShape, this);
			// Only need to remove handler if has been added before
			if (markerCount > 3) {
				this._markers[markerCount - 2].off('dblclick', this._finishShape, this);
			}
		}
	},

	_getTooltipText: function () {
		var text, subtext;

		if (this._markers.length === 0) {
			text = L.drawLocal.draw.handlers.polygon.tooltip.start;
		} else if (this._markers.length < 3) {
			text = L.drawLocal.draw.handlers.polygon.tooltip.cont;
			subtext = this._getMeasurementString();
		} else {
			text = L.drawLocal.draw.handlers.polygon.tooltip.end;
			subtext = this._getMeasurementString();
		}

		return {
			text: text,
			subtext: subtext
		};
	},

	_getMeasurementString: function () {
		var area = this._area,
			measurementString = '';


		if (!area && !this.options.showLength) {
			return null;
		}

		if (this.options.showLength) {
			measurementString = L.Draw.Polyline.prototype._getMeasurementString.call(this);
		}

		if (area) {
			measurementString += '<br>' + L.GeometryUtil.readableArea(area, this.options.metric, this.options.precision);
		}

		return measurementString;
	},

	_shapeIsValid: function () {
		return this._markers.length >= 3;
	},

	_vertexChanged: function (latlng, added) {
		var latLngs;

		// Check to see if we should show the area
		if (!this.options.allowIntersection && this.options.showArea) {
			latLngs = this._poly.getLatLngs();

			this._area = L.GeometryUtil.geodesicArea(latLngs);
		}

		L.Draw.Polyline.prototype._vertexChanged.call(this, latlng, added);
	},

	_cleanUpShape: function () {
		var markerCount = this._markers.length;

		if (markerCount > 0) {
			this._markers[0].off('click', this._finishShape, this);

			if (markerCount > 2) {
				this._markers[markerCount - 1].off('dblclick', this._finishShape, this);
			}
		}
	}
});



L.SimpleShape = {};
/**
 * @class L.Draw.SimpleShape
 * @aka Draw.SimpleShape
 * @inherits L.Draw.Feature
 */
L.Draw.SimpleShape = L.Draw.Feature.extend({
	options: {
		repeatMode: false
	},

	// @method initialize(): void
	initialize: function (map, options) {
		this._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end;

		L.Draw.Feature.prototype.initialize.call(this, map, options);
	},

	// @method addHooks(): void
	// Add listener hooks to this handler.
	addHooks: function () {
		L.Draw.Feature.prototype.addHooks.call(this);
		if (this._map) {
			this._mapDraggable = this._map.dragging.enabled();

			if (this._mapDraggable) {
				this._map.dragging.disable();
			}

			//TODO refactor: move cursor to styles
			this._container.style.cursor = 'crosshair';

			this._tooltip.updateContent({text: this._initialLabelText});

			this._map
				.on('mousedown', this._onMouseDown, this)
				.on('mousemove', this._onMouseMove, this)
				.on('touchstart', this._onMouseDown, this)
				.on('touchmove', this._onMouseMove, this);

			// we should prevent default, otherwise default behavior (scrolling) will fire,
			// and that will cause document.touchend to fire and will stop the drawing
			// (circle, rectangle) in touch mode.
			// (update): we have to send passive now to prevent scroll, because by default it is {passive: true} now, which means,
			// handler can't event.preventDefault
			// check the news https://developers.google.com/web/updates/2016/06/passive-event-listeners
			document.addEventListener('touchstart', L.DomEvent.preventDefault, {passive: false});
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler.
	removeHooks: function () {
		L.Draw.Feature.prototype.removeHooks.call(this);
		if (this._map) {
			if (this._mapDraggable) {
				this._map.dragging.enable();
			}

			//TODO refactor: move cursor to styles
			this._container.style.cursor = '';

			this._map
				.off('mousedown', this._onMouseDown, this)
				.off('mousemove', this._onMouseMove, this)
				.off('touchstart', this._onMouseDown, this)
				.off('touchmove', this._onMouseMove, this);

			L.DomEvent.off(document, 'mouseup', this._onMouseUp, this);
			L.DomEvent.off(document, 'touchend', this._onMouseUp, this);

			document.removeEventListener('touchstart', L.DomEvent.preventDefault);

			// If the box element doesn't exist they must not have moved the mouse, so don't need to destroy/return
			if (this._shape) {
				this._map.removeLayer(this._shape);
				delete this._shape;
			}
		}
		this._isDrawing = false;
	},

	_getTooltipText: function () {
		return {
			text: this._endLabelText
		};
	},

	_onMouseDown: function (e) {
		this._isDrawing = true;
		this._startLatLng = e.latlng;

		L.DomEvent
			.on(document, 'mouseup', this._onMouseUp, this)
			.on(document, 'touchend', this._onMouseUp, this)
			.preventDefault(e.originalEvent);
	},

	_onMouseMove: function (e) {
		var latlng = e.latlng;

		this._tooltip.updatePosition(latlng);
		if (this._isDrawing) {
			this._tooltip.updateContent(this._getTooltipText());
			this._drawShape(latlng);
		}
	},

	_onMouseUp: function () {
		if (this._shape) {
			this._fireCreatedEvent();
		}

		this.disable();
		if (this.options.repeatMode) {
			this.enable();
		}
	}
});



/**
 * @class L.Draw.Rectangle
 * @aka Draw.Rectangle
 * @inherits L.Draw.SimpleShape
 */
L.Draw.Rectangle = L.Draw.SimpleShape.extend({
	statics: {
		TYPE: 'rectangle'
	},

	options: {
		shapeOptions: {
			stroke: true,
			color: '#3388ff',
			weight: 4,
			opacity: 0.5,
			fill: true,
			fillColor: null, //same as color by default
			fillOpacity: 0.2,
			clickable: true
		},
		showArea: true, //Whether to show the area in the tooltip
		metric: true // Whether to use the metric measurement system or imperial
	},

	// @method initialize(): void
	initialize: function (map, options) {
		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.Rectangle.TYPE;

		this._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;

		L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
	},

	// @method disable(): void
	disable: function () {
		if (!this._enabled) {
			return;
		}

		this._isCurrentlyTwoClickDrawing = false;
		L.Draw.SimpleShape.prototype.disable.call(this);
	},

	_onMouseUp: function (e) {
		if (!this._shape && !this._isCurrentlyTwoClickDrawing) {
			this._isCurrentlyTwoClickDrawing = true;
			return;
		}

		// Make sure closing click is on map
		if (this._isCurrentlyTwoClickDrawing && !_hasAncestor(e.target, 'leaflet-pane')) {
			return;
		}

		L.Draw.SimpleShape.prototype._onMouseUp.call(this);
	},

	_drawShape: function (latlng) {
		if (!this._shape) {
			this._shape = new L.Rectangle(new L.LatLngBounds(this._startLatLng, latlng), this.options.shapeOptions);
			this._map.addLayer(this._shape);
		} else {
			this._shape.setBounds(new L.LatLngBounds(this._startLatLng, latlng));
		}
	},

	_fireCreatedEvent: function () {
		var rectangle = new L.Rectangle(this._shape.getBounds(), this.options.shapeOptions);
		L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, rectangle);
	},

	_getTooltipText: function () {
		var tooltipText = L.Draw.SimpleShape.prototype._getTooltipText.call(this),
			shape = this._shape,
			showArea = this.options.showArea,
			latLngs, area, subtext;

		if (shape) {
			latLngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs();
			area = L.GeometryUtil.geodesicArea(latLngs);
			subtext = showArea ? L.GeometryUtil.readableArea(area, this.options.metric) : '';
		}

		return {
			text: tooltipText.text,
			subtext: subtext
		};
	}
});

function _hasAncestor(el, cls) {
	while ((el = el.parentElement) && !el.classList.contains(cls)) {
		;
	}
	return el;
}



/**
 * @class L.Draw.Marker
 * @aka Draw.Marker
 * @inherits L.Draw.Feature
 */
L.Draw.Marker = L.Draw.Feature.extend({
	statics: {
		TYPE: 'marker'
	},

	options: {
		icon: new L.Icon.Default(),
		repeatMode: false,
		zIndexOffset: 2000 // This should be > than the highest z-index any markers
	},

	// @method initialize(): void
	initialize: function (map, options) {
		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.Marker.TYPE;

		this._initialLabelText = L.drawLocal.draw.handlers.marker.tooltip.start;

		L.Draw.Feature.prototype.initialize.call(this, map, options);
	},

	// @method addHooks(): void
	// Add listener hooks to this handler.
	addHooks: function () {
		L.Draw.Feature.prototype.addHooks.call(this);

		if (this._map) {
			this._tooltip.updateContent({text: this._initialLabelText});

			// Same mouseMarker as in Draw.Polyline
			if (!this._mouseMarker) {
				this._mouseMarker = L.marker(this._map.getCenter(), {
					icon: L.divIcon({
						className: 'leaflet-mouse-marker',
						iconAnchor: [20, 20],
						iconSize: [40, 40]
					}),
					opacity: 0,
					zIndexOffset: this.options.zIndexOffset
				});
			}

			this._mouseMarker
				.on('click', this._onClick, this)
				.addTo(this._map);

			this._map.on('mousemove', this._onMouseMove, this);
			this._map.on('click', this._onTouch, this);
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler.
	removeHooks: function () {
		L.Draw.Feature.prototype.removeHooks.call(this);

		if (this._map) {
			this._map
				.off('click', this._onClick, this)
				.off('click', this._onTouch, this);
			if (this._marker) {
				this._marker.off('click', this._onClick, this);
				this._map
					.removeLayer(this._marker);
				delete this._marker;
			}

			this._mouseMarker.off('click', this._onClick, this);
			this._map.removeLayer(this._mouseMarker);
			delete this._mouseMarker;

			this._map.off('mousemove', this._onMouseMove, this);
		}
	},

	_onMouseMove: function (e) {
		var latlng = e.latlng;

		this._tooltip.updatePosition(latlng);
		this._mouseMarker.setLatLng(latlng);

		if (!this._marker) {
			this._marker = this._createMarker(latlng);
			// Bind to both marker and map to make sure we get the click event.
			this._marker.on('click', this._onClick, this);
			this._map
				.on('click', this._onClick, this)
				.addLayer(this._marker);
		}
		else {
			latlng = this._mouseMarker.getLatLng();
			this._marker.setLatLng(latlng);
		}
	},

	_createMarker: function (latlng) {
		return new L.Marker(latlng, {
			icon: this.options.icon,
			zIndexOffset: this.options.zIndexOffset
		});
	},

	_onClick: function () {
		this._fireCreatedEvent();

		this.disable();
		if (this.options.repeatMode) {
			this.enable();
		}
	},

	_onTouch: function (e) {
		// called on click & tap, only really does any thing on tap
		this._onMouseMove(e); // creates & places marker
		this._onClick(); // permanently places marker & ends interaction
	},

	_fireCreatedEvent: function () {
		var marker = new L.Marker.Touch(this._marker.getLatLng(), {icon: this.options.icon});
		L.Draw.Feature.prototype._fireCreatedEvent.call(this, marker);
	}
});



/**
 * @class L.Draw.CircleMarker
 * @aka Draw.CircleMarker
 * @inherits L.Draw.Marker
 */
L.Draw.CircleMarker = L.Draw.Marker.extend({
	statics: {
		TYPE: 'circlemarker'
	},

	options: {
		stroke: true,
		color: '#3388ff',
		weight: 4,
		opacity: 0.5,
		fill: true,
		fillColor: null, //same as color by default
		fillOpacity: 0.2,
		clickable: true,
		zIndexOffset: 2000 // This should be > than the highest z-index any markers
	},

	// @method initialize(): void
	initialize: function (map, options) {
		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.CircleMarker.TYPE;

		this._initialLabelText = L.drawLocal.draw.handlers.circlemarker.tooltip.start;

		L.Draw.Feature.prototype.initialize.call(this, map, options);
	},


	_fireCreatedEvent: function () {
		var circleMarker = new L.CircleMarker(this._marker.getLatLng(), this.options);
		L.Draw.Feature.prototype._fireCreatedEvent.call(this, circleMarker);
	},

	_createMarker: function (latlng) {
		return new L.CircleMarker(latlng, this.options);
	}
});



/**
 * @class L.Draw.Circle
 * @aka Draw.Circle
 * @inherits L.Draw.SimpleShape
 */
L.Draw.Circle = L.Draw.SimpleShape.extend({
	statics: {
		TYPE: 'circle'
	},

	options: {
		shapeOptions: {
			stroke: true,
			color: '#3388ff',
			weight: 4,
			opacity: 0.5,
			fill: true,
			fillColor: null, //same as color by default
			fillOpacity: 0.2,
			clickable: true
		},
		showRadius: true,
		metric: true, // Whether to use the metric measurement system or imperial
		feet: true, // When not metric, use feet instead of yards for display
		nautic: false // When not metric, not feet use nautic mile for display
	},

	// @method initialize(): void
	initialize: function (map, options) {
		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.Draw.Circle.TYPE;

		this._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;

		L.Draw.SimpleShape.prototype.initialize.call(this, map, options);
	},

	_drawShape: function (latlng) {
		// Calculate the distance based on the version
		if (L.GeometryUtil.isVersion07x()) {
			var distance = this._startLatLng.distanceTo(latlng);
		} else {
			var distance = this._map.distance(this._startLatLng, latlng);
		}

		if (!this._shape) {
			this._shape = new L.Circle(this._startLatLng, distance, this.options.shapeOptions);
			this._map.addLayer(this._shape);
		} else {
			this._shape.setRadius(distance);
		}
	},

	_fireCreatedEvent: function () {
		var circle = new L.Circle(this._startLatLng, this._shape.getRadius(), this.options.shapeOptions);
		L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this, circle);
	},

	_onMouseMove: function (e) {
		var latlng = e.latlng,
			showRadius = this.options.showRadius,
			useMetric = this.options.metric,
			radius;

		this._tooltip.updatePosition(latlng);
		if (this._isDrawing) {
			this._drawShape(latlng);

			// Get the new radius (rounded to 1 dp)
			radius = this._shape.getRadius().toFixed(1);

			var subtext = '';
			if (showRadius) {
				subtext = L.drawLocal.draw.handlers.circle.radius + ': ' +
					L.GeometryUtil.readableDistance(radius, useMetric, this.options.feet, this.options.nautic);
			}
			this._tooltip.updateContent({
				text: this._endLabelText,
				subtext: subtext
			});
		}
	}
});



L.Edit = L.Edit || {};

/**
 * @class L.Edit.Marker
 * @aka Edit.Marker
 */
L.Edit.Marker = L.Handler.extend({
	// @method initialize(): void
	initialize: function (marker, options) {
		this._marker = marker;
		L.setOptions(this, options);
	},

	// @method addHooks(): void
	// Add listener hooks to this handler
	addHooks: function () {
		var marker = this._marker;

		marker.dragging.enable();
		marker.on('dragend', this._onDragEnd, marker);
		this._toggleMarkerHighlight();
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler
	removeHooks: function () {
		var marker = this._marker;

		marker.dragging.disable();
		marker.off('dragend', this._onDragEnd, marker);
		this._toggleMarkerHighlight();
	},

	_onDragEnd: function (e) {
		var layer = e.target;
		layer.edited = true;
		this._map.fire(L.Draw.Event.EDITMOVE, {layer: layer});
	},

	_toggleMarkerHighlight: function () {
		var icon = this._marker._icon;

		// Don't do anything if this layer is a marker but doesn't have an icon. Markers
		// should usually have icons. If using Leaflet.draw with Leaflet.markercluster there
		// is a chance that a marker doesn't.
		if (!icon) {
			return;
		}

		// This is quite naughty, but I don't see another way of doing it. (short of setting a new icon)
		icon.style.display = 'none';

		if (L.DomUtil.hasClass(icon, 'leaflet-edit-marker-selected')) {
			L.DomUtil.removeClass(icon, 'leaflet-edit-marker-selected');
			// Offset as the border will make the icon move.
			this._offsetMarker(icon, -4);

		} else {
			L.DomUtil.addClass(icon, 'leaflet-edit-marker-selected');
			// Offset as the border will make the icon move.
			this._offsetMarker(icon, 4);
		}

		icon.style.display = '';
	},

	_offsetMarker: function (icon, offset) {
		var iconMarginTop = parseInt(icon.style.marginTop, 10) - offset,
			iconMarginLeft = parseInt(icon.style.marginLeft, 10) - offset;

		icon.style.marginTop = iconMarginTop + 'px';
		icon.style.marginLeft = iconMarginLeft + 'px';
	}
});

L.Marker.addInitHook(function () {
	if (L.Edit.Marker) {
		this.editing = new L.Edit.Marker(this);

		if (this.options.editable) {
			this.editing.enable();
		}
	}
});



L.Edit = L.Edit || {};

/**
 * @class L.Edit.Polyline
 * @aka L.Edit.Poly
 * @aka Edit.Poly
 */
L.Edit.Poly = L.Handler.extend({
	// @method initialize(): void
	initialize: function (poly) {

		this.latlngs = [poly._latlngs];
		if (poly._holes) {
			this.latlngs = this.latlngs.concat(poly._holes);
		}

		this._poly = poly;

		this._poly.on('revert-edited', this._updateLatLngs, this);
	},

	// Compatibility method to normalize Poly* objects
	// between 0.7.x and 1.0+
	_defaultShape: function () {
		if (!L.Polyline._flat) {
			return this._poly._latlngs;
		}
		return L.Polyline._flat(this._poly._latlngs) ? this._poly._latlngs : this._poly._latlngs[0];
	},

	_eachVertexHandler: function (callback) {
		for (var i = 0; i < this._verticesHandlers.length; i++) {
			callback(this._verticesHandlers[i]);
		}
	},

	// @method addHooks(): void
	// Add listener hooks to this handler
	addHooks: function () {
		this._initHandlers();
		this._eachVertexHandler(function (handler) {
			handler.addHooks();
		});
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler
	removeHooks: function () {
		this._eachVertexHandler(function (handler) {
			handler.removeHooks();
		});
	},

	// @method updateMarkers(): void
	// Fire an update for each vertex handler
	updateMarkers: function () {
		this._eachVertexHandler(function (handler) {
			handler.updateMarkers();
		});
	},

	_initHandlers: function () {
		this._verticesHandlers = [];
		for (var i = 0; i < this.latlngs.length; i++) {
			this._verticesHandlers.push(new L.Edit.PolyVerticesEdit(this._poly, this.latlngs[i], this._poly.options.poly));
		}
	},

	_updateLatLngs: function (e) {
		this.latlngs = [e.layer._latlngs];
		if (e.layer._holes) {
			this.latlngs = this.latlngs.concat(e.layer._holes);
		}
	}

});

/**
 * @class L.Edit.PolyVerticesEdit
 * @aka Edit.PolyVerticesEdit
 */
L.Edit.PolyVerticesEdit = L.Handler.extend({
	options: {
		icon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon'
		}),
		touchIcon: new L.DivIcon({
			iconSize: new L.Point(20, 20),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
		}),
		drawError: {
			color: '#b00b00',
			timeout: 1000
		}


	},

	// @method intialize(): void
	initialize: function (poly, latlngs, options) {
		// if touch, switch to touch icon
		if (L.Browser.touch) {
			this.options.icon = this.options.touchIcon;
		}
		this._poly = poly;

		if (options && options.drawError) {
			options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
		}

		this._latlngs = latlngs;

		L.setOptions(this, options);
	},

	// Compatibility method to normalize Poly* objects
	// between 0.7.x and 1.0+
	_defaultShape: function () {
		if (!L.Polyline._flat) {
			return this._latlngs;
		}
		return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
	},

	// @method addHooks(): void
	// Add listener hooks to this handler.
	addHooks: function () {
		var poly = this._poly;
		var path = poly._path;

		if (!(poly instanceof L.Polygon)) {
			poly.options.fill = false;
			if (poly.options.editing) {
				poly.options.editing.fill = false;
			}
		}

		if (path) {
			if (poly.options.editing && poly.options.editing.className) {
				if (poly.options.original.className) {
					poly.options.original.className.split(' ').forEach(function (className) {
						L.DomUtil.removeClass(path, className);
					});
				}
				poly.options.editing.className.split(' ').forEach(function (className) {
					L.DomUtil.addClass(path, className);
				});
			}
		}

		poly.setStyle(poly.options.editing);

		if (this._poly._map) {

			this._map = this._poly._map; // Set map

			if (!this._markerGroup) {
				this._initMarkers();
			}
			this._poly._map.addLayer(this._markerGroup);
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler.
	removeHooks: function () {
		var poly = this._poly;
		var path = poly._path;

		if (path) {
			if (poly.options.editing && poly.options.editing.className) {
				poly.options.editing.className.split(' ').forEach(function (className) {
					L.DomUtil.removeClass(path, className);
				});
				if (poly.options.original.className) {
					poly.options.original.className.split(' ').forEach(function (className) {
						L.DomUtil.addClass(path, className);
					});
				}
			}
		}

		poly.setStyle(poly.options.original);

		if (poly._map) {
			poly._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
			delete this._markers;
		}
	},

	// @method updateMarkers(): void
	// Clear markers and update their location
	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		if (!this._markerGroup) {
			this._markerGroup = new L.LayerGroup();
		}
		this._markers = [];

		var latlngs = this._defaultShape(),
			i, j, len, marker;

		for (i = 0, len = latlngs.length; i < len; i++) {

			marker = this._createMarker(latlngs[i], i);
			marker.on('click', this._onMarkerClick, this);
			marker.on('contextmenu', this._onContextMenu, this);
			this._markers.push(marker);
		}

		var markerLeft, markerRight;

		for (i = 0, j = len - 1; i < len; j = i++) {
			if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
				continue;
			}

			markerLeft = this._markers[j];
			markerRight = this._markers[i];

			this._createMiddleMarker(markerLeft, markerRight);
			this._updatePrevNext(markerLeft, markerRight);
		}
	},

	_createMarker: function (latlng, index) {
		// Extending L.Marker in TouchEvents.js to include touch.
		var marker = new L.Marker.Touch(latlng, {
			draggable: true,
			icon: this.options.icon,
		});

		marker._origLatLng = latlng;
		marker._index = index;

		marker
			.on('dragstart', this._onMarkerDragStart, this)
			.on('drag', this._onMarkerDrag, this)
			.on('dragend', this._fireEdit, this)
			.on('touchmove', this._onTouchMove, this)
			.on('touchend', this._fireEdit, this)
			.on('MSPointerMove', this._onTouchMove, this)
			.on('MSPointerUp', this._fireEdit, this);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_onMarkerDragStart: function () {
		this._poly.fire('editstart');
	},

	_spliceLatLngs: function () {
		var latlngs = this._defaultShape();
		var removed = [].splice.apply(latlngs, arguments);
		this._poly._convertLatLngs(latlngs, true);
		this._poly.redraw();
		return removed;
	},

	_removeMarker: function (marker) {
		var i = marker._index;

		this._markerGroup.removeLayer(marker);
		this._markers.splice(i, 1);
		this._spliceLatLngs(i, 1);
		this._updateIndexes(i, -1);

		marker
			.off('dragstart', this._onMarkerDragStart, this)
			.off('drag', this._onMarkerDrag, this)
			.off('dragend', this._fireEdit, this)
			.off('touchmove', this._onMarkerDrag, this)
			.off('touchend', this._fireEdit, this)
			.off('click', this._onMarkerClick, this)
			.off('MSPointerMove', this._onTouchMove, this)
			.off('MSPointerUp', this._fireEdit, this);
	},

	_fireEdit: function () {
		this._poly.edited = true;
		this._poly.fire('edit');
		this._poly._map.fire(L.Draw.Event.EDITVERTEX, {layers: this._markerGroup, poly: this._poly});
	},

	_onMarkerDrag: function (e) {
		var marker = e.target;
		var poly = this._poly;

		var oldOrigLatLng = L.LatLngUtil.cloneLatLng(marker._origLatLng);
		L.extend(marker._origLatLng, marker._latlng);
		if (poly.options.poly) {
			var tooltip = poly._map._editTooltip; // Access the tooltip

			// If we don't allow intersections and the polygon intersects
			if (!poly.options.poly.allowIntersection && poly.intersects()) {
				L.extend(marker._origLatLng, oldOrigLatLng);
				marker.setLatLng(oldOrigLatLng);
				var originalColor = poly.options.color;
				poly.setStyle({color: this.options.drawError.color});
				if (tooltip) {
					tooltip.updateContent({
						text: L.drawLocal.draw.handlers.polyline.error
					});
				}

				// Reset everything back to normal after a second
				setTimeout(function () {
					poly.setStyle({color: originalColor});
					if (tooltip) {
						tooltip.updateContent({
							text: L.drawLocal.edit.handlers.edit.tooltip.text,
							subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
						});
					}
				}, 1000);
			}
		}

		if (marker._middleLeft) {
			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
		}
		if (marker._middleRight) {
			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
		}

		//refresh the bounds when draging
		this._poly._bounds._southWest = L.latLng(Infinity, Infinity);
		this._poly._bounds._northEast = L.latLng(-Infinity, -Infinity);
		var latlngs = this._poly.getLatLngs();
		this._poly._convertLatLngs(latlngs, true);
		this._poly.redraw();
		this._poly.fire('editdrag');
	},

	_onMarkerClick: function (e) {

		var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3,
			marker = e.target;

		// If removing this point would create an invalid polyline/polygon don't remove
		if (this._defaultShape().length < minPoints) {
			return;
		}

		// remove the marker
		this._removeMarker(marker);

		// update prev/next links of adjacent markers
		this._updatePrevNext(marker._prev, marker._next);

		// remove ghost markers near the removed marker
		if (marker._middleLeft) {
			this._markerGroup.removeLayer(marker._middleLeft);
		}
		if (marker._middleRight) {
			this._markerGroup.removeLayer(marker._middleRight);
		}

		// create a ghost marker in place of the removed one
		if (marker._prev && marker._next) {
			this._createMiddleMarker(marker._prev, marker._next);

		} else if (!marker._prev) {
			marker._next._middleLeft = null;

		} else if (!marker._next) {
			marker._prev._middleRight = null;
		}

		this._fireEdit();
	},

	_onContextMenu: function (e) {
		var marker = e.target;
		var poly = this._poly;
		this._poly._map.fire(L.Draw.Event.MARKERCONTEXT, {marker: marker, layers: this._markerGroup, poly: this._poly});
		L.DomEvent.stopPropagation;
	},

	_onTouchMove: function (e) {

		var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
			latlng = this._map.layerPointToLatLng(layerPoint),
			marker = e.target;

		L.extend(marker._origLatLng, latlng);

		if (marker._middleLeft) {
			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
		}
		if (marker._middleRight) {
			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
		}

		this._poly.redraw();
		this.updateMarkers();
	},

	_updateIndexes: function (index, delta) {
		this._markerGroup.eachLayer(function (marker) {
			if (marker._index > index) {
				marker._index += delta;
			}
		});
	},

	_createMiddleMarker: function (marker1, marker2) {
		var latlng = this._getMiddleLatLng(marker1, marker2),
			marker = this._createMarker(latlng),
			onClick,
			onDragStart,
			onDragEnd;

		marker.setOpacity(0.6);

		marker1._middleRight = marker2._middleLeft = marker;

		onDragStart = function () {
			marker.off('touchmove', onDragStart, this);
			var i = marker2._index;

			marker._index = i;

			marker
				.off('click', onClick, this)
				.on('click', this._onMarkerClick, this);

			latlng.lat = marker.getLatLng().lat;
			latlng.lng = marker.getLatLng().lng;
			this._spliceLatLngs(i, 0, latlng);
			this._markers.splice(i, 0, marker);

			marker.setOpacity(1);

			this._updateIndexes(i, 1);
			marker2._index++;
			this._updatePrevNext(marker1, marker);
			this._updatePrevNext(marker, marker2);

			this._poly.fire('editstart');
		};

		onDragEnd = function () {
			marker.off('dragstart', onDragStart, this);
			marker.off('dragend', onDragEnd, this);
			marker.off('touchmove', onDragStart, this);

			this._createMiddleMarker(marker1, marker);
			this._createMiddleMarker(marker, marker2);
		};

		onClick = function () {
			onDragStart.call(this);
			onDragEnd.call(this);
			this._fireEdit();
		};

		marker
			.on('click', onClick, this)
			.on('dragstart', onDragStart, this)
			.on('dragend', onDragEnd, this)
			.on('touchmove', onDragStart, this);

		this._markerGroup.addLayer(marker);
	},

	_updatePrevNext: function (marker1, marker2) {
		if (marker1) {
			marker1._next = marker2;
		}
		if (marker2) {
			marker2._prev = marker1;
		}
	},

	_getMiddleLatLng: function (marker1, marker2) {
		var map = this._poly._map,
			p1 = map.project(marker1.getLatLng()),
			p2 = map.project(marker2.getLatLng());

		return map.unproject(p1._add(p2)._divideBy(2));
	}
});

L.Polyline.addInitHook(function () {

	// Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit
	if (this.editing) {
		return;
	}

	if (L.Edit.Poly) {

		this.editing = new L.Edit.Poly(this);

		if (this.options.editable) {
			this.editing.enable();
		}
	}

	this.on('add', function () {
		if (this.editing && this.editing.enabled()) {
			this.editing.addHooks();
		}
	});

	this.on('remove', function () {
		if (this.editing && this.editing.enabled()) {
			this.editing.removeHooks();
		}
	});
});



L.Edit = L.Edit || {};
/**
 * @class L.Edit.SimpleShape
 * @aka Edit.SimpleShape
 */
L.Edit.SimpleShape = L.Handler.extend({
	options: {
		moveIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
		}),
		resizeIcon: new L.DivIcon({
			iconSize: new L.Point(8, 8),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'
		}),
		touchMoveIcon: new L.DivIcon({
			iconSize: new L.Point(20, 20),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move leaflet-touch-icon'
		}),
		touchResizeIcon: new L.DivIcon({
			iconSize: new L.Point(20, 20),
			className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize leaflet-touch-icon'
		}),
	},

	// @method intialize(): void
	initialize: function (shape, options) {
		// if touch, switch to touch icon
		if (L.Browser.touch) {
			this.options.moveIcon = this.options.touchMoveIcon;
			this.options.resizeIcon = this.options.touchResizeIcon;
		}

		this._shape = shape;
		L.Util.setOptions(this, options);
	},

	// @method addHooks(): void
	// Add listener hooks to this handler
	addHooks: function () {
		var shape = this._shape;
		if (this._shape._map) {
			this._map = this._shape._map;
			shape.setStyle(shape.options.editing);

			if (shape._map) {
				this._map = shape._map;
				if (!this._markerGroup) {
					this._initMarkers();
				}
				this._map.addLayer(this._markerGroup);
			}
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler
	removeHooks: function () {
		var shape = this._shape;

		shape.setStyle(shape.options.original);

		if (shape._map) {
			this._unbindMarker(this._moveMarker);

			for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
				this._unbindMarker(this._resizeMarkers[i]);
			}
			this._resizeMarkers = null;

			this._map.removeLayer(this._markerGroup);
			delete this._markerGroup;
		}

		this._map = null;
	},

	// @method updateMarkers(): void
	// Remove the edit markers from this layer
	updateMarkers: function () {
		this._markerGroup.clearLayers();
		this._initMarkers();
	},

	_initMarkers: function () {
		if (!this._markerGroup) {
			this._markerGroup = new L.LayerGroup();
		}

		// Create center marker
		this._createMoveMarker();

		// Create edge marker
		this._createResizeMarker();
	},

	_createMoveMarker: function () {
		// Children override
	},

	_createResizeMarker: function () {
		// Children override
	},

	_createMarker: function (latlng, icon) {
		// Extending L.Marker in TouchEvents.js to include touch.
		var marker = new L.Marker.Touch(latlng, {
			draggable: true,
			icon: icon,
			zIndexOffset: 10
		});

		this._bindMarker(marker);

		this._markerGroup.addLayer(marker);

		return marker;
	},

	_bindMarker: function (marker) {
		marker
			.on('dragstart', this._onMarkerDragStart, this)
			.on('drag', this._onMarkerDrag, this)
			.on('dragend', this._onMarkerDragEnd, this)
			.on('touchstart', this._onTouchStart, this)
			.on('touchmove', this._onTouchMove, this)
			.on('MSPointerMove', this._onTouchMove, this)
			.on('touchend', this._onTouchEnd, this)
			.on('MSPointerUp', this._onTouchEnd, this);
	},

	_unbindMarker: function (marker) {
		marker
			.off('dragstart', this._onMarkerDragStart, this)
			.off('drag', this._onMarkerDrag, this)
			.off('dragend', this._onMarkerDragEnd, this)
			.off('touchstart', this._onTouchStart, this)
			.off('touchmove', this._onTouchMove, this)
			.off('MSPointerMove', this._onTouchMove, this)
			.off('touchend', this._onTouchEnd, this)
			.off('MSPointerUp', this._onTouchEnd, this);
	},

	_onMarkerDragStart: function (e) {
		var marker = e.target;
		marker.setOpacity(0);

		this._shape.fire('editstart');
	},

	_fireEdit: function () {
		this._shape.edited = true;
		this._shape.fire('edit');
	},

	_onMarkerDrag: function (e) {
		var marker = e.target,
			latlng = marker.getLatLng();

		if (marker === this._moveMarker) {
			this._move(latlng);
		} else {
			this._resize(latlng);
		}

		this._shape.redraw();
		this._shape.fire('editdrag');
	},

	_onMarkerDragEnd: function (e) {
		var marker = e.target;
		marker.setOpacity(1);

		this._fireEdit();
	},

	_onTouchStart: function (e) {
		L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);

		if (typeof(this._getCorners) === 'function') {
			// Save a reference to the opposite point
			var corners = this._getCorners(),
				marker = e.target,
				currentCornerIndex = marker._cornerIndex;

			marker.setOpacity(0);

			// Copyed from Edit.Rectangle.js line 23 _onMarkerDragStart()
			// Latlng is null otherwise.
			this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];
			this._toggleCornerMarkers(0, currentCornerIndex);
		}

		this._shape.fire('editstart');
	},

	_onTouchMove: function (e) {
		var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
			latlng = this._map.layerPointToLatLng(layerPoint),
			marker = e.target;

		if (marker === this._moveMarker) {
			this._move(latlng);
		} else {
			this._resize(latlng);
		}

		this._shape.redraw();

		// prevent touchcancel in IOS
		// e.preventDefault();
		return false;
	},

	_onTouchEnd: function (e) {
		var marker = e.target;
		marker.setOpacity(1);
		this.updateMarkers();
		this._fireEdit();
	},

	_move: function () {
		// Children override
	},

	_resize: function () {
		// Children override
	}
});



L.Edit = L.Edit || {};
/**
 * @class L.Edit.Rectangle
 * @aka Edit.Rectangle
 * @inherits L.Edit.SimpleShape
 */
L.Edit.Rectangle = L.Edit.SimpleShape.extend({
	_createMoveMarker: function () {
		var bounds = this._shape.getBounds(),
			center = bounds.getCenter();

		this._moveMarker = this._createMarker(center, this.options.moveIcon);
	},

	_createResizeMarker: function () {
		var corners = this._getCorners();

		this._resizeMarkers = [];

		for (var i = 0, l = corners.length; i < l; i++) {
			this._resizeMarkers.push(this._createMarker(corners[i], this.options.resizeIcon));
			// Monkey in the corner index as we will need to know this for dragging
			this._resizeMarkers[i]._cornerIndex = i;
		}
	},

	_onMarkerDragStart: function (e) {
		L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this, e);

		// Save a reference to the opposite point
		var corners = this._getCorners(),
			marker = e.target,
			currentCornerIndex = marker._cornerIndex;

		this._oppositeCorner = corners[(currentCornerIndex + 2) % 4];

		this._toggleCornerMarkers(0, currentCornerIndex);
	},

	_onMarkerDragEnd: function (e) {
		var marker = e.target,
			bounds, center;

		// Reset move marker position to the center
		if (marker === this._moveMarker) {
			bounds = this._shape.getBounds();
			center = bounds.getCenter();

			marker.setLatLng(center);
		}

		this._toggleCornerMarkers(1);

		this._repositionCornerMarkers();

		L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);
	},

	_move: function (newCenter) {
		var latlngs = this._shape._defaultShape ? this._shape._defaultShape() : this._shape.getLatLngs(),
			bounds = this._shape.getBounds(),
			center = bounds.getCenter(),
			offset, newLatLngs = [];

		// Offset the latlngs to the new center
		for (var i = 0, l = latlngs.length; i < l; i++) {
			offset = [latlngs[i].lat - center.lat, latlngs[i].lng - center.lng];
			newLatLngs.push([newCenter.lat + offset[0], newCenter.lng + offset[1]]);
		}

		this._shape.setLatLngs(newLatLngs);

		// Reposition the resize markers
		this._repositionCornerMarkers();

		this._map.fire(L.Draw.Event.EDITMOVE, {layer: this._shape});
	},

	_resize: function (latlng) {
		var bounds;

		// Update the shape based on the current position of this corner and the opposite point
		this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner));

		// Reposition the move marker
		bounds = this._shape.getBounds();
		this._moveMarker.setLatLng(bounds.getCenter());

		this._map.fire(L.Draw.Event.EDITRESIZE, {layer: this._shape});
	},

	_getCorners: function () {
		var bounds = this._shape.getBounds(),
			nw = bounds.getNorthWest(),
			ne = bounds.getNorthEast(),
			se = bounds.getSouthEast(),
			sw = bounds.getSouthWest();

		return [nw, ne, se, sw];
	},

	_toggleCornerMarkers: function (opacity) {
		for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
			this._resizeMarkers[i].setOpacity(opacity);
		}
	},

	_repositionCornerMarkers: function () {
		var corners = this._getCorners();

		for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
			this._resizeMarkers[i].setLatLng(corners[i]);
		}
	}
});

L.Rectangle.addInitHook(function () {
	if (L.Edit.Rectangle) {
		this.editing = new L.Edit.Rectangle(this);

		if (this.options.editable) {
			this.editing.enable();
		}
	}
});



L.Edit = L.Edit || {};
/**
 * @class L.Edit.CircleMarker
 * @aka Edit.Circle
 * @inherits L.Edit.SimpleShape
 */
L.Edit.CircleMarker = L.Edit.SimpleShape.extend({
	_createMoveMarker: function () {
		var center = this._shape.getLatLng();

		this._moveMarker = this._createMarker(center, this.options.moveIcon);
	},

	_createResizeMarker: function () {
		// To avoid an undefined check in L.Edit.SimpleShape.removeHooks
		this._resizeMarkers = [];
	},

	_move: function (latlng) {
		if (this._resizeMarkers.length) {
			var resizemarkerPoint = this._getResizeMarkerPoint(latlng);
			// Move the resize marker
			this._resizeMarkers[0].setLatLng(resizemarkerPoint);
		}

		// Move the circle
		this._shape.setLatLng(latlng);

		this._map.fire(L.Draw.Event.EDITMOVE, {layer: this._shape});
	},
});

L.CircleMarker.addInitHook(function () {
	if (L.Edit.CircleMarker) {
		this.editing = new L.Edit.CircleMarker(this);

		if (this.options.editable) {
			this.editing.enable();
		}
	}

	this.on('add', function () {
		if (this.editing && this.editing.enabled()) {
			this.editing.addHooks();
		}
	});

	this.on('remove', function () {
		if (this.editing && this.editing.enabled()) {
			this.editing.removeHooks();
		}
	});
});



L.Edit = L.Edit || {};
/**
 * @class L.Edit.Circle
 * @aka Edit.Circle
 * @inherits L.Edit.CircleMarker
 */
L.Edit.Circle = L.Edit.CircleMarker.extend({

	_createResizeMarker: function () {
		var center = this._shape.getLatLng(),
			resizemarkerPoint = this._getResizeMarkerPoint(center);

		this._resizeMarkers = [];
		this._resizeMarkers.push(this._createMarker(resizemarkerPoint, this.options.resizeIcon));
	},

	_getResizeMarkerPoint: function (latlng) {
		// From L.shape.getBounds()
		var delta = this._shape._radius * Math.cos(Math.PI / 4),
			point = this._map.project(latlng);
		return this._map.unproject([point.x + delta, point.y - delta]);
	},

	_resize: function (latlng) {
		var moveLatLng = this._moveMarker.getLatLng();

		// Calculate the radius based on the version
		if (L.GeometryUtil.isVersion07x()) {
			radius = moveLatLng.distanceTo(latlng);
		} else {
			radius = this._map.distance(moveLatLng, latlng);
		}
		this._shape.setRadius(radius);

		if (this._map.editTooltip) {
			this._map._editTooltip.updateContent({
				text: L.drawLocal.edit.handlers.edit.tooltip.subtext + '<br />' + L.drawLocal.edit.handlers.edit.tooltip.text,
				subtext: L.drawLocal.draw.handlers.circle.radius + ': ' +
				L.GeometryUtil.readableDistance(radius, true, this.options.feet, this.options.nautic)
			});
		}

		this._shape.setRadius(radius);

		this._map.fire(L.Draw.Event.EDITRESIZE, {layer: this._shape});
	}
});

L.Circle.addInitHook(function () {
	if (L.Edit.Circle) {
		this.editing = new L.Edit.Circle(this);

		if (this.options.editable) {
			this.editing.enable();
		}
	}
});



L.Map.mergeOptions({
	touchExtend: true
});

/**
 * @class L.Map.TouchExtend
 * @aka TouchExtend
 */
L.Map.TouchExtend = L.Handler.extend({

	// @method initialize(): void
	// Sets TouchExtend private accessor variables
	initialize: function (map) {
		this._map = map;
		this._container = map._container;
		this._pane = map._panes.overlayPane;
	},

	// @method addHooks(): void
	// Adds dom listener events to the map container
	addHooks: function () {
		L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this);
		L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this);
		L.DomEvent.on(this._container, 'touchmove', this._onTouchMove, this);
		if (this._detectIE()) {
			L.DomEvent.on(this._container, 'MSPointerDown', this._onTouchStart, this);
			L.DomEvent.on(this._container, 'MSPointerUp', this._onTouchEnd, this);
			L.DomEvent.on(this._container, 'MSPointerMove', this._onTouchMove, this);
			L.DomEvent.on(this._container, 'MSPointerCancel', this._onTouchCancel, this);

		} else {
			L.DomEvent.on(this._container, 'touchcancel', this._onTouchCancel, this);
			L.DomEvent.on(this._container, 'touchleave', this._onTouchLeave, this);
		}
	},

	// @method removeHooks(): void
	// Removes dom listener events from the map container
	removeHooks: function () {
		L.DomEvent.off(this._container, 'touchstart', this._onTouchStart, this);
		L.DomEvent.off(this._container, 'touchend', this._onTouchEnd, this);
		L.DomEvent.off(this._container, 'touchmove', this._onTouchMove, this);
		if (this._detectIE()) {
			L.DomEvent.off(this._container, 'MSPointerDown', this._onTouchStart, this);
			L.DomEvent.off(this._container, 'MSPointerUp', this._onTouchEnd, this);
			L.DomEvent.off(this._container, 'MSPointerMove', this._onTouchMove, this);
			L.DomEvent.off(this._container, 'MSPointerCancel', this._onTouchCancel, this);
		} else {
			L.DomEvent.off(this._container, 'touchcancel', this._onTouchCancel, this);
			L.DomEvent.off(this._container, 'touchleave', this._onTouchLeave, this);
		}
	},

	_touchEvent: function (e, type) {
		// #TODO: fix the pageX error that is do a bug in Android where a single touch triggers two click events
		// _filterClick is what leaflet uses as a workaround.
		// This is a problem with more things than just android. Another problem is touchEnd has no touches in
		// its touch list.
		var touchEvent = {};
		if (typeof e.touches !== 'undefined') {
			if (!e.touches.length) {
				return;
			}
			touchEvent = e.touches[0];
		} else if (e.pointerType === 'touch') {
			touchEvent = e;
			if (!this._filterClick(e)) {
				return;
			}
		} else {
			return;
		}

		var containerPoint = this._map.mouseEventToContainerPoint(touchEvent),
			layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
			latlng = this._map.layerPointToLatLng(layerPoint);

		this._map.fire(type, {
			latlng: latlng,
			layerPoint: layerPoint,
			containerPoint: containerPoint,
			pageX: touchEvent.pageX,
			pageY: touchEvent.pageY,
			originalEvent: e
		});
	},

	/** Borrowed from Leaflet and modified for bool ops **/
	_filterClick: function (e) {
		var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
			elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);

		// are they closer together than 500ms yet more than 100ms?
		// Android typically triggers them ~300ms apart while multiple listeners
		// on the same event should be triggered far faster;
		// or check if click is simulated on the element, and if it is, reject any non-simulated events
		if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
			L.DomEvent.stop(e);
			return false;
		}
		L.DomEvent._lastClick = timeStamp;
		return true;
	},

	_onTouchStart: function (e) {
		if (!this._map._loaded) {
			return;
		}

		var type = 'touchstart';
		this._touchEvent(e, type);

	},

	_onTouchEnd: function (e) {
		if (!this._map._loaded) {
			return;
		}

		var type = 'touchend';
		this._touchEvent(e, type);
	},

	_onTouchCancel: function (e) {
		if (!this._map._loaded) {
			return;
		}

		var type = 'touchcancel';
		if (this._detectIE()) {
			type = 'pointercancel';
		}
		this._touchEvent(e, type);
	},

	_onTouchLeave: function (e) {
		if (!this._map._loaded) {
			return;
		}

		var type = 'touchleave';
		this._touchEvent(e, type);
	},

	_onTouchMove: function (e) {
		if (!this._map._loaded) {
			return;
		}

		var type = 'touchmove';
		this._touchEvent(e, type);
	},

	_detectIE: function () {
		var ua = window.navigator.userAgent;

		var msie = ua.indexOf('MSIE ');
		if (msie > 0) {
			// IE 10 or older => return version number
			return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
		}

		var trident = ua.indexOf('Trident/');
		if (trident > 0) {
			// IE 11 => return version number
			var rv = ua.indexOf('rv:');
			return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
		}

		var edge = ua.indexOf('Edge/');
		if (edge > 0) {
			// IE 12 => return version number
			return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
		}

		// other browser
		return false;
	}
});

L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend);


/**
 * @class L.Marker.Touch
 * @aka Marker.Touch
 *
 * This isn't full Touch support. This is just to get markers to also support dom touch events after creation
 * #TODO: find a better way of getting markers to support touch.
 */
L.Marker.Touch = L.Marker.extend({

	_initInteraction: function () {
		if (!this.addInteractiveTarget) {
			// 0.7.x support
			return this._initInteractionLegacy();
		}
		// TODO this may need be updated to re-add touch events for 1.0+
		return L.Marker.prototype._initInteraction.apply(this);
	},

	// This is an exact copy of https://github.com/Leaflet/Leaflet/blob/v0.7/src/layer/marker/Marker.js
	// with the addition of the touch events
	_initInteractionLegacy: function () {

		if (!this.options.clickable) {
			return;
		}

		// TODO refactor into something shared with Map/Path/etc. to DRY it up

		var icon = this._icon,
			events = ['dblclick',
				'mousedown',
				'mouseover',
				'mouseout',
				'contextmenu',
				'touchstart',
				'touchend',
				'touchmove'];
		if (this._detectIE) {
			events.concat(['MSPointerDown',
				'MSPointerUp',
				'MSPointerMove',
				'MSPointerCancel']);
		} else {
			events.concat(['touchcancel']);
		}

		L.DomUtil.addClass(icon, 'leaflet-clickable');
		L.DomEvent.on(icon, 'click', this._onMouseClick, this);
		L.DomEvent.on(icon, 'keypress', this._onKeyPress, this);

		for (var i = 0; i < events.length; i++) {
			L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
		}

		if (L.Handler.MarkerDrag) {
			this.dragging = new L.Handler.MarkerDrag(this);

			if (this.options.draggable) {
				this.dragging.enable();
			}
		}
	},

	_detectIE: function () {
		var ua = window.navigator.userAgent;

		var msie = ua.indexOf('MSIE ');
		if (msie > 0) {
			// IE 10 or older => return version number
			return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
		}

		var trident = ua.indexOf('Trident/');
		if (trident > 0) {
			// IE 11 => return version number
			var rv = ua.indexOf('rv:');
			return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
		}

		var edge = ua.indexOf('Edge/');
		if (edge > 0) {
			// IE 12 => return version number
			return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
		}

		// other browser
		return false;
	}
});



/**
 * @class L.LatLngUtil
 * @aka LatLngUtil
 */
L.LatLngUtil = {
	// Clones a LatLngs[], returns [][]

	// @method cloneLatLngs(LatLngs[]): L.LatLngs[]
	// Clone the latLng point or points or nested points and return an array with those points
	cloneLatLngs: function (latlngs) {
		var clone = [];
		for (var i = 0, l = latlngs.length; i < l; i++) {
			// Check for nested array (Polyline/Polygon)
			if (Array.isArray(latlngs[i])) {
				clone.push(L.LatLngUtil.cloneLatLngs(latlngs[i]));
			} else {
				clone.push(this.cloneLatLng(latlngs[i]));
			}
		}
		return clone;
	},

	// @method cloneLatLng(LatLng): L.LatLng
	// Clone the latLng and return a new LatLng object.
	cloneLatLng: function (latlng) {
		return L.latLng(latlng.lat, latlng.lng);
	}
};



(function () {

	var defaultPrecision = {
		km: 2,
		ha: 2,
		m: 0,
		mi: 2,
		ac: 2,
		yd: 0,
		ft: 0,
		nm: 2
	};


	/**
	 * @class L.GeometryUtil
	 * @aka GeometryUtil
	 */
	L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
		// Ported from the OpenLayers implementation. See https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270

		// @method geodesicArea(): number
		geodesicArea: function (latLngs) {
			var pointsCount = latLngs.length,
				area = 0.0,
				d2r = Math.PI / 180,
				p1, p2;

			if (pointsCount > 2) {
				for (var i = 0; i < pointsCount; i++) {
					p1 = latLngs[i];
					p2 = latLngs[(i + 1) % pointsCount];
					area += ((p2.lng - p1.lng) * d2r) *
						(2 + Math.sin(p1.lat * d2r) + Math.sin(p2.lat * d2r));
				}
				area = area * 6378137.0 * 6378137.0 / 2.0;
			}

			return Math.abs(area);
		},

		// @method formattedNumber(n, precision): string
		// Returns n in specified number format (if defined) and precision
		formattedNumber: function (n, precision) {
			var formatted = parseFloat(n).toFixed(precision),
				format = L.drawLocal.format && L.drawLocal.format.numeric,
				delimiters = format && format.delimiters,
				thousands = delimiters && delimiters.thousands,
				decimal = delimiters && delimiters.decimal;

			if (thousands || decimal) {
				var splitValue = formatted.split('.');
				formatted = thousands ? splitValue[0].replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + thousands) : splitValue[0];
				decimal = decimal || '.';
				if (splitValue.length > 1) {
					formatted = formatted + decimal + splitValue[1];
				}
			}

			return formatted;
		},

		// @method readableArea(area, isMetric, precision): string
		// Returns a readable area string in yards or metric.
		// The value will be rounded as defined by the precision option object.
		readableArea: function (area, isMetric, precision) {
			var areaStr,
				units,
				precision = L.Util.extend({}, defaultPrecision, precision);

			if (isMetric) {
				units = ['ha', 'm'];
				type = typeof isMetric;
				if (type === 'string') {
					units = [isMetric];
				} else if (type !== 'boolean') {
					units = isMetric;
				}

				if (area >= 1000000 && units.indexOf('km') !== -1) {
					areaStr = L.GeometryUtil.formattedNumber(area * 0.000001, precision['km']) + ' km²';
				} else if (area >= 10000 && units.indexOf('ha') !== -1) {
					areaStr = L.GeometryUtil.formattedNumber(area * 0.0001, precision['ha']) + ' ha';
				} else {
					areaStr = L.GeometryUtil.formattedNumber(area, precision['m']) + ' m²';
				}
			} else {
				area /= 0.836127; // Square yards in 1 meter

				if (area >= 3097600) { //3097600 square yards in 1 square mile
					areaStr = L.GeometryUtil.formattedNumber(area / 3097600, precision['mi']) + ' mi²';
				} else if (area >= 4840) { //4840 square yards in 1 acre
					areaStr = L.GeometryUtil.formattedNumber(area / 4840, precision['ac']) + ' acres';
				} else {
					areaStr = L.GeometryUtil.formattedNumber(area, precision['yd']) + ' yd²';
				}
			}

			return areaStr;
		},

		// @method readableDistance(distance, units): string
		// Converts a metric distance to one of [ feet, nauticalMile, metric or yards ] string
		//
		// @alternative
		// @method readableDistance(distance, isMetric, useFeet, isNauticalMile, precision): string
		// Converts metric distance to distance string.
		// The value will be rounded as defined by the precision option object.
		readableDistance: function (distance, isMetric, isFeet, isNauticalMile, precision) {
			var distanceStr,
				units,
				precision = L.Util.extend({}, defaultPrecision, precision);

			if (isMetric) {
				units = typeof isMetric == 'string' ? isMetric : 'metric';
			} else if (isFeet) {
				units = 'feet';
			} else if (isNauticalMile) {
				units = 'nauticalMile';
			} else {
				units = 'yards';
			}

			switch (units) {
				case 'metric':
					// show metres when distance is < 1km, then show km
					if (distance > 1000) {
						distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['km']) + ' km';
					} else {
						distanceStr = L.GeometryUtil.formattedNumber(distance, precision['m']) + ' m';
					}
					break;
				case 'feet':
					distance *= 1.09361 * 3;
					distanceStr = L.GeometryUtil.formattedNumber(distance, precision['ft']) + ' ft';

					break;
				case 'nauticalMile':
					distance *= 0.53996;
					distanceStr = L.GeometryUtil.formattedNumber(distance / 1000, precision['nm']) + ' nm';
					break;
				case 'yards':
				default:
					distance *= 1.09361;

					if (distance > 1760) {
						distanceStr = L.GeometryUtil.formattedNumber(distance / 1760, precision['mi']) + ' miles';
					} else {
						distanceStr = L.GeometryUtil.formattedNumber(distance, precision['yd']) + ' yd';
					}
					break;
			}
			return distanceStr;
		},

		// @method isVersion07x(): boolean
		// Returns true if the Leaflet version is 0.7.x, false otherwise.
		isVersion07x: function () {
			var version = L.version.split('.');
			//If Version is == 0.7.*
			return parseInt(version[0], 10) === 0 && parseInt(version[1], 10) === 7;
		},
	});

})();



/**
 * @class L.LineUtil
 * @aka Util
 * @aka L.Utils
 */
L.Util.extend(L.LineUtil, {

	// @method segmentsIntersect(): boolean
	// Checks to see if two line segments intersect. Does not handle degenerate cases.
	// http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf
	segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) {
		return this._checkCounterclockwise(p, p2, p3) !==
			this._checkCounterclockwise(p1, p2, p3) &&
			this._checkCounterclockwise(p, p1, p2) !==
			this._checkCounterclockwise(p, p1, p3);
	},

	// check to see if points are in counterclockwise order
	_checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
		return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x);
	}
});



/**
 * @class L.Polyline
 * @aka Polyline
 */
L.Polyline.include({

	// @method intersects(): boolean
	// Check to see if this polyline has any linesegments that intersect.
	// NOTE: does not support detecting intersection for degenerate cases.
	intersects: function () {
		var points = this._getProjectedPoints(),
			len = points ? points.length : 0,
			i, p, p1;

		if (this._tooFewPointsForIntersection()) {
			return false;
		}

		for (i = len - 1; i >= 3; i--) {
			p = points[i - 1];
			p1 = points[i];


			if (this._lineSegmentsIntersectsRange(p, p1, i - 2)) {
				return true;
			}
		}

		return false;
	},

	// @method newLatLngIntersects(): boolean
	// Check for intersection if new latlng was added to this polyline.
	// NOTE: does not support detecting intersection for degenerate cases.
	newLatLngIntersects: function (latlng, skipFirst) {
		// Cannot check a polyline for intersecting lats/lngs when not added to the map
		if (!this._map) {
			return false;
		}

		return this.newPointIntersects(this._map.latLngToLayerPoint(latlng), skipFirst);
	},

	// @method newPointIntersects(): boolean
	// Check for intersection if new point was added to this polyline.
	// newPoint must be a layer point.
	// NOTE: does not support detecting intersection for degenerate cases.
	newPointIntersects: function (newPoint, skipFirst) {
		var points = this._getProjectedPoints(),
			len = points ? points.length : 0,
			lastPoint = points ? points[len - 1] : null,
			// The previous previous line segment. Previous line segment doesn't need testing.
			maxIndex = len - 2;

		if (this._tooFewPointsForIntersection(1)) {
			return false;
		}

		return this._lineSegmentsIntersectsRange(lastPoint, newPoint, maxIndex, skipFirst ? 1 : 0);
	},

	// Polylines with 2 sides can only intersect in cases where points are collinear (we don't support detecting these).
	// Cannot have intersection when < 3 line segments (< 4 points)
	_tooFewPointsForIntersection: function (extraPoints) {
		var points = this._getProjectedPoints(),
			len = points ? points.length : 0;
		// Increment length by extraPoints if present
		len += extraPoints || 0;

		return !points || len <= 3;
	},

	// Checks a line segment intersections with any line segments before its predecessor.
	// Don't need to check the predecessor as will never intersect.
	_lineSegmentsIntersectsRange: function (p, p1, maxIndex, minIndex) {
		var points = this._getProjectedPoints(),
			p2, p3;

		minIndex = minIndex || 0;

		// Check all previous line segments (beside the immediately previous) for intersections
		for (var j = maxIndex; j > minIndex; j--) {
			p2 = points[j - 1];
			p3 = points[j];

			if (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) {
				return true;
			}
		}

		return false;
	},

	_getProjectedPoints: function () {
		if (!this._defaultShape) {
			return this._originalPoints;
		}
		var points = [],
			_shape = this._defaultShape();

		for (var i = 0; i < _shape.length; i++) {
			points.push(this._map.latLngToLayerPoint(_shape[i]));
		}
		return points;
	}
});



/**
 * @class L.Polygon
 * @aka Polygon
 */
L.Polygon.include({

	// @method intersects(): boolean
	// Checks a polygon for any intersecting line segments. Ignores holes.
	intersects: function () {
		var polylineIntersects,
			points = this._getProjectedPoints(),
			len, firstPoint, lastPoint, maxIndex;

		if (this._tooFewPointsForIntersection()) {
			return false;
		}

		polylineIntersects = L.Polyline.prototype.intersects.call(this);

		// If already found an intersection don't need to check for any more.
		if (polylineIntersects) {
			return true;
		}

		len = points.length;
		firstPoint = points[0];
		lastPoint = points[len - 1];
		maxIndex = len - 2;

		// Check the line segment between last and first point. Don't need to check the first line segment (minIndex = 1)
		return this._lineSegmentsIntersectsRange(lastPoint, firstPoint, maxIndex, 1);
	}
});



/**
 * @class L.Control.Draw
 * @aka L.Draw
 */
L.Control.Draw = L.Control.extend({

	// Options
	options: {
		position: 'topleft',
		draw: {},
		edit: false
	},

	// @method initialize(): void
	// Initializes draw control, toolbars from the options
	initialize: function (options) {
		if (L.version < '0.7') {
			throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/');
		}

		L.Control.prototype.initialize.call(this, options);

		var toolbar;

		this._toolbars = {};

		// Initialize toolbars
		if (L.DrawToolbar && this.options.draw) {
			toolbar = new L.DrawToolbar(this.options.draw);

			this._toolbars[L.DrawToolbar.TYPE] = toolbar;

			// Listen for when toolbar is enabled
			this._toolbars[L.DrawToolbar.TYPE].on('enable', this._toolbarEnabled, this);
		}

		if (L.EditToolbar && this.options.edit) {
			toolbar = new L.EditToolbar(this.options.edit);

			this._toolbars[L.EditToolbar.TYPE] = toolbar;

			// Listen for when toolbar is enabled
			this._toolbars[L.EditToolbar.TYPE].on('enable', this._toolbarEnabled, this);
		}
		L.toolbar = this; //set global var for editing the toolbar
	},

	// @method onAdd(): container
	// Adds the toolbar container to the map
	onAdd: function (map) {
		var container = L.DomUtil.create('div', 'leaflet-draw'),
			addedTopClass = false,
			topClassName = 'leaflet-draw-toolbar-top',
			toolbarContainer;

		for (var toolbarId in this._toolbars) {
			if (this._toolbars.hasOwnProperty(toolbarId)) {
				toolbarContainer = this._toolbars[toolbarId].addToolbar(map);

				if (toolbarContainer) {
					// Add class to the first toolbar to remove the margin
					if (!addedTopClass) {
						if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) {
							L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName);
						}
						addedTopClass = true;
					}

					container.appendChild(toolbarContainer);
				}
			}
		}

		return container;
	},

	// @method onRemove(): void
	// Removes the toolbars from the map toolbar container
	onRemove: function () {
		for (var toolbarId in this._toolbars) {
			if (this._toolbars.hasOwnProperty(toolbarId)) {
				this._toolbars[toolbarId].removeToolbar();
			}
		}
	},

	// @method setDrawingOptions(options): void
	// Sets options to all toolbar instances
	setDrawingOptions: function (options) {
		for (var toolbarId in this._toolbars) {
			if (this._toolbars[toolbarId] instanceof L.DrawToolbar) {
				this._toolbars[toolbarId].setOptions(options);
			}
		}
	},

	_toolbarEnabled: function (e) {
		var enabledToolbar = e.target;

		for (var toolbarId in this._toolbars) {
			if (this._toolbars[toolbarId] !== enabledToolbar) {
				this._toolbars[toolbarId].disable();
			}
		}
	}
});

L.Map.mergeOptions({
	drawControlTooltips: true,
	drawControl: false
});

L.Map.addInitHook(function () {
	if (this.options.drawControl) {
		this.drawControl = new L.Control.Draw();
		this.addControl(this.drawControl);
	}
});



/**
 * @class L.Draw.Toolbar
 * @aka Toolbar
 *
 * The toolbar class of the API — it is used to create the ui
 * This will be depreciated
 *
 * @example
 *
 * ```js
 *    var toolbar = L.Toolbar();
 *    toolbar.addToolbar(map);
 * ```
 *
 * ### Disabling a toolbar
 *
 * If you do not want a particular toolbar in your app you can turn it off by setting the toolbar to false.
 *
 * ```js
 *      var drawControl = new L.Control.Draw({
 *          draw: false,
 *          edit: {
 *              featureGroup: editableLayers
 *          }
 *      });
 * ```
 *
 * ### Disabling a toolbar item
 *
 * If you want to turn off a particular toolbar item, set it to false. The following disables drawing polygons and
 * markers. It also turns off the ability to edit layers.
 *
 * ```js
 *      var drawControl = new L.Control.Draw({
 *          draw: {
 *              polygon: false,
 *              marker: false
 *          },
 *          edit: {
 *              featureGroup: editableLayers,
 *              edit: false
 *          }
 *      });
 * ```
 */
L.Toolbar = L.Class.extend({
	// @section Methods for modifying the toolbar

	// @method initialize(options): void
	// Toolbar constructor
	initialize: function (options) {
		L.setOptions(this, options);

		this._modes = {};
		this._actionButtons = [];
		this._activeMode = null;

		var version = L.version.split('.');
		//If Version is >= 1.2.0
		if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
			L.Toolbar.include(L.Evented.prototype);
		} else {
			L.Toolbar.include(L.Mixin.Events);
		}
	},

	// @method enabled(): boolean
	// Gets a true/false of whether the toolbar is enabled
	enabled: function () {
		return this._activeMode !== null;
	},

	// @method disable(): void
	// Disables the toolbar
	disable: function () {
		if (!this.enabled()) {
			return;
		}

		this._activeMode.handler.disable();
	},

	// @method addToolbar(map): L.DomUtil
	// Adds the toolbar to the map and returns the toolbar dom element
	addToolbar: function (map) {
		var container = L.DomUtil.create('div', 'leaflet-draw-section'),
			buttonIndex = 0,
			buttonClassPrefix = this._toolbarClass || '',
			modeHandlers = this.getModeHandlers(map),
			i;

		this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
		this._map = map;

		for (i = 0; i < modeHandlers.length; i++) {
			if (modeHandlers[i].enabled) {
				this._initModeHandler(
					modeHandlers[i].handler,
					this._toolbarContainer,
					buttonIndex++,
					buttonClassPrefix,
					modeHandlers[i].title
				);
			}
		}

		// if no buttons were added, do not add the toolbar
		if (!buttonIndex) {
			return;
		}

		// Save button index of the last button, -1 as we would have ++ after the last button
		this._lastButtonIndex = --buttonIndex;

		// Create empty actions part of the toolbar
		this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions');

		// Add draw and cancel containers to the control container
		container.appendChild(this._toolbarContainer);
		container.appendChild(this._actionsContainer);

		return container;
	},

	// @method removeToolbar(): void
	// Removes the toolbar and drops the handler event listeners
	removeToolbar: function () {
		// Dispose each handler
		for (var handlerId in this._modes) {
			if (this._modes.hasOwnProperty(handlerId)) {
				// Unbind handler button
				this._disposeButton(
					this._modes[handlerId].button,
					this._modes[handlerId].handler.enable,
					this._modes[handlerId].handler
				);

				// Make sure is disabled
				this._modes[handlerId].handler.disable();

				// Unbind handler
				this._modes[handlerId].handler
					.off('enabled', this._handlerActivated, this)
					.off('disabled', this._handlerDeactivated, this);
			}
		}
		this._modes = {};

		// Dispose the actions toolbar
		for (var i = 0, l = this._actionButtons.length; i < l; i++) {
			this._disposeButton(
				this._actionButtons[i].button,
				this._actionButtons[i].callback,
				this
			);
		}
		this._actionButtons = [];
		this._actionsContainer = null;
	},

	_initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) {
		var type = handler.type;

		this._modes[type] = {};

		this._modes[type].handler = handler;

		this._modes[type].button = this._createButton({
			type: type,
			title: buttonTitle,
			className: classNamePredix + '-' + type,
			container: container,
			callback: this._modes[type].handler.enable,
			context: this._modes[type].handler
		});

		this._modes[type].buttonIndex = buttonIndex;

		this._modes[type].handler
			.on('enabled', this._handlerActivated, this)
			.on('disabled', this._handlerDeactivated, this);
	},

	/* Detect iOS based on browser User Agent, based on:
	 * http://stackoverflow.com/a/9039885 */
	_detectIOS: function () {
		var iOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
		return iOS;
	},

	_createButton: function (options) {

		var link = L.DomUtil.create('a', options.className || '', options.container);
		// Screen reader tag
		var sr = L.DomUtil.create('span', 'sr-only', options.container);

		link.href = '#';
		link.appendChild(sr);

		if (options.title) {
			link.title = options.title;
			sr.innerHTML = options.title;
		}

		if (options.text) {
			link.innerHTML = options.text;
			sr.innerHTML = options.text;
		}

		/* iOS does not use click events */
		var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';

		L.DomEvent
			.on(link, 'click', L.DomEvent.stopPropagation)
			.on(link, 'mousedown', L.DomEvent.stopPropagation)
			.on(link, 'dblclick', L.DomEvent.stopPropagation)
			.on(link, 'touchstart', L.DomEvent.stopPropagation)
			.on(link, 'click', L.DomEvent.preventDefault)
			.on(link, buttonEvent, options.callback, options.context);

		return link;
	},

	_disposeButton: function (button, callback) {
		/* iOS does not use click events */
		var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';

		L.DomEvent
			.off(button, 'click', L.DomEvent.stopPropagation)
			.off(button, 'mousedown', L.DomEvent.stopPropagation)
			.off(button, 'dblclick', L.DomEvent.stopPropagation)
			.off(button, 'touchstart', L.DomEvent.stopPropagation)
			.off(button, 'click', L.DomEvent.preventDefault)
			.off(button, buttonEvent, callback);
	},

	_handlerActivated: function (e) {
		// Disable active mode (if present)
		this.disable();

		// Cache new active feature
		this._activeMode = this._modes[e.handler];

		L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');

		this._showActionsToolbar();

		this.fire('enable');
	},

	_handlerDeactivated: function () {
		this._hideActionsToolbar();

		L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');

		this._activeMode = null;

		this.fire('disable');
	},

	_createActions: function (handler) {
		var container = this._actionsContainer,
			buttons = this.getActions(handler),
			l = buttons.length,
			li, di, dl, button;

		// Dispose the actions toolbar (todo: dispose only not used buttons)
		for (di = 0, dl = this._actionButtons.length; di < dl; di++) {
			this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback);
		}
		this._actionButtons = [];

		// Remove all old buttons
		while (container.firstChild) {
			container.removeChild(container.firstChild);
		}

		for (var i = 0; i < l; i++) {
			if ('enabled' in buttons[i] && !buttons[i].enabled) {
				continue;
			}

			li = L.DomUtil.create('li', '', container);

			button = this._createButton({
				title: buttons[i].title,
				text: buttons[i].text,
				container: li,
				callback: buttons[i].callback,
				context: buttons[i].context
			});

			this._actionButtons.push({
				button: button,
				callback: buttons[i].callback
			});
		}
	},

	_showActionsToolbar: function () {
		var buttonIndex = this._activeMode.buttonIndex,
			lastButtonIndex = this._lastButtonIndex,
			toolbarPosition = this._activeMode.button.offsetTop - 1;

		// Recreate action buttons on every click
		this._createActions(this._activeMode.handler);

		// Correctly position the cancel button
		this._actionsContainer.style.top = toolbarPosition + 'px';

		if (buttonIndex === 0) {
			L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
			L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top');
		}

		if (buttonIndex === lastButtonIndex) {
			L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
			L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
		}

		this._actionsContainer.style.display = 'block';
		this._map.fire(L.Draw.Event.TOOLBAROPENED);
	},

	_hideActionsToolbar: function () {
		this._actionsContainer.style.display = 'none';

		L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
		L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
		L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top');
		L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
		this._map.fire(L.Draw.Event.TOOLBARCLOSED);
	}
});



L.Draw = L.Draw || {};
/**
 * @class L.Draw.Tooltip
 * @aka Tooltip
 *
 * The tooltip class — it is used to display the tooltip while drawing
 * This will be depreciated
 *
 * @example
 *
 * ```js
 *    var tooltip = L.Draw.Tooltip();
 * ```
 *
 */
L.Draw.Tooltip = L.Class.extend({

	// @section Methods for modifying draw state

	// @method initialize(map): void
	// Tooltip constructor
	initialize: function (map) {
		this._map = map;
		this._popupPane = map._panes.popupPane;
		this._visible = false;

		this._container = map.options.drawControlTooltips ?
			L.DomUtil.create('div', 'leaflet-draw-tooltip', this._popupPane) : null;
		this._singleLineLabel = false;

		this._map.on('mouseout', this._onMouseOut, this);
	},

	// @method dispose(): void
	// Remove Tooltip DOM and unbind events
	dispose: function () {
		this._map.off('mouseout', this._onMouseOut, this);

		if (this._container) {
			this._popupPane.removeChild(this._container);
			this._container = null;
		}
	},

	// @method updateContent(labelText): this
	// Changes the tooltip text to string in function call
	updateContent: function (labelText) {
		if (!this._container) {
			return this;
		}
		labelText.subtext = labelText.subtext || '';

		// update the vertical position (only if changed)
		if (labelText.subtext.length === 0 && !this._singleLineLabel) {
			L.DomUtil.addClass(this._container, 'leaflet-draw-tooltip-single');
			this._singleLineLabel = true;
		}
		else if (labelText.subtext.length > 0 && this._singleLineLabel) {
			L.DomUtil.removeClass(this._container, 'leaflet-draw-tooltip-single');
			this._singleLineLabel = false;
		}

		this._container.innerHTML =
			(labelText.subtext.length > 0 ?
				'<span class="leaflet-draw-tooltip-subtext">' + labelText.subtext + '</span>' + '<br />' : '') +
			'<span>' + labelText.text + '</span>';

		if (!labelText.text && !labelText.subtext) {
			this._visible = false;
			this._container.style.visibility = 'hidden';
		} else {
			this._visible = true;
			this._container.style.visibility = 'inherit';
		}

		return this;
	},

	// @method updatePosition(latlng): this
	// Changes the location of the tooltip
	updatePosition: function (latlng) {
		var pos = this._map.latLngToLayerPoint(latlng),
			tooltipContainer = this._container;

		if (this._container) {
			if (this._visible) {
				tooltipContainer.style.visibility = 'inherit';
			}
			L.DomUtil.setPosition(tooltipContainer, pos);
		}

		return this;
	},

	// @method showAsError(): this
	// Applies error class to tooltip
	showAsError: function () {
		if (this._container) {
			L.DomUtil.addClass(this._container, 'leaflet-error-draw-tooltip');
		}
		return this;
	},

	// @method removeError(): this
	// Removes the error class from the tooltip
	removeError: function () {
		if (this._container) {
			L.DomUtil.removeClass(this._container, 'leaflet-error-draw-tooltip');
		}
		return this;
	},

	_onMouseOut: function () {
		if (this._container) {
			this._container.style.visibility = 'hidden';
		}
	}
});



/**
 * @class L.DrawToolbar
 * @aka Toolbar
 */
L.DrawToolbar = L.Toolbar.extend({

	statics: {
		TYPE: 'draw'
	},

	options: {
		polyline: {},
		polygon: {},
		rectangle: {},
		circle: {},
		marker: {},
		circlemarker: {}
	},

	// @method initialize(): void
	initialize: function (options) {
		// Ensure that the options are merged correctly since L.extend is only shallow
		for (var type in this.options) {
			if (this.options.hasOwnProperty(type)) {
				if (options[type]) {
					options[type] = L.extend({}, this.options[type], options[type]);
				}
			}
		}

		this._toolbarClass = 'leaflet-draw-draw';
		L.Toolbar.prototype.initialize.call(this, options);
	},

	// @method getModeHandlers(): object
	// Get mode handlers information
	getModeHandlers: function (map) {
		return [
			{
				enabled: this.options.polyline,
				handler: new L.Draw.Polyline(map, this.options.polyline),
				title: L.drawLocal.draw.toolbar.buttons.polyline
			},
			{
				enabled: this.options.polygon,
				handler: new L.Draw.Polygon(map, this.options.polygon),
				title: L.drawLocal.draw.toolbar.buttons.polygon
			},
			{
				enabled: this.options.rectangle,
				handler: new L.Draw.Rectangle(map, this.options.rectangle),
				title: L.drawLocal.draw.toolbar.buttons.rectangle
			},
			{
				enabled: this.options.circle,
				handler: new L.Draw.Circle(map, this.options.circle),
				title: L.drawLocal.draw.toolbar.buttons.circle
			},
			{
				enabled: this.options.marker,
				handler: new L.Draw.Marker(map, this.options.marker),
				title: L.drawLocal.draw.toolbar.buttons.marker
			},
			{
				enabled: this.options.circlemarker,
				handler: new L.Draw.CircleMarker(map, this.options.circlemarker),
				title: L.drawLocal.draw.toolbar.buttons.circlemarker
			}
		];
	},

	// @method getActions(): object
	// Get action information
	getActions: function (handler) {
		return [
			{
				enabled: handler.completeShape,
				title: L.drawLocal.draw.toolbar.finish.title,
				text: L.drawLocal.draw.toolbar.finish.text,
				callback: handler.completeShape,
				context: handler
			},
			{
				enabled: handler.deleteLastVertex,
				title: L.drawLocal.draw.toolbar.undo.title,
				text: L.drawLocal.draw.toolbar.undo.text,
				callback: handler.deleteLastVertex,
				context: handler
			},
			{
				title: L.drawLocal.draw.toolbar.actions.title,
				text: L.drawLocal.draw.toolbar.actions.text,
				callback: this.disable,
				context: this
			}
		];
	},

	// @method setOptions(): void
	// Sets the options to the toolbar
	setOptions: function (options) {
		L.setOptions(this, options);

		for (var type in this._modes) {
			if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) {
				this._modes[type].handler.setOptions(options[type]);
			}
		}
	}
});



/*L.Map.mergeOptions({
 editControl: true
 });*/
/**
 * @class L.EditToolbar
 * @aka EditToolbar
 */
L.EditToolbar = L.Toolbar.extend({
	statics: {
		TYPE: 'edit'
	},

	options: {
		edit: {
			selectedPathOptions: {
				dashArray: '10, 10',

				fill: true,
				fillColor: '#fe57a1',
				fillOpacity: 0.1,

				// Whether to user the existing layers color
				maintainColor: false
			}
		},
		remove: {},
		poly: null,
		featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */
	},

	// @method intialize(): void
	initialize: function (options) {
		// Need to set this manually since null is an acceptable value here
		if (options.edit) {
			if (typeof options.edit.selectedPathOptions === 'undefined') {
				options.edit.selectedPathOptions = this.options.edit.selectedPathOptions;
			}
			options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions);
		}

		if (options.remove) {
			options.remove = L.extend({}, this.options.remove, options.remove);
		}

		if (options.poly) {
			options.poly = L.extend({}, this.options.poly, options.poly);
		}

		this._toolbarClass = 'leaflet-draw-edit';
		L.Toolbar.prototype.initialize.call(this, options);

		this._selectedFeatureCount = 0;
	},

	// @method getModeHandlers(): object
	// Get mode handlers information
	getModeHandlers: function (map) {
		var featureGroup = this.options.featureGroup;
		return [
			{
				enabled: this.options.edit,
				handler: new L.EditToolbar.Edit(map, {
					featureGroup: featureGroup,
					selectedPathOptions: this.options.edit.selectedPathOptions,
					poly: this.options.poly
				}),
				title: L.drawLocal.edit.toolbar.buttons.edit
			},
			{
				enabled: this.options.remove,
				handler: new L.EditToolbar.Delete(map, {
					featureGroup: featureGroup
				}),
				title: L.drawLocal.edit.toolbar.buttons.remove
			}
		];
	},

	// @method getActions(): object
	// Get actions information
	getActions: function (handler) {
		var actions = [
			{
				title: L.drawLocal.edit.toolbar.actions.save.title,
				text: L.drawLocal.edit.toolbar.actions.save.text,
				callback: this._save,
				context: this
			},
			{
				title: L.drawLocal.edit.toolbar.actions.cancel.title,
				text: L.drawLocal.edit.toolbar.actions.cancel.text,
				callback: this.disable,
				context: this
			}
		];

		if (handler.removeAllLayers) {
			actions.push({
				title: L.drawLocal.edit.toolbar.actions.clearAll.title,
				text: L.drawLocal.edit.toolbar.actions.clearAll.text,
				callback: this._clearAllLayers,
				context: this
			});
		}

		return actions;
	},

	// @method addToolbar(map): L.DomUtil
	// Adds the toolbar to the map
	addToolbar: function (map) {
		var container = L.Toolbar.prototype.addToolbar.call(this, map);

		this._checkDisabled();

		this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this);

		return container;
	},

	// @method removeToolbar(): void
	// Removes the toolbar from the map
	removeToolbar: function () {
		this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this);

		L.Toolbar.prototype.removeToolbar.call(this);
	},

	// @method disable(): void
	// Disables the toolbar
	disable: function () {
		if (!this.enabled()) {
			return;
		}

		this._activeMode.handler.revertLayers();

		L.Toolbar.prototype.disable.call(this);
	},

	_save: function () {
		this._activeMode.handler.save();
		if (this._activeMode) {
			this._activeMode.handler.disable();
		}
	},

	_clearAllLayers: function () {
		this._activeMode.handler.removeAllLayers();
		if (this._activeMode) {
			this._activeMode.handler.disable();
		}
	},

	_checkDisabled: function () {
		var featureGroup = this.options.featureGroup,
			hasLayers = featureGroup.getLayers().length !== 0,
			button;

		if (this.options.edit) {
			button = this._modes[L.EditToolbar.Edit.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
					L.drawLocal.edit.toolbar.buttons.edit
					: L.drawLocal.edit.toolbar.buttons.editDisabled
			);
		}

		if (this.options.remove) {
			button = this._modes[L.EditToolbar.Delete.TYPE].button;

			if (hasLayers) {
				L.DomUtil.removeClass(button, 'leaflet-disabled');
			} else {
				L.DomUtil.addClass(button, 'leaflet-disabled');
			}

			button.setAttribute(
				'title',
				hasLayers ?
					L.drawLocal.edit.toolbar.buttons.remove
					: L.drawLocal.edit.toolbar.buttons.removeDisabled
			);
		}
	}
});



/**
 * @class L.EditToolbar.Edit
 * @aka EditToolbar.Edit
 */
L.EditToolbar.Edit = L.Handler.extend({
	statics: {
		TYPE: 'edit'
	},

	// @method intialize(): void
	initialize: function (map, options) {
		L.Handler.prototype.initialize.call(this, map);

		L.setOptions(this, options);

		// Store the selectable layer group for ease of access
		this._featureGroup = options.featureGroup;

		if (!(this._featureGroup instanceof L.FeatureGroup)) {
			throw new Error('options.featureGroup must be a L.FeatureGroup');
		}

		this._uneditedLayerProps = {};

		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.EditToolbar.Edit.TYPE;

		var version = L.version.split('.');
		//If Version is >= 1.2.0
		if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
			L.EditToolbar.Edit.include(L.Evented.prototype);
		} else {
			L.EditToolbar.Edit.include(L.Mixin.Events);
		}
	},

	// @method enable(): void
	// Enable the edit toolbar
	enable: function () {
		if (this._enabled || !this._hasAvailableLayers()) {
			return;
		}
		this.fire('enabled', {handler: this.type});
		//this disable other handlers

		this._map.fire(L.Draw.Event.EDITSTART, {handler: this.type});
		//allow drawLayer to be updated before beginning edition.

		L.Handler.prototype.enable.call(this);
		this._featureGroup
			.on('layeradd', this._enableLayerEdit, this)
			.on('layerremove', this._disableLayerEdit, this);
	},

	// @method disable(): void
	// Disable the edit toolbar
	disable: function () {
		if (!this._enabled) {
			return;
		}
		this._featureGroup
			.off('layeradd', this._enableLayerEdit, this)
			.off('layerremove', this._disableLayerEdit, this);
		L.Handler.prototype.disable.call(this);
		this._map.fire(L.Draw.Event.EDITSTOP, {handler: this.type});
		this.fire('disabled', {handler: this.type});
	},

	// @method addHooks(): void
	// Add listener hooks for this handler
	addHooks: function () {
		var map = this._map;

		if (map) {
			map.getContainer().focus();

			this._featureGroup.eachLayer(this._enableLayerEdit, this);

			this._tooltip = new L.Draw.Tooltip(this._map);
			this._tooltip.updateContent({
				text: L.drawLocal.edit.handlers.edit.tooltip.text,
				subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
			});

			// Quickly access the tooltip to update for intersection checking
			map._editTooltip = this._tooltip;

			this._updateTooltip();

			this._map
				.on('mousemove', this._onMouseMove, this)
				.on('touchmove', this._onMouseMove, this)
				.on('MSPointerMove', this._onMouseMove, this)
				.on(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks for this handler
	removeHooks: function () {
		if (this._map) {
			// Clean up selected layers.
			this._featureGroup.eachLayer(this._disableLayerEdit, this);

			// Clear the backups of the original layers
			this._uneditedLayerProps = {};

			this._tooltip.dispose();
			this._tooltip = null;

			this._map
				.off('mousemove', this._onMouseMove, this)
				.off('touchmove', this._onMouseMove, this)
				.off('MSPointerMove', this._onMouseMove, this)
				.off(L.Draw.Event.EDITVERTEX, this._updateTooltip, this);
		}
	},

	// @method revertLayers(): void
	// Revert each layer's geometry changes
	revertLayers: function () {
		this._featureGroup.eachLayer(function (layer) {
			this._revertLayer(layer);
		}, this);
	},

	// @method save(): void
	// Save the layer geometries
	save: function () {
		var editedLayers = new L.LayerGroup();
		this._featureGroup.eachLayer(function (layer) {
			if (layer.edited) {
				editedLayers.addLayer(layer);
				layer.edited = false;
			}
		});
		this._map.fire(L.Draw.Event.EDITED, {layers: editedLayers});
	},

	_backupLayer: function (layer) {
		var id = L.Util.stamp(layer);

		if (!this._uneditedLayerProps[id]) {
			// Polyline, Polygon or Rectangle
			if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
				this._uneditedLayerProps[id] = {
					latlngs: L.LatLngUtil.cloneLatLngs(layer.getLatLngs())
				};
			} else if (layer instanceof L.Circle) {
				this._uneditedLayerProps[id] = {
					latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng()),
					radius: layer.getRadius()
				};
			} else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker
				this._uneditedLayerProps[id] = {
					latlng: L.LatLngUtil.cloneLatLng(layer.getLatLng())
				};
			}
		}
	},

	_getTooltipText: function () {
		return ({
			text: L.drawLocal.edit.handlers.edit.tooltip.text,
			subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
		});
	},

	_updateTooltip: function () {
		this._tooltip.updateContent(this._getTooltipText());
	},

	_revertLayer: function (layer) {
		var id = L.Util.stamp(layer);
		layer.edited = false;
		if (this._uneditedLayerProps.hasOwnProperty(id)) {
			// Polyline, Polygon or Rectangle
			if (layer instanceof L.Polyline || layer instanceof L.Polygon || layer instanceof L.Rectangle) {
				layer.setLatLngs(this._uneditedLayerProps[id].latlngs);
			} else if (layer instanceof L.Circle) {
				layer.setLatLng(this._uneditedLayerProps[id].latlng);
				layer.setRadius(this._uneditedLayerProps[id].radius);
			} else if (layer instanceof L.Marker || layer instanceof L.CircleMarker) { // Marker or CircleMarker
				layer.setLatLng(this._uneditedLayerProps[id].latlng);
			}

			layer.fire('revert-edited', {layer: layer});
		}
	},

	_enableLayerEdit: function (e) {
		var layer = e.layer || e.target || e,
			pathOptions, poly;

		// Back up this layer (if haven't before)
		this._backupLayer(layer);

		if (this.options.poly) {
			poly = L.Util.extend({}, this.options.poly);
			layer.options.poly = poly;
		}

		// Set different style for editing mode
		if (this.options.selectedPathOptions) {
			pathOptions = L.Util.extend({}, this.options.selectedPathOptions);

			// Use the existing color of the layer
			if (pathOptions.maintainColor) {
				pathOptions.color = layer.options.color;
				pathOptions.fillColor = layer.options.fillColor;
			}

			layer.options.original = L.extend({}, layer.options);
			layer.options.editing = pathOptions;

		}

		if (layer instanceof L.Marker) {
			if (layer.editing) {
				layer.editing.enable();
			}
			layer.dragging.enable();
			layer
				.on('dragend', this._onMarkerDragEnd)
				// #TODO: remove when leaflet finally fixes their draggable so it's touch friendly again.
				.on('touchmove', this._onTouchMove, this)
				.on('MSPointerMove', this._onTouchMove, this)
				.on('touchend', this._onMarkerDragEnd, this)
				.on('MSPointerUp', this._onMarkerDragEnd, this);
		} else {
			layer.editing.enable();
		}
	},

	_disableLayerEdit: function (e) {
		var layer = e.layer || e.target || e;

		layer.edited = false;
		if (layer.editing) {
			layer.editing.disable();
		}

		delete layer.options.editing;
		delete layer.options.original;
		// Reset layer styles to that of before select
		if (this._selectedPathOptions) {
			if (layer instanceof L.Marker) {
				this._toggleMarkerHighlight(layer);
			} else {
				// reset the layer style to what is was before being selected
				layer.setStyle(layer.options.previousOptions);
				// remove the cached options for the layer object
				delete layer.options.previousOptions;
			}
		}

		if (layer instanceof L.Marker) {
			layer.dragging.disable();
			layer
				.off('dragend', this._onMarkerDragEnd, this)
				.off('touchmove', this._onTouchMove, this)
				.off('MSPointerMove', this._onTouchMove, this)
				.off('touchend', this._onMarkerDragEnd, this)
				.off('MSPointerUp', this._onMarkerDragEnd, this);
		} else {
			layer.editing.disable();
		}
	},

	_onMouseMove: function (e) {
		this._tooltip.updatePosition(e.latlng);
	},

	_onMarkerDragEnd: function (e) {
		var layer = e.target;
		layer.edited = true;
		this._map.fire(L.Draw.Event.EDITMOVE, {layer: layer});
	},

	_onTouchMove: function (e) {
		var touchEvent = e.originalEvent.changedTouches[0],
			layerPoint = this._map.mouseEventToLayerPoint(touchEvent),
			latlng = this._map.layerPointToLatLng(layerPoint);
		e.target.setLatLng(latlng);
	},

	_hasAvailableLayers: function () {
		return this._featureGroup.getLayers().length !== 0;
	}
});



/**
 * @class L.EditToolbar.Delete
 * @aka EditToolbar.Delete
 */
L.EditToolbar.Delete = L.Handler.extend({
	statics: {
		TYPE: 'remove' // not delete as delete is reserved in js
	},

	// @method intialize(): void
	initialize: function (map, options) {
		L.Handler.prototype.initialize.call(this, map);

		L.Util.setOptions(this, options);

		// Store the selectable layer group for ease of access
		this._deletableLayers = this.options.featureGroup;

		if (!(this._deletableLayers instanceof L.FeatureGroup)) {
			throw new Error('options.featureGroup must be a L.FeatureGroup');
		}

		// Save the type so super can fire, need to do this as cannot do this.TYPE :(
		this.type = L.EditToolbar.Delete.TYPE;

		var version = L.version.split('.');
		//If Version is >= 1.2.0
		if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
			L.EditToolbar.Delete.include(L.Evented.prototype);
		} else {
			L.EditToolbar.Delete.include(L.Mixin.Events);
		}

	},

	// @method enable(): void
	// Enable the delete toolbar
	enable: function () {
		if (this._enabled || !this._hasAvailableLayers()) {
			return;
		}
		this.fire('enabled', {handler: this.type});

		this._map.fire(L.Draw.Event.DELETESTART, {handler: this.type});

		L.Handler.prototype.enable.call(this);

		this._deletableLayers
			.on('layeradd', this._enableLayerDelete, this)
			.on('layerremove', this._disableLayerDelete, this);
	},

	// @method disable(): void
	// Disable the delete toolbar
	disable: function () {
		if (!this._enabled) {
			return;
		}

		this._deletableLayers
			.off('layeradd', this._enableLayerDelete, this)
			.off('layerremove', this._disableLayerDelete, this);

		L.Handler.prototype.disable.call(this);

		this._map.fire(L.Draw.Event.DELETESTOP, {handler: this.type});

		this.fire('disabled', {handler: this.type});
	},

	// @method addHooks(): void
	// Add listener hooks to this handler
	addHooks: function () {
		var map = this._map;

		if (map) {
			map.getContainer().focus();

			this._deletableLayers.eachLayer(this._enableLayerDelete, this);
			this._deletedLayers = new L.LayerGroup();

			this._tooltip = new L.Draw.Tooltip(this._map);
			this._tooltip.updateContent({text: L.drawLocal.edit.handlers.remove.tooltip.text});

			this._map.on('mousemove', this._onMouseMove, this);
		}
	},

	// @method removeHooks(): void
	// Remove listener hooks from this handler
	removeHooks: function () {
		if (this._map) {
			this._deletableLayers.eachLayer(this._disableLayerDelete, this);
			this._deletedLayers = null;

			this._tooltip.dispose();
			this._tooltip = null;

			this._map.off('mousemove', this._onMouseMove, this);
		}
	},

	// @method revertLayers(): void
	// Revert the deleted layers back to their prior state.
	revertLayers: function () {
		// Iterate of the deleted layers and add them back into the featureGroup
		this._deletedLayers.eachLayer(function (layer) {
			this._deletableLayers.addLayer(layer);
			layer.fire('revert-deleted', {layer: layer});
		}, this);
	},

	// @method save(): void
	// Save deleted layers
	save: function () {
		this._map.fire(L.Draw.Event.DELETED, {layers: this._deletedLayers});
	},

	// @method removeAllLayers(): void
	// Remove all delateable layers
	removeAllLayers: function () {
		// Iterate of the delateable layers and add remove them
		this._deletableLayers.eachLayer(function (layer) {
			this._removeLayer({layer: layer});
		}, this);
		this.save();
	},

	_enableLayerDelete: function (e) {
		var layer = e.layer || e.target || e;

		layer.on('click', this._removeLayer, this);
	},

	_disableLayerDelete: function (e) {
		var layer = e.layer || e.target || e;

		layer.off('click', this._removeLayer, this);

		// Remove from the deleted layers so we can't accidentally revert if the user presses cancel
		this._deletedLayers.removeLayer(layer);
	},

	_removeLayer: function (e) {
		var layer = e.layer || e.target || e;

		this._deletableLayers.removeLayer(layer);

		this._deletedLayers.addLayer(layer);

		layer.fire('deleted');
	},

	_onMouseMove: function (e) {
		this._tooltip.updatePosition(e.latlng);
	},

	_hasAvailableLayers: function () {
		return this._deletableLayers.getLayers().length !== 0;
	}
});



}(window, document));
//# sourceMappingURL=leaflet.draw-src.map

/***/ }),
/* 124 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
var ReverseGeocodingDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPreverseGeocoding");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################### Methods of main container ##################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing
   *
   * @returns {DOMElement} DOM element
   */
  _createShowReverseGeocodingElement: function _createShowReverseGeocodingElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowReverseGeocoding");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show ReverseGeocoding
   *
   * @returns {DOMElement} DOM element
   */
  _createShowReverseGeocodingPictoElement: function _createShowReverseGeocodingPictoElement() {
    // contexte d'execution
    var self = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowReverseGeocodingPicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowReverseGeocoding");
    label.title = "Ouvrir la recherche inverse";

    // Close all results and panels when minimizing the widget
    if (label.addEventListener) {
      label.addEventListener("click", function () {
        self.onShowReverseGeocodingClick();
      });
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function () {
        self.onShowReverseGeocodingClick();
      });
    }
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowReverseGeocodingOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  /**
   * Create Waiting Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingWaitingElement: function _createReverseGeocodingWaitingElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPreverseGeocodingCalcWaitingContainer");
    div.className = "GPreverseGeocodingCalcWaitingContainerHidden";
    var p = document.createElement("p");
    p.className = "GPreverseGeocodingCalcWaiting";
    p.innerHTML = "Recherche en cours...";
    div.appendChild(p);
    return div;
  },
  /**
   * Reverse geocoding results panel element.
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingResultsPanelElement: function _createReverseGeocodingResultsPanelElement() {
    var resultsPanelDiv = document.createElement("div");
    resultsPanelDiv.id = this._addUID("GPreverseGeocodingResultsPanel");
    resultsPanelDiv.className = "GPpanel GPreverseGeocodingComponentHidden";
    return resultsPanelDiv;
  },
  /**
   * Reverse geocoding results list.
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingResultsListElement: function _createReverseGeocodingResultsListElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPreverseGeocodingResultsList");
    // Results are dynamically filled in Javascript by reverse geocoding service
    return container;
  },
  /**
   *  Add Result
   * (results dynamically generate !)
   *
   * @param {String} locationDescription - reverse geocoded location results
   * @param {Number} id - ID
   */
  _createReverseGeocodingResultElement: function _createReverseGeocodingResultElement(locationDescription, id) {
    // contexte
    var context = this;
    var container = document.getElementById(this._addUID("GPreverseGeocodingResultsList"));
    var div = document.createElement("div");
    div.id = this._addUID("ReverseGeocodedLocation_" + id);
    div.className = "GPautoCompleteProposal";
    div.innerHTML = locationDescription;
    div.title = locationDescription;
    if (div.addEventListener) {
      div.addEventListener("mouseover", function (e) {
        context.onReverseGeocodingResultMouseOver(e);
      });
      div.addEventListener("mouseout", function (e) {
        context.onReverseGeocodingResultMouseOut(e);
      });
      div.addEventListener("click", function (e) {
        if (typeof context.onReverseGeocodingResultClick === "function") {
          context.onReverseGeocodingResultClick(e);
        }
      });
    } else if (div.attachEvent) {
      div.attachEvent("onmouseover", function (e) {
        context.onReverseGeocodingResultMouseOver(e);
      });
      div.attachEvent("onmouseout", function (e) {
        context.onReverseGeocodingResultMouseOut(e);
      });
      div.attachEvent("onclick", function (e) {
        if (typeof context.onReverseGeocodingResultClick === "function") {
          context.onReverseGeocodingResultClick(e);
        }
      });
    }
    container.appendChild(div);
  },
  // ################################################################### //
  // ######################### Inputs panel ############################ //
  // ################################################################### //

  /**
   * Create Container Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelElement: function _createReverseGeocodingPanelElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPreverseGeocodingPanel");
    div.className = "GPpanel";
    return div;
  },
  /**
   * Create Header Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelHeaderElement: function _createReverseGeocodingPanelHeaderElement() {
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    // info: on sépare les appels pour la création du picto de retour,
    // du titre et de la croix de fermeture pour les récupérer dans le composant
    return container;
  },
  /**
   * Create return picto in panel header
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelReturnPictoElement: function _createReverseGeocodingPanelReturnPictoElement() {
    // contexte
    var self = this;
    var divNew = document.createElement("div");
    divNew.id = this._addUID("GPreverseGeocodingReturnPicto");
    divNew.title = "Nouvelle recherche";
    divNew.className = "GPreverseGeocodingReturnPictoHidden";
    if (divNew.addEventListener) {
      divNew.addEventListener("click", function (e) {
        document.getElementById(self._addUID("GPreverseGeocodingResultsPanel")).className = "GProuteComponentHidden";
        document.getElementById(self._addUID("GPreverseGeocodingForm")).className = "";
        document.getElementById(self._addUID("GPreverseGeocodingHeaderTitle")).innerHTML = "Recherche inverse";
        document.getElementById(self._addUID("GPreverseGeocodingReturnPicto")).className = "GPreverseGeocodingReturnPictoHidden";
        self.onGPreverseGeocodingReturnPictoClick(e);
      });
    } else if (divNew.attachEvent) {
      divNew.attachEvent("onclick", function (e) {
        document.getElementById(self._addUID("GPreverseGeocodingResultsPanel")).className = "GProuteComponentHidden";
        document.getElementById(self._addUID("GPreverseGeocodingForm")).className = "";
        document.getElementById(self._addUID("GPreverseGeocodingHeaderTitle")).innerHTML = "Recherche inverse";
        document.getElementById(self._addUID("GPreverseGeocodingReturnPicto")).className = "GPreverseGeocodingReturnPictoHidden";
        self.onGPreverseGeocodingReturnPictoClick(e);
      });
    }
    return divNew;
  },
  /**
   * Create Header Title Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelTitleElement: function _createReverseGeocodingPanelTitleElement() {
    var div = document.createElement("div");
    div.className = "GPpanelTitle";
    div.id = this._addUID("GPreverseGeocodingHeaderTitle");
    div.innerHTML = "Recherche inverse";
    return div;
  },
  /**
   * Create Header close div
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelCloseElement: function _createReverseGeocodingPanelCloseElement() {
    // contexte
    var self = this;
    var divClose = document.createElement("div");
    divClose.id = this._addUID("GPreverseGeocodingPanelClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer le panneau";

    // Link panel close / visibility checkbox
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPshowReverseGeocodingPicto")).click();
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPshowReverseGeocodingPicto")).click();
      });
    }
    return divClose;
  },
  /**
   * Create Form
   * see event !
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingPanelFormElement: function _createReverseGeocodingPanelFormElement() {
    // contexte d'execution
    var self = this;
    var form = document.createElement("form");
    form.id = this._addUID("GPreverseGeocodingForm");
    if (form.addEventListener) {
      form.addEventListener("submit", function (e) {
        e.preventDefault();
        self.onReverseGeocodingSubmit();
      });
    } else if (form.attachEvent) {
      form.attachEvent("onsubmit", function (e) {
        e.preventDefault();
        self.onReverseGeocodingSubmit();
      });
    }
    return form;
  },
  // ################################################################### //
  // ####################### Choice mode into form ##################### //
  // ################################################################### //

  /**
   * Create Container to Mode choice geocoding type
   *
   * @param {Array} resources - geocoding resources to be displayed (and used)
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingFormModeChoiceGeocodingTypeElement: function _createReverseGeocodingFormModeChoiceGeocodingTypeElement(resources) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.className = "GPflexInput";
    var label = document.createElement("label");
    label.className = "GPreverseGeocodingCodeLabel";
    label.innerHTML = "Recherche par";
    label.title = "Recherche par";
    div.appendChild(label);
    var select = document.createElement("select");
    select.className = "GPreverseGeocodingCode";
    // gestionnaire d'evenement : on stocke la valeur du type de geocodage,
    // utilisé dans la requête de géocodage inverse
    if (select.addEventListener) {
      select.addEventListener("change", function (e) {
        context.onReverseGeocodingTypeChange(e);
      });
    } else if (select.attachEvent) {
      select.attachEvent("onchange", function (e) {
        context.onReverseGeocodingTypeChange(e);
      });
    }

    // on prend soit les valeurs passées par l'utilisateur, soit des valeurs par défaut
    if (!resources || !Array.isArray(resources)) {
      resources = ["StreetAddress", "PositionOfInterest", "CadastralParcel"];
    }
    for (var i = 0; i < resources.length; i++) {
      switch (resources[i]) {
        case "PositionOfInterest":
          var POIOption = document.createElement("option");
          POIOption.value = "PositionOfInterest";
          POIOption.text = "Lieux/toponymes";
          select.appendChild(POIOption);
          break;
        case "StreetAddress":
          var SAOption = document.createElement("option");
          SAOption.value = "StreetAddress";
          SAOption.text = "Adresses";
          select.appendChild(SAOption);
          break;
        case "CadastralParcel":
          var CPOption = document.createElement("option");
          CPOption.value = "CadastralParcel";
          CPOption.text = "Parcelles cadastrales";
          select.appendChild(CPOption);
          break;
        default:
          break;
      }
    }
    div.appendChild(select);
    return div;
  },
  /**
   * Create Container to Mode choice geocoding delimitation
   *
   * @param {Array} delimitations - geocoding delimitations to be displayed (and used)
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingFormModeChoiceGeocodingDelimitationElement: function _createReverseGeocodingFormModeChoiceGeocodingDelimitationElement(delimitations) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.className = "GPflexInput";
    var label = document.createElement("label");
    label.className = "GPreverseGeocodingCodeLabel";
    label.innerHTML = "Délimitation";
    label.title = "Délimitation";
    div.appendChild(label);
    var select = document.createElement("select");
    select.className = "GPreverseGeocodingCode";
    // gestionnaire d'evenement : on stocke la valeur du type de délimitation,
    // et on modifie l'événement de pointage sur la carte en fonction
    if (select.addEventListener) {
      select.addEventListener("change", function (e) {
        context.onReverseGeocodingDelimitationChange(e);
      });
    } else if (select.attachEvent) {
      select.attachEvent("onchange", function (e) {
        context.onReverseGeocodingDelimitationChange(e);
      });
    }

    // on prend soit les valeurs passées par l'utilisateur, soit des valeurs par défaut
    if (!delimitations || !Array.isArray(delimitations)) {
      delimitations = ["Point", "Circle", "Extent"];
    }
    for (var i = 0; i < delimitations.length; i++) {
      switch (delimitations[i].toLowerCase()) {
        case "point":
          var pointOption = document.createElement("option");
          pointOption.value = "point";
          pointOption.text = "Pointer un lieu";
          select.appendChild(pointOption);
          break;
        case "circle":
          var circleOption = document.createElement("option");
          circleOption.value = "circle";
          circleOption.text = "Dessiner un cercle";
          select.appendChild(circleOption);
          break;
        case "extent":
          var extentOption = document.createElement("option");
          extentOption.value = "extent";
          extentOption.text = "Dessiner une emprise";
          select.appendChild(extentOption);
          break;
        default:
          break;
      }
    }
    div.appendChild(select);
    return div;
  },
  // ################################################################### //
  // ########################### Submit Form ########################### //
  // ################################################################### //

  /**
   * Create Submit Form Element
   *
   * @returns {DOMElement} DOM element
   */
  _createReverseGeocodingSubmitFormElement: function _createReverseGeocodingSubmitFormElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPreverseGeocodingSubmit");
    input.className = "GPinputSubmit";
    input.type = "submit";
    input.value = "Rechercher";
    return input;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ReverseGeocodingDOM);

/***/ }),
/* 125 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37);
/* harmony import */ var _LocationSelector__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(104);
/* harmony import */ var _Common_Controls_RouteDOM__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(126);






var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("route(plus)");

/**
 * @classdesc
 *
 * Leaflet Control Class to compute and display route between start and end points using routing service of the geoportal platform.
 *
 * Use {@link module:Controls.Route L.geoportalControl.Route()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.Route
 */
var Route = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends L.geoportalControl.Route.prototype */{
  includes: _Common_Controls_RouteDOM__WEBPACK_IMPORTED_MODULE_5__["default"],
  /**
   * Options du service
   *
   * @private
   */
  options: {
    position: "topleft",
    collapsed: true,
    // plier !
    graphs: ["Voiture", "Pieton"],
    exclusions: {
      toll: false,
      tunnel: false,
      bridge: false
    },
    disableReverse: false,
    routeOptions: {},
    // FIXME a t on besoin des options de ce service ?
    autocompleteOptions: {}
  },
  /**
   * @constructor Route
   * @private
   * @param {Object} options - options for function call.
   * @param {String}   [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {String}  [options.position = "topleft"] - position of component into the map, 'topleft' by default
   * @param {Boolean} [options.collapsed = false] - collapse mode, false by default
   * @param {Object}  [options.exclusions = {"toll" : false, "tunnel" : false, "bridge" : false}] - list of exclusions with status
   * @param {Array}   [options.graphs = ["Voiture", "Pieton"]] - list of resources, by default : ["Voiture", "Pieton"], and the first element is selected
   * @param {Boolean} [options.disableReverse = false] - whether to enable/disable the reverse geocoding
   * @param {Object}  [options.autocompleteOptions = {}] - options of autocomplete service
   * @param {Object}  [options.routeOptions = {}] - options of route service
   * @example
   *  var route = L.geoportalControl.Route({
   *      position : "topright",
   *      collapsed : true,
   *      exclusions : {
   *         "toll" : true,
   *         "bridge" : false,
   *         "tunnel" : true
   *      },
   *      graphs : ['Pieton', 'Voiture'],
   *      autocompleteOptions : {},
   *      routeOptions : {}
   *  });
   */
  initialize: function initialize(options) {
    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.setOptions(this, options);

    /** uuid */
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].generate();

    // initialisation
    this._initTransport();
    this._initExclusions();
    this._initComputation();

    /** container principaux */
    this._showRouteContainer = null;
    this._pictoRouteContainer = null;
    this._waitingContainer = null;
    this._formRouteContainer = null;
    this._resultsRouteContainer = null;

    /** detection du support : desktop ou tactile */
    this._isDesktop = this._detectSupport();

    /** liste de points selectionnée */
    this._currentPoints = [];

    /** Mode de transport selectionné : 'Voiture' ou 'Pieton' */
    this._currentTransport = null;

    /** Mode de calcul selectionné : 'Plus rapide' ou 'plus court' */
    this._currentComputation = null;

    /** Exclusions selectionnées : Tunnel, Toll et Bridge */
    this._currentExclusions = [];

    /** la geometrie du parcours */
    this._geojsonRoute = null;

    /** la geometrie des troncons */
    this._geojsonSections = null;

    /** si un calcul est en cours ou non */
    this._waiting = false;
    /** timer pour cacher la patience après un certain temps */
    this._timer = null;

    /**
     * reponse du service
     * Ex. {
     *   totalTime, totalDistance, bbox, routeGeometry,
     *   routeInstructions : [{duration, distance, code, instruction, bbox, geometry}]
     * }
     */
    this._currentRouteInformations = null;

    /**
     * liste des ressources avec droits par service
     * Ex. {
     *   "Route" : {
     *       key : "ger4g456re45er456t4er5ge5",
     *       resources : ["Pieton", "Voiture"]
     *   }
     * }
     */
    this._resources = {};
  },
  /**
   * this method is called by this.addTo(map) when the control is added on the map
   * and fills variable 'this._container = this.onAdd(map)',
   * and create or disable events on map.
   *
   * @param {Object} map - the map
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  onAdd: function onAdd(map) {
    // initialisation du DOM du composant
    var container = this._container = this._initLayout(map);

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    return container;
  },
  /**
   * TODO this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @private
   */
  onRemove: function onRemove( /* map */) {},
  // ################################################################### //
  // ####################### init application ########################## //
  // ################################################################### //

  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initTransport: function _initTransport() {
    // Mode de transport selectionné
    this._currentTransport = "Voiture"; // par defaut

    // par defaut
    var transport = this.options.graphs;
    if (!transport || transport.length === 0) {
      this.options.graphs = ["Voiture", "Pieton"];
    }

    // option
    if (leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.isArray(transport) && transport.length) {
      // FIXME pb si le 1er graphe n'est pas une ressource connue !
      if (transport[0] === "Voiture" || transport[0] === "Pieton") {
        this._currentTransport = transport[0];
      }
    }

    // TODO option sur le service
    var serviceOptions = this.options.routeOptions;
    if (serviceOptions.graph) {
      this._currentTransport = serviceOptions.graph;
    }
  },
  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initComputation: function _initComputation() {
    // Mode de calcul selectionné
    this._currentComputation = "fastest"; // par defaut

    // TODO option sur le service
    var serviceOptions = this.options.routeOptions;
    if (serviceOptions.routePreference) {
      this._currentComputation = serviceOptions.routePreference;
    }
  },
  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initExclusions: function _initExclusions() {
    // Exclusions selectionnées : Tunnel, Toll et Bridge
    this._currentExclusions = []; // par defaut

    // par defaut
    var exclusion = this.options.exclusions;
    if (!exclusion || Object.keys(exclusion).length === 0) {
      this.options.exclusions = {
        toll: false,
        tunnel: false,
        bridge: false
      };
    }

    // option
    if (exclusion && Object.keys(exclusion).length) {
      for (var k in exclusion) {
        if (exclusion.hasOwnProperty(k)) {
          if (exclusion.k) {
            this._currentExclusions.push(k);
          }
        }
      }
    }

    // TODO option sur le service
    var serviceOptions = this.options.routeOptions;
    if (leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.isArray(serviceOptions.exclusions)) {
      this._currentExclusions = serviceOptions.exclusions;
    }
  },
  // ################################################################### //
  // ############################## other init ######################### //
  // ################################################################### //

  /**
   * TODO this method is called by the constructor.
   * this information is useful to switch to touch mode.
   * Detection : test for desktop or tactile
   *
   * @returns {Boolean} is desktop
   *
   * @private
   */
  _detectSupport: function _detectSupport() {
    // TODO
    // Choix de gérer la détection dans le code du composant au lieu du DOM car :
    // Utilisation de l'implémentation Leaflet
    // http://leafletjs.com/reference.html#browser

    var isDesktop = true;
    var userAgent = window.navigator.userAgent.toLowerCase();
    if (userAgent.indexOf("iphone") !== -1 || userAgent.indexOf("ipod") !== -1 || userAgent.indexOf("ipad") !== -1 || userAgent.indexOf("android") !== -1 || userAgent.indexOf("mobile") !== -1 || userAgent.indexOf("blackberry") !== -1 || userAgent.indexOf("tablet") !== -1 || userAgent.indexOf("phone") !== -1 || userAgent.indexOf("touch") !== -1) {
      isDesktop = false;
    }
    if (userAgent.indexOf("msie") !== -1 || userAgent.indexOf("trident") !== -1) {
      isDesktop = true;
    }
    return isDesktop;
  },
  // ################################################################### //
  // ########################### init dom ############################## //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @param {Object} map - the map
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  _initLayout: function _initLayout(map) {
    // create main container
    var container = this._createMainContainerElement();
    var inputShow = this._showRouteContainer = this._createShowRouteElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (!this.options.collapsed) {
      inputShow.checked = true;
    }
    var picto = this._pictoRouteContainer = this._createShowRoutePictoElement();
    container.appendChild(picto);
    var routePanel = this._createRoutePanelElement();

    // header form
    var routeHeader = this._createRoutePanelHeaderElement();
    routePanel.appendChild(routeHeader);

    // form
    var routeForm = this._formRouteContainer = this._createRoutePanelFormElement();

    // form: menu des points
    var points = this._createRoutePanelFormPointsElement(map);
    for (var i = 0; i < points.length; i++) {
      routeForm.appendChild(points[i]);
    }

    // form: menu des modes
    var choice = this._createRoutePanelFormModeChoiceElement();
    choice.appendChild(this._createRoutePanelFormModeChoiceTransportElement(this.options.graphs));
    choice.appendChild(this._createRoutePanelFormModeChoiceComputeElement());
    routeForm.appendChild(choice);

    // form: menu des exclusions
    routeForm.appendChild(this._createShowRouteExclusionsElement());
    routeForm.appendChild(this._createShowRouteExclusionsPictoElement());
    var exclusion = this._createRoutePanelFormExclusionsElement();
    exclusion.appendChild(this._createRoutePanelFormExclusionOptionsElement(this.options.exclusions));
    routeForm.appendChild(exclusion);

    // form: bouton du calcul
    var submit = this._createRouteSubmitFormElement();
    routeForm.appendChild(submit);
    routePanel.appendChild(routeForm);

    // results
    var routeResults = this._resultsRouteContainer = this._createRoutePanelResultsElement();
    routePanel.appendChild(routeResults);

    // waiting
    var waiting = this._waitingContainer = this._createRouteWaitingElement();
    routePanel.appendChild(waiting);
    container.appendChild(routePanel);
    return container;
  },
  // ################################################################### //
  // ############################## DOM ################################ //
  // ################################################################### //

  /**
   * Create List Points
   * FIXME OVERWRITTEN RouteDOM._createRoutePanelFormPointsElement() !
   *
   * @param {Object} map - the map
   *
   * @returns {Array} List DOM element
   *
   * @private
   */
  _createRoutePanelFormPointsElement: function _createRoutePanelFormPointsElement(map) {
    var points = [];
    var count = 1;
    // point de depart
    var start = new _LocationSelector__WEBPACK_IMPORTED_MODULE_4__["default"]({
      apiKey: this.options.apiKey || null,
      tag: {
        id: count,
        unique: this._uid,
        label: "Départ",
        color: "blue",
        display: true
      },
      disableReverse: this.options.disableReverse,
      autocompleteOptions: this.options.autocompleteOptions || null
    });
    start.setMap(map);
    var opts = this.options.routeOptions;
    if (opts.startPoint) {
      start._inputAutoCompleteContainer.value = opts.startPoint.x + " , " + opts.startPoint.y;
      start.setCoordinate({
        lng: opts.startPoint.x,
        lat: opts.startPoint.y
      });
    }
    points.push(start.getContainer());
    this._currentPoints.push(start);
    // points intermediaires
    for (count = 2; count < 7; count++) {
      var step = new _LocationSelector__WEBPACK_IMPORTED_MODULE_4__["default"]({
        apiKey: this.options.apiKey || null,
        tag: {
          id: count,
          unique: this._uid,
          label: "Etape",
          color: "green",
          display: false,
          removeOption: true
        },
        disableReverse: this.options.disableReverse,
        autocompleteOptions: this.options.autocompleteOptions || null
      });
      step.setMap(map);
      points.push(step.getContainer());
      this._currentPoints.push(step);
    }
    // point d'arrivé
    var end = new _LocationSelector__WEBPACK_IMPORTED_MODULE_4__["default"]({
      apiKey: this.options.apiKey || null,
      tag: {
        id: count,
        unique: this._uid,
        label: "Arrivée",
        color: "red",
        display: true,
        addOption: true,
        removeOption: false
      },
      disableReverse: this.options.disableReverse,
      autocompleteOptions: this.options.autocompleteOptions || null
    });
    end.setMap(map);
    if (opts.endPoint) {
      end._inputAutoCompleteContainer.value = opts.endPoint.x + " , " + opts.endPoint.y;
      end.setCoordinate({
        lng: opts.endPoint.x,
        lat: opts.endPoint.y
      });
    }
    points.push(end.getContainer());
    this._currentPoints.push(end);
    return points;
  },
  // ################################################################### //
  // ####################### handlers events to dom #################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on ''
   * tag label (cf. this._createShowRoutePictoElement),
   * and it cleans all value of input.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowRoutePanelClick: function onShowRoutePanelClick(e) {
    logger.log("onShowRoutePanelClick", e);
    // clean !
    if (!this._geojsonSections) {
      this._clear();
    }
  },
  /**
   * this method is called by event 'change' on '' tag select
   * (cf. this.).
   * this value is saved as a parameter for the service route.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteModeComputationChange: function onRouteModeComputationChange(e) {
    logger.log("onRouteModeComputationChange", e);
    var idx = e.target.selectedIndex;
    var value = e.target.options[idx].value;
    if (!value) {
      return;
    }
    logger.log(value);
    this._currentComputation = value;
  },
  /**
   * this method is called by event 'change' on '' tag select
   * (cf. this.).
   * this value is saved as a parameter for the service route,
   * and this launches the route request !
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteModeComputationChangeAndRun: function onRouteModeComputationChangeAndRun(e) {
    logger.log("onRouteModeComputationChangeAndRun", e);

    // event choice computation
    this.onRouteModeComputationChange(e);

    // clean avant un nouveau calcul !
    this._clearRouteResultsDetails();
    this._clearRouteResultsGeometry();
    this._clearRouteResultsFeatureGeometry();

    // submit request
    this.onRouteComputationSubmit({
      computation: this._currentComputation,
      transport: this._currentTransport,
      exclusions: this._currentExclusions
    });
  },
  /**
   * this method is called by event 'change' on '' tag input
   * (cf. this.).
   * this value is saved as a parameter for the service route.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteModeTransportChange: function onRouteModeTransportChange(e) {
    logger.log("onRouteModeTransportChange", e);
    var value = e.target.value;
    if (!value) {
      return;
    }
    logger.log(value);
    this._currentTransport = value;
  },
  /**
   * this method is called by event 'click' on '' tag input
   * (cf. this.), and it displays the panel options of exclusions.
   * Not use !
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowRouteExclusionsClick: function onShowRouteExclusionsClick(e) {
    logger.log("onShowRouteExclusionsClick", e);
    // not use !
  },
  /**
   * this method is called by event 'change' on '' tag input
   * (cf. this.).
   * this value is saved as a parameter for the service route.
   * Not use !
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteExclusionsChange: function onRouteExclusionsChange(e) {
    logger.log("onRouteExclusionsChange", e);
    var value = e.target.value;
    var checked = e.target.checked;
    if (!value) {
      return;
    }
    logger.log(value, checked);
    var bFound = false;
    var iFound = null;
    for (var i = 0; i < this._currentExclusions.length; i++) {
      if (this._currentExclusions[i] === value) {
        iFound = i;
        bFound = true;
      }
    }
    // on l'ajoute si la valeur n'existe pas et est selectionnée
    if (!bFound && checked) {
      this._currentExclusions.push(value);
    }
    // on la retire si la valeur existe et est desselectionnée
    if (bFound && !checked) {
      this._currentExclusions[iFound] = null;
    }
  },
  /**
   * this method is called by event 'submit' on '' tag form
   * (cf. this.), and it displays the results.
   *
   * @param {Object} options - options
   *
   * @private
   */
  onRouteComputationSubmit: function onRouteComputationSubmit(options) {
    logger.log("onRouteComputationSubmit", options);

    // FIXME on lance une requête en EPSG:4326, les coordonnées
    // doivent donc être du type cad en lat/lon.
    // hors, BUG du service du calcul d'itineraire car les
    // coordonnées envoyées doivent être en lon/lat avec une SRS en EPSG:4326 !?
    // sinon, ça plante...

    // Liste des points
    var points = this._currentPoints;

    // - point de depart
    var start;
    if (points[0].getCoordinate) {
      var startCoordinate = points[0].getCoordinate();
      start = {
        x: startCoordinate.lon || startCoordinate.lng,
        y: startCoordinate.lat
      };
    }
    points[0].dragging(false);
    logger.log("start", start);
    // - point d'arrivée
    var end;
    if (points[points.length - 1] && points[points.length - 1].getCoordinate) {
      var endCoordinate = points[points.length - 1].getCoordinate();
      end = {
        x: endCoordinate.lon || endCoordinate.lng,
        y: endCoordinate.lat
      };
    }
    points[points.length - 1].dragging(false);
    logger.log("end", end);
    // - les étapes
    var step = [];
    for (var i = 1; i < points.length - 1; i++) {
      if (points[i] && points[i].getCoordinate) {
        var iCoordinate = points[i].getCoordinate();
        if (iCoordinate) {
          var coordinate = {
            x: iCoordinate.lon || iCoordinate.lng,
            y: iCoordinate.lat
          };
          logger.log("step", coordinate);
          step.push(coordinate);
        }
      }
    }

    // valeurs selectionnées
    this._currentTransport = options.transport;
    this._currentComputation = options.computation;
    this._currentExclusions = options.exclusions;

    // on recupere les éventuelles options du service passées par l'utilisateur
    var routeOptions = this.options.routeOptions;

    // OVERLOAD : la resource bd-topo-osrm ne gère pas le calcul piéton en mode fastest
    // dans ce cas, on utilise valhalla dans le cas d'une utilisation par défaut du widget
    // sans paramétrage de resource explicitement demandé
    var routeResource;
    if (!routeOptions.resource) {
      if (this._currentComputation === "fastest" && this._currentTransport === "Pieton") {
        routeResource = "bdtopo-valhalla";
      }
    } else {
      routeResource = routeOptions.resource;
    }
    if (typeof this.options.routeOptions.geometryInInstructions === "undefined") {
      this.options.routeOptions.geometryInInstructions = true;
    }

    // mise en place de la patience
    this._displayWaitingContainer();

    // on met en place l'affichage des resultats dans la fenetre de resultats.
    var context = this;
    this._requestRouting({
      startPoint: start,
      endPoint: end,
      viaPoints: step,
      graph: this._currentTransport,
      routePreference: this._currentComputation,
      resource: routeResource,
      exclusions: this._currentExclusions,
      geometryInInstructions: this.options.routeOptions.geometryInInstructions,
      distanceUnit: "m",
      // surcharge obligatoire !
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results) {
          context._fillRouteResultsDetails(results);
          if (context.options.routeOptions.onSuccess) {
            context.options.routeOptions.onSuccess(results);
          }
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME mise à jour du controle mais le service ne repond pas en 200 !?
        context._hideWaitingContainer();
        context._clearRouteResultsDetails();
        logger.log(error.message);
      }
    });
  },
  /**
   * this method is called by event 'click' on ''
   * tag label (cf. this.),
   * and it cleans the old route geometry.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowRouteResultsNewClick: function onShowRouteResultsNewClick(e) {
    logger.log("onShowRouteResultsNewClick", e);

    // on reactive le drag&drop
    var points = this._currentPoints;
    for (var i = 0; i < points.length; i++) {
      points[i].dragging(true);
    }

    // clean avant un nouveau calcul !
    this._clearRouteResultsDetails();
    this._clearRouteResultsGeometry();
    this._clearRouteResultsFeatureGeometry();
  },
  /**
   * this method is called by event 'mouseover' on ''
   * tag label (cf. this.),
   * and it makes a style on feature route.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteResultsDetailsMouseOver: function onRouteResultsDetailsMouseOver(e) {
    logger.log("onRouteResultsDetailsMouseOver", e);
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);

    // valable uniquement pour le mode desktop !
    if (!this._isDesktop) {
      return;
    }
    if (!this._geojsonSections) {
      return;
    }
    this._geojsonSections.eachLayer(function (layer) {
      if (layer.feature.id === parseInt(idx, 10)) {
        layer.setStyle({
          weight: 10,
          color: "#0F9DE8",
          opacity: 0.5
        });
      }
    });
  },
  /**
   * this method is called by event 'mouseout' on ''
   * tag label (cf. this.),
   * and it deletes a style on feature route.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteResultsDetailsMouseOut: function onRouteResultsDetailsMouseOut(e) {
    logger.log("onRouteResultsDetailsMouseOut", e);
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);

    // valable uniquement pour le mode desktop !
    if (!this._isDesktop) {
      return;
    }
    if (!this._geojsonSections) {
      return;
    }
    this._geojsonSections.eachLayer(function (layer) {
      if (layer.feature.id === parseInt(idx, 10)) {
        layer.setStyle({
          color: "#ED7F10",
          weight: 5,
          opacity: 0.75
        });
      }
    });
  },
  /**
   * this method is called by event 'click' on ''
   * tag label (cf. this.),
   * and it deletes a style on feature route.
   * Only for mobile !
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onRouteResultsDetailsClick: function onRouteResultsDetailsClick(e) {
    logger.log("onRouteResultsDetailsClick", e);
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);
    var self = this;

    // valable uniquement pour le mode mobile !
    if (this._isDesktop) {
      return;
    }
    if (!this._geojsonSections) {
      return;
    }

    // afficher le detail cumulé du parcours !
    var newInstruction = e.target.title;
    var oldInstruction = e.target.innerHTML;
    this._geojsonSections.eachLayer(function (layer) {
      if (layer.feature.id === parseInt(idx, 10)) {
        e.target.innerHTML = newInstruction;
        layer.setStyle({
          weight: 10,
          color: "#0F9DE8",
          opacity: 0.5
        });
      }
    });
    clearTimeout(1000);
    setTimeout(function () {
      self._geojsonSections.eachLayer(function (layer) {
        if (layer.feature.id === parseInt(idx, 10)) {
          e.target.innerHTML = oldInstruction;
          layer.setStyle({
            color: "#ED7F10",
            weight: 5,
            opacity: 0.75
          });
        }
      });
    }, 1000);
  },
  // ################################################################### //
  // ########################### Routing ############################### //
  // ############## (methods to request and results) ################### //

  /**
   * this method is called by this.onRouteComputationSubmit()
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   * @param {Function} settings.onSuccess - callback
   * @param {Function} settings.onFailure - callback
   *
   * @private
   */
  _requestRouting: function _requestRouting(settings) {
    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si
    // - la parametre 'startPoint' est vide !
    if (!settings.startPoint) {
      return;
    }
    // - la parametre 'endPoint' est vide !
    if (!settings.endPoint) {
      return;
    }
    logger.log(settings);
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.routeOptions);
    // ainsi que les parametres de saisie et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);

    // cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle ou la clé "calcul" par défaut
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: this.options.routeOptions.apiKey || this.options.apiKey
    });

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      ssl: this.options.ssl
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.route(options);
  },
  /**
   * this method is called by this.onRouteComputationSubmit()
   * and fills the container of the route instructions list, distance and time
   * information, aslo, constructs the geometry route.
   *
   * @param {Object} results - results of the route calculation
   *
   * @private
   */
  _fillRouteResultsDetails: function _fillRouteResultsDetails(results) {
    // FIXME
    // gestion des temps de traitement avec des callback !?

    // Distance et Durée
    var distance = results.totalDistance;
    var duration = results.totalTime;
    // Détails avec simplifications des troncons
    var instructions = this._simplifiedInstructions(results.routeInstructions);
    // var instructions = results.routeInstructions;

    if (instructions) {
      this._fillRouteResultsDetailsContainer(distance, duration, instructions);
    }

    // Geometries simplifiées
    var geometry = results.routeGeometry;
    if (geometry) {
      this._fillRouteResultsDetailsGeometry(geometry);
    }
    if (this.options.routeOptions.geometryInInstructions) {
      // existe t il une geometrie pour chaque troncon de route ?
      var bGeometryInstructions = instructions && Array.isArray(instructions) && instructions[0].geometry.length !== 0;

      // Geometries des tronçon
      if (instructions && bGeometryInstructions) {
        this._fillRouteResultsDetailsFeatureGeometry(instructions);
      }
    }

    // Emprise
    var bbox = results.bbox;
    if (bbox) {
      var map = this._map;
      var bounds = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLngBounds([bbox.bottom, bbox.left], [bbox.top, bbox.right]);
      map.fitBounds(bounds, {
        padding: [1, 1]
      });
    }

    // sauvegarde de l'etat des resultats
    this._currentRouteInformations = results;

    // mise à jour du controle !
    this._formRouteContainer.className = "GProuteComponentHidden";
    this._hideWaitingContainer();
    this._resultsRouteContainer.className = "";
  },
  /**
   * this method is called by this._fillRouteResultsDetails()
   * and fills the container of the route instructions list, distance and time
   * information.
   *
   * @param {Number} distance - distance
   * @param {Number} duration - duration
   * @param {Object[]} instructions - list of instructions
   *
   * @private
   */
  _fillRouteResultsDetailsContainer: function _fillRouteResultsDetailsContainer(distance, duration, instructions) {
    // FIXME callback

    // Distance et Durée
    this._resultsRouteValuesContainer = this._addRouteResultsValuesElement(distance, duration, this._convertSecondsToTime);

    // Détails
    this._resultsRouteDetailsContainer = this._addRouteResultsDetailsElement(instructions, this._convertSecondsToTime);
  },
  /**
   * this method is called by this._fillRouteResultsDetails()
   * and constructs the simplified geometry route.
   *
   * @param {Object} geometry - geometry
   *
   * @private
   */
  _fillRouteResultsDetailsGeometry: function _fillRouteResultsDetailsGeometry(geometry) {
    // FIXME callback

    this._clearRouteResultsGeometry();
    var map = this._map;
    var _style = {
      color: "#ED7F10",
      weight: 5,
      opacity: 0.75
    };
    this._geojsonRoute = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoJson(geometry, {
      style: _style
    }).addTo(map);
  },
  /**
   * this method is called by this._fillRouteResultsDetails()
   * and constructs the geometries street with informations.
   *
   * @param {Object[]} instructions - instructions
   *
   * @private
   */
  _fillRouteResultsDetailsFeatureGeometry: function _fillRouteResultsDetailsFeatureGeometry(instructions) {
    // FIXME callback

    this._clearRouteResultsFeatureGeometry();
    var map = this._map;
    var _style = {
      color: "#ED7F10",
      weight: 5,
      opacity: 0.75
    };
    var _geometry = {
      type: "FeatureCollection",
      features: []
    };
    for (var i = 0; i < instructions.length; i++) {
      var o = instructions[i];
      var id = i + 1;
      _geometry.features.push({
        id: id,
        type: "Feature",
        geometry: o.geometry,
        properties: {
          popupContent: "(" + id + ") distance : " + this._convertDistance(o.distance) + " / temps : " + this._convertSecondsToTime(o.duration)
        }
      });
    }
    var self = this;
    function resetHighlight(e) {
      var layer = e.target;
      self._geojsonSections.resetStyle(layer);
      var div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteResultsDetailsInstruction_" + layer.feature.id + "-" + self._uid);
      leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.removeClass(div, "GProuteResultsDetailsHighlight");
    }
    function highlightFeature(e) {
      var layer = e.target;
      logger.log(layer);
      layer.setStyle({
        weight: 10,
        color: "#0F9DE8",
        opacity: 0.5
      });
      var div = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteResultsDetailsInstruction_" + layer.feature.id + "-" + self._uid);
      leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.addClass(div, "GProuteResultsDetailsHighlight");
    }
    this._geojsonSections = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.geoJson(_geometry, {
      style: _style,
      // Function that will be called on each created feature layer.
      onEachFeature: function onEachFeature(feature, layer) {
        layer.on({
          mouseover: highlightFeature,
          mouseout: resetHighlight
        });
        layer.bindPopup(feature.properties.popupContent);
      }
    }).addTo(map);
  },
  // ################################################################### //
  // ############################# Clean ############################### //
  // ################################################################### //

  /**
   * this method is called by this.onShowRoutePanelClick()
   * and it clears all elements (reinit).
   *
   * @private
   */
  _clear: function _clear() {
    this._currentTransport = null;
    this._currentExclusions = [];
    this._currentComputation = null;

    // les resultats
    this._clearRouteResultsDetails();
    // la geometrie
    this._clearRouteResultsGeometry();
    this._clearRouteResultsFeatureGeometry();
    // les points
    for (var i = 0; i < this._currentPoints.length; i++) {
      this._currentPoints[i].clear();
    }
  },
  /**
   * this method is called by this.onRouteComputationSubmit()
   * and it clears all route instructions.
   *
   * @private
   */
  _clearRouteResultsDetails: function _clearRouteResultsDetails() {
    this._currentRouteInformations = null;

    // doit on nettoyer le container "GProuteResultsDetails" ?
    // il sera de toute façon écrasé par la prochaine requête...
    if (this._resultsRouteDetailsContainer) {
      var divD = this._resultsRouteDetailsContainer;
      if (divD.childElementCount) {
        while (divD.firstChild) {
          divD.removeChild(divD.firstChild);
        }
      }
    }
    if (this._resultsRouteValuesContainer) {
      var divV = this._resultsRouteValuesContainer;
      if (divV.childElementCount) {
        while (divV.firstChild) {
          divV.removeChild(divV.firstChild);
        }
      }
    }
  },
  /**
   * this method is called by this.onRouteComputationSubmit()
   * and it clears all route geometries.
   *
   * @private
   */
  _clearRouteResultsGeometry: function _clearRouteResultsGeometry() {
    var map = this._map;
    if (this._geojsonRoute != null) {
      map.removeLayer(this._geojsonRoute);
      this._geojsonRoute = null;
    }
  },
  /**
   * this method is called by this.onRouteComputationSubmit()
   * and it clears all route geometries.
   *
   * @private
   */
  _clearRouteResultsFeatureGeometry: function _clearRouteResultsFeatureGeometry() {
    var map = this._map;
    if (this._geojsonSections != null) {
      map.removeLayer(this._geojsonSections);
      this._geojsonSections = null;
    }
  },
  // ################################################################### //
  // ############################ Patience ############################# //
  // ################################################################### //

  /**
   * this method displays waiting container and sets a timeout
   *
   * @private
   */
  _displayWaitingContainer: function _displayWaitingContainer() {
    this._waitingContainer.className = "GProuteCalcWaitingContainerVisible";
    this._waiting = true;

    // mise en place d'un timeout pour réinitialiser le panel (cacher la patience)
    // si on est toujours en attente (si la requête est bloquée par exemple)
    if (this._timer) {
      clearTimeout(this._timer);
      this._timer = null;
    }
    var context = this;
    this._timer = setTimeout(function () {
      if (context._waiting === true) {
        context._hideWaitingContainer();
      } else {
        if (context._timer) {
          clearTimeout(context._timer);
        }
      }
    }, 16000);
  },
  /**
   * this method hides waiting container and clears timeout
   *
   * @private
   */
  _hideWaitingContainer: function _hideWaitingContainer() {
    if (this._waiting) {
      this._waitingContainer.className = "GProuteCalcWaitingContainerHidden";
      this._waiting = false;
      clearTimeout(this._timer);
      this._timer = null;
    }
  },
  // ################################################################### //
  // ########################## Geometry ############################### //
  // ################################################################### //

  /**
   * simplifies instructions
   *
   * @param {Object[]} instructions - instructions
   *
   * @returns {Object[]} simplified instructions
   *
   * @private
   */
  _simplifiedInstructions: function _simplifiedInstructions(instructions) {
    var newInstructions = [];
    var current = instructions[0];
    // cas où...
    if (instructions.length === 1) {
      newInstructions.push(current);
    }
    for (var i = 1; i < instructions.length; i++) {
      var o = instructions[i];
      if (o.instruction === current.instruction) {
        current.distance = (parseFloat(o.distance) + parseFloat(current.distance)).toString();
        current.duration = (parseFloat(o.duration) + parseFloat(current.duration)).toString();
        for (var j = 1; j < o.geometry.coordinates.length; j++) {
          current.geometry.coordinates.push(o.geometry.coordinates[j]);
        }
        // last
        if (i === instructions.length - 1) {
          newInstructions.push(current);
          current = null;
        }
      } else {
        newInstructions.push(current);
        current = o;
        // last
        if (i === instructions.length - 1) {
          newInstructions.push(o);
          current = null;
        }
      }
    }
    logger.log(newInstructions);
    return newInstructions;
  },
  // ################################################################### //
  // ################# Utils for Distance/Duration ##################### //
  // ################################################################### //

  /**
   * convert seconds to time : HH:MM:SS
   *
   * @param {Number} duration - duration in seconds
   *
   * @returns {String} duration in HH:MM:SS
   *
   * @private
   */
  _convertSecondsToTime: function _convertSecondsToTime(duration) {
    var time = "";
    duration = Math.round(duration);
    var hours = Math.floor(duration / (60 * 60));
    if (!hours) {
      hours = "00";
    }
    var divisor4minutes = duration % (60 * 60);
    var minutes = Math.floor(divisor4minutes / 60);
    if (!minutes) {
      minutes = "00";
    }
    var divisor4seconds = divisor4minutes % 60;
    var seconds = Math.ceil(divisor4seconds);
    if (!seconds) {
      seconds = "00";
    }
    time = hours + "h " + minutes + "m " + seconds + "s";
    return time;
  },
  /**
   * convert distance in meters or kilometers
   *
   * @param {Number} distance - distance in meters
   *
   * @returns {String} distance in km
   *
   * @private
   */
  _convertDistance: function _convertDistance(distance) {
    var d = "";
    var distanceKm = parseInt(distance / 1000, 10);
    if (!distanceKm) {
      d = parseInt(distance, 10) + " m"; // arrondi !
    } else {
      d = distanceKm + " km";
    }
    return d;
  },
  // ################################################################### //
  // ###### METHODES PUBLIQUES (INTERFACE AVEC LE CONTROLE) ############ //
  // ################################################################### //

  /**
   * This method is public.
   * It allows to control the execution of a traitment.
   *
   * @param {Object} positions - positions = [{lng: , lat: }]
   * @param {Object} options - options = {...}
   */
  compute: function compute(positions, options) {
    if (!this._showRouteContainer.checked) {
      this._pictoRouteContainer.click();
    }
    var map = this._map;
    if (!map) {
      return;
    }

    // Les options par defauts
    var settings = {
      computation: "fastest",
      transport: "Voiture",
      exclusions: []
    };

    // On recupere les options
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(settings, options);

    // Liste des points !
    var points = this._currentPoints;
    var start = 0;
    points[start].setCoordinate(positions[start]);
    var startInput = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPlocationOrigin_" + 1 + "-" + this._uid);
    startInput.value = positions[start].lng + " , " + positions[start].lat;
    var end = positions.length - 1;
    points[6].setCoordinate(positions[end]);
    var endInput = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPlocationOrigin_" + 7 + "-" + this._uid);
    endInput.value = positions[end].lng + " , " + positions[end].lat;
    for (var i = 1; i < positions.length - 1; i++) {
      points[i].setCoordinate(positions[i]);
      var stepInput = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPlocationOrigin_" + i + "-" + this._uid);
      stepInput.value = positions[i].lng + " , " + positions[i].lat;
    }
    settings.transport === "Voiture" ? leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteTransportCar-" + this._uid).checked = true : leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteTransportPedestrian-" + this._uid).checked = true;
    settings.computation === "fastest" ? leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteComputationSelect-" + this._uid).selectedIndex = 0 : leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GProuteComputationSelect-" + this._uid).selectedIndex = 1;

    // TODO exclusion !

    // Calcul
    this.onRouteComputationSubmit(settings);
  }
});
/* harmony default export */ __webpack_exports__["default"] = (Route);

/***/ }),
/* 126 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(37);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(106);



var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("RouteDOM");
var RouteDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GProute");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################# Methods to display Main Panel ################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing panel
   *
   * @returns {DOMElement} DOM element
   */
  _createShowRouteElement: function _createShowRouteElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowRoute");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show route control
   * see event !
   *
   * @returns {DOMElement} DOM element
   */
  _createShowRoutePictoElement: function _createShowRoutePictoElement() {
    // contexte d'execution
    var context = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowRoutePicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowRoute");
    label.title = "Ouvrir le calcul d'itinéraire";

    // gestionnaire d'evenement :
    // on ouvre le menu de saisie du calcul d'itiniraire
    // L'ouverture/Fermeture permet de faire le menage
    // (reinitialisation)
    if (label.addEventListener) {
      label.addEventListener("click", function (e) {
        context.onShowRoutePanelClick(e);
      });
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function (e) {
        context.onShowRoutePanelClick(e);
      });
    }
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowRouteOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  // ################################################################### //
  // ################## Methods to display Inputs Panel ################ //
  // ################################################################### //

  /**
   * Create Container Panel
   *
   * FIXME
   * don't call this._createRoutePanelHeaderElement
   * don't call this._createRoutePanelFormElement
   * don't call this._createRoutePanelResultsElement
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelElement: function _createRoutePanelElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GProutePanel");
    div.className = "GPpanel";

    // div.appendChild(this._createRoutePanelHeaderElement());
    // div.appendChild(this._createRoutePanelFormElement());
    // div.appendChild(this._createRoutePanelResultsElement());

    return div;
  },
  /**
   * Create Header Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelHeaderElement: function _createRoutePanelHeaderElement() {
    // contexte d'execution
    var self = this;
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var div = document.createElement("div");
    div.className = "GPpanelTitle";
    div.innerHTML = "Calcul d'itinéraire";
    container.appendChild(div);
    var divClose = document.createElement("div");
    divClose.id = this._addUID("GProutePanelClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Masquer le panneau";

    // Link panel close / visibility checkbox
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPshowRoutePicto")).click();
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPshowRoutePicto")).click();
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * Create Form
   * see evenement !
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormElement: function _createRoutePanelFormElement() {
    // contexte d'execution
    var self = this;
    var form = document.createElement("form");
    form.id = this._addUID("GProuteForm");
    form.setAttribute("onkeypress", "return event.keyCode != 13;"); // FIXME hack pour desactiver l'execution via 'enter' au clavier !

    form.addEventListener("submit", function (e) {
      logger.log(e);
      e.preventDefault();

      // points
      var points = document.getElementsByClassName(self._addUID("GPlocationPoint"));

      // Must have at least two origin points
      var start = points[0].childNodes[0].id;
      var end = points[points.length - 1].childNodes[0].id;
      var startID = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(start);
      var endID = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(end);
      if (document.getElementById(self._addUID("GPlocationOrigin_" + startID)).value === "" && document.getElementById(self._addUID("GPlocationOriginCoords_" + startID)).value === "" || document.getElementById(self._addUID("GPlocationOrigin_" + endID)).value === "" && document.getElementById(self._addUID("GPlocationOriginCoords_" + endID)).value === "") {
        return false;
      }

      // Send stages to results panel
      self._addRouteResultsStagesValuesElement(points);

      // on peut récuperer les valeurs utiles pour les transmettre au service d'iti...
      // - le mode de calcul
      // - le mode de transport
      // - les exclusions
      // Les points sont déjà stockés dans l'application.

      // computation mode params
      var modeComputation = null;
      if (document.getElementById(self._addUID("GProuteComputationSelect"))) {
        var select = document.getElementById(self._addUID("GProuteResultsComputationSelect"));
        select.selectedIndex = document.getElementById(self._addUID("GProuteComputationSelect")).selectedIndex;
        modeComputation = select.options[select.selectedIndex].value;
      }

      // transport mode params
      var modeTransport = null;
      // voiture ?
      if (document.getElementById(self._addUID("GProuteTransportCar"))) {
        if (document.getElementById(self._addUID("GProuteTransportCar")).checked) {
          modeTransport = document.getElementById(self._addUID("GProuteTransportCar")).value;
        }
      }
      // pieton ?
      if (document.getElementById(self._addUID("GProuteTransportPedestrian"))) {
        if (document.getElementById(self._addUID("GProuteTransportPedestrian")).checked) {
          modeTransport = document.getElementById(self._addUID("GProuteTransportPedestrian")).value;
        }
      }

      // exclusions params
      var exclusions = [];
      var exclusionsElement = document.getElementsByClassName("GProuteExclusionsOption");
      for (var j = 0; j < exclusionsElement.length; j++) {
        var id = exclusionsElement[j].htmlFor;
        var el = document.getElementById(id);
        if (!el.checked) {
          exclusions.push(el.value);
        }
      }
      self.onRouteComputationSubmit({
        computation: modeComputation,
        transport: modeTransport,
        exclusions: exclusions
      });

      // FIXME mise à jour du controle dans le composant JS !
      // document.getElementById(self._addUID("GProuteForm")).className = "GProuteComponentHidden";
      // document.getElementById(self._addUID("GProuteResultsPanel")).className = "";

      return false;
    });
    return form;
  },
  /**
   * Create Results Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelResultsElement: function _createRoutePanelResultsElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GProuteResultsPanel");
    container.className = "GProuteComponentHidden";
    container.appendChild(this._createRouteResultsStagesElement());
    container.appendChild(this._createRouteResultsElement());
    var divBorderUp = document.createElement("div");
    divBorderUp.className = "GPfakeBorder GPfakeBorderLeft";
    container.appendChild(divBorderUp);
    container.appendChild(this._createRouteShowResultsDetailsElement());
    var labelShow = document.createElement("label");
    labelShow.htmlFor = this._addUID("GProuteResultsShowDetails");
    labelShow.innerHTML = "Afficher le détail";
    container.appendChild(labelShow);
    var labelHide = document.createElement("label");
    labelHide.htmlFor = this._addUID("GProuteResultsShowDetails");
    labelHide.innerHTML = "Masquer le détail";
    container.appendChild(labelHide);
    var divBorderDown = document.createElement("div");
    divBorderDown.className = "GPfakeBorder";
    container.appendChild(divBorderDown);
    container.appendChild(this._createRouteResultsDetailsElement());
    return container;
  },
  /**
   * Create Waiting Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteWaitingElement: function _createRouteWaitingElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GProuteCalcWaitingContainer");
    div.className = "GProuteCalcWaitingContainerHidden";
    var p = document.createElement("p");
    p.className = "GProuteCalcWaiting";
    p.innerHTML = "Calcul en cours...";
    div.appendChild(p);
    return div;
  },
  // ################################################################### //
  // ############### Methods to the window results ##################### //
  // ################################################################### //

  /**
   * Create Results Stages
   * (results dynamically generate !)
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteResultsStagesElement: function _createRouteResultsStagesElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GProuteResultsStages");
    return div;
  },
  /**
   * Add Stages Results
   *
   * @param {DOMElement} points - list of points
   */
  _addRouteResultsStagesValuesElement: function _addRouteResultsStagesValuesElement(points) {
    document.getElementById(this._addUID("GProuteResultsStages")).innerHTML = "";
    for (var i = 0; i < points.length; i++) {
      var tag = points[i].childNodes[0].id;
      var id = _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(tag);
      if (document.getElementById(this._addUID("GPlocationPoint_" + id)).className === "GPflexInput GPlocationStageFlexInput") {
        var resultStage = document.createElement("div");
        resultStage.className = "GProuteResultsStages";
        var resultStageLabel = document.createElement("div");
        resultStageLabel.className = "GProuteResultStageLabel";
        resultStageLabel.innerHTML = document.getElementById(this._addUID("GPlocationOriginLabel_" + id)).innerHTML + " :";
        resultStage.appendChild(resultStageLabel);
        var resultStageValue = document.createElement("div");
        resultStageValue.className = "GProuteResultStageValue";
        var elementCoords = document.getElementById(this._addUID("GPlocationOriginCoords_" + id));
        var stageCoords = elementCoords.value;
        var visible = elementCoords.className === "GPlocationOriginVisible";
        if (stageCoords !== null && stageCoords !== "" && visible) {
          resultStageValue.innerHTML = stageCoords;
        } else {
          resultStageValue.innerHTML = document.getElementById(this._addUID("GPlocationOrigin_" + id)).value;
        }
        resultStage.appendChild(resultStageValue);
        if (resultStageValue.innerHTML !== "") {
          document.getElementById(this._addUID("GProuteResultsStages")).appendChild(resultStage);
        }
      }
    }
  },
  /**
   * Create Show Results
   * see event!
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteResultsElement: function _createRouteResultsElement() {
    // contexte
    var self = this;
    var container = document.createElement("div");
    container.id = this._addUID("GProuteResults");

    // FIXME Route results are dynamically filled in Javascript by route service
    var divValue = document.createElement("div");
    divValue.id = this._addUID("GProuteResultsValues");
    container.appendChild(divValue);
    var divMode = document.createElement("div");
    divMode.id = this._addUID("GProuteResultsMode");
    var select = document.createElement("select");
    select.id = this._addUID("GProuteResultsComputationSelect");
    select.className = "GPinputSelect";
    // gestionnaire d'evenement :
    // on stocke la valeur du mode de calcul, et on relance le calcul d'itiniraire
    select.addEventListener("change", function (e) {
      self.onRouteModeComputationChangeAndRun(e);
    });
    var computes = [{
      code: "fastest",
      label: "Plus rapide"
    }, {
      code: "shortest",
      label: "Plus court"
    }];
    for (var i = 0; i < computes.length; i++) {
      var option = document.createElement("option");
      option.value = computes[i].code;
      option.text = computes[i].label;
      select.appendChild(option);
    }
    divMode.appendChild(select);
    container.appendChild(divMode);
    var divNew = document.createElement("div");
    divNew.id = this._addUID("GProuteResultsNew");
    divNew.title = "Modifier le calcul";
    divNew.addEventListener("click", function (e) {
      document.getElementById(self._addUID("GProuteResultsPanel")).className = "GProuteComponentHidden";
      document.getElementById(self._addUID("GProuteForm")).className = "";
      self.onShowRouteResultsNewClick(e);
    });
    container.appendChild(divNew);
    return container;
  },
  /**
   * Add Results Duration and Distance
   * (results dynamically generate !)
   * see event!
   * @param {Number} distance - distance
   * @param {Number} duration - duration
   * @param {Function} fconvert - fconvert
   *
   * @returns {DOMElement} DOM element
   */
  _addRouteResultsValuesElement: function _addRouteResultsValuesElement(distance, duration, fconvert) {
    var div = document.getElementById(this._addUID("GProuteResultsValues"));

    // clean !
    if (div.childElementCount) {
      while (div.firstChild) {
        div.removeChild(div.firstChild);
      }
    }
    var containerDistance = document.createElement("div");
    containerDistance.className = "GProuteResultsValue";
    var labelDistance = document.createElement("label");
    labelDistance.className = "GProuteResultsValueLabel";
    labelDistance.innerHTML = "Distance :";
    containerDistance.appendChild(labelDistance);
    var distanceLabel = 0;
    var isKm = parseInt(distance / 1000, 10);
    if (!isKm) {
      distanceLabel = Math.round(distance) + " m";
    } else {
      var distanceArrondi = Math.round(distance);
      distanceArrondi = distanceArrondi / 1000;
      distanceLabel = distanceArrondi + " km";
    }
    var divDistance = document.createElement("div");
    divDistance.id = this._addUID("GProuteResultsValueDist");
    divDistance.innerHTML = distanceLabel;
    containerDistance.appendChild(divDistance);
    div.appendChild(containerDistance);
    var containerDuration = document.createElement("div");
    containerDuration.className = "GProuteResultsValue";
    var labelDuration = document.createElement("label");
    labelDuration.className = "GProuteResultsValueLabel";
    labelDuration.innerHTML = "Durée :";
    containerDuration.appendChild(labelDuration);
    var divDuration = document.createElement("div");
    divDuration.id = this._addUID("GProuteResultsValueDist");
    divDuration.innerHTML = fconvert(duration);
    containerDuration.appendChild(divDuration);
    div.appendChild(containerDuration);
    return div;
  },
  /**
   * Create Show Results Details
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteShowResultsDetailsElement: function _createRouteShowResultsDetailsElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GProuteResultsShowDetails");
    input.type = "checkbox";
    return input;
  },
  /**
   *  Create Results Details
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteResultsDetailsElement: function _createRouteResultsDetailsElement() {
    // <!-- Route results details are dynamically filled in Javascript by route service -->
    var div = document.createElement("div");
    div.id = this._addUID("GProuteResultsDetails");
    return div;
  },
  /**
   *  Add Results Details
   * (results dynamically generate !)
   * @param {Object[]} instructions - instructions
   * @param {Function} fconvert - fconvert
   *
   * @returns {DOMElement} DOM element
   */
  _addRouteResultsDetailsElement: function _addRouteResultsDetailsElement(instructions, fconvert) {
    // contexte
    var context = this;
    var div = document.getElementById(this._addUID("GProuteResultsDetails"));

    // clean !
    if (div.childElementCount) {
      while (div.firstChild) {
        div.removeChild(div.firstChild);
      }
    }

    // calcul des valeurs cumulé !
    var distanceCumul = 0;
    var durationCumul = 0;

    /* jshint -W083 */
    for (var i = 0; i < instructions.length; i++) {
      var id = i + 1;
      var o = instructions[i];
      var divNum = document.createElement("div");
      divNum.className = "GProuteResultsDetailsNumber";
      divNum.innerHTML = id + ".";
      div.appendChild(divNum);
      durationCumul += parseFloat(o.duration);
      distanceCumul += parseFloat(o.distance);
      var distance = 0;
      var isCumulKm = parseInt(distanceCumul / 1000, 10);
      if (!isCumulKm) {
        distance = Math.round(distanceCumul) + " m";
      } else {
        var distanceArrondi = Math.round(distanceCumul);
        distanceArrondi = distanceArrondi / 1000;
        distance = distanceArrondi + " km";
      }
      var divIns = document.createElement("div");
      divIns.className = "GProuteResultsDetailsInstruction";
      divIns.id = this._addUID("GProuteResultsDetailsInstruction_" + id);
      divIns.title = "distance : " + distance + " / " + "temps : " + fconvert(durationCumul);
      divIns.innerHTML = o.instruction;
      divIns.addEventListener("mouseover", function (e) {
        context.onRouteResultsDetailsMouseOver(e);
      });
      divIns.addEventListener("mouseout", function (e) {
        context.onRouteResultsDetailsMouseOut(e);
      });
      divIns.addEventListener("click", function (e) {
        // mode mobile !
        if (typeof context.onRouteResultsDetailsClick === "function") {
          context.onRouteResultsDetailsClick(e);
        }
      });
      div.appendChild(divIns);
    }
    return div;
  },
  // ################################################################### //
  // ################### Methods to the form points #################### //
  // ################# OVERWRITTEN BY LOCATIONSELECTOR ! ################# //

  /**
   * Create Point
   * see event !
   * OVERWRITTEN BY LOCATIONSELECTOR !
   * (version initial without LOCATIONSELECTOR PLUGIN)
   * @param {Integer} n - n
   * @param {String} text - text
   * @param {Boolean} visibility - visibility
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormPointElement: function _createRoutePanelFormPointElement(n, text, visibility) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.id = "GProutePoint" + n;
    div.className = visibility ? "GPflexInput GProuteStageFlexInput" : "GPflexInput GProuteStageFlexInputHidden";
    var labelOrigin = document.createElement("label");
    labelOrigin.id = "GProuteOriginLabel" + n;
    labelOrigin.htmlFor = "GProuteOrigin" + n;
    labelOrigin.innerHTML = text;
    labelOrigin.addEventListener("click", function () {
      var i = this.id.charAt(this.id.length - 1);
      document.getElementById("GProuteOriginCoords" + i).value = "";
      for (var j = 1; j < 8; j++) {
        document.getElementById("GProutePoint" + j).style.display = "flex";
      }
      document.getElementById("GProuteForm").className = "";
      document.getElementById("GProuteOriginPointer" + i).checked = false;
      document.getElementById("GProuteOrigin" + i).className = "GProuteOriginVisible";
      document.getElementById("GProuteOriginCoords" + i).className = "GProuteOriginHidden";
    });
    div.appendChild(labelOrigin);
    var inputOrigin = document.createElement("input");
    inputOrigin.id = "GProuteOrigin" + n;
    inputOrigin.className = "GProuteOriginVisible";
    inputOrigin.type = "text";
    inputOrigin.placeholder = "Saisir une adresse";
    inputOrigin.addEventListener("keyup", function (e) {
      var charCode = e.which || e.keyCode;
      if (charCode === 13 || charCode === 10) {
        return;
      }
      var i = this.id.charAt(this.id.length - 1);
      if (document.getElementById("GProuteOrigin" + i).value.length > 2) {
        document.getElementById("GProuteAutoCompleteList" + i).style.display = "block";
      } else {
        document.getElementById("GProuteAutoCompleteList" + i).style.display = "none";
      }
      // gestionnaire d'evenement :
      // on récupère la valeur de saisie pour une requête sur le service d'autocompletion.
      // le resultat de la requête nous permet de recuperer les coordonnées du point...
      context.onAutoCompleteSearchText(e);
    });
    inputOrigin.addEventListener("blur", function () {
      var i = this.id.charAt(this.id.length - 1);
      document.getElementById("GProuteAutoCompleteList" + i).style.display = "none";
    });
    div.appendChild(inputOrigin);
    var inputOriginCoord = document.createElement("input");
    inputOriginCoord.id = "GProuteOriginCoords" + n;
    inputOriginCoord.className = "GProuteOriginHidden";
    inputOriginCoord.type = "text";
    inputOriginCoord.disabled = true;
    div.appendChild(inputOriginCoord);
    var inputOriginPointer = document.createElement("input");
    inputOriginPointer.id = "GProuteOriginPointer" + n;
    inputOriginPointer.type = "checkbox";
    div.appendChild(inputOriginPointer);
    var labelOriginPointer = document.createElement("label");
    labelOriginPointer.id = "GProuteOriginPointerImg" + n;
    labelOriginPointer.htmlFor = "GProuteOriginPointer" + n;
    labelOriginPointer.className = "GProuteOriginPointerImg";
    labelOriginPointer.title = "Pointer un lieu sur la carte";
    labelOriginPointer.addEventListener("click", function (evt) {
      evt.preventDefault();
      evt.stopPropagation();
      var i = this.id.charAt(this.id.length - 1);
      var j;
      for (j = 1; j < 8; j++) {
        if (i !== j) {
          document.getElementById("GProuteOriginPointer" + j).checked = false;
          if (document.getElementById("GProuteOriginCoords" + j).value === "Pointer un lieu sur la carte") {
            document.getElementById("GProuteOriginCoords" + j).value = "";
            document.getElementById("GProuteOrigin" + j).className = "GProuteOriginVisible";
            document.getElementById("GProuteOriginCoords" + j).className = "GProuteOriginHidden";
          }
        }
      }
      if (document.getElementById("GProuteOriginPointer" + i).checked) {
        document.getElementById("GProuteOriginCoords" + i).value = "";
        for (j = 1; j < 8; j++) {
          document.getElementById("GProutePoint" + j).style.display = "flex";
        }
        document.getElementById("GProuteForm").className = "";
        document.getElementById("GProuteOriginPointer" + i).checked = false;
        document.getElementById("GProuteOrigin" + i).className = "GProuteOriginVisible";
        document.getElementById("GProuteOriginCoords" + i).className = "GProuteOriginHidden";
      } else {
        document.getElementById("GProuteOriginCoords" + i).value = "Pointer un lieu sur la carte";
        for (j = 1; j < 8; j++) {
          if (i === j) {
            document.getElementById("GProutePoint" + j).style.display = "flex";
          } else {
            document.getElementById("GProutePoint" + j).style.display = "none";
          }
        }
        document.getElementById("GProuteForm").className = "GProuteFormMini";
        document.getElementById("GProuteOriginPointer" + i).checked = true;
        document.getElementById("GProuteOrigin" + i).className = "GProuteOriginHidden";
        document.getElementById("GProuteOriginCoords" + i).className = "GProuteOriginVisible";
      }
      // gestionnaire d'evenement :
      // on stocke la valeur du point, utilisée pour la requête sur le service de calcul d'itiniraire
      context.onRouteMapPointClick(evt);
    });
    div.appendChild(labelOriginPointer);
    return div;
  },
  /**
   * Create Remove Point tag
   * see event !
   * OVERWRITTEN BY LOCATIONSELECTOR !
   * (version initial without LOCATIONSELECTOR PLUGIN)
   * @param {Integer} n - n
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormRemoveStageElement: function _createRoutePanelFormRemoveStageElement(n) {
    // contexte d'execution
    var context = this;
    var divRm = document.createElement("div");
    divRm.id = "GProuteStageRemove" + n;
    divRm.className = "GProuteStageRemove";
    divRm.title = "Supprimer l'étape";
    if (n !== 1 && n !== 7) {
      divRm.addEventListener("click", function (e) {
        var i = this.id.charAt(this.id.length - 1);
        document.getElementById("GProutePoint" + i).className = "GPflexInput GProuteStageFlexInputHidden";
        document.getElementById("GProuteOrigin" + i).value = "";
        document.getElementById("GProuteOrigin" + i).className = "GProuteOriginVisible";
        document.getElementById("GProuteOriginCoords" + i).value = "";
        document.getElementById("GProuteOriginCoords" + i).className = "GProuteOriginHidden";
        document.getElementById("GProuteStageAdd").style.display = "";
        // Moving up exclusions picto
        // var exclusionsPictoTop = document.getElementById("GPshowRouteExclusionsPicto").style.top;
        // document.getElementById("GPshowRouteExclusionsPicto").style.top = (parseInt(exclusionsPictoTop, 10) - 33).toString() + "px";
        // gestionnaire d'evenement :
        // on supprime le point, utilisé pour la requête sur le service d'itiniraire
        context.onRouteRemovePointClick(e);
      });
    }
    return divRm;
  },
  /**
   * Create Add Point tag
   * see event !
   * OVERWRITTEN BY LOCATIONSELECTOR !
   * (version initial without LOCATIONSELECTOR PLUGIN)
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormAddStageElement: function _createRoutePanelFormAddStageElement() {
    // contexte d'execution
    var context = this;
    var divAdd = document.createElement("div");
    divAdd.id = "GProuteStageAdd";
    divAdd.title = "Ajouter une étape";
    divAdd.addEventListener("click", function (e) {
      var lastStage = 1;
      var nbStages = 0;
      for (var i = 2; i < 7; i++) {
        if (document.getElementById("GProutePoint" + i).className === "GPflexInput GProuteStageFlexInputHidden") {
          if (lastStage === 1) {
            lastStage = i;
          }
        } else {
          nbStages++;
        }
      }
      if (lastStage < 7) {
        document.getElementById("GProutePoint" + lastStage).className = "GPflexInput GProuteStageFlexInput";
        // Moving down exclusions picto
        // var exclusionsPictoTop = document.getElementById("GPshowRouteExclusionsPicto").style.top;
        // document.getElementById("GPshowRouteExclusionsPicto").style.top = (parseInt(exclusionsPictoTop, 10) + 33).toString() + "px";
      }
      if (nbStages === 4) {
        document.getElementById("GProuteStageAdd").style.display = "none";
      }
      // gestionnaire d'evenement :
      // on ajoute le point, utilisé pour la requête sur le service d'itiniraire
      context.onRouteAddPointClick(e);
    });
    return divAdd;
  },
  /**
   * Create Results autocompletion to the point
   * see event!
   * OVERWRITTEN BY LOCATIONSELECTOR !
   * (version initial without LOCATIONSELECTOR PLUGIN)
   * @param {Integer} n - n
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormAutoCompleteListElement: function _createRoutePanelFormAutoCompleteListElement(n) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.id = "GProuteAutoCompleteList" + n;
    div.className = "GPadvancedAutoCompleteList";
    if (div.addEventListener) {
      div.addEventListener("click", function (e) {
        context.onAutoCompletedResultsItemClick(e);
        document.getElementById("GProuteAutoCompleteList" + n).style.display = "none";
      }, false);
    } else if (div.attachEvent) {
      div.attachEvent("onclick", function (e) {
        context.onAutoCompletedResultsItemClick(e);
        document.getElementById("GProuteAutoCompleteList" + n).style.display = "none";
      });
    }

    // Proposals are dynamically filled in Javascript by autocomplete service
    // <div class="GPautoCompleteProposal">...</div>

    return div;
  },
  /**
   * Autocompletion result to a point.
   * Proposals are dynamically filled in Javascript by autocomplete service
   * OVERWRITTEN BY LOCATIONSELECTOR !
   * (version initial without LOCATIONSELECTOR PLUGIN)
   *
   *
   * @param {Object} location - suggested location results
   * @param {Number} n  - number of the point
   * @param {Number} id - ID
   */
  _createRouteAutoCompletedLocationElement: function _createRouteAutoCompletedLocationElement(location, n, id) {
    var container = document.getElementById("GProuteAutoCompleteList" + n);
    var div = document.createElement("div");
    div.id = "AutoCompletedLocation" + id;
    div.className = "GPautoCompleteProposal";
    div.innerHTML = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_2__["default"].getSuggestedLocationFreeform(location);
    container.appendChild(div);
  },
  // ################################################################### //
  // ############## Methods to the choice mode into form ############### //
  // ################################################################### //

  /**
   * Create Container to Mode choice transport
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormModeChoiceElement: function _createRoutePanelFormModeChoiceElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GProuteModeChoice");

    // div.appendChild(this._createRoutePanelFormModeChoiceTransportElement());
    // div.appendChild(this._createRoutePanelFormModeChoiceComputeElement());

    return div;
  },
  /**
   * Create Mode choice transport
   * see event !
   * FIXME event not useful
   * @param {String[]} transports - transports
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormModeChoiceTransportElement: function _createRoutePanelFormModeChoiceTransportElement(transports) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.id = this._addUID("GProuteTransportChoice");
    var span = document.createElement("span");
    span.className = "GProuteModeLabel";
    span.innerHTML = "Mode de transport";
    div.appendChild(span);

    /* jshint -W083 */
    for (var i = 0; i < transports.length; i++) {
      var transport = transports[i];
      if (transport === "Voiture") {
        var inputCar = document.createElement("input");
        inputCar.id = this._addUID("GProuteTransportCar");
        inputCar.type = "radio";
        inputCar.name = "GProuteTransport";
        inputCar.value = "Voiture";
        if (i === 0) {
          inputCar.checked = true;
        }
        // gestionnaire d'evenement :
        // on stocke le mode de transport,
        // utilisation pour la requête sur le service de calcul d'itiniraire
        if (inputCar.addEventListener) {
          inputCar.addEventListener("change", function (e) {
            context.onRouteModeTransportChange(e);
          });
        } else if (inputCar.attachEvent) {
          inputCar.attachEvent("onchange", function (e) {
            context.onRouteModeTransportChange(e);
          });
        }
        div.appendChild(inputCar);
        var labelCar = document.createElement("label");
        labelCar.className = "GProuteTransportImg";
        labelCar.htmlFor = this._addUID("GProuteTransportCar");
        labelCar.title = "Voiture";
        div.appendChild(labelCar);
      }
      if (transport === "Pieton") {
        var inputPedestrian = document.createElement("input");
        inputPedestrian.id = this._addUID("GProuteTransportPedestrian");
        inputPedestrian.type = "radio";
        inputPedestrian.name = "GProuteTransport";
        inputPedestrian.value = "Pieton";
        if (i === 0) {
          inputPedestrian.checked = true;
        }
        // gestionnaire d'evenement :
        // on stocke le mode de transport,
        // utilisation pour la requête sur le service de calcul d'itiniraire
        if (inputPedestrian.addEventListener) {
          inputPedestrian.addEventListener("change", function (e) {
            context.onRouteModeTransportChange(e);
          });
        } else if (inputPedestrian.attachEvent) {
          inputPedestrian.attachEvent("onchange", function (e) {
            context.onRouteModeTransportChange(e);
          });
        }
        div.appendChild(inputPedestrian);
        var labelPedestrian = document.createElement("label");
        labelPedestrian.className = "GProuteTransportImg";
        labelPedestrian.htmlFor = this._addUID("GProuteTransportPedestrian");
        labelPedestrian.title = "Piéton";
        div.appendChild(labelPedestrian);
      }
    }
    return div;
  },
  /**
   * Create Mode choice computation
   * see event!
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormModeChoiceComputeElement: function _createRoutePanelFormModeChoiceComputeElement() {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.id = this._addUID("GProuteComputationChoice");
    var label = document.createElement("label");
    label.htmlFor = this._addUID("GProuteComputationSelect");
    label.innerHTML = "Mode de calcul";
    var span = document.createElement("span");
    span.className = "GProuteModeLabel";
    span.appendChild(label);
    div.appendChild(span);
    var select = document.createElement("select");
    select.id = this._addUID("GProuteComputationSelect");
    select.className = "GPinputSelect";
    // gestionnaire d'evenement :
    // on stocke la valeur du mode de calcul,
    // utilisation pour la requête sur le service de calcul d'itiniraire
    select.addEventListener("change", function (e) {
      context.onRouteModeComputationChange(e);
    });
    var computes = [{
      code: "fastest",
      label: "Plus rapide"
    }, {
      code: "shortest",
      label: "Plus court"
    }];
    for (var i = 0; i < computes.length; i++) {
      var option = document.createElement("option");
      option.value = computes[i].code;
      option.text = computes[i].label;
      select.appendChild(option);
    }
    div.appendChild(select);
    return div;
  },
  // ################################################################### //
  // ################# Methods to the choice exclusions ################ //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing Exclusions Options
   *
   * @returns {DOMElement} DOM element
   */
  _createShowRouteExclusionsElement: function _createShowRouteExclusionsElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowRouteExclusions");
    input.type = "checkbox";
    return input;
  },
  /**
   * Label to Exclusions Options
   * see event !
   * FIXME event not useful
   *
   * @returns {DOMElement} DOM element
   */
  _createShowRouteExclusionsPictoElement: function _createShowRouteExclusionsPictoElement() {
    // contexte d'execution
    var context = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowRouteExclusionsPicto");
    label.className = "GPshowMoreOptionsImage GPshowMoreOptions GPshowRouteExclusionsPicto";
    label.htmlFor = this._addUID("GPshowRouteExclusions");
    label.title = "Exclusions";
    // label.style.top = "185px";

    // gestionnaire d'evenement :
    // on ouvre le menu des options des exclusions
    if (label.addEventListener) {
      label.addEventListener("click", function (e) {
        context.onShowRouteExclusionsClick(e);
      });
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function (e) {
        context.onShowRouteExclusionsClick(e);
      });
    }
    return label;
  },
  /**
   * Create Container to Exclusions
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormExclusionsElement: function _createRoutePanelFormExclusionsElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GProuteExclusions");
    var span = document.createElement("span");
    span.className = "GProuteExclusionsLabel";
    span.innerHTML = "Passages autorisés";
    div.appendChild(span);

    // div.appendChild(this._createRoutePanelFormExclusionOptionsElement());

    return div;
  },
  /**
   * Create Exclusions Options
   * see event !
   * FIXME event not useful
   * @param {Object[]} exclusions - exclusions
   *
   * @returns {DOMElement} DOM element
   */
  _createRoutePanelFormExclusionOptionsElement: function _createRoutePanelFormExclusionOptionsElement(exclusions) {
    // contexte d'execution
    var context = this;
    var div = document.createElement("div");
    div.className = "GProuteExclusionsOptions";

    /* jshint -W083 */
    for (var value in exclusions) {
      if (exclusions.hasOwnProperty(value)) {
        var status = exclusions[value];
        switch (value) {
          case "toll":
            var inputToll = document.createElement("input");
            inputToll.id = this._addUID("GProuteExclusionsToll");
            inputToll.type = "checkbox";
            inputToll.value = "Toll";
            inputToll.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputToll.addEventListener) {
              inputToll.addEventListener("change", function (e) {
                context.onRouteExclusionsChange(e);
              });
            } else if (inputToll.attachEvent) {
              inputToll.attachEvent("onchange", function (e) {
                context.onRouteExclusionsChange(e);
              });
            }
            div.appendChild(inputToll);
            var labelToll = document.createElement("label");
            labelToll.className = "GProuteExclusionsOption";
            labelToll.htmlFor = this._addUID("GProuteExclusionsToll");
            labelToll.innerHTML = "Péages";
            div.appendChild(labelToll);
            break;
          case "tunnel":
            var inputTunnel = document.createElement("input");
            inputTunnel.id = this._addUID("GProuteExclusionsTunnel");
            inputTunnel.type = "checkbox";
            inputTunnel.value = "Tunnel";
            inputTunnel.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputTunnel.addEventListener) {
              inputTunnel.addEventListener("change", function (e) {
                context.onRouteExclusionsChange(e);
              });
            } else if (inputTunnel.attachEvent) {
              inputTunnel.attachEvent("onchange", function (e) {
                context.onRouteExclusionsChange(e);
              });
            }
            div.appendChild(inputTunnel);
            var labelTunnel = document.createElement("label");
            labelTunnel.className = "GProuteExclusionsOption";
            labelTunnel.htmlFor = this._addUID("GProuteExclusionsTunnel");
            labelTunnel.innerHTML = "Tunnels";
            div.appendChild(labelTunnel);
            break;
          case "bridge":
            var inputBridge = document.createElement("input");
            inputBridge.id = this._addUID("GProuteExclusionsBridge");
            inputBridge.type = "checkbox";
            inputBridge.value = "Bridge";
            inputBridge.checked = !status;
            // gestionnaire d'evenement :
            // on stocke l'exclusion,
            // utilisation pour la requête sur le service de calcul d'itiniraire
            if (inputBridge.addEventListener) {
              inputBridge.addEventListener("change", function (e) {
                context.onRouteExclusionsChange(e);
              });
            } else if (inputBridge.attachEvent) {
              inputBridge.attachEvent("onchange", function (e) {
                context.onRouteExclusionsChange(e);
              });
            }
            div.appendChild(inputBridge);
            var labelBridge = document.createElement("label");
            labelBridge.className = "GProuteExclusionsOption";
            labelBridge.htmlFor = this._addUID("GProuteExclusionsBridge");
            labelBridge.innerHTML = "Ponts";
            div.appendChild(labelBridge);
            break;
        }
      }
    }
    return div;
  },
  // ################################################################### //
  // ############################### Submit Form ####################### //
  // ################################################################### //

  /**
   * Create Submit Form Element
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteSubmitFormElement: function _createRouteSubmitFormElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GProuteSubmit");
    input.className = "GPinputSubmit";
    input.type = "submit";
    input.value = "Calculer";
    return input;
  },
  // ################################################################### //
  // ############################### Reset picto ####################### //
  // ################################################################### //

  /**
   * Create Reset Picto Element
   *
   * @returns {DOMElement} DOM element
   */
  _createRouteFormResetElement: function _createRouteFormResetElement() {
    var self = this;
    var divReset = document.createElement("div");
    divReset.id = this._addUID("GProuteReset");
    divReset.title = "Réinitialiser les paramètres";
    divReset.addEventListener("click", function (e) {
      self.onRouteResetClick(e);
    });
    return divReset;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (RouteDOM);

/***/ }),
/* 127 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(37);
/* harmony import */ var _Common_Utils_SearchEngineUtils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(128);
/* harmony import */ var _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(106);
/* harmony import */ var _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(108);
/* harmony import */ var _Common_Controls_SearchEngineDOM__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(129);
/* harmony import */ var _Common_Utils__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(130);
/* global KeyboardEvent */









var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("searchengine");

/**
 * @classdesc
 *
 * Leaflet Control Class to search positons of geographic identifiers (places names, address, cadastral parcel) using :
 *
 * - the [geocoding web service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/geocodage.html}.
 * - the [autocompletion service of the Geoportal Platform]{@link https://geoservices.ign.fr/documentation/geoservices/autocompletion.html}
 * <br/>
 *
 * Use {@link module :Controls.SearchEngine L.geoportalControl.SearchEngine()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.SearchEngine
 */
var SearchEngine = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends L.geoportalControl.SearchEngine.prototype */{
  includes: _Common_Controls_SearchEngineDOM__WEBPACK_IMPORTED_MODULE_7__["default"],
  /**
   * options by default
   *
   * @private
   */
  options: {
    position: "topleft",
    collapsed: true,
    displayInfo: true,
    zoomTo: "",
    resources: [],
    placeholder: "Rechercher un lieu, une adresse",
    displayMarker: true,
    markerStyle: "blue",
    displayAdvancedSearch: true,
    advancedSearch: {},
    geocodeOptions: {},
    autocompleteOptions: {
      serviceOptions: {},
      triggerGeocode: false,
      triggerDelay: 1000
    }
  },
  /**
   * @constructor SearchEngine
   *
   * @private
   * @alias SearchEngine
   * @extends {L.Control}
   * @param {Object} options - control options
   * @param {String} [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Boolean} [options.collapsed] - collapse mode, false by default
   * @param {String} [options.position] - position of component into the map, 'topleft' by default
   * @param {Boolean} [options.displayInfo] - get informations on popup marker
   * @param {String|Numeric|Function} [options.zoomTo] - zoom to results, by default, current zoom.
   *       Value possible : auto or zoom level.
   *       Possible to overload it with a function :
   *       zoomTo : function (info) {
   *           // do some stuff...
   *           return zoom;
   *       }
   * @param {String}  [options.placeholder] - set placeholder in search bar. Default is "Rechercher un lieu, une adresse".
   * @param {Boolean}  [options.displayMarker] - set a marker on search result, defaults to true.
   * @param {String|Object}  [options.markerStyle] - set a marker style. Currently possible values are "blue" (default value), "orange", "red" and "green". But you can use an L.Icon object (see {@link http://leafletjs.com/reference-1.2.0.html#icon L.Icon }).
   * @param {Sting} [options.apiKey] - API key. The "calcul" key is used by default.
   * @param {String} [options.resources.geocode] - resources geocoding, by default : "location"
   * @param {Object} [options.resources.autocomplete] - resources to be used by autocompletion service, by default : ["StreetAddress", "PositionOfInterest"]
   * @param {Boolean} [options.displayAdvancedSearch] - False to disable advanced search tools (it will not be displayed). Default is true (displayed)
   * @param {Object} [options.advancedSearch] - advanced search for geocoding (filters)
   * @param {Object} [options.geocodeOptions] - options of geocode service
   * @param {Object} [options.autocompleteOptions] - options of autocomplete service
   * @param {Object} [options.autocompleteOptions.serviceOptions] - options of autocomplete service
   * @param {Boolean} [options.autocompleteOptions.triggerGeocode] - trigger a geocoding request if the autocompletion does not return any suggestions, false by default
   * @param {Number}  [options.autocompleteOptions.triggerDelay] - waiting time before sending the geocoding request, 1000ms by default
   * @example
   *  var SearchEngine = L.geoportalControl.SearchEngine({
   *      position : "topright",
   *      collapsed : true,
   *      displayInfo : true,
   *      displayAdvancedSearch : true,
   *      placeholder : "Rechercher un lieu, une adresse",
   *      displayMarker : true,
   *      markerStyle : L.icon(iconUrl : 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png');
   *      zoomTo : 15,
   *      resources : ["PositionOfInterest", "StreetAddress"],
   *      advancedSearch : {
   *          PositionOfInterest : [{name : "municipality", title : "Ville"}],
   *          StreetAddress : [{...}],
   *          CadastralParcel : null,
   *      },
   *      apiKey : "zfgzrgffg57rfg8ar7gr4g5r4",
   *      geocodeOptions : {},
   *      autocompleteOptions : {}
   *  });
   *
   */
  initialize: function initialize(options) {
    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.setOptions(this, options);
    if (typeof this.options.resources === "undefined") {
      this.options.resources = {};
    }
    if (typeof this.options.resources.geocode === "undefined" || this.options.resources.geocode === "") {
      this.options.resources.geocode = "location";
    }
    if (typeof this.options.resources.autocomplete === "undefined" || this.options.resources.autocomplete.length === 0) {
      this.options.resources.autocomplete = ["PositionOfInterest", "StreetAddress"];
    }

    /** uuid */
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].generate();

    /** affichage du container de saisie */
    this._showContainer = null;
    this._pictoContainer = null;

    /** container de la saisie du la recherche */
    this._inputContainer = null;

    /** container des reponses de l'autocompletion */
    this._suggestedContainer = null;

    /** listes des reponses de l'autocompletion */
    this._suggestedLocations = [];

    /** container des reponses du geocodage */
    this._geocodedContainer = null;

    /** liste des reponses du geocodage */
    this._geocodedLocations = [];

    /** container des filtres du geocodage */
    this._filterContainer = null;

    /** ressource de geocodage selectionnée pour le geocodage avancé */
    this._currentGeocodingCode = null;

    /** localisant */
    this._currentGeocodingLocation = null;

    /** liste des filtres du geocodage pour le geocodage avancé */
    this._advancedSearchFilters = {};

    /** liste des ressources du geocodage pour le geocodage avancé */
    this._advancedSearchCodes = [];

    /** marker */
    this._marker = null;

    // trigger geocode
    this._triggerHandler = null;
  },
  /**
   * this method is called by this.addTo(map)
   * and fills variable : this._container = this.onAdd(map)
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  onAdd: function onAdd( /* map */
  ) {
    // TODO initialisation des ressources du geocodage avancé
    this._initAdvancedSearchCodes();

    // initialisation des filtres du geocodage avancé
    this._initAdvancedSearchFilters();

    // initialisation du DOM du composant
    var container = this._initLayout();

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    return container;
  },
  /**
   * this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @param {Object} map - the map
   *
   * @private
   */
  onRemove: function onRemove(map) {
    this._clearSuggestedLocation();
    this._clearGeocodedLocation();
    if (this._marker != null) {
      map.removeLayer(this._marker);
      this._marker = null;
    }
  },
  // ################################################################### //
  // ########################## methods DOM ############################ //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  _initLayout: function _initLayout() {
    // create main container
    var container = this._createMainContainerElement();

    // create show search engine element
    var inputShow = this._showContainer = this._createShowSearchEngineElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (!this.options.collapsed) {
      inputShow.checked = "true";
    }

    // create search engine picto
    var picto = this._pictoContainer = this._createShowSearchEnginePictoElement();
    container.appendChild(picto);
    var search = this._createSearchInputElement(this.options.placeholder);
    container.appendChild(search);
    if (this.options.displayAdvancedSearch) {
      var advancedShow = this._createShowAdvancedSearchElement();
      container.appendChild(advancedShow);

      // INFO je decompose les appels car j'ai besoin de recuperer le container
      // des filtres
      var advancedPanel = this._createAdvancedSearchPanelElement();
      var advancedHeader = this._createAdvancedSearchPanelHeaderElement();
      var advancedForm = this._createAdvancedSearchPanelFormElement(this._advancedSearchCodes);
      var advancedFormFilters = this._filterContainer = this._createAdvancedSearchFormFiltersElement();
      this._setFilter(this._advancedSearchCodes[0].id); // ex "PositionOfInterest"
      var advancedFormInput = this._createAdvancedSearchFormInputElement();
      advancedForm.appendChild(advancedFormFilters);
      advancedForm.appendChild(advancedFormInput);
      advancedPanel.appendChild(advancedHeader);
      advancedPanel.appendChild(advancedForm);
      container.appendChild(advancedPanel);
    }

    // INFO je decompose les appels car j'ai besoin de recuperer le container
    // des resultats de l'autocompletion
    var autocomplete = this._createAutoCompleteElement();
    var autocompleteList = this._suggestedContainer = this._createAutoCompleteListElement();
    autocomplete.appendChild(autocompleteList);
    container.appendChild(autocomplete);

    // INFO je decompose les appels car j'ai besoin de recuperer le container
    // des resultats du geocodage
    var geocode = this._createGeocodeResultsElement();
    var geocodeList = this._geocodedContainer = this._createGeocodeResultsListElement();
    geocode.appendChild(geocodeList);
    container.appendChild(geocode);
    return container;
  },
  // ################################################################### //
  // ################# methods Filters Geocode Advanced ################ //
  // ################################################################### //

  /**
   * this method is called by this.onAdd()
   * and initialize the geocoding resources.
   * TODO
   *
   * @private
   */
  _initAdvancedSearchCodes: function _initAdvancedSearchCodes() {
    // INFORMATION
    // on y ajoute les filtres attributaires pour une table de ressources
    // selectionnée via un evenement (onchange) de la liste deroulante du
    // menu avancé du geocodage.
    // cf. onGeocodingAdvancedSearchCodeChange() pour la selection de la
    // ressource de geocodage à afficher

    var geocodeResources = this.options.resources.geocode;
    if (geocodeResources === "location") {
      geocodeResources = ["PositionOfInterest", "StreetAddress", "CadastralParcel"];
    }
    if (!Array.isArray(geocodeResources)) {
      geocodeResources = [geocodeResources];
    }
    for (var i = 0; i < geocodeResources.length; i++) {
      switch (geocodeResources[i]) {
        case "PositionOfInterest":
          this._advancedSearchCodes.push({
            id: "PositionOfInterest",
            title: "Lieux/toponymes"
          });
          break;
        case "StreetAddress":
          this._advancedSearchCodes.push({
            id: "StreetAddress",
            title: "Adresses"
          });
          break;
        case "CadastralParcel":
          this._advancedSearchCodes.push({
            id: "CadastralParcel",
            title: "Parcelles cadastrales"
          });
          break;
        default:
          break;
      }
    }
    // par défaut, au cas où aucune ressource passée en option ne correspond à celles attendues
    if (this._advancedSearchCodes.length === 0) {
      this._advancedSearchCodes = [{
        id: "StreetAddress",
        title: "Adresses"
      }, {
        id: "PositionOfInterest",
        title: "Lieux/toponymes"
      }, {
        id: "CadastralParcel",
        title: "Cadastre"
      }];
    }
    logger.log("advancedSearchCodes", this._advancedSearchCodes);
  },
  /**
   * this method is called by this.onAdd()
   * and initialize the advanced geocoding filters.
   * FIXME
   *
   * @private
   */
  _initAdvancedSearchFilters: function _initAdvancedSearchFilters() {
    // FIXME la liste des filtres attributaires doit elle être recuperée
    // de l'objet geocode ? doit on tous les mettre ou doit on faire un choix ?

    // liste des filtres par defauts pour toutes les ressources
    this._advancedSearchFilters = _Common_Utils_SearchEngineUtils__WEBPACK_IMPORTED_MODULE_4__["default"].advancedSearchFiltersByDefault;

    // on merge les options avancées avec celles par defaut
    var advancedSearchFiltersCustom = this.options.advancedSearch;
    _Common_Utils__WEBPACK_IMPORTED_MODULE_8__["default"].assign(this._advancedSearchFilters, advancedSearchFiltersCustom);
    logger.log("advancedSearchFilters", this._advancedSearchFilters);
  },
  /**
   * this method is called by :
   * - this._initLayout() : ...
   * - this.onGeocodingAdvancedSearchCodeChoice() : ...
   * and initialize or create the filters container HTMLElement
   * to the geocoding advanced menu.
   *
   * @param {String} code - resource geocoding name
   *
   * @returns {DOMElement} DOM element
   *
   * @private
   */
  _setFilter: function _setFilter(code) {
    // INFORMATION
    // Nous avons 2 solutions possibles pour la mise en place des filtres.
    // 1. Soit on decide de creer tous les filtres pour chaque ressource
    // de geocodage à l'initialisation du composant, et on joue sur le
    // mode 'hidden' pour n'afficher que la ressource selectionnée.
    // 2. Soit on decide de creer à chaque fois les filtres pour la
    // ressource selectionnée.
    // Chaque solution a ses inconvenients/avantages.
    // Implementation du choix 2 car elle offre plus de souplesse pour
    // recuperer les 'form-data'...

    var container = this._filterContainer;
    var codeFound = false;
    for (var i = 0; i < this._advancedSearchCodes.length; i++) {
      if (this._advancedSearchCodes[i].id === code) {
        codeFound = true;
        break;
      }
    }
    if (!codeFound) {
      // cette ressource n'est pas disponible,
      // on supprime les anciens enfants...
      while (container.firstChild) {
        container.removeChild(container.firstChild);
      }
      return;
    }

    // on sauvegarde la ressource de geocodage sélectionnée
    this._currentGeocodingCode = code;

    // on supprime les enfants...
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
    var lstAttributs = this._advancedSearchFilters[code];
    if (!lstAttributs || lstAttributs.length === 0) {
      // cette ressource n'est pas parametrable
      return;
    }
    var divTable = this._createAdvancedSearchFiltersTableElement(code, true);
    for (var j = 0; j < lstAttributs.length; j++) {
      var divFilter = this._createAdvancedSearchFiltersAttributElement(lstAttributs[j]);
      divTable.appendChild(divFilter);
    }
    container.appendChild(divTable);
    return container;
  },
  // ################################################################### //
  // ################ methods to request and results ################### //
  // ################################################################### //

  /**
   * this method is called by this.onAutoCompleteSearch()
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   * @param {String}   settings.text - text
   * @param {Function} settings.onSuccess - callback
   * @param {Function} settings.onFailure - callback
   *
   * @private
   */
  _requestAutoComplete: function _requestAutoComplete(settings) {
    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si la parametre 'text' est vide !
    if (!settings.text) {
      return;
    }
    logger.log(settings);
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.autocompleteOptions.serviceOptions);
    // ainsi que la recherche et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);

    // cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle ou la clé "calcul" par défaut.
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      ssl: this.options.ssl
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.autoComplete(options);
  },
  /**
   * this method is called by this.onGeocodingSearch()
   * and fills the container of the location list.
   * it creates a HTML Element per location
   * (cf. this. ...)
   *
   * @param {Array} locations - Array of Gp.Services.AutoComplete.SuggestedLocation corresponding to autocomplete results list
   * @private
   */
  _fillAutoCompletedLocationListContainer: function _fillAutoCompletedLocationListContainer(locations) {
    if (!locations || locations.length === 0) {
      return;
    }

    // on vide la liste avant de la construire
    var element = this._suggestedContainer;
    if (element.childElementCount) {
      while (element.firstChild) {
        element.removeChild(element.firstChild);
      }
    }
    for (var i = 0; i < locations.length; i++) {
      // Proposals are dynamically filled in Javascript by autocomplete service
      this._createAutoCompletedLocationElement(locations[i], i);
    }
  },
  /**
   * this method is called by this.onAutoCompleteSearch()
   * and executes a request to the service.
   *
   * @param {Object} settings - service settings
   * @param {String}   settings.location - text
   * @param {Function} settings.onSuccess - callback
   * @param {Function} settings.onFailure - callback
   *
   * @private
   */
  _requestGeocoding: function _requestGeocoding(settings) {
    // on ne fait pas de requête si on n'a pas renseigné de parametres !
    if (!settings || Object.keys(settings).length === 0) {
      return;
    }

    // on ne fait pas de requête si la parametre 'text' est vide !
    if (settings.query === null) {
      return;
    }
    logger.log(settings);
    var options = {};
    // on recupere les options du service
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.geocodeOptions);
    // ainsi que la recherche, les filtres du geocodage avancé et les callbacks
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, settings);

    // on ajoute le paramètre index spécifiant les ressources.
    var resources = this.options.resources.geocode;
    if (resources) {
      // il se peut que l'utilisateur ait surchargé ce paramètre dans geocodeOptions,
      // ou qu'il ait déjà été rempli (cas de la recherche avancée)
      if (!options.index) {
        options.index = resources;
      }
    }

    // cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle ou la clé "calcul" par défaut.
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      ssl: this.options.ssl
    });
    logger.log(options);
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.geocode(options);
  },
  /**
   * this method is called by this.onGeocodingSearch()
   * and fills the container of the location results.
   * it creates a HTML Element per location
   * (cf. this. ...)
   *
   * @param {Object[]} locations - locations
   *
   * @private
   */
  _fillGeocodedLocationListContainer: function _fillGeocodedLocationListContainer(locations) {
    if (!locations || locations.length === 0) {
      this._clearGeocodedLocation();
      return;
    }

    // on vide la liste avant de la construire
    var element = this._geocodedContainer;
    if (element.childElementCount) {
      while (element.firstChild) {
        element.removeChild(element.firstChild);
      }
    }
    for (var i = 0; i < locations.length; i++) {
      logger.log(locations[i]);
      // Proposals are dynamically filled in Javascript by autocomplete service
      this._createGeocodedLocationElement(locations[i], i);
    }

    // sauvegarde de l'etat des locations
    this._geocodedLocations = locations;
  },
  /**
   * this method is called by Gp.Services.autoComplete callback in case of success
   * (cf. this.onAutoCompleteSearchText), for suggested locations with null coordinates
   * (case of postalCode research for instance).
   * Send a geocode request with suggested location 'fullText' attribute, to get its coordinates and display it in autocomplete results list container.
   *
   * @param {Gp.Services.AutoCompleteResponse.SuggestedLocation} suggestedLocation - autocompletion result (with null coordinates) to be geocoded
   * @param {Number} i - suggestedLocation position in Gp.Services.AutoCompleteResponse.suggestedLocations autocomplete results list
   * @private
   */
  _getGeocodeCoordinatesFromFullText: function _getGeocodeCoordinatesFromFullText(suggestedLocation, i) {
    var _location = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_5__["default"].getSuggestedLocationFreeform(suggestedLocation);
    var context = this;
    this._requestGeocoding({
      query: _location,
      // callback onSuccess
      onSuccess: function onSuccess(response) {
        logger.log("request from Geocoding (coordinates null)", response);
        if (response.locations && response.locations.length !== 0 && response.locations[0].position) {
          // on modifie les coordonnées du résultat en EPSG:4326 donc lat,lon
          if (context._suggestedLocations && context._suggestedLocations[i]) {
            context._suggestedLocations[i].position = {
              lat: response.locations[0].position.y,
              lon: response.locations[0].position.x
            };
            // et on l'affiche dans la liste
            context._locationsToBeDisplayed.unshift(context._suggestedLocations[i]);
            context._fillAutoCompletedLocationListContainer(context._locationsToBeDisplayed);
          }
        }
      },
      // callback onFailure
      onFailure: function onFailure() {
        // si on n'a pas réussi à récupérer les coordonnées, on affiche quand même le résultat
        if (context._suggestedLocations && context._suggestedLocations[i]) {
          context._createAutoCompletedLocationElement(context._suggestedLocations[i], i);
        }
      }
    });
  },
  // ################################################################### //
  // ######################### other methods ########################### //
  // ################################################################### //

  /**
   * this sends the label to the input panel.
   *
   * FIXME appel en dur d'un identifiant CSS !
   *
   * @param {String} label - label suggested location
   *
   * @private
   */
  _setLabel: function _setLabel(label) {
    var element = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPsearchInputText-" + this._uid);
    element.value = label || "";
  },
  /**
   * this method is called by this.on*ResultsItemClick()
   * and move/zoom on a position.
   *
   * @param {Object} position - {x : ..., y : ...}
   * @param {Number} zoom - zoom level
   *
   * @private
   */
  _setPosition: function _setPosition(position, zoom) {
    var map = this._map;
    map.setZoomAround(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(position), zoom, true);
    map.panTo(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(position));
  },
  /**
   * this method is called by this.on*ResultsItemClick()
   * and get zoom.
   *
   * @param {Object} info - info
   *
   * @returns {Integer} zoom level
   *
   * @private
   */
  _getZoom: function _getZoom(info) {
    var map = this._map;
    var key = this.options.zoomTo;
    var zoom = null;

    // les valeurs du zooms sont determinées
    // soit par les mots clefs suivants :  max, min ou auto
    // soit par un niveau de zoom
    // soit defini par l'utilisateur via une fonction

    if (typeof key === "function") {
      logger.trace("zoom function");
      zoom = key.call(this, info);
    }
    if (typeof key === "number") {
      logger.trace("zoom level");
      zoom = key;
    }
    if (typeof key === "string") {
      // if (key === "max") {
      //     zoom = map.getMaxZoom();
      // } else if (key === "min") {
      //     zoom = map.getMinZoom();
      // } else

      if (key === "auto") {
        logger.trace("zoom auto");
        zoom = _Common_Utils_SearchEngineUtils__WEBPACK_IMPORTED_MODULE_4__["default"].zoomToResultsByDefault(info);
      } else {
        logger.trace("zoom level parsing");
        var value = parseInt(key, 10);
        if (!isNaN(value)) {
          logger.trace("zoom parsing");
          zoom = value;
        }
      }
    }

    // polyfill IE
    Number.isInteger = Number.isInteger || function (value) {
      return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
    };

    // test de validité du zoom,
    // on prend le zoom courant par defaut ...
    if (!zoom || zoom === "" || !Number.isInteger(zoom)) {
      logger.trace("zoom not found, current zoom...");
      zoom = map.getZoom();
    }

    // test si le zoom est dans l'espace de la carte
    var min = map.getMinZoom();
    var max = map.getMaxZoom();
    if (zoom < min) {
      logger.trace("zoom level min...");
      zoom = min;
    }
    if (zoom > max) {
      logger.trace("zoom level max...");
      zoom = max;
    }
    logger.trace("zoom", zoom);
    return zoom;
  },
  /**
   * this method is called by this.on*ResultsItemClick()
   * and displays a marker.
   * FIXME
   *
   * @param {Object} position - position {x : ..., y : ...}
   * @param {Object} information - suggested or geocoded information
   * @param {Boolean} display - display a popup information
   * @param {String} marker - style style
   *
   * @private
   */
  _setMarker: function _setMarker(position, information, display, marker) {
    var map = this._map;
    if (this._marker != null) {
      map.removeLayer(this._marker);
      this._marker = null;
    }
    if (position) {
      var _icon = null;
      if (typeof marker === "string") {
        _icon = new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__["default"](marker);
      } else if (marker instanceof leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Icon) {
        _icon = marker;
      } else {
        _icon = new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__["default"]("blue");
        logger.log("Utilisation du marker par défaut !");
      }

      // cf. http://leafletjs.com/reference.html#marker-options
      var options = {
        clickable: true,
        zIndexOffset: 1000,
        icon: _icon
      };
      this._marker = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.marker(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(position), options);
      this._marker.addTo(map);

      // FIXME
      // doit on mettre une information
      // - correctement construite ?
      // - uniquement informatif ?
      // - RIEN ?
      if (display) {
        var popupContent = null;
        if (typeof information !== "string") {
          if (information.service === "GeocodedLocation") {
            popupContent = "<ul>";
            var attributes = information.location.placeAttributes;
            for (var attr in attributes) {
              if (attributes.hasOwnProperty(attr)) {
                if (attr !== "trueGeometry" && attr !== "extraFields" && attr !== "houseNumberInfos" && attr !== "_count") {
                  popupContent += "<li>";
                  popupContent += "<span class=\"gp-attname-others-span\">" + attr.toUpperCase() + " : </span>";
                  popupContent += attributes[attr];
                  popupContent += " </li>";
                }
              }
            }
            popupContent += " </ul>";
          } else if (information.service === "SuggestedLocation") {
            popupContent = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_5__["default"].getSuggestedLocationFreeform(information.location);
          } else {
            popupContent = "sans informations.";
          }
        } else {
          popupContent = information;
        }
        this._marker.bindPopup(popupContent);
      }
    }
  },
  /**
   * this method is called by this.onSearchReset()
   * and it clears all results and the marker.
   *
   * @private
   */
  _clearResults: function _clearResults() {
    this._currentGeocodingLocation = null;
    this._clearSuggestedLocation();
    this._clearGeocodedLocation();
    this._setMarker();
  },
  /**
   * this method is called by this.onAutoCompleteSearchText()
   * and it clears all suggested location.
   *
   * @private
   */
  _clearSuggestedLocation: function _clearSuggestedLocation() {
    this._suggestedLocations = [];
    if (this._suggestedContainer) {
      while (this._suggestedContainer.firstChild) {
        this._suggestedContainer.removeChild(this._suggestedContainer.firstChild);
      }
    }
  },
  /**
   * this method is called by this.onGeocodingAdvancedSearchSubmit()
   * and it clears all geocoded location.
   *
   * @private
   */
  _clearGeocodedLocation: function _clearGeocodedLocation() {
    this._geocodedLocations = [];
    if (this._geocodedContainer) {
      while (this._geocodedContainer.firstChild) {
        this._geocodedContainer.removeChild(this._geocodedContainer.firstChild);
      }
    }
  },
  // ################################################################### //
  // ###################### other handlers events ###################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on 'GPshowSearchEnginePicto' tag label
   * (cf. this._createShowSearchEnginePictoElement), and it cleans the component
   * when it's closed.
   * FIXME
   *
   * @private
   */
  onShowSearchEngineClick: function onShowSearchEngineClick() {
    // FIXME on nettoie ou pas ?
    // this._clearResults();
  },
  /**
   * this method is called by event 'click' on 'GPsearchInputReset' tag div
   * (cf. this._createSearchInputElement), and it cleans the value of input.
   *
   * @private
   */
  onSearchResetClick: function onSearchResetClick() {
    this._clearResults();
  },
  // ################################################################### //
  // ################## handlers events AutoComplete ################### //
  // ################################################################### //

  /**
   * this method is called by event 'keyup' on 'GPsearchInputText' tag input
   * (cf. this._createSearchInputElement), and it gets the value of input.
   * this value is passed as a parameter for the service autocomplete (text).
   * the results of the request are displayed into a drop down menu.
   * FIXME
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onAutoCompleteSearchText: function onAutoCompleteSearchText(e) {
    var value = e.target.value;
    if (!value) {
      return;
    }

    // on sauvegarde le localisant
    this._currentGeocodingLocation = value;

    // on limite les requêtes à partir de 3 car. saisie !
    if (value.length < 3) {
      return;
    }
    var _triggerGeocode = this.options.autocompleteOptions.triggerGeocode;
    var _triggerDelay = this.options.autocompleteOptions.triggerDelay;

    // INFORMATION
    // on effectue la requête au service d'autocompletion.
    // on met en place des callbacks afin de recuperer les resultats ou
    // les messages d'erreurs du service.
    // les resultats sont affichés dans une liste deroulante.
    // les messages d'erreurs sont affichés sur la console (?)

    var context = this;
    this._requestAutoComplete({
      text: value,
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log("request from AutoComplete", results);
        if (results) {
          // on sauvegarde l'etat des résultats
          context._suggestedLocations = results.suggestedLocations;
          context._locationsToBeDisplayed = [];

          // on vérifie qu'on n'a pas récupéré des coordonnées nulles (par ex recherche par code postal)
          for (var i = 0; i < context._suggestedLocations.length; i++) {
            var ilocation = context._suggestedLocations[i];
            if (ilocation.position && ilocation.position.x === 0 && ilocation.position.y === 0 && ilocation.fullText) {
              // si les coordonnées sont nulles, il faut relancer une requête de géocodage avec l'attribut "fullText" récupéré
              context._getGeocodeCoordinatesFromFullText(ilocation, i);
            } else {
              // sinon on peut afficher normalement le résultat dans la liste
              context._locationsToBeDisplayed.push(ilocation);
            }
          }
          ;

          // on affiche les résultats qui n'ont pas des coordonnées nulles
          context._fillAutoCompletedLocationListContainer(context._locationsToBeDisplayed);
          // on annule eventuellement une requete de geocodage en cours car on obtient des
          // de nouveau des resultats d'autocompletion...
          if (context._triggerHandler) {
            clearTimeout(context._triggerHandler);
            context._triggerHandler = null;
            logger.warn("Cancel a geocode request !");
          }
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME
        // où affiche t on les messages : ex. 'No suggestion matching the search' ?
        context._clearSuggestedLocation();
        logger.log(error.message);
        // on envoie une requete de geocodage si aucun resultat d'autocompletion
        // n'a été trouvé ! Et on n'oublie pas d'annuler celle qui est en cours !
        if (error.message === "No suggestion matching the search" && _triggerGeocode) {
          if (context._triggerHandler) {
            clearTimeout(context._triggerHandler);
            logger.warn("Cancel the last geocode request !");
          }
          context._triggerHandler = setTimeout(function () {
            logger.warn("Launch a geocode request (code postal) !");
            context._requestGeocoding({
              query: value,
              // callback onSuccess
              onSuccess: function onSuccess(results) {
                logger.log("request from Geocoding", results);
                if (results) {
                  context._locationsToBeDisplayed = [];
                  // on modifie la structure des reponses pour être
                  // compatible avec l'autocompletion !
                  var locations = results.locations;
                  for (var i = 0; i < locations.length; i++) {
                    var location = locations[i];
                    location.fullText = _Common_Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_5__["default"].getGeocodedLocationFreeform(location);
                    location.position = {
                      x: location.position.lon,
                      y: location.position.lat
                    };
                    context._locationsToBeDisplayed.push(location);
                  }
                  context._fillAutoCompletedLocationListContainer(locations);
                }
              },
              // callback onFailure
              onFailure: function onFailure(error) {
                logger.log(error.message);
              }
            });
          }, _triggerDelay);
        }
      }
    });
  },
  /**
   * this method is called by event 'click' on 'GPautoCompleteResultsList' tag div
   * (cf. this._createAutoCompleteListElement), and it selects the location.
   * this location displays a marker on the map.
   * FIXME
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onAutoCompletedResultsItemClick: function onAutoCompletedResultsItemClick(e) {
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);
    var label = e.target.innerHTML;
    logger.log(idx, label);
    logger.log(this._locationsToBeDisplayed[idx]);
    if (!idx) {
      return;
    }

    // FIXME
    // les coordonnées sont inversées entre les 2 services !?
    // AutoCompletion : lon/lat
    // Geocoding : lat/lon
    var position = {
      lat: this._locationsToBeDisplayed[idx].position.y,
      lon: this._locationsToBeDisplayed[idx].position.x
    };
    var info = {
      service: "SuggestedLocation",
      location: this._locationsToBeDisplayed[idx]
    };
    var zoom = this._getZoom(info);
    this._setLabel(label);
    this._setPosition(position, zoom);
    if (this.options.displayMarker) {
      this._setMarker(position, info, this.options.displayInfo, this.options.markerStyle);
    }

    /**
     * event triggered when an element of the results is clicked for autocompletion
     *
     * @event searchengine:autocomplete:click
     */
    this.fire("searchengine:autocomplete:click", {
      data: this._locationsToBeDisplayed[idx]
    });
  },
  // ################################################################### //
  // ################### handlers events Geocode ####################### //
  // ################################################################### //

  /**
   * this method is called by event 'submit' on 'GPsearchInput' tag form
   * (cf. this._createSearchInputElement), and it gets the value of input.
   * this value is passed as a parameter for the service geocoding.
   * the results of the request are displayed into a window.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onGeocodingSearchSubmit: function onGeocodingSearchSubmit(e) {
    logger.log(e);
    var value = e.target[0].value;
    if (!value) {
      return;
    }

    // on sauvegarde le localisant
    this._currentGeocodingLocation = value;

    // on met en place l'affichage des resultats dans une fenetre de recherche.
    var context = this;
    this._requestGeocoding({
      query: value,
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log("request from Geocoding", results);
        if (results) {
          var locations = results.locations;
          context._fillGeocodedLocationListContainer(locations);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME cf. this.onAutoCompleteSearch()
        context._clearGeocodedLocation();
        logger.log(error.message);
      }
    });
  },
  /**
   * this method is called by event 'submit' on 'GPgeocodeResultsList' tag div
   * (cf. this._createGeocodeResultsListElement), and it selects the location.
   * this location displays a marker on the map.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onGeocodedResultsItemClick: function onGeocodedResultsItemClick(e) {
    var idx = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_3__["default"].index(e.target.id);
    var label = e.target.innerHTML;
    logger.log(idx, label);
    logger.log(this._geocodedLocations[idx]);
    if (!idx) {
      return;
    }
    var position = this._geocodedLocations[idx].position;
    var info = {
      service: "GeocodedLocation",
      location: this._geocodedLocations[idx]
    };
    var zoom = this._getZoom(info);
    this._setLabel(label);
    this._setPosition(position, zoom);
    if (this.options.displayMarker) {
      this._setMarker(position, info, this.options.displayInfo, this.options.markerStyle);
    }

    /**
     * event triggered when an element of the results is clicked for geocoding
     *
     * @event searchengine:geocode:click
     */
    this.fire("searchengine:geocode:click", {
      data: this._geocodedLocations[idx]
    });
  },
  // ################################################################### //
  // ############## handlers events Geocode Advanced ################### //
  // ################################################################### //

  /**
   * this method is called by event 'change' on 'GPadvancedSearchCode' tag select
   * (cf. this._createAdvancedSearchFormCodeElement), and it gets the value of
   * option selected.
   * this value is passed as a parameter to create the attributs container.
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onGeocodingAdvancedSearchCodeChange: function onGeocodingAdvancedSearchCodeChange(e) {
    logger.log(e);
    var idx = e.target.selectedIndex;
    var value = e.target.options[idx].value;
    if (!value) {
      return;
    }

    // INFORMATION
    // le declenchement de l'evenement va creer un container de filtre à la volée...
    // l'insertion des containers d'attributs dans le DOM sont :
    // - soit GPadvancedSearchFilters > PositionOfInterest
    // - soit GPadvancedSearchFilters > StreetAddress
    // - soit GPadvancedSearchFilters > CadastralParcel
    // cf. _setFilter() pour la creation du container

    this._setFilter(value);
  },
  /**
   * this method is called by event 'submit' on 'GPadvancedSearchForm' tag form
   * (cf. this._createAdvancedSearchPanelFormElement), and it gets the value of all input.
   * this value is passed as a parameter for the service geocoding.
   * the results of the request are displayed into a window.
   * TODO
   *
   * @param {Object} e - HTMLElement
   * @param {Array} data - [{key : ..., value : ...}]
   *
   * @private
   */
  onGeocodingAdvancedSearchSubmit: function onGeocodingAdvancedSearchSubmit(e, data) {
    logger.log(data);
    if (!data || data.length === 0) {
      return;
    }

    // recuperation des parametres des filtres pour les transmettre
    // à la requête, ainsi que le type de table de ressources de geocodage,
    // et le localisant
    var _index = this._currentGeocodingCode;
    var inputSearchTextContainer = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPsearchInputText-" + this._uid);
    var _location = inputSearchTextContainer.value;
    var _filterOptions = {};
    for (var i = 0; i < data.length; i++) {
      var filter = data[i];
      if (filter.value) {
        // On passe la section en majuscule car le service est caseSensitive
        if (filter.key === "section") {
          filter.value = filter.value.toUpperCase();
        }
        _filterOptions[filter.key] = filter.value;
      }
    }

    // on met en place l'affichage des resultats dans une fenetre de recherche.
    var context = this;
    this._requestGeocoding({
      query: _location,
      index: _index,
      filters: _filterOptions,
      // callback onSuccess
      onSuccess: function onSuccess(results) {
        logger.log(results);
        if (results) {
          var locations = results.locations;
          context._fillGeocodedLocationListContainer(locations);
        }
      },
      // callback onFailure
      onFailure: function onFailure(error) {
        // FIXME cf. this.onAutoCompleteSearch()
        context._clearGeocodedLocation();
        logger.log(error.message);
      }
    });
  },
  // ################################################################### //
  // ###### METHODES PUBLIQUES (INTERFACE AVEC LE CONTROLE) ############ //
  // ################################################################### //

  /**
   * This method is public.
   * It allows to control the execution of a geocoding or an autocompletion.
   *
   * @param {String} text - location
   * @param {Boolean} type - true (geocoding) / false (autocompletion)
   * @param {Object} options - options
   */
  setText: function setText(text, type, options) {
    if (!this._showContainer.checked) {
      this._pictoContainer.click();
    }

    // on récupere les options des services
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(this.options, options);
    var element = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPsearchInputText-" + this._uid);
    element.value = text;
    if (type) {
      var form = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPsearchInput-" + this._uid);
      form.dispatchEvent(new Event("submit", {
        bubbles: true,
        cancelable: true
      }));
    } else {
      element.dispatchEvent(new KeyboardEvent("keyup"));
    }
  }
});

/** mix in L.Evented into control */
leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.extend(SearchEngine.prototype, leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Evented.prototype);
/* harmony default export */ __webpack_exports__["default"] = (SearchEngine);

/***/ }),
/* 128 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * @module SearchEngineUtils
 * @alias [private] SearchEngineUtils
 * @description
 * ...
 *
 * @example
 * advancedSearchFiltersByDefault();
 * zoomToResultsByDefault();
 */
var SearchEngineUtils = {
  /**
   * Advanced Search Filters by default
   * @function advancedSearchFiltersByDefault
   */
  advancedSearchFiltersByDefault: {
    PositionOfInterest: [{
      name: "category",
      title: "Type",
      value: ["cimetière", "aérodrome", "réservoir", "administratif", "construction linéaire", "construction ponctuelle", "construction surfacique", "cours d'eau", "détail hydrographique", "détail orographique", "équipement de transport", "plan d'eau", "poste de transformation", "terrain de sport", "transport par câble", "zone d'activité ou d'intérêt", "zone d'habitation", "lieu-dit non habité"]
    }, {
      name: "postcode",
      title: "Code postal"
    }, {
      name: "citycode",
      title: "Code INSEE"
    }],
    StreetAddress: [{
      name: "city",
      title: "Ville"
    }, {
      name: "postcode",
      title: "Code postal"
    }, {
      name: "citycode",
      title: "Code INSEE"
    }],
    CadastralParcel: [{
      name: "departmentcode",
      title: "Code département (INSEE)",
      description: "Code INSEE du département (ex: 01, 94)"
    }, {
      name: "municipalitycode",
      title: "Code commune (INSEE)",
      description: "Code INSEE de la commune : 3 chiffres (ex: 067)"
    }, {
      name: "oldmunicipalitycode",
      title: "Commune absorbée",
      description: "Commune absorbée : 3 chiffres (ex: 000, 001)"
    }, {
      name: "districtcode",
      title: "Arrondissement",
      description: "Arrondissement : 3 chiffres (ex: 004, 012)"
    }, {
      name: "section",
      title: "Section",
      description: "Section Cadastrale : 2 caractères (chiffre et/ou lettre)"
    }, {
      name: "number",
      title: "Numéro",
      description: "Numéro de la parcelle : 4 chiffres (ex: 0041, 0250)"
    }, {
      name: "sheet",
      title: "Feuille",
      description: "Numéro de la feuille cadastrale"
    }]
  },
  /**
   * Provides default zoom based on results.
   *
   * @function zoomToResultsByDefault
   * @param {Object} info - location information
   * @returns {Integer} zoom level
   */
  zoomToResultsByDefault: function zoomToResultsByDefault(info) {
    // FIXME
    // la classification du geocodage est differente de l'importance de l'autocompletion !

    var zoom = 15;
    var service = info.service;
    var fields = info.fields;
    var type = info.type;
    var importance = {
      1: 11,
      2: 12,
      3: 13,
      4: 14,
      5: 15,
      6: 16,
      7: 17,
      8: 17
    };

    // AutoCompletion POI
    if (service === "SuggestedLocation") {
      if (type === "PositionOfInterest") {
        zoom = importance[fields.classification];
      }
    }

    // Geocodage POI
    if (service === "GeocodedLocation") {
      if (type === "PositionOfInterest") {
        zoom = importance[fields.importance] || 14; // au cas où la recherche est en freeform !
      }
    }
    if (type === "StreetAddress") {
      zoom = 17;
    }
    if (type === "CadastralParcel") {
      zoom = 17;
    }
    return zoom;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (SearchEngineUtils);

/***/ }),
/* 129 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(37);
/* harmony import */ var _Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(106);


var SearchEngineDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPsearchEngine");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################### Methods of main container ##################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing
   *
   * @returns {DOMElement} DOM element
   */
  _createShowSearchEngineElement: function _createShowSearchEngineElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowSearchEngine");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show search engine
   *
   * @returns {DOMElement} DOM element
   */
  _createShowSearchEnginePictoElement: function _createShowSearchEnginePictoElement() {
    // contexte d'execution
    var self = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowSearchEnginePicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowSearchEngine");
    label.title = "Afficher/masquer la recherche par lieux";

    // Close all results and panels when minimizing the widget
    label.addEventListener("click", function () {
      document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      var showAdvancedSearch = document.getElementById(self._addUID("GPshowAdvancedSearch"));
      if (showAdvancedSearch) {
        showAdvancedSearch.style.display = null;
        document.getElementById(self._addUID("GPadvancedSearchPanel")).style.display = "none";
      }
      var id = "#GPsearchInput-" + self._uid;
      document.querySelector(id + " input").disabled = false; // FIXME form[id^=GPsearchInput] = #GPsearchInput ?
      self.onShowSearchEngineClick();
    });
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowSearchEngineOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  /**
   * Simple search input
   * @param {String} placeholder - placeholder
   *
   * @returns {DOMElement} DOM element
   */
  _createSearchInputElement: function _createSearchInputElement(placeholder) {
    // contexte d'execution
    var self = this;
    var form = document.createElement("form");
    form.id = this._addUID("GPsearchInput");
    // Open geocode results panel when submitting the input
    form.addEventListener("submit", function (e) {
      e.preventDefault();
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "block";
      document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      // cf. FIXME
      // document.querySelector("#GPsearchInput input").blur ();

      // gestionnaire d'evenement :
      // on récupère la valeur de saisie pour requête sur le service de geocodage
      self.onGeocodingSearchSubmit(e);
      return false;
    });
    var input = document.createElement("input");
    input.id = this._addUID("GPsearchInputText");
    input.type = "text";
    input.placeholder = placeholder;
    input.autocomplete = "off";
    // Manage autocomplete list appearance when filling the address input
    input.addEventListener("keyup", function (e) {
      var charCode = e.which || e.keyCode;
      if (charCode === 13 || charCode === 10 || charCode === 38 || charCode === 40) {
        return;
      }
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      if (input.value.length > 2) {
        document.getElementById(self._addUID("GPautoCompleteList")).style.display = "block";
      } else {
        document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      }
      // gestionnaire d'evenement :
      // on récupère la valeur de saisie pour requête sur le service d'autocompletion
      self.onAutoCompleteSearchText(e);
    });

    // FIXME ce code interfere avec le click sur la liste des suggested locations !
    // input.addEventListener("blur", function(e) {
    //     document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
    // });

    input.addEventListener("keydown", function (e) {
      // FIXME
      // l'action clavier 'enter (13)' lance le submit de la form !
      // Ce comportement n'est pas souhaité car le submit execute un geocodage !
      // Il faut donc trouver le moyen d'eviter le submit sur un return venant
      // seulement d'une selection de suggestion...

      var charCode = e.which || e.keyCode;
      var container = document.getElementById(self._addUID("GPautocompleteResults"));

      // si aucun container !?
      if (!container) {
        return;
      }
      var curr = container.getElementsByClassName("GPautoCompleteProposal current");
      var list = container.getElementsByClassName("GPautoCompleteProposal");

      // si aucune suggestion, on ne va pas plus loin !
      var length = list.length;
      if (!length) {
        return;
      }
      var current = null;

      // si aucun item courant, on prend le 1er !
      if (!curr.length) {
        current = list[0];
        current.className = "GPautoCompleteProposal current";
        current.style.color = "#000000";
        current.style["background-color"] = "#CEDBEF";
        return;
      } else {
        current = curr[0];
      }
      var index = parseInt(_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_0__["default"].index(current.id), 10);
      var next = index === length - 1 ? list[0] : list[index + 1];
      var prev = index === 0 ? list[length - 1] : list[index - 1];
      current.style["background-color"] = "";
      current.style.color = "";
      prev.style["background-color"] = "";
      prev.style.color = "";
      next.style["background-color"] = "";
      next.style.color = "";
      switch (charCode) {
        case 38:
          // arrow up
          current.className = "GPautoCompleteProposal";
          prev.className = "GPautoCompleteProposal current";
          prev.style.color = "#000000";
          prev.style["background-color"] = "#CEDBEF";
          break;
        case 40:
          // arrow down
          current.className = "GPautoCompleteProposal";
          next.className = "GPautoCompleteProposal current";
          next.style.color = "#000000";
          next.style["background-color"] = "#CEDBEF";
          break;
        case 13:
          // enter
          // cf. FIXME
          e.preventDefault();
          current.click(e);
          break;
      }
      current.focus();
    });
    form.appendChild(input);
    var div = document.createElement("div");
    div.id = this._addUID("GPsearchInputReset");
    // Reset input
    div.addEventListener("click", function () {
      document.getElementById(self._addUID("GPsearchInputText")).value = "";
      document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      self.onSearchResetClick();
    });
    form.appendChild(div);
    return form;
  },
  /**
   * Show advanced search panel
   *
   * @returns {DOMElement} DOM element
   */
  _createShowAdvancedSearchElement: function _createShowAdvancedSearchElement() {
    // contexte d'execution
    var self = this;
    var div = document.createElement("div");
    div.id = this._addUID("GPshowAdvancedSearch");
    div.className = "GPshowAdvancedToolPicto";
    div.title = "Ouvrir la recherche avancée";

    // Open advanced search
    div.addEventListener("click", function () {
      var id = "#GPsearchInput-" + self._uid;
      document.querySelector(id + " input").disabled = true;
      document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      document.getElementById(self._addUID("GPshowAdvancedSearch")).style.display = "none";
      document.getElementById(self._addUID("GPadvancedSearchPanel")).style.display = "inline-block";
    });
    var span = document.createElement("span");
    span.id = this._addUID("GPshowAdvancedSearchOpen");
    span.className = "GPshowAdvancedToolOpen";
    div.appendChild(span);
    return div;
  },
  /**
   * Advanced search panel
   *
   * FIXME
   * don't call this._createAdvancedSearchPanelHeaderElement
   * don't call this._createAdvancedSearchPanelFormElement
   *
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchPanelElement: function _createAdvancedSearchPanelElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPadvancedSearchPanel");
    div.className = "GPpanel";
    div.style.display = "none";

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // div.appendChild(this._createAdvancedSearchPanelHeaderElement ());
    // div.appendChild(this._createAdvancedSearchPanelFormElement ());

    return div;
  },
  /**
   * Geocoding results
   *
   * FIXME
   * don't call this._createGeocodeResultsListElement
   *
   * @returns {DOMElement} DOM element
   */
  _createGeocodeResultsElement: function _createGeocodeResultsElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPgeocodeResultsList");
    div.className = "GPpanel";
    div.style.display = "none";
    div.appendChild(this._createGeocodeResultsHeaderElement());

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // div.appendChild(this._createGeocodeResultsListElement ());

    return div;
  },
  /**
   * Autocompletion results
   *
   * FIXME
   * don't call this._createAutoCompleteListElement
   *
   * @returns {DOMElement} DOM element
   */
  _createAutoCompleteElement: function _createAutoCompleteElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPautoCompleteList");
    div.className = "GPautoCompleteList"; // GPpanel ?
    div.style.display = "none";

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...
    // div.appendChild(this._createAutoCompleteListElement ());

    return div;
  },
  // ################################################################### //
  // ################### Autocompletion container ###################### //
  // ################################################################### //

  /**
   * Autocompletion results list.
   *
   * @returns {DOMElement} DOM element
   */
  _createAutoCompleteListElement: function _createAutoCompleteListElement() {
    // contexte d'execution
    var self = this;
    var container = document.createElement("div");
    container.id = this._addUID("GPautocompleteResults");
    if (container.addEventListener) {
      container.addEventListener("click", function (e) {
        self.onAutoCompletedResultsItemClick(e);
        document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      }, false);
    } else if (container.attachEvent) {
      container.attachEvent("onclick", function (e) {
        self.onAutoCompletedResultsItemClick(e);
        document.getElementById(self._addUID("GPautoCompleteList")).style.display = "none";
      });
    }

    // Proposals are dynamically filled in Javascript by autocomplete service
    // <div class="GPautoCompleteProposal">...</div>

    return container;
  },
  /**
   * Autocompletion result.
   * Proposals are dynamically filled in Javascript by autocomplete service
   *
   * TODO formaliser le contenu des reponse
   *
   * @param {Object} location - suggested or geocoded location results
   * @param {Number} id - ID
   */
  _createAutoCompletedLocationElement: function _createAutoCompletedLocationElement(location, id) {
    var container = document.getElementById(this._addUID("GPautocompleteResults"));
    var div = document.createElement("div");
    div.id = this._addUID("AutoCompletedLocation_" + id);
    div.className = "GPautoCompleteProposal";
    div.innerHTML = _Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_1__["default"].getSuggestedLocationFreeform(location);
    if (div.addEventListener) {
      div.addEventListener("click", function (e) {
        container.click(e);
      }, false);
    } else if (div.attachEvent) {
      div.attachEvent("onclick", function (e) {
        container.click(e);
      });
    }
    container.appendChild(div);
  },
  // ################################################################### //
  // ############### Geocoding with advanced container ################# //
  // ################################################################### //

  /**
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchPanelHeaderElement: function _createAdvancedSearchPanelHeaderElement() {
    // contexte d'execution
    var self = this;
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var divTitle = document.createElement("div");
    divTitle.className = "GPpanelTitle";
    divTitle.innerHTML = "Recherche avancée";
    container.appendChild(divTitle);
    var divClose = document.createElement("div");
    divClose.id = this._addUID("GPadvancedSearchClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer la recherche avancée";
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        var id = "#GPsearchInput-" + self._uid;
        document.querySelector(id + " input").disabled = false;
        document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
        document.getElementById(self._addUID("GPshowAdvancedSearch")).style.display = "inline-block";
        document.getElementById(self._addUID("GPadvancedSearchPanel")).style.display = "none";
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        var id = "#GPsearchInput-" + self._uid;
        document.querySelector(id + " input").disabled = false;
        document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
        document.getElementById(self._addUID("GPshowAdvancedSearch")).style.display = "inline-block";
        document.getElementById(self._addUID("GPadvancedSearchPanel")).style.display = "none";
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * @param {Object[]} advancedSearchCodes - codes
   *
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchPanelFormElement: function _createAdvancedSearchPanelFormElement(advancedSearchCodes) {
    // contexte d'execution
    var self = this;
    var form = document.createElement("form");
    form.id = this._addUID("GPadvancedSearchForm");
    form.addEventListener("submit", function (e) {
      e.preventDefault();
      // data
      var data = [];
      // liste des attributs de la ressource de geocodage
      var id = "#GPadvancedSearchFilters-" + self._uid;
      var matchesFilters = document.querySelectorAll(id + " > div > div > input");
      for (var i = 0; i < matchesFilters.length; i++) {
        var element = matchesFilters[i];
        data.push({
          key: element.name,
          value: element.value
        });
      }

      // gestionnaire d'evenement :
      // on récupère les valeurs de saisies pour requête sur le service de geocodage
      self.onGeocodingAdvancedSearchSubmit(e, data);
      document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "block";
      return false;
    });
    var div = document.createElement("div");
    div.className = "GPflexInput";
    var label = document.createElement("label");
    label.className = "GPadvancedSearchCodeLabel";
    label.innerHTML = "Recherche par";
    div.appendChild(label);
    var select = this._createAdvancedSearchFormCodeElement(advancedSearchCodes);
    div.appendChild(select);

    // FIXME on decompose la fonction pour les besoins du controle,
    // on ajoutera ces childs à la main...

    // var filters = this._createAdvancedSearchFormFiltersElement ();
    // form.appendChild(filters);

    // var input = this._createAdvancedSearchFormInputElement ();
    // form.appendChild(input);

    form.appendChild(div);
    return form;
  },
  /**
   * @param {Object[]} codes - codes
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchFormCodeElement: function _createAdvancedSearchFormCodeElement(codes) {
    // contexte d'execution
    var self = this;
    var select = document.createElement("select");
    select.id = this._addUID("GPadvancedSearchCode");
    select.className = "GPadvancedSearchCode";
    select.addEventListener("change", function (e) {
      // var idx   = e.target.selectedIndex;
      // var value = e.target.options[idx].value;
      // gestionnaire d'evenement :
      // permet de recuperer des informations diverses...
      self.onGeocodingAdvancedSearchCodeChange(e);
    }, false);

    // liste statique au cas où des codes n'ont pas été passés en entrée
    if (!codes) {
      codes = [{
        id: "PositionOfInterest",
        title: "Lieux/toponymes"
      }, {
        id: "StreetAddress",
        title: "Adresses"
      }, {
        id: "CadastralParcel",
        title: "Parcelles cadastrales"
      }];
    }
    for (var i = 0; i < codes.length; i++) {
      var option = document.createElement("option");
      option.value = codes[i].id;
      option.text = codes[i].title;
      select.appendChild(option);
    }
    return select;
  },
  /**
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchFormInputElement: function _createAdvancedSearchFormInputElement() {
    var input = document.createElement("input");
    input.type = "submit";
    input.id = this._addUID("GPadvancedSearchSubmit");
    input.className = "GPinputSubmit";
    input.value = "Chercher";
    return input;
  },
  /**
   * Filters geocoding.
   *
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchFormFiltersElement: function _createAdvancedSearchFormFiltersElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPadvancedSearchFilters");
    return container;
  },
  /**
   * Create filter container for resources :
   * "PositionOfInterest", "StreetAddress", ...
   *
   * @param {String} code - code of geocoding resource
   * @param {Boolean} display - display
   *
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchFiltersTableElement: function _createAdvancedSearchFiltersTableElement(code, display) {
    var container = document.createElement("div");
    container.id = this._addUID(code);
    if (!display) {
      container.style.display = "none";
    }
    return container;
  },
  /**
   * Create filter attribut for a resource :
   * "PositionOfInterest", "StreetAddress", ...
   * Research filters are filled in Javascript depending on developer choice
   *
   * @param {Object} filterAttributes - filter attributes :
   * @param {String} filterAttributes.code - code of geocoding resource
   * @param {String} filterAttributes.name - ID
   * @param {String} filterAttributes.title - label
   * @param {String} filterAttributes.description - description
   * @param {String} filterAttributes.value - value
   *
   * @returns {DOMElement} DOM element
   */
  _createAdvancedSearchFiltersAttributElement: function _createAdvancedSearchFiltersAttributElement(filterAttributes) {
    // INFORMATION
    // cette methode peut être appelée si le document n'existe pas, elle
    // permet ainsi de creer une div sans insertion dans le container...

    var container = null;
    var name = filterAttributes.name;
    var title = filterAttributes.title;
    var description = filterAttributes.description;
    var code = filterAttributes.code;
    var value = filterAttributes.value;
    var div = document.createElement("div");
    div.className = "GPflexInput";
    var label = document.createElement("label");
    label.className = "GPadvancedSearchFilterLabel";
    label.htmlFor = name;
    label.title = description || title;
    label.innerHTML = title;
    div.appendChild(label);
    var input = document.createElement("input");
    input.id = name;
    input.className = "GPadvancedSearchFilterInput";
    input.type = "text";
    input.name = name;
    if (value) {
      if (Array.isArray(value)) {
        var listId = name + "_list";
        input.setAttribute("list", listId);
        var dl = document.createElement("datalist");
        dl.id = listId;
        for (var i = 0; i < value.length; ++i) {
          var option = document.createElement("option");
          option.value = value[i];
          dl.appendChild(option);
        }
        div.appendChild(dl);
      } else {
        input.value = value;
      }
    }
    div.appendChild(input);
    container = document.getElementById(this._addUID(code));
    if (container) {
      container.appendChild(div);
    } else {
      // le container, c'est la div !
      container = div;
    }
    return container;
  },
  // ################################################################### //
  // ################## Geocoding results container #################### //
  // ################################################################### //

  /**
   * @returns {DOMElement} DOM element
   */
  _createGeocodeResultsHeaderElement: function _createGeocodeResultsHeaderElement() {
    var self = this;
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var divTitle = document.createElement("div");
    divTitle.className = "GPpanelTitle";
    divTitle.innerHTML = "Résultats de la recherche";
    container.appendChild(divTitle);
    var divClose = document.createElement("div");
    divClose.id = this._addUID("GPgeocodeResultsClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer la fenêtre de résultats";
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * Geocoding results list.
   *
   * @returns {DOMElement} DOM element
   */
  _createGeocodeResultsListElement: function _createGeocodeResultsListElement() {
    // contexte d'execution
    var self = this;
    var container = document.createElement("div");
    container.id = this._addUID("GPgeocodeResults");
    if (container.addEventListener) {
      container.addEventListener("click", function (e) {
        if (!e.ctrlKey) {
          document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
        }
        self.onGeocodedResultsItemClick(e);
      }, false);
    } else if (container.attachEvent) {
      container.attachEvent("onclick", function (e) {
        if (!e.ctrlKey) {
          document.getElementById(self._addUID("GPgeocodeResultsList")).style.display = "none";
        }
        self.onGeocodedResultsItemClick(e);
      });
    }
    // Results are dynamically filled in Javascript by geocoding service
    // <div class="GPautoCompleteProposal">...</div>

    return container;
  },
  /**
   * Geocoding result.
   * Results are dynamically filled in Javascript by geocoding service
   *
   * TODO formaliser le contenu des reponses
   * FIXME formater la reponse en amont !
   *
   * @param {Object} location - suggested or geocoded location results
   * @param {Number} id - ID
   */
  _createGeocodedLocationElement: function _createGeocodedLocationElement(location, id) {
    var container = document.getElementById(this._addUID("GPgeocodeResults"));
    var div = document.createElement("div");
    div.id = this._addUID("GeocodedLocation_" + id);
    div.className = "GPautoCompleteProposal";
    if (typeof location === "string") {
      div.innerHTML = location;
    } else {
      div.innerHTML = _Utils_GeocodeUtils__WEBPACK_IMPORTED_MODULE_1__["default"].getGeocodedLocationFreeform(location);
    }
    container.appendChild(div);
  }
};
/* harmony default export */ __webpack_exports__["default"] = (SearchEngineDOM);

/***/ }),
/* 130 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
/**
* @module Utils
* @alias Gp.olUtils
* @description
* ...
*
* @example
* detectSupport();
* assign();
* mergeParams();
*/
var Utils = {
  /**
   * this method is called by the constructor.
   * this information is useful to switch to touch mode.
   * Detection : test for desktop or tactile
   *
   * @function detectSupport
   * @returns {Boolean} isDesktop - true for desktop userAgent, false for mobile
   */
  detectSupport: function detectSupport() {
    var isDesktop = true;
    var userAgent = window.navigator.userAgent.toLowerCase();
    if (userAgent.indexOf("iphone") !== -1 || userAgent.indexOf("ipod") !== -1 || userAgent.indexOf("ipad") !== -1 || userAgent.indexOf("android") !== -1 || userAgent.indexOf("mobile") !== -1 || userAgent.indexOf("blackberry") !== -1 || userAgent.indexOf("tablet") !== -1 || userAgent.indexOf("phone") !== -1 || userAgent.indexOf("touch") !== -1) {
      isDesktop = false;
    }
    if (userAgent.indexOf("msie") !== -1 || userAgent.indexOf("trident") !== -1) {
      isDesktop = true;
    }
    return isDesktop;
  },
  /**
   *  Copies all source object members to dest
   *
   * @function assign
   * @param {Object} dest - destination object where properties and method will be copied
   * @param {Object} source - source object from which properties and method will be copied
   * @returns {Object} dest
   */
  assign: function assign(dest, source) {
    dest = dest || {};
    for (var prop in source) {
      if (source.hasOwnProperty(prop)) {
        dest[prop] = source[prop];
      }
    }
    return dest;
  },
  /**
   * Merge two objects parameters (deeper than assign)
   *
   * @function mergeParams
   * @param {Object} dest     - destination object where properties and method will be merge
   * @param {Object} source   - source object from which properties and method will be merge
   * @param {Boolean} replace - replace destination value by source if exists or not (true by default)
   */
  mergeParams: function mergeParams(dest, source, replace) {
    if (typeof dest === "undefined" || typeof source === "undefined") {
      return;
    }
    if (typeof replace === "undefined") {
      replace = true;
    }
    for (var param in source) {
      if (source.hasOwnProperty(param)) {
        if (_typeof(source[param]) === "object") {
          if (dest.hasOwnProperty(param)) {
            this.mergeParams(dest[param], source[param], replace);
          } else {
            dest[param] = source[param];
          }
        } else {
          if (dest.hasOwnProperty(param)) {
            if (replace) {
              dest[param] = source[param];
            }
          } else {
            dest[param] = source[param];
          }
        }
      }
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (Utils);

/***/ }),
/* 131 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var leaflet_draw__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(123);
/* harmony import */ var leaflet_draw__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(leaflet_draw__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(37);
/* harmony import */ var _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(107);
/* harmony import */ var _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(108);
/* harmony import */ var _Common_Controls_ElevationPathDOM__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(132);
/* harmony import */ var _Common_Controls_ProfileElevationPathDOM__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(133);
/* globals AmCharts, d3 */









var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_3__["default"].getLogger("ElevationPath");

/**
 * @classdesc
 *
 * Leaflet Control Class to compute and display Profil Elevation.
 *
 * Use {@link module:Controls.ElevationPath L.geoportalControl.ElevationPath()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#control" target="_blank">L.Control</a> native class.
 *
 * @namespace
 * @alias L.geoportalControl.ElevationPath
 */
var ElevationPath = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Control.extend( /** @lends L.geoportalControl.ElevationPath.prototype */{
  includes: _Common_Controls_ElevationPathDOM__WEBPACK_IMPORTED_MODULE_7__["default"],
  /**
   * Options du service
   *
   * @private
   */
  options: {
    position: "topleft",
    active: false,
    elevationPathOptions: {},
    stylesOptions: {},
    displayProfileOptions: {
      greaterSlope: true,
      meanSlope: true,
      ascendingElevation: true,
      descendingElevation: true,
      currentSlope: true,
      apply: null,
      target: null
    }
  },
  /**
   * @constructor ElevationPath
   *
   * @private
   * @param {Object} options - ElevationPath control options
   * @param {String}   [options.apiKey] - API key for services call (isocurve and autocomplete services). The "calcul" key is used by default.
   * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol)
   * @param {Boolean} [options.active] - Specify if widget has to be actived to drawing (true) or not (false) on map loading. Default is false.
   * @param {Object} [options.elevationPathOptions = {}] - elevation service options. See {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~getAltitude Gp.Services.getAltitude()} to know all elevation options
   * @param {Object} [options.displayProfileOptions = {}] - profile options.
   * @param {Function} [options.displayProfileOptions.apply] - function to display profil panel.
   * @param {Object} [options.displayProfileOptions.target] - container DOM for the profil panel.
   * @param {Boolean} [options.displayProfileOptions.greaterSlope = true] - display the greater slope into the graph
   * @param {Boolean} [options.displayProfileOptions.meanSlope = true] -  display the mean slope into the graph
   * @param {Boolean} [options.displayProfileOptions.ascendingElevation = true] -  display the ascending elevation into the graph
   * @param {Boolean} [options.displayProfileOptions.descendingElevation = true] -  display the descending elevation into the graph
   * @param {Boolean} [options.displayProfileOptions.currentSlope = true] -  display current slope value on profile mouseover
   *
   * @example
   *  var e = L.geoportalControl.ElevationPath({
   *      active : false,
   *      stylesOptions : {},
   *      elevationPathOptions : {},
   *      displayProfileOptions : {
   *       apply : null,
   *       target : null
   *      }
   *  });
   * Exemples :
   * - displayProfileOptions.apply : null
   * - displayProfileOptions.apply : function (elevations, container, context) {  // do some stuff... }
   * - displayProfileOptions.apply : ol.control.ElevationPath.DISPLAY_PROFILE_{LIB_AMCHARTS | LIB_D3 | RAW}
   * (detect auto lib. : d3 / AmCharts)
   */
  initialize: function initialize(options) {
    // on transmet les options au controle
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.setOptions(this, options);

    // uuid
    this._uid = _Common_Utils_SelectorID__WEBPACK_IMPORTED_MODULE_4__["default"].generate();

    // initialisation
    this._initDisplayProfileOptions();

    // les container
    this._showContainer = null;
    this._pictoContainer = null;
    this._panelContainer = null;
    this._profilContainer = null;
    this._waitingContainer = null;
    this._infoContainer = null;

    // timer sur la fenetre d'informations des données
    this._timerHdlr = null;

    // detection si le panneau est reduit
    this._reducePanel = false;

    // couche vectorielle dans laquelle seront saisis les points (features ci-dessus)
    this._featuresLayer = null;
    this._lastIdLayer = 0;
    this._currentIdLayer = 0;
    this._currentFeature = null;

    // graph
    this._profile = null;
    this._marker = null;

    // geometry à transmettre au service :  { lon : [], lat : []}
    this._geometry = null;

    // distance du segment
    this._distance = 0;

    // data elevations
    this._data = {};
  },
  /**
   * this method is called by this.addTo(map) when the control is added on the map
   * and fills variable 'this._container = this.onAdd(map)',
   * and create or disable events on map.
   *
   * @param {Object} map - the map
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  onAdd: function onAdd(map) {
    // initialisation du DOM du composant
    var container = this._container = this._initLayout();
    if (map) {
      // lors de l'ajout à la map, on active la saisie du point,
      // mais seulement si le widget est ouvert
      if (this.options.active) {
        if (this._profile === null) {
          this._panelContainer.style.display = "none";
          // this._panelContainer.style.visibility = "hidden";
        }
        this._activateMapInteraction(map);
      }
    }

    // deactivate of events that may interfere with the map
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomEvent.disableClickPropagation(container).disableScrollPropagation(container);
    return container;
  },
  /**
   * TODO this method is called when the control is removed from the map
   * and removes events on map.
   *
   * @private
   */
  onRemove: function onRemove( /* map */) {},
  // ################################################################### //
  // ####################### init application ########################## //
  // ################################################################### //

  /**
   * this method is called by the constructor and initialize the ...
   *
   * @private
   */
  _initDisplayProfileOptions: function _initDisplayProfileOptions() {
    // gestion de l'affichage du profil
    var _profileOpts = this.options.displayProfileOptions;

    // gestion de la fonction du profil
    var displayFunction = _profileOpts.apply;
    _profileOpts.apply = typeof displayFunction === "function" ? displayFunction : ElevationPath.DISPLAY_PROFILE_BY_DEFAULT;

    // gestion du container du profil
    var displayContainer = _profileOpts.target;
    _profileOpts.target = typeof displayContainer !== "undefined" ? displayContainer : null;

    // les autres options
    var _protoOpts = Object.getPrototypeOf(this.options);
    if (typeof _profileOpts.meanSlope === "undefined") {
      _profileOpts.meanSlope = _protoOpts.displayProfileOptions.meanSlope;
    }
    if (typeof _profileOpts.greaterSlope === "undefined") {
      _profileOpts.greaterSlope = _protoOpts.displayProfileOptions.greaterSlope;
    }
    if (typeof _profileOpts.ascendingElevation === "undefined") {
      _profileOpts.ascendingElevation = _protoOpts.displayProfileOptions.ascendingElevation;
    }
    if (typeof _profileOpts.descendingElevation === "undefined") {
      _profileOpts.descendingElevation = _protoOpts.displayProfileOptions.descendingElevation;
    }
    if (typeof _profileOpts.currentSlope === "undefined") {
      _profileOpts.currentSlope = _protoOpts.displayProfileOptions.currentSlope;
    }
  },
  // ################################################################### //
  // ########################### init dom ############################## //
  // ################################################################### //

  /**
   * this method is called by this.onAdd(map)
   * and initialize the container HTMLElement
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  _initLayout: function _initLayout() {
    // create main container
    var container = this._createMainContainerElement();
    var inputShow = this._showContainer = this._createShowElevationPathElement();
    container.appendChild(inputShow);

    // mode "collapsed"
    if (this.options.active) {
      this._showContainer.checked = true;
    }
    var picto = this._pictoContainer = this._createShowElevationPathPictoElement();
    container.appendChild(picto);

    // panneau
    var panel = this._panelContainer = this._createElevationPathPanelElement();

    // header
    var header = this._createElevationPathPanelHeaderElement();
    panel.appendChild(header);

    // profil
    var profil = this._profilContainer = this._createElevationPathPanelProfilElement();
    panel.appendChild(profil);

    // waiting
    var waiting = this._waitingContainer = this._createElevationPathWaitingElement();
    panel.appendChild(waiting);

    // info
    var info = this._infoContainer = this._createElevationPathInformationsElement();
    panel.appendChild(info);
    container.appendChild(panel);
    return container;
  },
  // ################################################################### //
  // ####################### handlers events to dom #################### //
  // ################################################################### //

  /**
   * this method is called by event 'click' on '' picto
   * and ...
   *
   * @param {Object} e - HTMLElement
   *
   * @private
   */
  onShowElevationPathClick: function onShowElevationPathClick(e) {
    logger.trace(e);
    var map = this._map;

    // interactions avec la carte
    if (!this._reducePanel) {
      if (this._showContainer.checked) {
        this._pictoContainer.style.display = "block";
        this._panelContainer.style.display = "none";
        this._removeMapInteraction(map);
        this._clear();
      } else {
        if (this._profile === null) {
          this._panelContainer.style.display = "none";
        }
        this._activateMapInteraction(map);
      }
    } else {
      if (this._profile !== null) {
        if (this.options.displayProfileOptions.target === null) {
          this._pictoContainer.style.display = "none";
        }
        this._panelContainer.style.display = "block";
      }
    }
    this._reducePanel = false;
  },
  /**
   * this method is called by event 'click' on '' picto
   * (cf. this.),
   * and reduce the panel
   *
   * @private
   */
  onReduceElevationPathPanelClick: function onReduceElevationPathPanelClick() {
    this._reducePanel = true;
    this._pictoContainer.style.display = "block";
    this._panelContainer.style.display = "none";
  },
  /**
   * this method is called by event 'click' on '' picto
   * (cf. this.),
   * and display the panel info
   * TODO
   *
   * @private
   */
  onOpenElevationPathInfoClick: function onOpenElevationPathInfoClick() {
    // options d'affichage
    var meanSlope = this.options.displayProfileOptions.meanSlope;
    var greaterSlope = this.options.displayProfileOptions.greaterSlope;
    var ascendingElevation = this.options.displayProfileOptions.ascendingElevation;
    var descendingElevation = this.options.displayProfileOptions.descendingElevation;

    // clean
    var div = this._infoContainer;
    if (div.childElementCount) {
      while (div.firstChild) {
        div.removeChild(div.firstChild);
      }
    }

    // creation des infomations

    if (ascendingElevation) {
      this._addElevationPathInformationsItem("Dénivelé positif : " + this._data.ascendingElevation.toLocaleString() + " m");
    }
    if (descendingElevation) {
      this._addElevationPathInformationsItem("Dénivelé négatif : " + this._data.descendingElevation.toLocaleString() + " m");
    }
    if (meanSlope) {
      this._addElevationPathInformationsItem("Pente moyenne : " + this._data.meanSlope.toLocaleString() + " %");
    }
    if (greaterSlope) {
      this._addElevationPathInformationsItem("Plus forte pente : " + this._data.greaterSlope.toLocaleString() + " %");
    }

    // show des informations !
    if (div.className === "GPelevationPathInformationsContainerVisible") {
      clearTimeout(this._timerHdlr);
      div.className = "GPelevationPathInformationsContainerHidden";
    } else {
      div.className = "GPelevationPathInformationsContainerVisible";
    }

    // hidden des informations !
    this._timerHdlr = setTimeout(function () {
      div.className = "GPelevationPathInformationsContainerHidden";
    }, 4000);
  },
  // ################################################################### //
  // ################### Map interactions management ################### //
  // ################################################################### //

  /**
   * this method is called by this.onShowElevationPathClick,
   * and calls method corresponding to current delimitation, if widget is not collapsed.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activateMapInteraction: function _activateMapInteraction(map) {
    logger.info("_activateMapInteraction()");

    // Creation de la couche vectorielle sur laquelle on va dessiner
    if (this._featuresLayer === null) {
      this._featuresLayer = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.FeatureGroup();
      map.addLayer(this._featuresLayer);
      var self = this;
      /* evenements : on desactive le menu systeme pour la saisie */
      map.on("contextmenu", function () {});

      /* evenement sur la carte lors d'une saisie,
      on y ajoute le layer, et on y stocke les coordonnées */
      map.on("draw:created", function (e) {
        logger.trace("draw:created");
        self._currentIdLayer = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.stamp(e.layer);
        self._getFeatureGeometry(e.layer);
        self._addFeatureLayer(e.layer);
      });

      /* evenements */
      map.on("draw:drawstart", function () {
        logger.trace("draw:drawstart");
        self._removeFeatureLayer(self._lastIdLayer);
        self._lastIdLayer = self._currentIdLayer;
      });

      /* evenements */
      map.on("draw:drawstop", function () {
        logger.trace("draw:drawstop");
        if (typeof self.options.elevationPathOptions.onSuccess === "undefined" && self.options.displayProfileOptions.target === null) {
          self._pictoContainer.style.display = "none";
          self._panelContainer.style.display = "block";
        }
        self._altiRequest();
      });
    }
    this._activatePolyLineInteraction(map);
  },
  /**
   * remove draw interaction from map (if exists)
   *
   * @param {Object} map - control map.
   * @private
   */
  _removeMapInteraction: function _removeMapInteraction(map) {
    if (!map) {
      return;
    }
    if (this._featuresLayer !== null) {
      map.off("draw:created");
      map.off("draw:drawstart");
      map.off("draw:drawstop");
      map.removeLayer(this._featuresLayer);
      this._featuresLayer = null;
    }
    this._lastIdLayer = this._currentIdLayer = 0;

    // FIXME delete this._currentFeature ?
    if (this._currentFeature) {
      this._currentFeature.disable();
    }
  },
  /**
   * this method is called by this._activateMapInteraction,
   * and creates map polyline drawing interaction.
   *
   * @param {Object} map - control map.
   * @private
   */
  _activatePolyLineInteraction: function _activatePolyLineInteraction(map) {
    if (this._currentFeature) {
      this._currentFeature.disable();
    }

    // liste des options par defaut
    // cf. https://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html
    // var polylineOptions = {
    //     allowIntersection : true,
    //     repeatMode : false,
    //     drawError : {
    //         color : "#b00b00",
    //         timeout : 2500
    //     },
    //     icon : new L.DivIcon({
    //         iconSize : new L.Point(8, 8),
    //         className : 'leaflet-div-icon leaflet-editing-icon'
    //     }),
    //     touchIcon : new L.DivIcon({
    //         iconSize : new L.Point(20, 20),
    //         className : 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
    //     }),
    //     guidelineDistance : 20,
    //     maxGuideLineLength : 4000,
    //     shapeOptions : {
    //         stroke : true,
    //         color : '#f06eaa',
    //         weight : 4,
    //         opacity : 0.5,
    //         fill : false,
    //         clickable : true
    //     },
    //     metric : true, // Whether to use the metric measurement system or imperial
    //     feet : true, // When not metric, to use feet instead of yards for display.
    //     nautic : false, // When not metric, not feet use nautic mile for display
    //     showLength : true, // Whether to display distance in the tooltip
    //     zIndexOffset : 2000 // This should be > than the highest z-index any map layersallowIntersection : true,
    // };

    var styles = this.options.stylesOptions || {};
    var _shapeOptions = Object.keys(styles).length !== 0 ? styles : {
      stroke: true,
      color: "#C77A04",
      weight: 4,
      opacity: 0.5,
      fill: false
    };
    this._currentFeature = new leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Draw.Polyline(map, {
      shapeOptions: _shapeOptions
    });
    this._currentFeature.enable();
  },
  /**
   * set current position of feature
   *
   * @param {Object} layer - layer
   * @private
   */
  _getFeatureGeometry: function _getFeatureGeometry(layer) {
    // on transmet toujours des coordonnées au service en EPSG:4326
    logger.log(layer.getLatLngs());
    if (this._geometry !== null) {
      this._geometry = null;
    }
    this._geometry = [];
    this._distance = 0;
    var geometry = layer.getLatLngs();
    for (var i = 0; i < geometry.length; i++) {
      // on transmet au service des coordonnées en EPSG:4326
      var LatLngI = geometry[i];
      var LatLngJ = geometry[i + 1];
      this._geometry.push({
        lon: LatLngI.lng,
        lat: LatLngI.lat
      });
      // on calcul la distance du segment
      if (LatLngJ) {
        this._distance += LatLngI.distanceTo(LatLngJ);
      }
    }
    logger.log("Geometry", this._geometry);
    logger.log("Distance", this._distance);
  },
  /**
   * set current layer of feature
   *
   * @param {Object} layer - layer
   * @private
   */
  _addFeatureLayer: function _addFeatureLayer(layer) {
    if (!this._featuresLayer) {
      return;
    }
    this._featuresLayer.addLayer(layer);
  },
  /**
   * remove layer feature from group
   *
   * @param {Integer} id - id
   * @private
   */
  _removeFeatureLayer: function _removeFeatureLayer(id) {
    if (!this._featuresLayer) {
      return;
    }
    if (id === 0) {
      return;
    }
    if (!id) {
      this._featuresLayer.clearLayers();
    } else {
      this._featuresLayer.removeLayer(id);
    }
  },
  // ################################################################### //
  // ############################ Alti request ######################### //
  // ################################################################### //

  /**
   * this methode is called by this. method,
   * it generates and sends alti request, then displays results
   *
   * @private
   */
  _altiRequest: function _altiRequest() {
    logger.log("_altiRequest");

    // les coordonnées sont obligatoires
    if (!this._geometry) {
      logger.log("missing position");
      return;
    }

    // on construit les options pour la requête
    var options = {};

    // on surcharge avec les options de l'utilisateur
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, this.options.elevationPathOptions);

    // au cas où la clef API n'est pas renseignée dans les options du service,
    // on utilise celle renseignée au niveau du controle, sinon la clé "calcul" est utilisée par défaut.
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      apiKey: options.apiKey || this.options.apiKey
    });

    // si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
    // true par défaut (https)
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      ssl: this.options.ssl
    });

    // le sampling est soit defini par l'utilisateur (opts),
    // ou soit calculé dynamiquement...
    var _sampling = options.sampling;
    if (!_sampling) {
      // computing sampling
      var _computeSampling;
      var _length = this._currentFeature._measurementRunningTotal; // FIXME !!!
      logger.trace("length", _length);
      var p = Math.floor(_length) / 5; // en mètre sur un pas moyen de 5m !
      if (p >= 200) {
        _computeSampling = 200;
      } else {
        _computeSampling = Math.floor(p);
      }
      _sampling = _computeSampling;
    }

    // on y ajoute les callbacks ainsi que les options par defaut
    var self = this;
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      // sampling à 200 (iso portail)
      sampling: _sampling,
      // callback onSuccess
      onSuccess: this.options.elevationPathOptions.onSuccess || function (result) {
        logger.log(result);
        if (result) {
          if (self.options.displayProfileOptions.target !== null) {
            self._pictoContainer.style.display = "block";
            self._panelContainer.style.display = "block";
          }
          self._displayProfil(result.elevations);
          self._waitingContainer.className = "GPelevationPathCalcWaitingContainerHidden";
          self._waiting = false;
        }
      },
      // callback onFailure
      onFailure: this.options.elevationPathOptions.onFailure || function (error) {
        logger.log(error.message);
        self._pictoContainer.style.display = "block";
        self._panelContainer.style.display = "none";
        self._waitingContainer.className = "GPelevationPathCalcWaitingContainerHidden";
        self._waiting = false;
        self._clear();
      }
    });

    // et enfin, la geometrie
    var positions = this._geometry;
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(options, {
      positions: positions
    });
    logger.log(options);

    // mise en place de la patience
    this._waitingContainer.className = "GPelevationPathCalcWaitingContainerVisible";

    // Request altitude service
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.getAltitude(options);
  },
  // ################################################################### //
  // ########################## Profil display ######################### //
  // ################################################################### //

  /**
   * this method computes results elevations (Z and distance)
   *
   * @param {Array} elevations - array of elevation
   * @return {Array} elevations
   * @private
   */
  _computeElevationMeasure: function _computeElevationMeasure(elevations) {
    // Returns the distance from c1 to c2 using the haversine formula
    var _haversineDistance = function _haversineDistance(c1, c2) {
      var lat1 = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__["default"].decimalToRadian(c1[1]);
      var lat2 = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__["default"].decimalToRadian(c2[1]);
      var deltaLatBy2 = (lat2 - lat1) / 2;
      var deltaLonBy2 = _Utils_PositionFormater__WEBPACK_IMPORTED_MODULE_5__["default"].decimalToRadian(c2[0] - c1[0]) / 2;
      var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) + Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) * Math.cos(lat1) * Math.cos(lat2);
      return 2 * 6378137 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    };
    var _data = elevations;
    var _unit = "m";
    var _sketchPoints = this._geometry;
    // section actuelle du sketch sur laquelle on est
    var _currentSection = 0;
    // longueur cumulée des sections précédentes
    var _previousSectionsLength = 0;
    var _nextSectionBegining = _sketchPoints[1];

    // Calcul de la distance au départ pour chaque point + arrondi des lat/lon
    _data[0].dist = 0;
    _data[0].slope = 0;
    _data[0].lat = Math.round(_data[0].lat * 10000) / 10000;
    _data[0].lon = Math.round(_data[0].lon * 10000) / 10000;
    var _distanceMinus = 0;
    var _distancePlus = 0;
    var _ascendingElevation = 0;
    var _descendingElevation = 0;
    var _distance = 0;
    var _slopes = 0;
    var distances = [];
    for (var i = 1; i < _data.length; i++) {
      var a = [_data[i].lon, _data[i].lat];
      var distanceToStart = _previousSectionsLength + _haversineDistance(a, [_sketchPoints[_currentSection].lon, _sketchPoints[_currentSection].lat]);
      var dist = distanceToStart - _distance;

      // Changement de section
      if (a[0].toFixed(8) === _nextSectionBegining.lon.toFixed(8) && a[1].toFixed(8) === _nextSectionBegining.lat.toFixed(8)) {
        _currentSection++;
        _previousSectionsLength = distanceToStart;
        // Pas de next section si on est sur le dernier point
        if (i !== _data.length - 1) {
          _nextSectionBegining = _sketchPoints[_currentSection + 1];
        }
      }
      var za = _data[i].z;
      var zb = _data[i - 1].z;
      if (za < 0) {
        za = 0;
      }
      if (zb < 0) {
        zb = 0;
      }
      var slope = za - zb;
      if (slope < 0) {
        _distanceMinus += dist;
        _descendingElevation += slope;
      } else if (slope > 0) {
        _distancePlus += dist;
        _ascendingElevation += slope;
      }
      _distance = distanceToStart;
      _data[i].dist = distanceToStart;
      distances.push(distanceToStart);
      _slopes += slope ? Math.abs(Math.round(slope / dist * 100)) : 0;
      _data[i].slope = slope ? Math.abs(Math.round(slope / dist * 100)) : 0;

      // EVOL ?
      // cf. gradiant
      // http://www.color-hex.com/color/00b798
      var value = _data[i].slope;
      if (value > 15 && value < 30) {
        _data[i].color = "#005b4c";
      } else if (value > 30 && value < 45) {
        _data[i].color = "#00362d";
      } else if (value > 45) {
        _data[i].color = "#00120f";
      } else {
        _data[i].color = "#00B798";
      }
      _data[i].lat = Math.round(_data[i].lat * 10000) / 10000;
      _data[i].lon = Math.round(_data[i].lon * 10000) / 10000;
    }

    // check distance totale
    logger.trace("List Distances", distances);

    // Correction des altitudes aberrantes + arrondi des calculs de distance + ...
    var _altMin = _data[0].z;
    var _altMax = _data[0].z;
    var _greaterSlope = _data[0].slope;
    for (var ji = 0; ji < _data.length; ji++) {
      var d = _data[ji];
      if (d.z < -100) {
        d.z = 0;
      }
      if (d.z > _altMax) {
        _altMax = d.z;
      }
      if (d.z < _altMin) {
        _altMin = d.z;
      }
      if (d.slope > _greaterSlope) {
        _greaterSlope = d.slope;
      }
    }
    return {
      greaterSlope: _greaterSlope,
      // pente max
      meanSlope: Math.round(_slopes / _data.length),
      // pente moyenne
      distancePlus: _distancePlus,
      // distance cumulée positive
      distanceMinus: _distanceMinus,
      // distance cumulée négative
      ascendingElevation: _ascendingElevation,
      // dénivelé cumulée positive
      descendingElevation: _descendingElevation,
      // dénivelé cumulée négative
      altMin: _altMin.toLocaleString(),
      // altitude min TODO: inutile ?
      altMax: _altMax.toLocaleString(),
      // altitude max TODO: inutile ?
      distance: this._distance,
      // distance totale
      unit: _unit,
      // unité des mesures de distance
      points: _data
    };
  },
  /**
   * this method is called by this. (in case of success)
   * and display results
   *
   * @param {Array} elevations - array of elevation
   * @private
   */
  _displayProfil: function _displayProfil(elevations) {
    // on reactive le menu systeme en fin de saisie !
    var map = this._map;
    map.off("contextmenu");

    // data
    if (this._data) {
      this._data = {};
    }

    // sauvegarde des données
    var data = this._data = this._computeElevationMeasure(elevations);

    // container
    var container = this.options.displayProfileOptions.target;
    if (container) {
      container.appendChild(this._panelContainer);
    }
    container = this._profilContainer;

    // TODO contexte ?
    var context = this;
    var _profileOpts = this.options.displayProfileOptions;

    // fonction
    var displayFunction = _profileOpts.apply;

    // Calcul du profil
    if (typeof AmCharts !== "undefined" && typeof d3 !== "undefined") {
      logger.trace("Aucune lib. n'est presente !");
    }

    // execution...
    displayFunction.call(this, data, container, context);

    // affichage des informations du profil ?
    var element = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.DomUtil.get("GPelevationPathPanelInfo-" + this._uid);
    if (_profileOpts.greaterSlope || _profileOpts.meanSlope || _profileOpts.ascendingElevation || _profileOpts.descendingElevation) {
      // on affiche les informations
      element.style.display = "block";
    }
  },
  // ################################################################### //
  // ################################ clean ############################ //
  // ################################################################### //

  /**
   * this method clears all data
   *
   * @private
   */
  _clear: function _clear() {
    this._geometry = null;
    this._profile = null;

    // on vide le container
    if (this._profilContainer) {
      while (this._profilContainer.firstChild) {
        this._profilContainer.removeChild(this._profilContainer.firstChild);
      }
    }

    // on supprime le marker
    var map = this._map;
    if (this._marker) {
      map.removeLayer(this._marker);
      this._marker = null;
    }
  }
});

/**
 * create Profile Marker
 *
 * @param {Object} context - context
 * @param {Object} data - data
 */
ElevationPath.__createProfileMarker = function (context, data) {
  logger.log("__createProfileMarker");
  var self = context;
  var map = self._map;

  // var _srs    = L.CRS.EPSG4326;
  // var _pointA = _srs.latLngToPoint(L.latLng(self._geometry[0].lat, self._geometry[0].lon));
  // var _pointB = _srs.latLngToPoint(L.latLng(self._geometry[self._geometry.length - 1].lat, self._geometry[self._geometry.length - 1].lon));
  // var _point  = L.LineUtil.closestPointOnSegment(_srs.latLngToPoint(L.latLng(data.lat, data.lon)), _pointA, _pointB );

  // creation d"un marker
  self._marker = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.marker(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(data), {
    icon: new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__["default"]("orange"),
    draggable: false,
    clickable: false,
    zIndexOffset: 1000
  });
  self._marker.addTo(map);
};

/**
 * update Profile Marker
 *
 * @param {Object} context - context
 * @param {Object} data - data
 */
ElevationPath.__updateProfileMarker = function (context, data) {
  logger.log("__updateProfileMarker");
  var self = context;
  var map = self._map;

  // var _srs    = L.CRS.EPSG4326;
  // var _pointA = _srs.latLngToPoint(L.latLng(self._geometry[0].lat, self._geometry[0].lon));
  // var _pointB = _srs.latLngToPoint(L.latLng(self._geometry[self._geometry.length - 1].lat, self._geometry[self._geometry.length - 1].lon));
  // var _point  = L.LineUtil.closestPointOnSegment( _srs.latLngToPoint(L.latLng(data.lat, data.lon)), _pointA, _pointB );

  if (self._marker) {
    self._marker.setLatLng(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(data));
    self._marker.update();
  } else {
    // creation d"un marker
    self._marker = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.marker(leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.latLng(data), {
      icon: new _Utils_IconDefault__WEBPACK_IMPORTED_MODULE_6__["default"]("orange"),
      draggable: false,
      clickable: false,
      zIndexOffset: 1000
    });
    self._marker.addTo(map);
  }
};

/**
 * remove Profile Marker
 *
 * @param {Object} context - context
 */
ElevationPath.__removeProfileMarker = function (context) {
  logger.log("__removeProfileMarker");
  var self = context;
  var map = self._map;
  if (self._marker) {
    map.removeLayer(self._marker);
    self._marker = null;
  }
};

/**
 * custom operation into raw profil...
 * TODO
 */
ElevationPath.__customRawProfileOperation = function () {
  logger.log("__customRawProfileOperation");
};

/**
 * custom operation into raw profil...
 * TODO
 *
 * @param {Object} context - context
 * @param {Object} e - event
 */
ElevationPath.__customRawProfileMouseOverEvent = function (context, e) {
  logger.log("__customRawProfileMouseOverEvent", context, e);
};

/**
 * Display Profile function used by default : no additonal framework needed.
 *
 * @static
 * @param {Object} data - elevations values for profile
 * @param {HTMLElement} container - html container where to display profile
 * @param {Object} context - this control object
 */
ElevationPath.DISPLAY_PROFILE_BY_DEFAULT = function (data, container, context) {
  logger.trace("ElevationPath.DISPLAY_PROFILE_BY_DEFAULT");
  var profile = _Common_Controls_ProfileElevationPathDOM__WEBPACK_IMPORTED_MODULE_8__["default"].displayProfileByDefault(data, container, context, ElevationPath);
  // on sauvegarde le profil du container dans l'objet
  if (profile) {
    this._profile = profile;
  }
};

/**
 * Display Profile without graphical rendering (raw service response)
 *
 * @static
 * @param {Object} data - elevations values for profile
 * @param {HTMLElement} container - html container where to display profile
 * @param {Object} context - this control object
 */
ElevationPath.DISPLAY_PROFILE_RAW = function (data, container, context) {
  logger.trace("ElevationPath.DISPLAY_PROFILE_RAW");
  var profile = _Common_Controls_ProfileElevationPathDOM__WEBPACK_IMPORTED_MODULE_8__["default"].displayProfileRaw(data, container, context, ElevationPath);
  // on sauvegarde le profil du container dans l'objet
  if (profile) {
    this._profile = profile;
  }
};

/**
 * Display Profile using D3 javascript framework. This method needs D3 libraries to be loaded.
 *
 * @static
 * @param {Object} data - elevations values for profile
 * @param {HTMLElement} container - html container where to display profile
 * @param {Object} context - this control object
 */
ElevationPath.DISPLAY_PROFILE_LIB_D3 = function (data, container, context) {
  logger.trace("ElevationPath.DISPLAY_PROFILE_LIB_D3");
  if (typeof d3 === "undefined") {
    logger.log("Lib. D3 is not loaded !");
    return;
  }
  var profile = _Common_Controls_ProfileElevationPathDOM__WEBPACK_IMPORTED_MODULE_8__["default"].displayProfileLibD3(data, container, context, ElevationPath);
  // on sauvegarde le profil du container dans l'objet
  if (profile) {
    this._profile = profile;
  }
};

/**
 * Display Profile using Amcharts framework. This method needs AmCharts libraries to be loaded.
 *
 * @static
 * @param {Object} data - elevations values for profile
 * @param {HTMLElement} container - html container where to display profile
 * @param {Object} context - this control object
 */
ElevationPath.DISPLAY_PROFILE_LIB_AMCHARTS = function (data, container, context) {
  logger.trace("ElevationPath.DISPLAY_PROFILE_LIB_AMCHARTS");

  // Calcul du profile
  if (typeof AmCharts === "undefined") {
    logger.log("Lib. AmCharts is not loaded !");
    return;
  }
  var profile = _Common_Controls_ProfileElevationPathDOM__WEBPACK_IMPORTED_MODULE_8__["default"].displayProfileLibAmCharts(data, container, context, ElevationPath);
  // on sauvegarde le profil du container dans l'objet
  if (profile) {
    this._profile = profile;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ElevationPath);

/***/ }),
/* 132 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
var ElevationPathDOM = {
  /**
  * Add uuid to the tag ID
  * @param {String} id - id selector
  * @returns {String} uid - id selector with an unique id
  */
  _addUID: function _addUID(id) {
    var uid = this._uid ? id + "-" + this._uid : id;
    return uid;
  },
  /**
   * Main container (DOM)
   *
   * @returns {DOMElement} DOM element
   */
  _createMainContainerElement: function _createMainContainerElement() {
    var container = document.createElement("div");
    container.id = this._addUID("GPelevationPath");
    container.className = "GPwidget";
    return container;
  },
  // ################################################################### //
  // ################# Methods to display Main Panel ################### //
  // ################################################################### //

  /**
   * Hidden checkbox for minimizing/maximizing panel
   *
   * @returns {DOMElement} DOM element
   */
  _createShowElevationPathElement: function _createShowElevationPathElement() {
    var input = document.createElement("input");
    input.id = this._addUID("GPshowElevationPath");
    input.type = "checkbox";
    return input;
  },
  /**
   * Show control
   * see event !
   *
   * @returns {DOMElement} DOM element
   */
  _createShowElevationPathPictoElement: function _createShowElevationPathPictoElement() {
    // contexte d'execution
    var context = this;
    var label = document.createElement("label");
    label.id = this._addUID("GPshowElevationPathPicto");
    label.className = "GPshowAdvancedToolPicto";
    label.htmlFor = this._addUID("GPshowElevationPath");
    label.title = "Calculer un profil";

    // gestionnaire d'evenement :
    // on ouvre le menu de saisie de saisie
    // L'ouverture/Fermeture permet de faire le menage
    // (reinitialisation)
    if (label.addEventListener) {
      label.addEventListener("click", function (e) {
        context.onShowElevationPathClick(e);
      });
    } else if (label.attachEvent) {
      label.attachEvent("onclick", function (e) {
        context.onShowElevationPathClick(e);
      });
    }
    var spanOpen = document.createElement("span");
    spanOpen.id = this._addUID("GPshowElevationPathOpen");
    spanOpen.className = "GPshowAdvancedToolOpen";
    label.appendChild(spanOpen);
    return label;
  },
  // ################################################################### //
  // ######################### Methods to Panel ######################## //
  // ################################################################### //

  /**
   * Create Container Panel
   *
   * FIXME
   * don't call this._createElevationPathPanelHeaderElement
   * don't call this._createElevationPathPanelProfilElement
   *
   * @returns {DOMElement} DOM element
   */
  _createElevationPathPanelElement: function _createElevationPathPanelElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPelevationPathPanel");
    div.className = "GPpanel";

    // div.appendChild(this._createElevationPathPanelHeaderElement());
    // div.appendChild(this._createElevationPathPanelProfilElement());

    return div;
  },
  /**
   * Create Header Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createElevationPathPanelHeaderElement: function _createElevationPathPanelHeaderElement() {
    var self = this;
    var container = document.createElement("div");
    container.className = "GPpanelHeader";
    var divInfo = document.createElement("div");
    divInfo.id = this._addUID("GPelevationPathPanelInfo");
    divInfo.className = "GPpanelInfo";
    divInfo.title = "Informations";
    // add event on click
    if (divInfo.addEventListener) {
      divInfo.addEventListener("click", function () {
        self.onOpenElevationPathInfoClick();
      });
    } else if (divInfo.attachEvent) {
      // internet explorer
      divInfo.attachEvent("onclick", function () {
        self.onOpenElevationPathInfoClick();
      });
    }
    container.appendChild(divInfo);
    var divTitle = document.createElement("div");
    divTitle.className = "GPpanelTitle";
    divTitle.innerHTML = "Profil Altimétrique";
    container.appendChild(divTitle);
    var divReduce = document.createElement("div");
    divReduce.id = this._addUID("GPelevationPathPanelReduce");
    divReduce.className = "GPpanelReduce";
    divReduce.title = "Masquer le panneau";
    if (divReduce.addEventListener) {
      divReduce.addEventListener("click", function () {
        if (typeof self.onReduceElevationPathPanelClick === "function") {
          document.getElementById(self._addUID("GPshowElevationPath")).checked = false;
          self.onReduceElevationPathPanelClick();
        }
      }, false);
    } else if (divReduce.attachEvent) {
      divReduce.attachEvent("onclick", function () {
        if (typeof self.onReduceElevationPathPanelClick === "function") {
          document.getElementById(self._addUID("GPshowElevationPath")).checked = false;
          self.onReduceElevationPathPanelClick();
        }
      });
    }
    container.appendChild(divReduce);
    var divClose = document.createElement("div");
    divClose.id = this._addUID("GPelevationPathPanelClose");
    divClose.className = "GPpanelClose";
    divClose.title = "Fermer le panneau";

    // Link panel close / visibility checkbox
    if (divClose.addEventListener) {
      divClose.addEventListener("click", function () {
        document.getElementById(self._addUID("GPshowElevationPathPicto")).click();
      }, false);
    } else if (divClose.attachEvent) {
      divClose.attachEvent("onclick", function () {
        document.getElementById(self._addUID("GPshowElevationPathPicto")).click();
      });
    }
    container.appendChild(divClose);
    return container;
  },
  /**
   * Create Form
   * see evenement !
   *
   * @returns {DOMElement} DOM element
   */
  _createElevationPathPanelProfilElement: function _createElevationPathPanelProfilElement() {
    var div = document.createElement("div");
    div.id = "GPelevationPathProfil";
    return div;
  },
  /**
   * Create Waiting Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createElevationPathWaitingElement: function _createElevationPathWaitingElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPelevationPathCalcWaitingContainer");
    div.className = "GPelevationPathCalcWaitingContainerHidden";
    var p = document.createElement("p");
    p.className = "GPelevationPathCalcWaiting";
    p.innerHTML = "Calcul en cours...";
    div.appendChild(p);
    return div;
  },
  /**
   * Create information Panel
   *
   * @returns {DOMElement} DOM element
   */
  _createElevationPathInformationsElement: function _createElevationPathInformationsElement() {
    var div = document.createElement("div");
    div.id = this._addUID("GPelevationPathInformationsContainer");
    div.className = "GPelevationPathInformationsContainerHidden";
    var p = document.createElement("p");
    p.className = "GPelevationPathInformations";
    p.innerHTML = "Aucune information...";
    div.appendChild(p);
    return div;
  },
  /**
   * Add a information into Panel
   *
   * @param {String} value - value of item
   * @returns {DOMElement} DOM element
   */
  _addElevationPathInformationsItem: function _addElevationPathInformationsItem(value) {
    var div = document.getElementById(this._addUID("GPelevationPathInformationsContainer"));
    if (div) {
      var p = document.createElement("p");
      p.className = "GPelevationPathInformations";
      p.innerHTML = value;
      div.appendChild(p);
    }
    return div;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ElevationPathDOM);

/***/ }),
/* 133 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* globals AmCharts, d3 */

/**
 * @module ProfileElevationPathDOM
 * @alias [private] ProfileElevationPathDOM
 * @description
 * create DOM element
 */
var ProfileElevationPathDOM = {
  /**
   * Gets a css property from an element
   *
   * @private
   * @param {HTMLElement} element The element to get the property from
   * @param {String} property The css property
   * @returns {String} The value of the property
   *
   * @see https://stackoverflow.com/questions/7444451/how-to-get-the-actual-rendered-font-when-its-not-defined-in-css
   */
  _getCssProperty: function _getCssProperty(element, property) {
    return window.getComputedStyle(element, null).getPropertyValue(property);
  },
  /**
   * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
   *
   * @private
   * @param {String} text The text to be rendered.
   * @param {HTMLElement} container The container of the text
   * @param {String} font The font of the container if known, format: 'weight size familiy'
   * @returns {Number} The width of the text
   *
   * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
   */
  _getTextWidth: function _getTextWidth(text, container) {
    var font = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
    // re-use canvas object for better performance
    var canvas = /** ts-syntax */this.canvas || (this.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    if (font === null) {
      context.font = "".concat(this._getCssProperty(container, "font-weight"), " ").concat(this._getCssProperty(container, "font-size"), " ").concat(this._getCssProperty(container, "font-family"));
    } else {
      context.font = font;
    }
    var metrics = context.measureText(text);
    return metrics.width;
  },
  /**
   * Converts a data point z to svg y coord
   *
   * @private
   * @param {Object} z The z to convert.
   * @param {Number} pathHeight The height of the path in the svg container in px
   * @param {Number} minGraphZ Min z of the graph
   * @param {Number} pxPerMZ Number of pixels per meter for the z (y) axis
   * @returns {Number} The y svg coordinate of the point
   *
   */
  _dataZToSvgY: function _dataZToSvgY(z, pathHeight, minGraphZ, pxPerMZ) {
    return pathHeight - (z - minGraphZ) * pxPerMZ - 0.5;
  },
  /**
   * Converts a data point dist value to svg x coord
   *
   * @private
   * @param {Number} dist The dist to convert
   * @param {Number} svgWidth The witdth of the svg container in px
   * @param {Number} pathWidth The witdth of the path in the svg container in px
   * @param {Number} pxPerMX Number of pixels per meter for the x axis
   * @returns {Array} The x svg coordinate of the point
   *
   */
  _dataDistToSvgX: function _dataDistToSvgX(dist, svgWidth, pathWidth, pxPerMX) {
    return svgWidth - pathWidth + dist * pxPerMX;
  },
  /**
   * Converts a svg x coord to dist value
   *
   * @private
   * @param {Number} svgX The dist to convert
   * @param {Number} svgWidth The witdth of the svg container in px
   * @param {Number} pathWidth The witdth of the path in the svg container in px
   * @param {Number} pxPerMX Number of pixels per meter for the x axis
   * @returns {Array} The dist value
   *
   */
  _svgXToDataDist: function _svgXToDataDist(svgX, svgWidth, pathWidth, pxPerMX) {
    return (svgX + pathWidth - svgWidth) / pxPerMX;
  },
  /**
   * Returns the index of value if it were inserted in sorted (by dist) array of data points.
   *
   * @private
   * @param {Array} array Sorted array of data points (with dist property)
   * @param {Number} value Value to test the index of.
   * @returns {Number} The index the value would have.
   *
   */
  _arrayBisect: function _arrayBisect(array, value) {
    var idx;
    if (array.length === 0) {
      return 0;
    }
    for (idx = 0; idx < array.length; idx++) {
      if (value < array[idx].dist) {
        return idx;
      }
    }
    return idx - 1;
  },
  /**
   * Display Profile function used by default : no additonal framework needed.
   *
   * @public
   * @param {Object} data - elevations values for profile
   * @param {HTMLElement} container - html container where to display profile
   * @param {Object} context - this control object
   * @param {Object} className - calling class (ie ElevationPath)
   * @returns {DOMElement} profil container
   */
  displayProfileByDefault: function displayProfileByDefault(data, container, context, className) {
    var self = context;
    if (!container) {
      return;
    }
    if (!data) {
      return;
    }

    // on nettoie toujours...
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
    var margin = {
      top: 25,
      right: 15,
      bottom: 10,
      left: 10
    };
    var _displayProfileOptions = self.options.displayProfileOptions;
    var _points = data.points;
    var sortedElev = JSON.parse(JSON.stringify(_points));
    sortedElev.sort(function (e1, e2) {
      return e1.z - e2.z;
    });
    var minZ = sortedElev[0].z;
    var maxZ = sortedElev[sortedElev.length - 1].z;
    var dist = data.distance;
    var distUnit = "m";
    var widgetDiv = document.createElement("div");
    widgetDiv.id = "profileElevationByDefault";
    container.appendChild(widgetDiv);

    // Détermination des tailles en pixels des éléments du widget
    var clientWidth = window.getComputedStyle(container).getPropertyValue("width").replace(/px/, "");
    var clientHeight = window.getComputedStyle(container).getPropertyValue("height").replace(/px/, "");
    var widgetHeigth = clientHeight - margin.top - margin.bottom;
    var widgetWidth = clientWidth - margin.left - margin.right;
    // const widgetHeigth = container.clientHeight - margin.top - margin.bottom;
    // const widgetWidth = container.clientWidth - margin.left - margin.right;

    var zLabelWidth = 17;
    var zGradWidth = this._getTextWidth(Math.round(maxZ).toLocaleString() + ",88", container, "400 10 Verdana");
    var xLabelHeight = 17;
    var xGradHeight = 15;
    var minZguideHeigth = 15;
    var minXguideWidth = this._getTextWidth(Math.round(dist).toLocaleString() + ",5", container);
    var minNumXGuides = 1;
    var pathHeight = widgetHeigth - xLabelHeight - xGradHeight;
    var pathWidth = widgetWidth - zLabelWidth - zGradWidth;
    var elevationSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    elevationSvg.id = "profileElevationByDefaultSvg";
    elevationSvg.setAttribute("style", "display: block; margin: auto; overflow: visible; position: absolute; left: 10px;");
    elevationSvg.setAttribute("viewBox", "0 0 ".concat(clientWidth, " ").concat(clientHeight));
    elevationSvg.setAttribute("width", "100%");
    elevationSvg.setAttribute("height", "100%");

    // Détermination des guides en ordonnée :
    var maxNumZguides = Math.floor(pathHeight / minZguideHeigth);
    var gradZ;
    // Traitement du cas altitude max = altitude min
    if (maxZ === minZ) {
      gradZ = 0.1;
    } else {
      gradZ = Math.pow(10, Math.ceil(Math.log((maxZ - minZ) / maxNumZguides) / Math.log(10))) / 2;
    }
    var minGraphZ = Math.floor(minZ / gradZ) * gradZ;
    var maxGraphZ = Math.ceil(maxZ / gradZ) * gradZ;
    // cas où le path atteint pile les graduations extremes : ajout d'une gradiation
    if (maxGraphZ === maxZ) {
      maxGraphZ += gradZ;
    }
    // cas où gradZ < 1 : nombres flottants capricieux...
    minGraphZ = Math.round(minGraphZ * 100) / 100;
    maxGraphZ = Math.round(maxGraphZ * 100) / 100;
    var numZguides = Math.round((maxGraphZ - minGraphZ) / gradZ);

    // Si plus de guides que le max, on passe à une graduation de 10**x en 10**x (et non 10**x / 2)
    if (numZguides + 1 > maxNumZguides) {
      gradZ = Math.pow(10, Math.ceil(Math.log((maxZ - minZ) / maxNumZguides) / Math.log(10)));
      minGraphZ = Math.floor(minZ / gradZ) * gradZ;
      maxGraphZ = Math.ceil(maxZ / gradZ) * gradZ;
      // cas où le path atteint pile les graduations extremes : ajout d'une gradiation
      if (maxGraphZ === maxZ) {
        maxGraphZ += gradZ;
      }
      // cas où gradZ < 1 : nombres flottants capricieux...
      minGraphZ = Math.round(minGraphZ * 100) / 100;
      maxGraphZ = Math.round(maxGraphZ * 100) / 100;
      numZguides = Math.floor((maxGraphZ - minGraphZ) / gradZ);
    }
    numZguides = Math.max(Math.round(numZguides), 1);
    var axisZ = document.createElementNS("http://www.w3.org/2000/svg", "g");
    axisZ.setAttribute("class", "profile-z-vertical");
    var guidesZ = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var gradZyOffsetPx = pathHeight / numZguides;
    var pxPerMZ;
    // Traitement du cas altitude max = altitude min
    if (maxZ === minZ) {
      pxPerMZ = pathHeight / 0.2;
    } else {
      pxPerMZ = pathHeight / (maxGraphZ - minGraphZ);
    }
    var gradZtext;
    var yTextTranslation;
    var yStrokeTranslation;
    var gradZstroke;
    var gradZpath;
    var gradZgrad;
    // Ajout des graduations au graphique
    for (var i = 0; i <= numZguides; i++) {
      gradZtext = document.createElementNS("http://www.w3.org/2000/svg", "text");
      gradZtext.setAttribute("class", "profile-z-graduation");
      gradZtext.setAttribute("font-family", "Verdana");
      gradZtext.setAttribute("font-size", "10px");
      gradZtext.setAttribute("fill", "#5E5E5E");
      // Cas où gradZ < 1 : nombres flottants capricieux...
      // Le Math.round est pour éviter des ennuis du genre 3 * 0.1 = 0.300000000000004
      gradZtext.textContent = (Math.round(100 * (minGraphZ + i * gradZ)) / 100).toLocaleString();
      yTextTranslation = pathHeight - i * gradZyOffsetPx;
      gradZtext.setAttribute("transform", "translate(".concat(zLabelWidth + zGradWidth - 8, ", ").concat(yTextTranslation + 5, ")"));
      gradZtext.setAttribute("text-anchor", "end");
      axisZ.appendChild(gradZtext);
      yStrokeTranslation = Math.round(yTextTranslation) - 0.5;
      gradZstroke = document.createElementNS("http://www.w3.org/2000/svg", "g");
      gradZpath = document.createElementNS("http://www.w3.org/2000/svg", "path");
      gradZpath.setAttribute("cs", "100,100");
      gradZpath.setAttribute("stroke-width", "1");
      if (i !== 0) {
        gradZpath.setAttribute("stroke-opacity", "0.2");
      } else {
        gradZpath.setAttribute("stroke-opacity", "1");
      }
      gradZpath.setAttribute("stroke", "#000000");
      gradZpath.setAttribute("fill", "none");
      gradZpath.setAttribute("d", "M".concat(zLabelWidth + zGradWidth, ",").concat(yStrokeTranslation, " L").concat(pathWidth + zLabelWidth + zGradWidth, ",").concat(yStrokeTranslation));
      gradZgrad = document.createElementNS("http://www.w3.org/2000/svg", "path");
      gradZgrad.setAttribute("cs", "100,100");
      gradZgrad.setAttribute("stroke-width", "1");
      gradZgrad.setAttribute("stroke-opacity", "1");
      gradZgrad.setAttribute("stroke", "#000000");
      gradZgrad.setAttribute("fill", "none");
      gradZgrad.setAttribute("d", "M".concat(zLabelWidth + zGradWidth, ",").concat(yStrokeTranslation, " L").concat(zLabelWidth + zGradWidth + 5, ",").concat(yStrokeTranslation));
      gradZgrad.setAttribute("transform", "translate(-5, 0)");
      gradZstroke.appendChild(gradZgrad);
      gradZstroke.appendChild(gradZpath);
      guidesZ.appendChild(gradZstroke);
    }
    var axisZLegend = document.createElementNS("http://www.w3.org/2000/svg", "text");
    axisZLegend.setAttribute("class", "profile-z-legend");
    axisZLegend.setAttribute("font-family", "Verdana");
    axisZLegend.setAttribute("font-size", "11px");
    axisZLegend.setAttribute("fill", "#5E5E5E");
    axisZLegend.textContent = "Altitude (m)";
    axisZLegend.setAttribute("transform", "translate(".concat(zLabelWidth - 8, ", ").concat(Math.round(pathHeight / 2), ") rotate(-90)"));
    axisZLegend.setAttribute("text-anchor", "middle");
    axisZ.appendChild(axisZLegend);
    elevationSvg.appendChild(axisZ);
    elevationSvg.appendChild(guidesZ);

    // Détermination des guides en abscisse :
    // Passage éventuel en km
    if (dist > 2000) {
      dist /= 1000;
      distUnit = "km";
    }
    var maxNumXguides = Math.floor(pathWidth / minXguideWidth);
    var gradX = Math.pow(10, Math.ceil(Math.log(dist / maxNumXguides) / Math.log(10))) / 2;
    var maxGraphX = dist;

    // Si plus de guides que le max, on passe à une graduation de 10**x en 10**x (et non 10**x / 2)
    var numXguides = Math.floor(maxGraphX / gradX);
    if (numXguides > maxNumXguides) {
      gradX = Math.pow(10, Math.ceil(Math.log(dist / maxNumXguides) / Math.log(10)));
      numXguides = Math.floor(maxGraphX / gradX);
    } else if (numXguides < minNumXGuides) {
      gradX = Math.pow(10, Math.ceil(Math.log(dist / maxNumXguides) / Math.log(10)) - 1);
      numXguides = Math.floor(maxGraphX / gradX);
    }
    numXguides = Math.max(numXguides, 1);
    var lastGradX = gradX * numXguides;
    var axisX = document.createElementNS("http://www.w3.org/2000/svg", "g");
    axisX.setAttribute("class", "profile-x-vertical");
    var guidesX = document.createElementNS("http://www.w3.org/2000/svg", "g");

    // Décalage des graduations pour que la dernière corresponde à la distance max
    var pxPerMX = pathWidth / maxGraphX;
    var xOffset = (maxGraphX - lastGradX) * pxPerMX;
    var gradXxOffsetPx = Math.round((pathWidth - xOffset) / numXguides);
    var gradXtext;
    var xTextTranslation;
    var xStrokeTranslation;
    var gradXstroke;
    var gradXpath;
    var gradXgrad;
    // Ajout des graduations au graphique
    for (var _i = 0; _i <= numXguides + 1; _i++) {
      gradXtext = document.createElementNS("http://www.w3.org/2000/svg", "text");
      gradXtext.setAttribute("class", "profile-x-graduation");
      gradXtext.setAttribute("font-family", "Verdana");
      gradXtext.setAttribute("font-size", "10px");
      gradXtext.setAttribute("fill", "#5E5E5E");

      // Exclusion du cas de la dernière graduation : correspond à la distance max : pas de texte
      if (_i !== numXguides + 1) {
        // Cas où gradX < 1 : nombres flottants capricieux...
        gradXtext.textContent = (Math.round(100 * _i * gradX) / 100).toLocaleString();
      }
      xTextTranslation = zLabelWidth + zGradWidth + _i * gradXxOffsetPx;
      // Cas de la dernière graduation : correspond à la distance max
      if (_i === numXguides + 1) {
        xTextTranslation = zLabelWidth + zGradWidth + pathWidth;
      }
      gradXtext.setAttribute("transform", "translate(".concat(xTextTranslation, ", ").concat(pathHeight + xGradHeight + 5, ")"));
      gradXtext.setAttribute("text-anchor", "middle");
      axisX.appendChild(gradXtext);
      xStrokeTranslation = xTextTranslation - 0.5;
      gradXstroke = document.createElementNS("http://www.w3.org/2000/svg", "g");
      gradXpath = document.createElementNS("http://www.w3.org/2000/svg", "path");
      gradXpath.setAttribute("cs", "100,100");
      gradXpath.setAttribute("stroke-width", "1");
      if (_i !== 0) {
        gradXpath.setAttribute("stroke-opacity", "0.2");
      } else {
        gradXpath.setAttribute("stroke-opacity", "1");
      }
      gradXpath.setAttribute("stroke", "#000000");
      gradXpath.setAttribute("fill", "none");
      gradXpath.setAttribute("d", "M".concat(xStrokeTranslation, ",").concat(pathHeight, " L").concat(xStrokeTranslation, ",0"));
      gradXgrad = document.createElementNS("http://www.w3.org/2000/svg", "path");
      gradXgrad.setAttribute("cs", "100,100");
      gradXgrad.setAttribute("stroke-width", "1");
      gradXgrad.setAttribute("stroke-opacity", "1");
      gradXgrad.setAttribute("stroke", "#000000");
      gradXgrad.setAttribute("fill", "none");
      gradXgrad.setAttribute("d", "M".concat(xStrokeTranslation, ",").concat(pathHeight, " L").concat(xStrokeTranslation, ",").concat(pathHeight - 5));
      gradXgrad.setAttribute("transform", "translate(0, 5)");
      gradXstroke.appendChild(gradXgrad);
      gradXstroke.appendChild(gradXpath);
      guidesX.appendChild(gradXstroke);
    }
    var axisXLegend = document.createElementNS("http://www.w3.org/2000/svg", "text");
    axisXLegend.setAttribute("class", "profile-x-legend");
    axisXLegend.setAttribute("font-family", "Verdana");
    axisXLegend.setAttribute("font-size", "11px");
    axisXLegend.setAttribute("fill", "#5E5E5E");
    axisXLegend.textContent = "Distance (".concat(distUnit, ")");
    axisXLegend.setAttribute("transform", "translate(".concat(zLabelWidth + zGradWidth + pathWidth / 2, ", ").concat(pathHeight + xGradHeight + xLabelHeight + 3, ")"));
    axisXLegend.setAttribute("text-anchor", "middle");
    axisX.appendChild(axisXLegend);
    elevationSvg.appendChild(axisX);
    elevationSvg.appendChild(guidesX);
    var elevationPathG = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var factor = 1;
    if (distUnit === "km") {
      factor = 1000;
    }
    var pointX = this._dataDistToSvgX(_points[0].dist / factor, widgetWidth, pathWidth, pxPerMX);
    var pointY = this._dataZToSvgY(_points[0].z, pathHeight, minGraphZ, pxPerMZ);
    var pathD = "M".concat(pointX, ",").concat(pointY);
    for (var _i2 = 1; _i2 < _points.length; _i2++) {
      pointX = this._dataDistToSvgX(_points[_i2].dist / factor, widgetWidth, pathWidth, pxPerMX);
      pointY = this._dataZToSvgY(_points[_i2].z, pathHeight, minGraphZ, pxPerMZ);
      pathD += " L".concat(pointX, ",").concat(pointY);
    }
    var pathPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
    pathPath.setAttribute("cs", "100,100");
    pathPath.setAttribute("stroke-width", "1");
    pathPath.setAttribute("stroke-opacity", "1");
    pathPath.setAttribute("stroke", "#0B6BA7");
    pathPath.setAttribute("fill", "none");
    pathPath.setAttribute("d", pathD);

    // Fermeture du path pour le fill
    pathD += " L".concat(pointX, ",").concat(pathHeight);
    pathD += " L".concat(widgetWidth - pathWidth, ",").concat(pathHeight);
    var pathFill = document.createElementNS("http://www.w3.org/2000/svg", "path");
    pathFill.setAttribute("cs", "100,100");
    pathFill.setAttribute("stroke-width", "1");
    pathFill.setAttribute("stroke-opacity", "0");
    pathFill.setAttribute("stroke", "#000000");
    pathFill.setAttribute("fill", "#00B798");
    pathFill.setAttribute("fill-opacity", "0.4");
    pathFill.setAttribute("d", pathD);
    elevationPathG.appendChild(pathPath);
    elevationPathG.appendChild(pathFill);
    elevationSvg.appendChild(elevationPathG);

    // Mise en place de l'écouteur d'évènement : pour l'affichage dynamique
    var dynamicsG = document.createElementNS("http://www.w3.org/2000/svg", "g");
    // Pour écouter la position de la souris
    var pathRectangle = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    pathRectangle.setAttribute("width", pathWidth);
    pathRectangle.setAttribute("height", pathHeight);
    pathRectangle.setAttribute("transform", "translate(".concat(widgetWidth - pathWidth, ",0)"));
    pathRectangle.setAttribute("visibility", "hidden");
    pathRectangle.setAttribute("pointer-events", "all");
    var sortedDist = JSON.parse(JSON.stringify(_points));
    sortedDist.sort(function (e1, e2) {
      return e1.dist - e2.dist;
    });
    var focusLineX = document.createElementNS("http://www.w3.org/2000/svg", "line");
    focusLineX.setAttribute("id", "focusLineX");
    focusLineX.setAttribute("class", "focusLine-default");
    focusLineX.setAttribute("fill", "none");
    focusLineX.setAttribute("stroke", "#F90");
    focusLineX.setAttribute("stroke-width", "0.5px");
    focusLineX.setAttribute("visibility", "hidden");
    var focusLineY = document.createElementNS("http://www.w3.org/2000/svg", "line");
    focusLineY.setAttribute("id", "focusLineY");
    focusLineY.setAttribute("class", "focusLine-default");
    focusLineY.setAttribute("fill", "none");
    focusLineY.setAttribute("stroke", "#F90");
    focusLineY.setAttribute("stroke-width", "0.5px");
    focusLineY.setAttribute("visibility", "hidden");
    var focusCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    focusCircle.setAttribute("id", "focusCircle");
    focusCircle.setAttribute("r", 4);
    focusCircle.setAttribute("class", "circle-default focusCircle-default");
    focusCircle.setAttribute("fill", "#F90");
    focusCircle.setAttribute("visibility", "hidden");
    dynamicsG.appendChild(focusCircle);
    dynamicsG.appendChild(focusLineX);
    dynamicsG.appendChild(focusLineY);

    // Tooltip
    var tooltipDiv = document.createElementNS("http://www.w3.org/2000/svg", "text");
    var altiSpan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
    var slopeSpan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
    var coordsSpan = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
    tooltipDiv.setAttribute("style", "text-align:center; max-width:220px; font-size:10px; color:#000000; font-family:Verdana; z-index:50;");
    tooltipDiv.style.pointerEvents = "none";
    tooltipDiv.style.position = "fixed";
    // tooltipDiv.classList.add("tooltipInit");
    // IE...
    tooltipDiv.setAttribute("class", "tooltipInit");
    tooltipDiv.setAttribute("text-anchor", "middle");
    widgetDiv.appendChild(tooltipDiv);
    altiSpan.setAttribute("class", "altiPathValue");
    altiSpan.setAttribute("x", "0");
    altiSpan.setAttribute("dy", "-.7em");
    slopeSpan.setAttribute("class", "altiPathValue");
    slopeSpan.setAttribute("x", "0");
    slopeSpan.setAttribute("dy", "1em");
    coordsSpan.setAttribute("class", "altiPathCoords");
    coordsSpan.setAttribute("x", "0");
    coordsSpan.setAttribute("dy", "1em");
    tooltipDiv.appendChild(altiSpan);
    if (_displayProfileOptions.currentSlope) {
      tooltipDiv.appendChild(slopeSpan);
    }
    tooltipDiv.appendChild(coordsSpan);
    var tooltipG = document.createElementNS("http://www.w3.org/2000/svg", "g");
    dynamicsG.appendChild(tooltipG);
    var tooltipBubble = document.createElementNS("http://www.w3.org/2000/svg", "path");
    tooltipBubble.setAttribute("cs", "100,100");
    tooltipBubble.setAttribute("fill", "#FFFFFF");
    tooltipBubble.setAttribute("stroke", "#CCCCCC");
    tooltipBubble.setAttribute("fill-opacity", "0.8");
    tooltipBubble.setAttribute("stroke-width", "1");
    tooltipBubble.setAttribute("stroke-opacity", "1");
    var tooltipBubbleShadow = document.createElementNS("http://www.w3.org/2000/svg", "path");
    tooltipBubbleShadow.setAttribute("cs", "100,100");
    tooltipBubbleShadow.setAttribute("fill", "#FFFFFF");
    tooltipBubbleShadow.setAttribute("stroke", "#000000");
    tooltipBubbleShadow.setAttribute("fill-opacity", "0");
    tooltipBubbleShadow.setAttribute("stroke-width", "1");
    tooltipBubbleShadow.setAttribute("stroke-opacity", "0.4");
    tooltipBubbleShadow.setAttribute("transform", "translate(1,1)");
    tooltipG.appendChild(tooltipBubbleShadow);
    tooltipG.appendChild(tooltipBubble);
    tooltipG.appendChild(tooltipDiv);

    // tooltipG.classList.add("tooltipInit");
    // IE... deprecated
    tooltipG.setAttribute("class", "tooltipInit");
    tooltipG.style.pointerEvents = "none";
    function onMouseOver() {
      focusLineX.setAttribute("visibility", "visible");
      focusLineY.setAttribute("visibility", "visible");
      focusCircle.setAttribute("visibility", "visible");
      className.__createProfileMarker(self, _points[0]);

      // tooltips
      // tooltipDiv.classList.remove("tooltipInit");
      // tooltipG.classList.remove("tooltipInit");
      // tooltipDiv.classList.remove("tooltipFadeOut");
      // tooltipG.classList.remove("tooltipFadeOut");
      // tooltipDiv.classList.add("tooltipFadeIn");
      // tooltipG.classList.add("tooltipFadeIn");
      // IE... deprecated
      tooltipDiv.setAttribute("class", "tooltipFadeIn");
      tooltipG.setAttribute("class", "tooltipFadeIn");
    }
    function onMouseOut() {
      focusLineX.setAttribute("visibility", "hidden");
      focusLineY.setAttribute("visibility", "hidden");
      focusCircle.setAttribute("visibility", "hidden");
      className.__removeProfileMarker(self);
      // tooltips
      // tooltipDiv.classList.remove("tooltipFadeIn");
      // tooltipG.classList.remove("tooltipFadeIn");
      // tooltipDiv.classList.add("tooltipFadeOut");
      // tooltipG.classList.add("tooltipFadeOut");
      // IE... deprecated
      tooltipDiv.setAttribute("class", "tooltipFadeOut");
      tooltipG.setAttribute("class", "tooltipFadeOut");
    }
    function onMouseMove(e) {
      var mousePoint = elevationSvg.createSVGPoint();
      mousePoint.x = e.clientX;
      mousePoint.y = e.clientY;
      var svgMousePoint = mousePoint.matrixTransform(elevationSvg.getScreenCTM().inverse());
      var mouseDist = this._svgXToDataDist(svgMousePoint.x, widgetWidth, pathWidth, pxPerMX) * factor;

      // Math.max pour éviter de sortir de l'array
      var distIndex = Math.max(1, this._arrayBisect(sortedDist, mouseDist));
      var d0 = _points[distIndex - 1];
      var d1 = _points[distIndex];
      var d = d0;
      if (mouseDist - d0.dist > d1.dist - mouseDist) {
        d = d1;
      }
      var focusX = this._dataDistToSvgX(d.dist / factor, widgetWidth, pathWidth, pxPerMX);
      var focusY = this._dataZToSvgY(d.z, pathHeight, minGraphZ, pxPerMZ);

      // Mise à jour des éléments graphiques
      focusCircle.setAttribute("cx", focusX);
      focusCircle.setAttribute("cy", focusY);
      focusLineX.setAttribute("x1", focusX);
      focusLineX.setAttribute("y1", pathHeight);
      focusLineX.setAttribute("x2", focusX);
      focusLineX.setAttribute("y2", 0);
      focusLineY.setAttribute("x1", zLabelWidth + zGradWidth);
      focusLineY.setAttribute("y1", focusY);
      focusLineY.setAttribute("x2", pathWidth + zLabelWidth + zGradWidth);
      focusLineY.setAttribute("y2", focusY);
      className.__updateProfileMarker(self, d);

      // Mise à jour du tooltip
      var altiSpanTxt = "Altitude : ".concat(d.z.toLocaleString(), " m");
      var slopeSpanTxt = "Pente : ".concat(d.slope, " %");
      var coordsSpanTxt = "(lat : ".concat(d.lat.toLocaleString(), " / lon : ").concat(d.lon.toLocaleString(), ")");
      altiSpan.innerHTML = altiSpanTxt;
      slopeSpan.innerHTML = slopeSpanTxt;
      coordsSpan.innerHTML = coordsSpanTxt;
      var tooltipTextWidth = Math.max(this._getTextWidth(coordsSpanTxt, coordsSpan), this._getTextWidth(altiSpanTxt, altiSpan));
      var toolTipBubbleD;
      if (d.dist > dist * factor / 2) {
        toolTipBubbleD = "M -0.5 -0.5 l -6 6 l 0 16 l -".concat(tooltipTextWidth + 10, " 0 l 0 -44 l ").concat(tooltipTextWidth + 10, " 0 l 0 16 l 6 6");
        tooltipDiv.setAttribute("transform", "translate(".concat(-(tooltipTextWidth / 2 + 12), ",0)")); // IE11 !
      } else if (d.dist <= dist * factor / 2) {
        toolTipBubbleD = "M -0.5 -0.5 l 6 6 l 0 16 l ".concat(tooltipTextWidth + 10, " 0 l 0 -44 l -").concat(tooltipTextWidth + 10, " 0 l 0 16 l -6 6");
        // Largeur de la fleche de la bulle du tooltip
        tooltipDiv.setAttribute("transform", "translate(".concat(tooltipTextWidth / 2 + 12, ",0)")); // IE11 !
      }
      tooltipBubble.setAttribute("d", toolTipBubbleD);
      tooltipBubbleShadow.setAttribute("d", toolTipBubbleD);
      tooltipG.setAttribute("transform", "translate(".concat(focusX, ",").concat(focusY, ")")); // IE11 !
      tooltipG.style.transform = "translate(".concat(focusX, "px,").concat(focusY, "px)");
    }
    pathRectangle.addEventListener("pointerover", onMouseOver);
    pathRectangle.addEventListener("pointerout", onMouseOut);
    pathRectangle.addEventListener("pointermove", onMouseMove.bind(this));
    dynamicsG.appendChild(pathRectangle);
    elevationSvg.appendChild(dynamicsG);
    widgetDiv.appendChild(elevationSvg);
    return container;
  },
  /**
   * Display Profile without graphical rendering (raw service response)
   *
   * @public
   * @param {Object} data - elevations values for profile
   * @param {HTMLElement} container - html container where to display profile
   * @param {Object} context - this control object
   * @param {Object} className - calling class (ie ElevationPath)
   * @returns {DOMElement} profil container
   */
  displayProfileRaw: function displayProfileRaw(data, container, context, className) {
    if (!container) {
      return;
    }

    // on nettoie toujours...
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
    var _points = data && data.points ? data.points : {};
    var div = document.createElement("textarea");
    div.id = "profilElevationResults";
    div.rows = 10;
    div.cols = 50;
    div.style.width = "100%";
    div.innerHTML = JSON.stringify(_points, undefined, 4);
    div.addEventListener("mouseover", function (e) {
      className.__customRawProfileMouseOverEvent(context, e);
    });

    // TODO
    // for (var i = 0; i < _points.length; i++) {
    //     var point = _points[i];
    //     var divC  = document.createElement("code");
    //     divC.id = "point_" + i;
    //     divC.innerHTML = JSON.stringify(point, undefined, 4);
    //     div.appendChild(divC);
    //     divC.addEventListener("mouseover", function (e) {
    //          className.__customRawProfileMouseOverEvent(context, e);
    //     });
    // }

    container.appendChild(div);
    return container;
  },
  /**
   * Display Profile using D3 javascript framework. This method needs D3 libraries to be loaded.
   *
   * @public
   * @param {Object} data - elevations values for profile
   * @param {HTMLElement} container - html container where to display profile
   * @param {Object} context - this control object
   * @param {Object} className - calling class (ie ElevationPath)
   * @returns {DOMElement} profil container
   */
  displayProfileLibD3: function displayProfileLibD3(data, container, context, className) {
    var self = context;
    if (!container) {
      return;
    }
    if (!data) {
      return;
    }

    // on nettoie toujours...
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
    var _points = data.points;
    if (data.distance > 2000) {
      data.unit = "km";
      for (var i = 0; i < _points.length; i++) {
        _points[i].dist /= 1000;
      }
    }
    var _displayProfileOptions = self.options.displayProfileOptions;
    var margin = {
      top: 20,
      right: 20,
      bottom: 30,
      left: 40
    };
    var widgetWidth = window.getComputedStyle(container).getPropertyValue("width");
    var widgetHeigth = window.getComputedStyle(container).getPropertyValue("height");
    var width = widgetWidth.replace(/px/, "") - margin.left - margin.right;
    var height = widgetHeigth.replace(/px/, "") - margin.top - margin.bottom;
    var x = d3.scale.linear().range([0, width]);
    var y = d3.scale.linear().range([height, 0]);
    var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5);
    var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5);
    var line = d3.svg.line().interpolate("basis").x(function (d) {
      return x(d.dist);
    }).y(function (d) {
      return y(d.z);
    });
    var area = d3.svg.area().interpolate("basis").x(function (d) {
      return x(d.dist);
    }).y0(height).y1(function (d) {
      return y(d.z);
    });
    var svg = d3.select(container).append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var xDomain = d3.extent(_points, function (d) {
      return d.dist;
    });
    x.domain(xDomain);
    var yDomain = [0, d3.max(_points, function (d) {
      return d.z;
    })];
    y.domain(yDomain);
    svg.append("path").datum(_points).attr("class", "area-d3").attr("d", area);
    svg.append("g").attr("class", "x axis-d3").attr("transform", "translate(0," + height + ")").call(xAxis).append("text").attr("y", -15).attr("dy", ".71em").attr("x", width).text("Distance (" + data.unit + ")");
    svg.append("g").attr("class", "y axis-d3").call(yAxis).append("text").attr("transform", "rotate(-90)").attr("y", 6).attr("dy", ".71em").text("Altitude (m)");
    svg.append("g").attr("class", "grid-d3 vertical").attr("transform", "translate(0," + height + ")").call(xAxis.orient("bottom").tickSize(-height, 0, 0).tickFormat(""));
    svg.append("g").attr("class", "grid-d3 horizontal").call(yAxis.orient("left").tickSize(-width, 0, 0).tickFormat(""));
    svg.append("path").datum(_points).attr("class", "line-d3").attr("d", line);
    svg.selectAll("circle").data(_points).enter().append("circle").attr("cx", function (d) {
      return x(d.dist);
    }).attr("cy", function (d) {
      return y(d.z);
    }).attr("r", 0).attr("class", "circle-d3");
    var focus = svg.append("g").style("display", "none");
    focus.append("line").attr("id", "focusLineX").attr("class", "focusLine-d3");
    focus.append("line").attr("id", "focusLineY").attr("class", "focusLine-d3");
    focus.append("circle").attr("id", "focusCircle").attr("r", 4).attr("class", "circle-d3 focusCircle-d3");
    var div = d3.select(container).append("div").attr("class", "tooltip-d3").style("opacity", 0);
    var bisectDist = d3.bisector(function (d) {
      return d.dist;
    }).left;
    svg.append("rect").attr("class", "overlay-d3").attr("width", width).attr("height", height).on("mouseover", function () {
      focus.style("display", null);
      className.__createProfileMarker(self, _points[0]);
    }).on("mouseout", function () {
      focus.style("display", "none");
      className.__removeProfileMarker(self);

      // tooltips
      div.transition().duration(500).style("opacity", 0);
    }).on("mousemove", function () {
      var m = d3.mouse(this);
      var distance = x.invert(m[0]);
      // Math.max pour éviter de sortir de l'array
      var i = Math.max(1, bisectDist(_points, distance));
      var d0 = _points[i - 1];
      var d1 = _points[i];
      var d = distance - d0[0] > d1[0] - distance ? d1 : d0;
      var xc = x(d.dist);
      var yc = y(d.z);
      focus.select("#focusCircle").attr("cx", xc).attr("cy", yc);
      focus.select("#focusLineX").attr("x1", xc).attr("y1", y(yDomain[0])).attr("x2", xc).attr("y2", y(yDomain[1]));
      focus.select("#focusLineY").attr("x1", x(xDomain[0])).attr("y1", yc).attr("x2", x(xDomain[1])).attr("y2", yc);
      className.__updateProfileMarker(self, d);

      // tooltips
      div.transition().duration(200).style("opacity", 0.9);
      var _message = "";
      _message += " Altitude : " + d.z + " m";
      if (_displayProfileOptions.currentSlope) {
        _message += "<br/> Pente : " + d.slope + " %";
      }
      _message += "<br/> (Lat : " + d.lat + "/ Lon : " + d.lon + ")";
      div.html(_message).style("left", d3.event.pageX + "px").style("top", d3.event.pageY - 28 + "px");
    });

    // return d3.selectAll("rect.overlay")[0][0];
    return svg;
  },
  /**
   * Display Profile using Amcharts framework. This method needs AmCharts libraries to be loaded.
   *
   * @public
   * @param {Object} data - elevations values for profile
   * @param {HTMLElement} container - html container where to display profile
   * @param {Object} context - this control object
   * @param {Object} className - calling class (ie ElevationPath)
   * @returns {DOMElement} profil container
   */
  displayProfileLibAmCharts: function displayProfileLibAmCharts(data, container, context, className) {
    var self = context;
    if (!container) {
      return;
    }
    if (!data) {
      return;
    }
    var _points = data.points;
    var ballonText = "<span class='altiPathValue'>[[title]] : [[value]]m</span><br/>";
    var currentSlope = self.options.displayProfileOptions.currentSlope;
    if (currentSlope) {
      ballonText += "<span class='altiPathValue'>Pente : [[slope]] %</span><br/>";
    }
    ballonText += "<span class='altiPathCoords'>(Lat: [[lat]] / Lon:[[lon]])</span>";
    AmCharts.addInitHandler(function () {});
    if (data.distance > 2000) {
      data.unit = "km";
      for (var i = 0; i < _points.length; i++) {
        _points[i].dist /= 1000;
      }
    }
    for (var _i3 = 0; _i3 < _points.length; _i3++) {
      var dist = _points[_i3].dist;
      var coeffArrond = 100;
      if (dist > 100) {
        coeffArrond = 1;
      } else if (dist > 10) {
        coeffArrond = 10;
      }

      // Correction arrondi distance totale
      dist = Math.round(dist * coeffArrond) / coeffArrond;
      _points[_i3].dist = dist;
    }
    var settings = {
      type: "serial",
      pathToImages: "http://cdn.amcharts.com/lib/3/images/",
      categoryField: "dist",
      autoMarginOffset: 0,
      marginRight: 10,
      marginTop: 10,
      startDuration: 0,
      color: "#5E5E5E",
      fontSize: 8,
      theme: "light",
      thousandsSeparator: "",
      numberFormatter: {
        precision: -1,
        decimalSeparator: ",",
        thousandsSeparator: " "
      },
      categoryAxis: {
        color: "#5E5E5E",
        gridPosition: "start",
        minHorizontalGap: 40,
        tickPosition: "start",
        title: "Distance (" + data.unit + ")",
        titleColor: "#5E5E5E",
        labelOffset: 0,
        startOnAxis: true
      },
      chartCursor: {
        animationDuration: 0,
        bulletsEnabled: true,
        bulletSize: 10,
        categoryBalloonEnabled: false,
        cursorColor: "#F90",
        graphBulletAlpha: 1,
        graphBulletSize: 1,
        zoomable: false
      },
      trendLines: [],
      graphs: [{
        balloonColor: "#CCCCCC",
        balloonText: ballonText,
        bullet: "round",
        bulletAlpha: 0,
        bulletBorderColor: "#FFF",
        bulletBorderThickness: 2,
        bulletColor: "#F90",
        bulletSize: 6,
        hidden: false,
        id: "AmGraph-1",
        fillAlphas: 0.4,
        fillColors: "#C77A04",
        lineAlpha: 1,
        lineColor: "#C77A04",
        lineThickness: 1,
        title: "Altitude",
        valueField: "z"
      }],
      guides: [],
      valueAxes: [{
        id: "ValueAxis-1",
        minVerticalGap: 20,
        title: "Altitude (m)"
      }],
      balloon: {
        borderColor: "#CCCCCC",
        borderThickness: 1,
        fillColor: "#FFFFFF",
        showBullet: true
      },
      titles: [],
      allLabels: [],
      dataProvider: _points
    };
    var _containerProfile = AmCharts.makeChart(container, settings);
    _containerProfile.addListener("changed", function (e) {
      var obj = e.chart.dataProvider[e.index];
      className.__updateProfileMarker(self, obj);
    });
    return _containerProfile;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ProfileElevationPathDOM);

/***/ }),
/* 134 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);


/**
 * @classdesc
 *
 * Control Logo
 *
 * @private
 * @constructor
 * @extends {L.Control}
 * @alias Logo
 * @param {Object} options - options for function call.
 * @param {String} options.position - 'topright' by default
 * @param {String} options.url - URL
 * @param {String} options.text - text
 * @param {String} options.picto - picto
 * @example
 * var map  = L.map('map').setView([48, 2], 4);
 * var logo = L.geoportalControl.Logo({
 *   position : "topright",
 *   picto : "http://www.ign.fr/logo-ign.jpg",
 *   url : "http://www.ign.fr",
 *   text : "© IGN",
 *   size : "70px"
 * });
 * logo.addTo(map);
 */
var Logo = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Control.extend( /** @lends Logo.prototype */{
  /**
   * Options du service
   *
   * @private
   */
  options: {
    position: "topright",
    picto: null,
    url: null,
    text: null,
    size: "30px"
  },
  /**
   * constructor
   *
   * @param {Object} options - options
   * @private
   */
  initialize: function initialize(options) {
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.setOptions(this, options);
  },
  /**
   * event
   *
   * @returns {DOMElement} DOM element
   * @private
   */
  onAdd: function onAdd( /* map */
  ) {
    var container = null;
    container = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.create("div", "gp-control-logo", container);
    var bLink = !!(this.options.url || this.options.text);
    var link = null;
    if (bLink) {
      link = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.create("a", "", container);
      link.target = "_blank";
      if (this.options.url) {
        link.href = this.options.url;
        if (this.options.text) link.title = this.options.text;
      }
    }

    // FIXME mise en forme à prévoir !
    if (bLink && this.options.text) {
      link.text = this.options.text;
    }
    var bImage = !!this.options.picto;
    var image = null;
    if (bImage) {
      if (bLink) {
        image = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.create("img", "", link);
      } else {
        image = leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.DomUtil.create("img", "", container);
      }
      image.src = this.options.picto;
      if (typeof this.options.size === "string") {
        image.style.height = image.style.width = this.options.size;
      } else {
        image.style.height = this.options.size.height;
        image.style.width = this.options.size.width;
      }
    }
    return container;
  }
});
/* harmony default export */ __webpack_exports__["default"] = (Logo);

/***/ }),
/* 135 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(35);
/* harmony import */ var _LayerConfig__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(136);
/* harmony import */ var _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(119);
/* harmony import */ var _WMS__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(138);
/* harmony import */ var _WMTS__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(140);






var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("layers");

/**
 * Geoportal Layers Factory to be used together with Leaflet Maps.
 *
 * @module Layers
 * @alias L.geoportalLayer
 * @example
 * var map = L.Map(...) ;
 * var layer = L.geoportalLayer.WMTS({
 *      layer : "ORTHOIMAGERY.ORTHOPHOTOS",
 * }).addTo(map) ;
 */
/** @type {L.geoportalLayer} */
var Layers = {
  options: {},
  params: {},
  protocol: null,
  serviceUrl: "http://localhost?no-rights-found-for=[{layer}]",
  /**
   * initialize options
   */
  _initOptions: function _initOptions() {
    if (!this.options || Object.keys(this.options).length === 0) {
      throw new Error("PARAM_MISSING : options !");
    }
    if (!this.options.layer) {
      throw new Error("PARAM_MISSING : layer !");
    }

    // FIXME est ce utile de le preciser ?
    if (!this.options.apiKey) {
      logger.log("PARAM_MISSING : apiKey !");
    }

    // par defaut
    if (typeof this.options.ssl === "undefined") {
      this.options.ssl = true;
    }
  },
  /**
   * get runtime context
   */
  _initContext: function _initContext() {
    // si ssl = false on fait du http
    // par défaut, ssl = true, on fait du https
    this.protocol = this.options.ssl === false ? "http://" : "https://";
  },
  /**
   * initialize parameters
   *
   * @param {String} service - service name, WMS or WMTS
   */
  _initParams: function _initParams(service) {
    // par defaut...
    if (!service) {
      service = "WMTS";
    }

    // Récupération de la configuration
    this.params = _LayerConfig__WEBPACK_IMPORTED_MODULE_2__["default"].get({
      key: this.options.apiKey,
      layer: this.options.layer,
      service: service
    });
    if (!this.params || Object.keys(this.params).length === 0) {
      this.params = {};
      if (!this.options.apiKey) {
        // FIXME on retire l'exception...
        logger.log("WARNING PARAM_MISSING : parameter 'apiKey' is mandatory if the contract key configuration has not been loaded !");
      }
    }
  },
  /**
   * Factory function for Geoportal or INSPIRE WMS Layers creation.
   *
   * @method WMS
   * @static
   * @alias L.geoportalLayer.WMS
   * @extends {L.TileLayer.WMS}
   *
   * @param {Object} options - options for function call.
   * @param {String} options.layer - layer name (e.g. "ORTHOIMAGERY.ORTHOPHOTOS")
   * @param {Boolean} [options.ssl] - if set true, enforce protocol https (only for nodejs)
   * @param {String} [options.apiKey] - access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
   * @param {Object} [settings] - other options for L.TileLayer.WMS function (see {@link http://leafletjs.com/reference.html#tilelayer-wms-options})
   * @param {Array} [settings.legends]   - Overloads the default legends objects associated to the layer
   * @param {Array} [settings.metadata]   - Overloads the default Metadata objects associated to the layer
   * @param {String} [settings.title]   - Overloads the default title of the layer
   * @param {String} [settings.description]   - Overloads the default description of the layer
   * @param {String} [settings.quicklookUrl]   - Overloads the default quicklookUrl of the layer
   *
   * @returns {L.geoportalLayer.WMS} WMS layer
   *
   * @example
   *  var map = L.Map('divmap').setView();
   *  var lyr = L.geoportalLayer.WMS(
   *    {
   *      layer : "OI.OrthoimageCoverage"
   *    },
   *    {
   *      opacity : 1,
   *      transparent : true,
   *      minZoom : 1,
   *      maxZoom : 21
   *      ...
   *    });
   *
   *  lyr.addTo(map); // ou map.addLayer(lyr);
   */
  WMS: function WMS(options, settings) {
    // gestion du logger
    var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("layers-wms");

    /** options du plugins */
    this.options = options || {};

    // gestion des options
    this._initOptions();

    /** options natives de Leaflet */
    this.settings = settings || {};

    // env d'execution : browser ou non ?
    this._initContext();

    // Récupération de la configuration
    this._initParams("WMS");
    logger.log(this.params);

    // url du service
    var serviceUrl = null;
    if (this.params.url) {
      // sinon on prend la première clé disponible pour la couche dans la Config
      serviceUrl = this.params.url;
    } else if (this.options.apiKey) {
      // une apiKey est fournie sans URL récupérée :
      // on tente le chemin privé du service WMS raster
      serviceUrl = "https://data.geopf.fr/private/wms-r";
    } else {
      // pas de Config, ni de clef API !
      // on construit le chemin public du service WMS raster
      serviceUrl = "https://data.geopf.fr/wms-r";
    }

    // params du service WMS (par defaut)
    var paramsWms = {
      layers: this.options.layer,
      styles: this.params.styles || "normal",
      format: this.params.format || "image/jpeg",
      version: this.params.version || "1.3.0"
    };
    if (serviceUrl.includes("/private/")) {
      var apiKey = this.options.apiKey || _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_3__["default"].configuration.getLayerKey(_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_3__["default"].configuration.getLayerId(paramsWms.layers, "WMS"))[0];
    }

    // options natives de leaflet (par defaut)
    var paramsNative = {
      // zoom level
      minZoom: this.params.minZoom || 1,
      maxZoom: this.params.maxZoom || 21
    };

    // merge des options utilisateur pour le service WMS
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(paramsWms, this.settings);
    // merge des options utilisateur aux options natives de leaflet
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(paramsNative, this.settings);
    return new _WMS__WEBPACK_IMPORTED_MODULE_4__["default"](serviceUrl.replace(/(http|https):\/\//, this.protocol), {
      paramsNative: paramsNative,
      paramsWms: paramsWms,
      apikey: apiKey,
      originators: this.params.originators || this.settings.originators || [],
      legends: this.settings.originators || this.params.legends || [],
      metadata: this.settings.metadata || this.params.metadata || [],
      title: this.settings.title || this.params.title || "",
      description: this.settings.description || this.params.description || "",
      quicklookUrl: this.settings.quicklookUrl || this.params.quicklookUrl || ""
    });
  },
  /**
   * Factory function for Geoportal WMTS Layers creation.
   *
   * @method WMTS
   * @static
   * @alias L.geoportalLayer.WMTS
   * @extends {L.TileLayer}
   *
   * @param {Object} options - options for function call.
   * @param {String} options.layer - layer name (e.g. "ORTHOIMAGERY.ORTHOPHOTOS")
   * @param {Boolean} [options.ssl] - if set true, enforce protocol https (only for nodejs)
   * @param {String} [options.apiKey] - free access key to Geoportal platform, obtained [here]{@link https://geoservices.ign.fr/services-web}.
   * @param {Object} [settings] - other options for L.TileLayer function (see {@link http://leafletjs.com/reference.html#tilelayer-options})
   *
   * @returns {L.geoportalLayer.WMTS} WMTS layer
   *
   * @example
   *  var map = L.Map('divmap').setView();
   *  var lyr = L.geoportalLayer.WMTS(
   *    {
   *      layer : "ORTHOIMAGERY.ORTHOPHOTOS"
   *    },
   *    {
   *      opacity : 1,
   *      transparent : true,
   *      minZoom : 1,
   *      maxZoom : 21
   *      ...
   *    });
   *
   *  lyr.addTo(map); // ou map.addLayer(lyr);
   */
  WMTS: function WMTS(options, settings) {
    // gestion du logger
    var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_1__["default"].getLogger("layers-wmts");

    /** options du plugins */
    this.options = options || {};

    // gestion des options
    this._initOptions();

    /** options natives de Leaflet */
    this.settings = settings || {};

    // env d'execution : browser ou non ?
    this._initContext();

    // Récupération de la configuration
    this._initParams("WMTS");
    logger.log(this.params);

    // url du service
    var serviceUrl = null;
    if (this.params.url) {
      // sinon on prend la première clé disponible pour la couche dans la Config
      serviceUrl = this.params.url;
    } else if (this.options.apiKey) {
      // une apiKey est fournie sans URL récupérée :
      // on tente le chemin privé du service WMTS
      serviceUrl = "https://data.geopf.fr/private/wmts";
    } else {
      // pas de Config, ni de clef API !
      // on construit le chemin public du service
      serviceUrl = "https://data.geopf.fr/wmts";
    }

    // params du service WMTS (par defaut)
    var paramsWmts = {
      layer: this.options.layer,
      style: this.params.styles || "normal",
      format: this.params.format || "image/jpeg",
      version: this.params.version || "1.0.0",
      tilematrixset: this.params.TMSLink || "PM"
    };
    if (serviceUrl.includes("/private/")) {
      var apiKey = this.options.apiKey || _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_3__["default"].configuration.getLayerKey(_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_3__["default"].configuration.getLayerId(paramsWmts.layer, "WMTS"))[0];
    }

    // options natives de leaflet (par defaut)
    //    minZoom : 0
    //    maxZoom : 18
    //    tileSize : 256
    //    subdomains : 'abc'
    //    errorTileUrl : ''
    //    attribution : ''
    //    zoomOffset : 0
    //    opacity : 1

    var paramsNative = {
      // zoom level
      minZoom: this.params.minZoom || 1,
      maxZoom: this.params.maxZoom || 21
    };

    // merge des options utilisateur pour le service WMTS
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(paramsWmts, this.settings);
    // merge des options utilisateur aux options natives de leaflet
    leaflet__WEBPACK_IMPORTED_MODULE_0___default.a.Util.extend(paramsNative, this.settings);
    return new _WMTS__WEBPACK_IMPORTED_MODULE_5__["default"](serviceUrl.replace(/(http|https):\/\//, this.protocol), {
      paramsNative: paramsNative,
      paramsWmts: paramsWmts,
      apikey: apiKey,
      originators: this.params.originators || this.settings.originators || [],
      legends: this.settings.originators || this.params.legends || [],
      metadata: this.settings.metadata || this.params.metadata || [],
      title: this.settings.title || this.params.title || "",
      description: this.settings.description || this.params.description || "",
      quicklookUrl: this.settings.quicklookUrl || this.params.quicklookUrl || ""
    });
  }
};
/* harmony default export */ __webpack_exports__["default"] = (Layers);

/***/ }),
/* 136 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(119);
/* harmony import */ var _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(137);



var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("layer-config");

/**
 * @classdesc
 *
 * Configuration des couches Geoplateforme via l'appel de la configuration.
 * @private
 */
var LayerConfig = {
  /**
   * options : key, layer, service
   *
   * @param {Object} options - options
   *
   * @returns {Object} layer parameters
   */
  get: function get(options) {
    var params = {};
    if (!_Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].isConfigLoaded()) {
      logger.warn("WARNING CONFIG_FAILED : config not loaded ?!");
      return;
    }

    // gestion des parametres
    params = _Common_Utils_Config__WEBPACK_IMPORTED_MODULE_1__["default"].configuration.getLayerParams(options.layer, options.service);
    if (!params || Object.keys(params).length === 0) {
      logger.warn("WARNING CONFIG_FAILED : params not found ?!");
      return;
    }

    // gestion des zoom
    params.minZoom = _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_2__["default"].getZoomLevelFromScaleDenominator(params.maxScale) || 1;
    params.maxZoom = _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_2__["default"].getZoomLevelFromScaleDenominator(params.minScale) || 21;
    return params;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LayerConfig);

/***/ }),
/* 137 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
* @module LayerUtils
* @alias Gp.LayerUtils
* @description
* ...
*
* @example
* getZoomLevelFromScaleDenominator();
* getAttributions();
* intersects();
*/
var LayerUtils = {
  /**
   * Obtenir le ZoomLevel à partir du ScaleDenominator
   * @function getZoomLevelFromScaleDenominator
   * @param {Number} scaleDenominator - the scale denominator
   * @param {String} crs - the crs
   *
   * @returns {Integer} zoom level
   */
  getZoomLevelFromScaleDenominator: function getZoomLevelFromScaleDenominator(scaleDenominator, crs) {
    // ------------------------------------------------- //
    // Code issu de l'API Geoportal/Catalogue/Config.js  //
    // ------------------------------------------------- //
    //     var configuration = Gp.Config;
    //     var general = configuration.generalOptions;
    //     var layers  = configuration.layersContext;
    //
    //     for (var tms in general.tileMatrixSets) {
    //         var tileMatrixSet = general.tileMatrixSets[tms];
    //         // IGN's WMTS bug : epsg:nnnn instead of EPSG:nnnn
    //         var crs = tileMatrixSet.supportedCRS = tileMatrixSet.supportedCRS.replace(/epsg/,"EPSG");
    //
    //         if (!Geoportal.Catalogue.CRSRESOLUTIONS.hasOwnProperty(crs)) {
    //             var p= new OpenLayers.Projection(crs);
    //             Geoportal.Catalogue.CRSRESOLUTIONS[crs]= [];
    //             var matrixIds= tileMatrixSet.matrixIds;
    //             for (var i= 0, li= matrixIds.length; i<li; ++i) {
    //                 var mid= matrixIds[i];
    //                 Geoportal.Catalogue.CRSRESOLUTIONS[crs].push(
    //                     0.00028*mid.scaleDenominator
    //                     /(OpenLayers.METERS_PER_INCH*OpenLayers.INCHES_PER_UNIT[p.getUnits()]));
    //                     mid.supportedCRS= mid.supportedCRS.replace(/epsg/,"EPSG");
    //                 }
    //                 Geoportal.Catalogue.CRSRESOLUTIONS[crs].sort(function (a,b){ return b-a; });
    //             }
    //         }
    //         var llR= Geoportal.Catalogue.CRSRESOLUTIONS['CRS:84'];
    //         if (!llR) {
    //             llR= Geoportal.Catalogue.CRSRESOLUTIONS['CRS:84']= general.resolutions.slice();
    //         }
    //         var wmR= Geoportal.Catalogue.CRSRESOLUTIONS['EPSG:3857'];
    //         if (!wmR) {//FIXME : should never happened !!
    //             // reproject resolutions from CRS84 to WebMercator (transform resolutions from degree/px to meter/px)
    //             wmR= Geoportal.Catalogue.CRSRESOLUTIONS['EPSG:3857']= new Array(llR.length);
    //             for (var i= 0, len= llR.length; i<len; i++) {
    //                 var pt= new OpenLayers.LonLat(llR[i], 0);
    //                 pt.transform(OpenLayers.Projection.CRS84, OpenLayers.Projection.WebMercator);
    //                 wmR[i]= pt.lon;
    //             }
    //         }
    //         Geoportal.Catalogue.RESOLUTIONS= wmR;
    //
    //         var getResolutionsFromCRS= function(crs) {
    //             if (OpenLayers.Projection.WebMercator.isAliasOf(crs)) {
    //                 return wmR;
    //             }
    //             if (OpenLayers.Projection.CRS84.isAliasOf(crs)) {
    //                 return llR;
    //             }
    //             return Geoportal.Catalogue.CRSRESOLUTIONS[crs]?Geoportal.Catalogue.CRSRESOLUTIONS[crs]:null ;
    //         };
    //
    //         var retrieveZoomFromResolution= function(resolutions, resolution) {
    //             for (var i= 0, li= resolutions.length; i<li; i++) {
    //                 if (resolutions[i]-resolution <= resolutions[li-1]) {
    //                     return i;
    //                 }
    //             }
    //             return -1;
    //         };
    //
    //         var getZoomLevelFromScaleDenominator= function(scaleDenominator,crs) {
    //             var resolution= scaleDenominator * 0.00028;
    //             var R= getResolutionsFromCRS(crs);
    //             if (R) {
    //                 return retrieveZoomFromResolution(R,resolution);
    //             }
    //             resolution= resolution/(OpenLayers.METERS_PER_INCH * OpenLayers.INCHES_PER_UNIT["degrees"]);
    //             return retrieveZoomFromResolution(llR,resolution);
    //         };
    //
    //         var getZoomLevelFromResolution= function(resolution,crs){
    //             var R= getResolutionsFromCRS(crs);
    //             if (R) {
    //                 return retrieveZoomFromResolution(R,resolution);
    //             }
    //             var pt0= new OpenLayers.LonLat(0, 0);
    //             var pt1= new OpenLayers.LonLat(1, 0);
    //             pt0.transform(new OpenLayers.Projection(crs),OpenLayers.Projection.CRS84);
    //             pt1.transform(new OpenLayers.Projection(crs),OpenLayers.Projection.CRS84);
    //             resolution= resolution*(Math.abs(pt1.lon-pt0.lon));
    //             return retrieveZoomFromResolution(llR,resolution);
    //         };

    // par defaut, on utilise la projection WebMercator (EPSG:3857 = PM)
    // soit la liste des resolutions natives
    var resolutionsNatives = {};
    switch (crs) {
      case "EPSG:2154":
        resolutionsNatives = {
          0: 104579.224549894,
          1: 52277.5323537905,
          2: 26135.4870785954,
          3: 13066.8913818,
          4: 6533.2286041135,
          5: 3266.5595244627,
          6: 1633.2660045974,
          7: 816.629554986,
          8: 408.3139146768,
          9: 204.1567415109,
          10: 102.0783167832,
          11: 51.0391448966,
          12: 25.5195690743,
          13: 12.7597836936,
          14: 6.379891636,
          15: 3.1899457653,
          16: 1.5949728695,
          17: 0.7974864315,
          18: 0.3987432149,
          19: 0.1993716073,
          20: 0.0996858037,
          21: 0.0498429018
        };
        break;
      default:
        resolutionsNatives = {
          0: 156543.033928041,
          1: 78271.51696402048,
          2: 39135.758482010235,
          3: 19567.87924100512,
          4: 9783.93962050256,
          5: 4891.96981025128,
          6: 2445.98490512564,
          7: 1222.99245256282,
          8: 611.49622628141,
          9: 305.7481131407048,
          10: 152.8740565703525,
          11: 76.43702828517624,
          12: 38.21851414258813,
          13: 19.10925707129406,
          14: 9.554628535647032,
          15: 4.777314267823516,
          16: 2.388657133911758,
          17: 1.194328566955879,
          18: 0.5971642834779395,
          19: 0.2985821417389697,
          20: 0.1492910708694849,
          21: 0.0746455354347424
        };
        break;
    }

    // gestion des autres SRS
    // TODO
    // if (crs) {
    // }

    var resolution = scaleDenominator * 0.00028;
    for (var index in resolutionsNatives) {
      if (resolutionsNatives.hasOwnProperty(index)) {
        if (resolutionsNatives[index] <= resolution) {
          index = parseInt(index, 10);
          return index;
        }
      }
    }
    return 0; // -1 ?
  },
  /**
   * Get attributions list for a layer, based on current zoom and extent
   *
   * @function getAttributions
   * @param {Object} params - function params
   * @param {Array.<Float>} params.extent - map current geographical extent (EPSG:4326) : [top, left, bottom, right] = [maxy, minx, miny, maxx]
   * @param {Number} params.zoom - map current zoom
   * @param {String} params.crs - map current projection code (ex "EPSG:2154")
   * @param {Boolean} params.visibility - layer visibility
   * @param {Gp.Services.Config.Originator} params.originators - resource originators (from Gp.Config.layers[].originators)
   * @returns {Object} attributions - associative array, mapping originators url (keys) with their properties : html attributions elements
   */
  getAttributions: function getAttributions(params) {
    var zoom = params.zoom;
    var attributions = [];
    if (params.originators != null && params.visibility) {
      // drawLogo = boolean, true if attribution should be displayed (zoom, extent), false otherwise
      var drawLogo;
      for (var j = 0, jl = params.originators.length; j < jl; j++) {
        drawLogo = true;
        var originator = params.originators[j];
        var constraints = params.originators[j].constraints || [];
        for (var k = 0, kl = constraints.length; k < kl; k++) {
          var constraint = constraints[k];
          drawLogo = true;
          var minZoomLevel = this.getZoomLevelFromScaleDenominator(constraint.maxScaleDenominator, params.crs);
          var maxZoomLevel = this.getZoomLevelFromScaleDenominator(constraint.minScaleDenominator, params.crs) || 21;

          // min zoom constraints
          if (minZoomLevel && minZoomLevel > zoom) {
            drawLogo = false;
          }

          // max zoom constraints
          if (drawLogo && maxZoomLevel && maxZoomLevel < zoom) {
            drawLogo = false;
          }

          // bbox constraints
          var bbox = constraint.bbox;
          if (drawLogo && bbox) {
            drawLogo = false;
            var viewExtent = params.extent;
            if (viewExtent) {
              var bounds = [bbox.top, bbox.left, bbox.bottom, bbox.right];
              if (this.intersects(viewExtent, bounds)) {
                // at least one constraint matches the map ones
                drawLogo = true;
                break;
              }
            }
          }
        }
        if (drawLogo) {
          // on a un originator qui correspond au zoom et à l'étendue.

          var logo = originator.logo;
          var url = originator.url;
          var name = originator.name ? originator.name : "";
          var text = originator.attribution;
          var container = document.createElement("div");
          container.className = "gp-control-attribution";

          // on crée un lien dans tous les cas (même s'il ne pointe pas vers une référence), pour avoir accès à la class CSS (pour surcharge)
          var link = null;
          link = document.createElement("a");
          link.className = "gp-control-attribution-link";
          link.target = "_blank";
          container.appendChild(link);
          if (url) {
            link.href = url;
          }
          var bImage = !!logo;
          var image = null;
          // si on a un logo, on l'affiche à l'interieur du lien
          if (bImage) {
            image = document.createElement("img");
            if (link) {
              image.className = "gp-control-attribution-image";
              link.appendChild(image);
            } else {
              image.className = "";
              container.appendChild(image);
            }
            image.src = logo;
            image.title = text || name;
            image.style.height = "30px";
            image.style.width = "30px";
          } else {
            // sinon, on affiche le nom de l'originator, ou sa description ou l'url.
            if (name) {
              link.textContent = name;
            } else if (text) {
              link.textContent = text;
            } else if (url) {
              link.textContent = url;
            } else {
              link.textContent = "";
            }
          }
          attributions.push(container.innerHTML + " ");
        }
      }
    }
    return attributions;
  },
  /**
   * Determines if one extent (extent1) intersects another (extent2)
   *
   * @function intersects
   * @param {Array.<Float>} extent1 - First extent : [top, left, bottom, right] = [maxy, minx, miny, maxx]
   * @param {Array.<Float>} extent2 - Second extent : [top, left, bottom, right] = [maxy, minx, miny, maxx]
   * @return {Boolean} intersects - True if the two extents intersect, false otherwise.
   */
  intersects: function intersects(extent1, extent2) {
    var intersectsX = extent1[1] <= extent2[3] && extent2[1] <= extent1[3];
    var intersectsY = extent1[2] <= extent2[0] && extent2[2] <= extent1[0];
    return intersectsX && intersectsY;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LayerUtils);

/***/ }),
/* 138 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _LayerEvent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(139);
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
var _package_json__WEBPACK_IMPORTED_MODULE_4___namespace = /*#__PURE__*/__webpack_require__.t(1, 1);
/**
* desativation JSHINT
* W106 - Identifier '_geoportal_id' is not in camel case
*/
/* jshint -W106 */





// package.json (extract version)

var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("wms");

/**
 * @namespace
 * @alias L.geoportalLayers.WMS
 * @classdesc
 *
 * Leaflet Layer Class for Geoportal or INSPIRE WMS Layers.
 *
 * Use {@link module:Layers.WMS L.geoportalLayer.WMS()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#tilelayer-wms" target="_blank">L.TileLayer.WMS</a> native class.
 *
 */
var WMS = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.WMS.extend( /** @lends WMS.prototype */{
  includes: _LayerEvent__WEBPACK_IMPORTED_MODULE_3__["default"],
  /**
   *
   * @constructor
   * @param {String} url - url service
   * @param {Object} options - options for function call.
   * @param {Array} [options.originators] - originators
   * @param {Array} [options.legends] - legends
   * @param {Array} [options.metadata] - metadata
   * @param {String} [options.title] - title
   * @param {String} [options.description] - description
   * @param {String} [options.quicklookUrl] - quicklookUrl
   * @param {Object} options.paramsWms - WMS options
   * @param {String} options.paramsWms.layers - eg "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO",
   * @param {String} options.paramsWms.styles - "normal",
   * @param {String} options.paramsWms.format - "image/jpeg",
   * @param {String} options.paramsWms.version - "1.3.0"
   * @param {Object} [options.paramsNative] - other options for L.TileLayer.WMS function (see {@link http://leafletjs.com/reference.html#tilelayer-wms-options})
   * @example
   * var wms = new WMS("https://data.geopf.fr/wms-r/wms", {
   *     paramsNative : {
   *         minZoom : 1,
   *         maxZoom : 21
   *     },
   *     paramsWms   : {
   *         layers  : "ORTHOIMAGERY.ORTHOPHOTOS.BDORTHO",
   *         styles  : "normal",
   *         format  : "image/jpeg",
   *         version : "1.3.0"
   *     },
   *     originators  : [],
   *     legends      : [],
   *     metadata     : [],
   *     title        : "",
   *     description  : "",
   *     quicklookUrl : ""
   * });
   *
   * @ignore
   */
  initialize: function initialize(url, options) {
    var settings = {};
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(settings, options.paramsWms, options.paramsNative);
    var urlParams = {
      "gp-leaflet-ext": _package_json__WEBPACK_IMPORTED_MODULE_4__.leafletExtVersion || _package_json__WEBPACK_IMPORTED_MODULE_4__.version
    };

    // ajout de l'apiKey en paramètre de la requête si couche à accès restreint
    if (options.apikey) {
      urlParams["apikey"] = options.apikey;
    }

    // appel du constructeur de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.WMS.prototype.initialize.call(this,
    // tracker extension leaflet
    // FIXME : gp-ext version en mode AMD
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Helper.normalyzeUrl(url, urlParams, false), settings);

    // sauvegarde
    this._originators = options.originators;
    this._legends = options.legends;
    this._metadata = options.metadata;
    this._title = options.title;
    this._description = options.description;
    this._quicklookUrl = options.quicklookUrl;

    // init id du Layer
    this._geoportal_id = 0; // FIXME L.stamp(this);
  },
  /**
   * event
   * (overwritten)
   *
   * @param {Object} map - map leaflet object
   * @private
   */
  onAdd: function onAdd(map) {
    logger.trace("onAdd layer", this._geoportal_id);

    // recuperation de la map
    this._map = map;

    // enregistrement de l'id Geoportal
    this._geoportal_id = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.stamp(this);

    // appel de la methode de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.WMS.prototype.onAdd.call(this, map);
    this.setVisible(true);

    // y a t il des attributions/originators pour ce layer ?
    this.updateAttributions(map);

    /**
     * Evenement sur l'ajout du layer sur la carte avec gestion des deplacements (zoom)
     * Les deplacemnts sur la carte permettent de mettre à jour la liste des attributions.
     */
    map.on({
      /**
       * Permet de desactiver la visibilité des attributions sur le retrait
       * d'un layer de type overlay.
       * Les attributions ne doivent plus apparaitre si le layer est invisible !
       * @private
       */
      overlayremove: this._onRemoveLayer,
      /**
       * Permet d'activer la visibilité des attributions sur l'ajout
       * d'un layer de type overlay.
       * Les attributions doivent apparaitre si le layer est visible !
       * @private
       */
      overlayadd: this._onAddLayer,
      /**
       * Permet de desactiver la visibilité des attributions sur le retrait
       * d'un layer de type layer.
       * Les attributions ne doivent plus apparaitre si le layer est invisible !
       * @private
       */
      layerremove: this._onRemoveLayer,
      /**
       * Permet d'activer la visibilité des attributions sur l'ajout
       * d'un layer de type layer.
       * Les attributions doivent apparaitre si le layer est visible !
       * @private
       */
      layeradd: this._onAddLayer,
      /**
       * Permet d'ajouter des fonctionnalités lors de la creation du layer
       * sur les evenements de fin de mouvemenent (move ou zoom)
       * @private
       */
      moveend: this._onMoveEndLayer
    }, this);

    // if (map.attributionControl) {
    //
    //     // ceci permet de mofifier le prefixe leaflet !
    //     // ce dernier etant obligatoire...
    //     // Ex. map.attributionControl.setPrefix("Plugin © IGN with Leaflet - 2016");
    //     // map.attributionControl.setPrefix("Leaflet + Géoportail");
    //     map.attributionControl.setPrefix("Plugin © " +
    //         "<a href=\"http://www.ign.fr\" " +
    //         "title=\"Institut national de l'information géographique et forestière\">IGN</a>" +
    //         " with " +
    //         "<a href=\"http://leafletjs.com/\" " +
    //         "title=\"an open-source JavaScript library for mobile-friendly interactive maps\">Leaflet</a>" +
    //         " - 2016");
    // }
  },
  /**
   * event
   * (overwritten)
   *
   * @param {Object} map - map leaflet object
   * @private
   */
  onRemove: function onRemove(map) {
    logger.trace("onRemove layer", this._geoportal_id);

    // recuperation de la map
    this._map = map;

    // appel de la methode de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.prototype.onRemove.call(this, map);
    this.setVisible(false);

    // suppression des attributions
    this.removeAttributions(map);

    // supprimer les evenements
    map.off({
      overlayremove: this._onRemoveLayer,
      overlayadd: this._onAddLayer,
      layerremove: this._onRemoveLayer,
      layeradd: this._onAddLayer,
      moveend: this._onMoveEndLayer
    }, this);
  },
  /**
   * event
   * (overwritten)
   *
   * @param {Object} tilePoint - Point object
   *
   * @returns {String} url
   * @private
   */
  getTileUrl: function getTileUrl(tilePoint) {
    // (Point, Number) -> String

    // FIXME
    // on surcharge cette methode à cause d'un BUG Leaflet sur l'inversion de
    // coordonnées sur les codes EPSG en geographiques en WMS 1.3.0.
    // En attente de resolution du ticket suivant :
    //   Axis option for crs, Issue 4253 on Leaflet/Leaflet
    //   https://github.com/Leaflet/Leaflet/issues/4253

    var lstProjEpsgGeographic = ["EPSG:4326"]; // ex. "EPSG:4641"

    var map = this._map;
    var tileSize = this.options.tileSize;
    var nwPoint = tilePoint.multiplyBy(tileSize);
    var sePoint = nwPoint.add([tileSize, tileSize]);
    var nw = this._crs.project(map.unproject(nwPoint, tilePoint.z));
    var se = this._crs.project(map.unproject(sePoint, tilePoint.z));
    var bbox = this._wmsVersion >= 1.3 && lstProjEpsgGeographic.indexOf(this._crs.code) !== -1 ? [se.y, nw.x, nw.y, se.x].join(",") : [nw.x, se.y, se.x, nw.y].join(",");
    var url = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.template(this._url, {
      s: this._getSubdomain(tilePoint)
    });
    return url + leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.getParamString(this.wmsParams, url, true) + "&BBOX=" + bbox;
  }
});
/* harmony default export */ __webpack_exports__["default"] = (WMS);

/***/ }),
/* 139 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(35);
/* harmony import */ var _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(137);


var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("layer-event");

/**
 * @classdesc
 *
 * Evenement sur les couches Geoplateforme
 * @private
 */
/** @type {LayerEvent} */
var LayerEvent = {
  _id: null,
  _attributions: [],
  _visibility: true,
  _originators: [],
  /**
   * activation du controle attribution
   *
   * @param {Object} map - the map
   *
   * @return {Boolean} attribution controle is enable
   */
  isEnable: function isEnable(map) {
    if (!map.attributionControl) {
      return false;
    }
    return true;
  },
  /**
   * visibilité de la couche
   *
   * @param {Boolean} visibility - true|false
   */
  setVisible: function setVisible(visibility) {
    logger.log("visibility", visibility);
    this._visibility = visibility;
    this.fire("visibilitychange");
  },
  /**
   * visibilité de la couche
   *
   * @returns {Boolean} visibility
   */
  getVisible: function getVisible() {
    return this._visibility;
  },
  /**
   * fonction de suppresion d'un layer du controle des layers
   *
   * @param {Object} e - event
   */
  _onRemoveLayer: function _onRemoveLayer(e) {
    logger.trace("onRemove event", e);
    if (e.layer._geoportal_id !== this._geoportal_id) {
      return;
    }
    // attributions non visibles
    this.setVisible(false);
  },
  /**
   * fonction d'ajout d'un layer du controle des layers
   *
   * @param {Object} e - event
   */
  _onAddLayer: function _onAddLayer(e) {
    logger.trace("onAdd event", e);
    if (e.layer._geoportal_id !== this._geoportal_id) {
      return;
    }
    // attributions visibles
    this.setVisible(true);
  },
  /**
   * fonction de deplacement d'un layer
   *
   * @param {Object} e - event
   */
  _onMoveEndLayer: function _onMoveEndLayer(e) {
    logger.trace("moveend event", e);
    // mise à jour des attributions
    this.updateAttributions(this._map, this);
  },
  /**
   * updateAttributions
   *
   * @param {Object} map - the map
   */
  updateAttributions: function updateAttributions(map) {
    // FIXME on peut realiser une mise à jour plus intelligente que cette manière brutale...
    // Ex. mise en place de la notion 'hidden' de l'originators à desactiver

    if (!this.isEnable(map)) {
      return;
    }
    this.removeAttributions(map);
    this.addAttributions(map);
    this.fire("attributionchange");
  },
  /**
   * removeAttributions
   *
   * @param {Object} map - the map
   */
  removeAttributions: function removeAttributions(map) {
    logger.trace("removeAttributions...", this._geoportal_id);
    // suppression des attributions
    // L.Map utilise la methode getAttribution() du layer.
    // La construction concerne le layer courant.
    // Cet evenement declenche la construction des attributions

    if (!this.isEnable(map)) {
      return;
    }
    for (var i = 0; i < this._attributions.length; i++) {
      map.attributionControl.removeAttribution(this._attributions[i]);
    }

    // suppression des attributions de liste
    this._attributions = [];
  },
  /**
   * addAttributions
   *
   * @param {Object} map - the map
   */
  addAttributions: function addAttributions(map) {
    logger.trace("addAttributions...", this._geoportal_id);
    // on interroge les originators en options pour obtenir les infos
    // suivantes :
    // - echelles
    // - contraintes d'emprise
    // - information sur le(s) proprietaire(s) du layer
    // - ...
    // mais on a besoin de qq informations sur la carte tels que :
    // - zoom
    // - bounds
    // - ...

    if (!this.isEnable(map)) {
      return;
    }

    // ajout des attributions
    var topLeft = map.getBounds().getNorthWest();
    var bottomRight = map.getBounds().getSouthEast();
    var arrayBounds = [topLeft.lat, topLeft.lng, bottomRight.lat, bottomRight.lng];
    var params = {
      extent: arrayBounds,
      // map.getBounds(),
      zoom: map.getZoom(),
      originators: this._originators,
      visibility: this._visibility
    };
    logger.log(params);
    var attributionsOriginators = _Common_Utils_LayerUtils__WEBPACK_IMPORTED_MODULE_1__["default"].getAttributions(params);
    logger.log(attributionsOriginators);
    if (attributionsOriginators && attributionsOriginators.length !== 0) {
      // on les ajoute dans la liste
      // et on ajoute les attributions dans le controle Leaflet "L.Control.Attribution"
      for (var i = 0; i < attributionsOriginators.length; i++) {
        this._attributions.push(attributionsOriginators[i]);
        map.attributionControl.addAttribution(attributionsOriginators[i]);
      }
    }
  }
};
/* harmony default export */ __webpack_exports__["default"] = (LayerEvent);

/***/ }),
/* 140 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(35);
/* harmony import */ var _LayerEvent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(139);
/* harmony import */ var _package_json__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
var _package_json__WEBPACK_IMPORTED_MODULE_4___namespace = /*#__PURE__*/__webpack_require__.t(1, 1);
/**
* desativation JSHINT
* W106 - Identifier '_geoportal_id' is not in camel case
*/





// package.json (extract version)

var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_2__["default"].getLogger("wmts");

/**
 * @namespace
 * @alias L.geoportalLayers.WMTS
 * @classdesc
 *
 * Leaflet Layer Class for Geoportal WMTS Layers.
 *
 * Use {@link module:Layers.WMTS L.geoportalLayer.WMTS()} factory to create instances of that class.
 *
 * **Extends** Leaflet <a href="http://leafletjs.com/reference.html#tilelayer" target="_blank">L.TileLayer</a> native class.
 *
 */
var WMTS = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.extend( /** @lends WMTS.prototype */{
  includes: _LayerEvent__WEBPACK_IMPORTED_MODULE_3__["default"],
  defaultWmtsParams: {
    service: "WMTS",
    request: "GetTile",
    version: "1.0.0",
    layer: "",
    style: "",
    tilematrixset: "PM",
    format: "image/jpeg"
  },
  /**
   *
   * @constructor
   * @param {String} url - url service
   * @param {Object} options - options for function call.
   * @param {Array} [options.originators] - originators
   * @param {Array} [options.legends] - legends
   * @param {Array} [options.metadata] - metadata
   * @param {String} [options.title] - title
   * @param {String} [options.description] - description
   * @param {String} [options.quicklookUrl] - quicklookUrl
   * @param {Object} options.paramsWmts - WMTS options
   * @param {String} options.paramsWmts.service - "WMTS",
   * @param {String} options.paramsWmts.request - "GetTile",
   * @param {String} options.paramsWmts.version - "1.0.0",
   * @param {String} options.paramsWmts.layer - "",
   * @param {String} options.paramsWmts.style - "",
   * @param {String} options.paramsWmts.tilematrixset - "PM",
   * @param {String} options.paramsWmts.format - "image/jpeg"
   * @param {Object} [options.paramsNative] - other options for L.TileLayer function (see {@link http://leafletjs.com/reference.html#tilelayer-options})
   * @example
   * var wmts = new WMTS("https://data.geopf.fr/wmts", {
   *     paramsNative : {
   *         minZoom : 1,
   *         maxZoom : 21
   *     },
   *     paramsWmts   : {
   *         layer   : "ORTHOIMAGERY.ORTHOPHOTOS",
   *         style   : "normal",
   *         format  : "image/jpeg",
   *         version : "1.0.0",
   *         tilematrixset : "PM"
   *     },
   *     originators  : [],
   *     legends      : [],
   *     metadata     : [],
   *     title        : "",
   *     description  : "",
   *     quicklookUrl : ""
   * });
   *
   * @ignore
   */
  initialize: function initialize(url, options) {
    logger.log("initialize");

    // parametres WMTS
    this._wmtsParams = {};
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.extend(this._wmtsParams, this.defaultWmtsParams, options.paramsWmts);
    var urlParams = {
      "gp-leaflet-ext": _package_json__WEBPACK_IMPORTED_MODULE_4__.leafletExtVersion || _package_json__WEBPACK_IMPORTED_MODULE_4__.version
    };

    // ajout de l'apiKey en paramètre de la requête si couche à accès restreint
    if (options.apikey) {
      urlParams["apikey"] = options.apikey;
    }

    // appel du constructeur de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.prototype.initialize.call(this,
    // tracker extension leaflet
    // FIXME : gp-ext version en mode AMD
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Helper.normalyzeUrl(url, urlParams, false), options.paramsNative);

    // sauvegarde des originators
    this._originators = options.originators;
    this._legends = options.legends;
    this._metadata = options.metadata;
    this._title = options.title;
    this._description = options.description;
    this._quicklookUrl = options.quicklookUrl;

    // id du Layer
    this._geoportal_id = 0; // FIXME L.stamp(this);
  },
  /**
   * event 'onAdd'
   * (overwritten)
   *
   * @param {Object} map - map leaflet object
   * @private
   */
  onAdd: function onAdd(map) {
    logger.trace("onAdd layer", this._geoportal_id);

    // recuperation de la map
    this._map = map;

    // enregistrement de l'id Geoportal
    this._geoportal_id = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.stamp(this);

    // appel de la methode de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.prototype.onAdd.call(this, map);
    this.setVisible(true);

    // y a t il des attributions/originators pour ce layer ?
    this.updateAttributions(map);

    /**
     * Evenement sur l'ajout du layer sur la carte avec gestion des deplacements (zoom)
     * Les deplacemnts sur la carte permettent de mettre à jour la liste des attributions.
     */
    map.on({
      /**
       * Permet de desactiver la visibilité des attributions sur le retrait
       * d'un layer de type overlay.
       * Les attributions ne doivent plus apparaitre si le layer est invisible !
       * @private
       */
      overlayremove: this._onRemoveLayer,
      /**
       * Permet d'activer la visibilité des attributions sur l'ajout
       * d'un layer de type overlay.
       * Les attributions doivent apparaitre si le layer est visible !
       * @private
       */
      overlayadd: this._onAddLayer,
      /**
       * Permet de desactiver la visibilité des attributions sur le retrait
       * d'un layer de type layer.
       * Les attributions ne doivent plus apparaitre si le layer est invisible !
       * @private
       */
      layerremove: this._onRemoveLayer,
      /**
       * Permet d'activer la visibilité des attributions sur l'ajout
       * d'un layer de type layer.
       * Les attributions doivent apparaitre si le layer est visible !
       * @private
       */
      layeradd: this._onAddLayer,
      /**
       * Permet d'ajouter des fonctionnalités lors de la creation du layer
       * sur les evenements de fin de mouvemenent (move ou zoom)
       * @private
       */
      moveend: this._onMoveEndLayer
    }, this);

    // if (map.attributionControl) {
    //     // ceci permet de mofifier le prefixe leaflet !
    //     // ce dernier etant obligatoire...
    //     // Ex. map.attributionControl.setPrefix("Plugin © IGN with Leaflet - 2016");
    //     // map.attributionControl.setPrefix("Leaflet + Géoportail");
    //     map.attributionControl.setPrefix("Plugin © " +
    //         "<a href=\"http://www.ign.fr\" " +
    //         "title=\"Institut national de l'information géographique et forestière\">IGN</a>" +
    //         " with " +
    //         "<a href=\"http://leafletjs.com/\" " +
    //         "title=\"an open-source JavaScript library for mobile-friendly interactive maps\">Leaflet</a>" +
    //         " - 2016");
    // }
  },
  /**
   * event 'onRemove'
   * (overwritten)
   *
   * @param {Object} map - map leaflet object
   * @private
   */
  onRemove: function onRemove(map) {
    logger.trace("onRemove layer", this._geoportal_id);

    // recuperation de la map
    this._map = map;

    // appel de la methode de la classe étendue
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.TileLayer.prototype.onRemove.call(this, map);
    this.setVisible(false);

    // suppression des attributions
    this.removeAttributions(map);

    // supprimer les evenements
    map.off({
      overlayremove: this._onRemoveLayer,
      overlayadd: this._onAddLayer,
      layerremove: this._onRemoveLayer,
      layeradd: this._onAddLayer,
      moveend: this._onMoveEndLayer
    }, this);
  },
  /**
   * event 'getTileUrl'
   * (overwritten)
   *
   * @param {Object} tilePoint - Point leaflet object
   *
   * @returns {String} url
   * @private
   */
  getTileUrl: function getTileUrl(tilePoint) {
    // (Point, Number) -> String

    // ex https://data.geopf.fr/wmts?
    // SERVICE=WMTS&
    // REQUEST=GetTile&
    // VERSION=1.0.0&
    // LAYER=ORTHOIMAGERY.ORTHOPHOTOS&
    // STYLE=normal&
    // TILEMATRIXSET=PM&
    // TILEMATRIX=2&
    // TILEROW=2&
    // TILECOL=1&
    // FORMAT=image%2Fjpeg

    var zoom = this._getZoomForUrl();
    var url = leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.template(this._url, {
      s: this._getSubdomain(tilePoint)
    });
    return url + leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.Util.getParamString(this._wmtsParams, url) + "&tilematrix=" + zoom + "&tilerow=" + tilePoint.y + "&tilecol=" + tilePoint.x;
  },
  /**
   * event 'setParams'
   * (overwritten)
   *
   * @param {Object} params - parameters
   * @param {Object} noRedraw - no redraw
   *
   * @returns {Object} this
   * @private
   */
  setParams: function setParams(params, noRedraw) {
    leaflet__WEBPACK_IMPORTED_MODULE_1___default.a.extend(this._wmtsParams, params);
    if (!noRedraw) {
      this.redraw();
    }
    return this;
  }
});
/* harmony default export */ __webpack_exports__["default"] = (WMTS);

/***/ }),
/* 141 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(41);

(function () {
  var scripts = document.getElementsByTagName("script");
  var key = scripts[scripts.length - 1].getAttribute("data-key");
  var url = scripts[scripts.length - 1].getAttribute("data-url");
  var timeout = scripts[scripts.length - 1].getAttribute("data-timeout");

  // callback
  var success = function success() {
    // Pas de messages en mode prod
    // console.log("GetConfig success!");
  };

  // callback
  var error = function error(e) {
    throw new Error("Configuration load failed : " + e.message);
  };
  if (!key && !url) {
    // pas de message d'information !
    // console.log("WARNING : parameters missing 'data-key' and 'data-url', the loading of configuration can not be done !");
    return;
  }
  var options = {
    apiKey: key,
    sync: true,
    onSuccess: success,
    onFailure: error
  };
  if (url) {
    options.customConfigFile = url;
    options.callbackSuffix = "";
  }
  if (timeout) {
    options.timeOut = timeout;
  }

  // test d'existance de la varibale globale Gp.Config
  if (!window.Gp) {
    // appel du service
    geoportal_access_lib__WEBPACK_IMPORTED_MODULE_0__["default"].Services.getConfig(options);
  }
})();

/***/ }),
/* 142 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(35);


/**
* @module ProxyUtils
* @alias Gp.ProxyUtils
* @description
* ...
*
* @example
* proxifyUrl();
*/
var ProxyUtils = {
  /**
   * Ajoute un proxy aux url des couches vecteurs si besoin.
   *
   * @function proxifyUrl
   * @param {String} url - Url to proxify.
   * @param {Object} [proxyOptions] - Object defining proxy options.
   * @param {String} proxyOptions.proxyUrl - Proxy URL.
   * @param {Array.<String>} [proxyOptions.noProxyDomains] - Proxy will not be used for this list of domain names.
   *
   * @returns {String} proxy url
   */
  proxifyUrl: function proxifyUrl(url, proxyOptions) {
    // logger

    var logger = _Common_Utils_LoggerByDefault__WEBPACK_IMPORTED_MODULE_0__["default"].getLogger("proxifyUrl");
    if (!proxyOptions || !proxyOptions.hasOwnProperty("proxyUrl") || proxyOptions.proxyUrl === null || proxyOptions.proxyUrl.trim().length === 0) {
      return url;
    }
    // on regarde si l'url nest pas dans les domaines sans proxy
    if (proxyOptions.noProxyDomains && Array.isArray(proxyOptions.noProxyDomains) && proxyOptions.noProxyDomains.length > 0) {
      for (var i in proxyOptions.noProxyDomains) {
        logger.trace("[ProxyUtils] proxifyUrl : analyzing " + proxyOptions.noProxyDomains[i]);
        if (url.indexOf(proxyOptions.noProxyDomains[i]) !== -1) {
          logger.info("[ProxyUtils] proxifyUrl : " + url + " found in noProxyDomains list (" + proxyOptions.noProxyDomains[i] + ").");
          return url;
        }
      }
    }
    return proxyOptions.proxyUrl + encodeURIComponent(url);
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ProxyUtils);

/***/ }),
/* 143 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/**
 * @module ColorUtils
 * @alias Gp.ColorUtils
 * @description
 * ...
 *
 * @example
 * arrayTorgba();
 * arrayToHex();
 * rgbaToHex();
 * hexToRgba();
 * isHex();
 * isRGB();
 */
var ColorUtils = {
  /**
   * Number to hex conversion
   *
   * @param {Number} number - 0-255
   * @returns {String} hex value
   */
  hex: function hex(number) {
    if (number > 255) {
      throw new Error("'" + number + "'' is greater than 255(0xff);");
    }
    var str = Number(number).toString(16);
    return ("0" + str).slice(-2);
  },
  /**
   * Hexa to number conversion
   *
   * @param {*} hexa 00-FF
   * @returns {Number} number value
   */
  num: function num(hexa) {
    return parseInt(hexa, 16);
  },
  /**
   * Converts an array ([255,255,255,1]) to rgba string
   *
   * @function arrayToRgba
   * @param {Array} values - array of values
   * @returns {String} A color of RGB or RGBA format
   */
  arrayToRgba: function arrayToRgba(values) {
    if (!Array.isArray(values)) {
      throw new Error("Not an array !");
    }
    var red = values[0];
    var green = values[1];
    var blue = values[2];
    var alpha = values[3] || 1;
    var result = "rgba(" + red + ", " + green + ", " + blue + ", " + parseFloat(alpha) + ")";
    return result;
  },
  /**
   * Converts an array ([255,255,255,1]) to #RRGGBBAA
   *
   * @function arrayToHex
   * @param {Array} values - array of values
   * @returns {Object}  hex and opacity formated values
   */
  arrayToHex: function arrayToHex(values) {
    if (!Array.isArray(values)) {
      throw new Error("Not an array !");
    }
    var red = values[0];
    var green = values[1];
    var blue = values[2];
    var alpha = values[3];
    var elems = [this.hex(red), this.hex(green), this.hex(blue)];
    var result = {};
    result.hex = "#" + elems.join("");
    if (alpha) {
      // elems.push(hex(alpha));
      result.opacity = parseFloat(alpha);
    }
    return result;
  },
  /**
   * Converts rgba string to #RRGGBBAA
   * (Code adapted from : https://gist.github.com/mstssk/afda4ce9e5c335fd79cd)
   *
   * @function rgbaToHex
   * @param {String} rgba - A color of RGB or RGBA format.
   * @returns {Object} hex and opacity formated values
   */
  rgbaToHex: function rgbaToHex(rgba) {
    var regex = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(0?.?\d+)\s*)?\)/;
    var parsed = regex.exec(rgba);
    if (!parsed) {
      throw new Error("Invalid format: " + rgba);
    }
    var red = parsed[1];
    var green = parsed[2];
    var blue = parsed[3];
    var alpha = parsed[4];
    var elems = [this.hex(red), this.hex(green), this.hex(blue)];
    var result = {};
    result.hex = "#" + elems.join("");
    if (alpha) {
      // elems.push(hex(alpha));
      result.opacity = parseFloat(alpha);
    }
    return result;
  },
  /**
   * Converts hex color and opacity value to rgba string.
   * (Code adapted from : http://stackoverflow.com/a/5624139)
   *
   * @function hexToRgba
   * @param {String} hex - A color value on RGB format (hexa).
   * @param {Number} opacity - A opacity value.
   * @returns {String} A color of RGB or RGBA format
   */
  hexToRgba: function hexToRgba(hex, opacity) {
    // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    if (!hex) {
      throw new Error("Invalid format");
    }
    hex = hex.replace(shorthandRegex, function (m, r, g, b) {
      return r + r + g + g + b + b;
    });
    var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    rgb = rgb ? {
      r: parseInt(rgb[1], 16),
      g: parseInt(rgb[2], 16),
      b: parseInt(rgb[3], 16)
    } : null;
    var result = rgb ? "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", " + opacity + ")" : null;
    return result;
  },
  /**
   * Determine if value is a correct hexa color.
   * @param {*} value - hex color (#FFFFFF)
   * @returns {Boolean} True if value is a hexa color
   */
  isHex: function isHex(value) {
    if (!value) {
      return false;
    }
    if (value.charAt(0) !== "#") {
      return false;
    }
    var regex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
    var parsed = regex.exec(value);
    if (!parsed) {
      return false;
    }
    return true;
  },
  /**
   * Determine if value is a correct rgba color.
   * @param {*} value - rgba color (rgba(125,125,125,1))
   * @returns {Boolean} True if value is a rgba color
   */
  isRGB: function isRGB(value) {
    if (!value) {
      return false;
    }
    var regex = /rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(0?.?\d+)\s*)?\)/;
    var parsed = regex.exec(value);
    if (!parsed) {
      return false;
    }
    return true;
  }
};
/* harmony default export */ __webpack_exports__["default"] = (ColorUtils);

/***/ })
/******/ ]);
});