diff --git a/dist/vizicities-worker.js b/dist/vizicities-worker.js
new file mode 100644
index 0000000..6569d96
--- /dev/null
+++ b/dist/vizicities-worker.js
@@ -0,0 +1,9190 @@
+(function webpackUniversalModuleDefinition(root, factory) {
+ if(typeof exports === 'object' && typeof module === 'object')
+ module.exports = factory(require("THREE"));
+ else if(typeof define === 'function' && define.amd)
+ define(["THREE"], factory);
+ else if(typeof exports === 'object')
+ exports["VIZI"] = factory(require("THREE"));
+ else
+ root["VIZI"] = factory(root["THREE"]);
+})(this, function(__WEBPACK_EXTERNAL_MODULE_18__) {
+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] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Flag the module as loaded
+/******/ module.loaded = 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;
+/******/
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+/******/
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ var _geoGeoJs = __webpack_require__(1);
+
+ var _geoGeoJs2 = _interopRequireDefault(_geoGeoJs);
+
+ var _layerLayer = __webpack_require__(4);
+
+ var _layerLayer2 = _interopRequireDefault(_layerLayer);
+
+ var _layerGeoJSONWorkerLayer = __webpack_require__(22);
+
+ var _layerGeoJSONWorkerLayer2 = _interopRequireDefault(_layerGeoJSONWorkerLayer);
+
+ var _layerGeometryPolygonLayer = __webpack_require__(36);
+
+ var _layerGeometryPolygonLayer2 = _interopRequireDefault(_layerGeometryPolygonLayer);
+
+ var _geoPoint = __webpack_require__(3);
+
+ var _geoPoint2 = _interopRequireDefault(_geoPoint);
+
+ var _geoLatLon = __webpack_require__(2);
+
+ var _geoLatLon2 = _interopRequireDefault(_geoLatLon);
+
+ var _utilIndex = __webpack_require__(41);
+
+ var _utilIndex2 = _interopRequireDefault(_utilIndex);
+
+ var VIZI = {
+ version: '0.3',
+
+ Geo: _geoGeoJs2['default'],
+ Layer: _layerLayer2['default'],
+ layer: _layerLayer.layer,
+ GeoJSONWorkerLayer: _layerGeoJSONWorkerLayer2['default'],
+ geoJSONWorkerLayer: _layerGeoJSONWorkerLayer.geoJSONWorkerLayer,
+ PolygonLayer: _layerGeometryPolygonLayer2['default'],
+ polygonLayer: _layerGeometryPolygonLayer.polygonLayer,
+ Point: _geoPoint2['default'],
+ point: _geoPoint.point,
+ LatLon: _geoLatLon2['default'],
+ latLon: _geoLatLon.latLon,
+ Util: _utilIndex2['default']
+ };
+
+ exports['default'] = VIZI;
+ module.exports = exports['default'];
+
+/***/ },
+/* 1 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ var _LatLon = __webpack_require__(2);
+
+ var _Point = __webpack_require__(3);
+
+ var Geo = {};
+
+ // Radius / WGS84 semi-major axis
+ Geo.R = 6378137;
+ Geo.MAX_LATITUDE = 85.0511287798;
+
+ // WGS84 eccentricity
+ Geo.ECC = 0.081819191;
+ Geo.ECC2 = 0.081819191 * 0.081819191;
+
+ Geo.project = function (latlon) {
+ var d = Math.PI / 180;
+ var max = Geo.MAX_LATITUDE;
+ var lat = Math.max(Math.min(max, latlon.lat), -max);
+ var sin = Math.sin(lat * d);
+
+ return (0, _Point.point)(Geo.R * latlon.lon * d, Geo.R * Math.log((1 + sin) / (1 - sin)) / 2);
+ }, Geo.unproject = function (point) {
+ var d = 180 / Math.PI;
+
+ return (0, _LatLon.latLon)((2 * Math.atan(Math.exp(point.y / Geo.R)) - Math.PI / 2) * d, point.x * d / Geo.R);
+ };
+
+ // Converts geo coords to pixel / WebGL ones
+ // This just reverses the Y axis to match WebGL
+ Geo.latLonToPoint = function (latlon) {
+ var projected = Geo.project(latlon);
+ projected.y *= -1;
+
+ return projected;
+ };
+
+ // Converts pixel / WebGL coords to geo coords
+ // This just reverses the Y axis to match WebGL
+ Geo.pointToLatLon = function (point) {
+ var _point = (0, _Point.point)(point.x, point.y * -1);
+ return Geo.unproject(_point);
+ };
+
+ // Scale factor for converting between real metres and projected metres
+ //
+ // projectedMetres = realMetres * pointScale
+ // realMetres = projectedMetres / pointScale
+ //
+ // Accurate scale factor uses proper Web Mercator scaling
+ // See pg.9: http://www.hydrometronics.com/downloads/Web%20Mercator%20-%20Non-Conformal,%20Non-Mercator%20(notes).pdf
+ // See: http://jsfiddle.net/robhawkes/yws924cf/
+ Geo.pointScale = function (latlon, accurate) {
+ var rad = Math.PI / 180;
+
+ var k;
+
+ if (!accurate) {
+ k = 1 / Math.cos(latlon.lat * rad);
+
+ // [scaleX, scaleY]
+ return [k, k];
+ } else {
+ var lat = latlon.lat * rad;
+ var lon = latlon.lon * rad;
+
+ var a = Geo.R;
+
+ var sinLat = Math.sin(lat);
+ var sinLat2 = sinLat * sinLat;
+
+ var cosLat = Math.cos(lat);
+
+ // Radius meridian
+ var p = a * (1 - Geo.ECC2) / Math.pow(1 - Geo.ECC2 * sinLat2, 3 / 2);
+
+ // Radius prime meridian
+ var v = a / Math.sqrt(1 - Geo.ECC2 * sinLat2);
+
+ // Scale N/S
+ var h = a / p / cosLat;
+
+ // Scale E/W
+ k = a / v / cosLat;
+
+ // [scaleX, scaleY]
+ return [k, h];
+ }
+ };
+
+ // Convert real metres to projected units
+ //
+ // Latitude scale is chosen because it fluctuates more than longitude
+ Geo.metresToProjected = function (metres, pointScale) {
+ return metres * pointScale[1];
+ };
+
+ // Convert projected units to real metres
+ //
+ // Latitude scale is chosen because it fluctuates more than longitude
+ Geo.projectedToMetres = function (projectedUnits, pointScale) {
+ return projectedUnits / pointScale[1];
+ };
+
+ // Convert real metres to a value in world (WebGL) units
+ Geo.metresToWorld = function (metres, pointScale) {
+ // Transform metres to projected metres using the latitude point scale
+ //
+ // Latitude scale is chosen because it fluctuates more than longitude
+ var projectedMetres = Geo.metresToProjected(metres, pointScale);
+
+ var scale = Geo.scale();
+
+ // Scale projected metres
+ var scaledMetres = scale * projectedMetres;
+
+ return scaledMetres;
+ };
+
+ // Convert world (WebGL) units to a value in real metres
+ Geo.worldToMetres = function (worldUnits, pointScale) {
+ var scale = Geo.scale();
+
+ var projectedUnits = worldUnits / scale;
+ var realMetres = Geo.projectedToMetres(projectedUnits, pointScale);
+
+ return realMetres;
+ };
+
+ // If zoom is provided, returns the map width in pixels for a given zoom
+ // Else, provides fixed scale value
+ Geo.scale = function (zoom) {
+ // If zoom is provided then return scale based on map tile zoom
+ if (zoom >= 0) {
+ return 256 * Math.pow(2, zoom);
+ // Else, return fixed scale value to expand projected coordinates from
+ // their 0 to 1 range into something more practical
+ } else {
+ return 1;
+ }
+ };
+
+ // Returns zoom level for a given scale value
+ // This only works with a scale value that is based on map pixel width
+ Geo.zoom = function (scale) {
+ return Math.log(scale / 256) / Math.LN2;
+ };
+
+ // Distance between two geographical points using spherical law of cosines
+ // approximation or Haversine
+ //
+ // See: http://www.movable-type.co.uk/scripts/latlong.html
+ Geo.distance = function (latlon1, latlon2, accurate) {
+ var rad = Math.PI / 180;
+
+ var lat1;
+ var lat2;
+
+ var a;
+
+ if (!accurate) {
+ lat1 = latlon1.lat * rad;
+ lat2 = latlon2.lat * rad;
+
+ a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlon2.lon - latlon1.lon) * rad);
+
+ return Geo.R * Math.acos(Math.min(a, 1));
+ } else {
+ lat1 = latlon1.lat * rad;
+ lat2 = latlon2.lat * rad;
+
+ var lon1 = latlon1.lon * rad;
+ var lon2 = latlon2.lon * rad;
+
+ var deltaLat = lat2 - lat1;
+ var deltaLon = lon2 - lon1;
+
+ var halfDeltaLat = deltaLat / 2;
+ var halfDeltaLon = deltaLon / 2;
+
+ a = Math.sin(halfDeltaLat) * Math.sin(halfDeltaLat) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(halfDeltaLon) * Math.sin(halfDeltaLon);
+
+ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+
+ return Geo.R * c;
+ }
+ };
+
+ Geo.bounds = (function () {
+ var d = Geo.R * Math.PI;
+ return [[-d, -d], [d, d]];
+ })();
+
+ exports['default'] = Geo;
+ module.exports = exports['default'];
+
+/***/ },
+/* 2 */
+/***/ function(module, exports) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+ /*
+ * LatLon is a helper class for ensuring consistent geographic coordinates.
+ *
+ * Based on:
+ * https://github.com/Leaflet/Leaflet/blob/master/src/geo/LatLng.js
+ */
+
+ var LatLon = (function () {
+ function LatLon(lat, lon, alt) {
+ _classCallCheck(this, LatLon);
+
+ if (isNaN(lat) || isNaN(lon)) {
+ throw new Error('Invalid LatLon object: (' + lat + ', ' + lon + ')');
+ }
+
+ this.lat = +lat;
+ this.lon = +lon;
+
+ if (alt !== undefined) {
+ this.alt = +alt;
+ }
+ }
+
+ _createClass(LatLon, [{
+ key: 'clone',
+ value: function clone() {
+ return new LatLon(this.lat, this.lon, this.alt);
+ }
+ }]);
+
+ return LatLon;
+ })();
+
+ exports['default'] = LatLon;
+
+ // Accepts (LatLon), ([lat, lon, alt]), ([lat, lon]) and (lat, lon, alt)
+ // Also converts between lng and lon
+ var noNew = function noNew(a, b, c) {
+ if (a instanceof LatLon) {
+ return a;
+ }
+ if (Array.isArray(a) && typeof a[0] !== 'object') {
+ if (a.length === 3) {
+ return new LatLon(a[0], a[1], a[2]);
+ }
+ if (a.length === 2) {
+ return new LatLon(a[0], a[1]);
+ }
+ return null;
+ }
+ if (a === undefined || a === null) {
+ return a;
+ }
+ if (typeof a === 'object' && 'lat' in a) {
+ return new LatLon(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
+ }
+ if (b === undefined) {
+ return null;
+ }
+ return new LatLon(a, b, c);
+ };
+
+ // Initialise without requiring new keyword
+ exports.latLon = noNew;
+
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+ /*
+ * Point is a helper class for ensuring consistent world positions.
+ *
+ * Based on:
+ * https://github.com/Leaflet/Leaflet/blob/master/src/geo/Point.js
+ */
+
+ var Point = (function () {
+ function Point(x, y, round) {
+ _classCallCheck(this, Point);
+
+ this.x = round ? Math.round(x) : x;
+ this.y = round ? Math.round(y) : y;
+ }
+
+ _createClass(Point, [{
+ key: "clone",
+ value: function clone() {
+ return new Point(this.x, this.y);
+ }
+
+ // Non-destructive
+ }, {
+ key: "add",
+ value: function add(point) {
+ return this.clone()._add(_point(point));
+ }
+
+ // Destructive
+ }, {
+ key: "_add",
+ value: function _add(point) {
+ this.x += point.x;
+ this.y += point.y;
+ return this;
+ }
+
+ // Non-destructive
+ }, {
+ key: "subtract",
+ value: function subtract(point) {
+ return this.clone()._subtract(_point(point));
+ }
+
+ // Destructive
+ }, {
+ key: "_subtract",
+ value: function _subtract(point) {
+ this.x -= point.x;
+ this.y -= point.y;
+ return this;
+ }
+ }]);
+
+ return Point;
+ })();
+
+ exports["default"] = Point;
+
+ // Accepts (point), ([x, y]) and (x, y, round)
+ var _point = function _point(x, y, round) {
+ if (x instanceof Point) {
+ return x;
+ }
+ if (Array.isArray(x)) {
+ return new Point(x[0], x[1]);
+ }
+ if (x === undefined || x === null) {
+ return x;
+ }
+ return new Point(x, y, round);
+ };
+
+ // Initialise without requiring new keyword
+ exports.point = _point;
+
+/***/ },
+/* 4 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+ var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var _eventemitter3 = __webpack_require__(5);
+
+ var _eventemitter32 = _interopRequireDefault(_eventemitter3);
+
+ var _lodashAssign = __webpack_require__(6);
+
+ var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
+
+ var _shortid = __webpack_require__(9);
+
+ var _shortid2 = _interopRequireDefault(_shortid);
+
+ var _three = __webpack_require__(18);
+
+ var _three2 = _interopRequireDefault(_three);
+
+ var _engineScene = __webpack_require__(19);
+
+ var _engineScene2 = _interopRequireDefault(_engineScene);
+
+ var _vendorCSS3DRenderer = __webpack_require__(20);
+
+ var _vendorCSS2DRenderer = __webpack_require__(21);
+
+ // TODO: Make sure nothing is left behind in the heap after calling destroy()
+
+ // TODO: Need a single move method that handles moving all the various object
+ // layers so that the DOM layers stay in sync with the 3D layer
+
+ // TODO: Double check that objects within the _object3D Object3D parent are frustum
+ // culled even if the layer position stays at the default (0,0,0) and the child
+ // objects are positioned much further away
+ //
+ // Or does the layer being at (0,0,0) prevent the child objects from being
+ // culled because the layer parent is effectively always in view even if the
+ // child is actually out of camera
+
+ var Layer = (function (_EventEmitter) {
+ _inherits(Layer, _EventEmitter);
+
+ function Layer(options) {
+ _classCallCheck(this, Layer);
+
+ _get(Object.getPrototypeOf(Layer.prototype), 'constructor', this).call(this);
+
+ var defaults = {
+ id: _shortid2['default'].generate(),
+ output: true,
+ outputToScene: true
+ };
+
+ this._options = (0, _lodashAssign2['default'])({}, defaults, options);
+
+ if (this.isOutput()) {
+ this._object3D = new _three2['default'].Object3D();
+
+ this._dom3D = document.createElement('div');
+ this._domObject3D = new _vendorCSS3DRenderer.CSS3DObject(this._dom3D);
+
+ this._dom2D = document.createElement('div');
+ this._domObject2D = new _vendorCSS2DRenderer.CSS2DObject(this._dom2D);
+ }
+ }
+
+ // Add THREE object directly to layer
+
+ _createClass(Layer, [{
+ key: 'add',
+ value: function add(object) {
+ this._object3D.add(object);
+ }
+
+ // Remove THREE object from to layer
+ }, {
+ key: 'remove',
+ value: function remove(object) {
+ this._object3D.remove(object);
+ }
+ }, {
+ key: 'addDOM3D',
+ value: function addDOM3D(object) {
+ this._domObject3D.add(object);
+ }
+ }, {
+ key: 'removeDOM3D',
+ value: function removeDOM3D(object) {
+ this._domObject3D.remove(object);
+ }
+ }, {
+ key: 'addDOM2D',
+ value: function addDOM2D(object) {
+ this._domObject2D.add(object);
+ }
+ }, {
+ key: 'removeDOM2D',
+ value: function removeDOM2D(object) {
+ this._domObject2D.remove(object);
+ }
+
+ // Add layer to world instance and store world reference
+ }, {
+ key: 'addTo',
+ value: function addTo(world) {
+ return world.addLayer(this);
+ }
+
+ // Internal method called by World.addLayer to actually add the layer
+ }, {
+ key: '_addToWorld',
+ value: function _addToWorld(world) {
+ var _this = this;
+
+ this._world = world;
+
+ return new Promise(function (resolve, reject) {
+ _this._onAdd(world).then(function () {
+ _this.emit('added');
+ resolve(_this);
+ })['catch'](reject);
+ });
+ }
+
+ // Must return a promise
+ }, {
+ key: '_onAdd',
+ value: function _onAdd(world) {
+ return Promise.resolve(this);
+ }
+ }, {
+ key: 'getPickingId',
+ value: function getPickingId() {
+ if (this._world._engine._picking) {
+ return this._world._engine._picking.getNextId();
+ }
+
+ return false;
+ }
+
+ // TODO: Tidy this up and don't access so many private properties to work
+ }, {
+ key: 'addToPicking',
+ value: function addToPicking(object) {
+ if (!this._world._engine._picking) {
+ return;
+ }
+
+ this._world._engine._picking.add(object);
+ }
+ }, {
+ key: 'removeFromPicking',
+ value: function removeFromPicking(object) {
+ if (!this._world._engine._picking) {
+ return;
+ }
+
+ this._world._engine._picking.remove(object);
+ }
+ }, {
+ key: 'isOutput',
+ value: function isOutput() {
+ return this._options.output;
+ }
+ }, {
+ key: 'isOutputToScene',
+ value: function isOutputToScene() {
+ return this._options.outputToScene;
+ }
+
+ // TODO: Also hide any attached DOM layers
+ }, {
+ key: 'hide',
+ value: function hide() {
+ this._object3D.visible = false;
+
+ if (this._pickingMesh) {
+ this._pickingMesh.visible = false;
+ }
+ }
+
+ // TODO: Also show any attached DOM layers
+ }, {
+ key: 'show',
+ value: function show() {
+ this._object3D.visible = true;
+
+ if (this._pickingMesh) {
+ this._pickingMesh.visible = true;
+ }
+ }
+
+ // Destroys the layer and removes it from the scene and memory
+ }, {
+ key: 'destroy',
+ value: function destroy() {
+ if (this._object3D && this._object3D.children) {
+ // Remove everything else in the layer
+ var child;
+ for (var i = this._object3D.children.length - 1; i >= 0; i--) {
+ child = this._object3D.children[i];
+
+ if (!child) {
+ continue;
+ }
+
+ this.remove(child);
+
+ if (child.geometry) {
+ // Dispose of mesh and materials
+ child.geometry.dispose();
+ child.geometry = null;
+ }
+
+ if (child.material) {
+ if (child.material.map) {
+ child.material.map.dispose();
+ child.material.map = null;
+ }
+
+ child.material.dispose();
+ child.material = null;
+ }
+ }
+ }
+
+ if (this._domObject3D && this._domObject3D.children) {
+ // Remove everything else in the layer
+ var child;
+ for (var i = this._domObject3D.children.length - 1; i >= 0; i--) {
+ child = this._domObject3D.children[i];
+
+ if (!child) {
+ continue;
+ }
+
+ this.removeDOM3D(child);
+ }
+ }
+
+ if (this._domObject2D && this._domObject2D.children) {
+ // Remove everything else in the layer
+ var child;
+ for (var i = this._domObject2D.children.length - 1; i >= 0; i--) {
+ child = this._domObject2D.children[i];
+
+ if (!child) {
+ continue;
+ }
+
+ this.removeDOM2D(child);
+ }
+ }
+
+ this._domObject3D = null;
+ this._domObject2D = null;
+
+ this._world = null;
+ this._object3D = null;
+ }
+ }]);
+
+ return Layer;
+ })(_eventemitter32['default']);
+
+ exports['default'] = Layer;
+
+ var noNew = function noNew(options) {
+ return new Layer(options);
+ };
+
+ exports.layer = noNew;
+
+/***/ },
+/* 5 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var has = Object.prototype.hasOwnProperty;
+
+ //
+ // We store our EE objects in a plain object whose properties are event names.
+ // If `Object.create(null)` is not supported we prefix the event names with a
+ // `~` to make sure that the built-in object properties are not overridden or
+ // used as an attack vector.
+ // We also assume that `Object.create(null)` is available when the event name
+ // is an ES6 Symbol.
+ //
+ var prefix = typeof Object.create !== 'function' ? '~' : false;
+
+ /**
+ * Representation of a single EventEmitter function.
+ *
+ * @param {Function} fn Event handler to be called.
+ * @param {Mixed} context Context for function execution.
+ * @param {Boolean} [once=false] Only emit once
+ * @api private
+ */
+ function EE(fn, context, once) {
+ this.fn = fn;
+ this.context = context;
+ this.once = once || false;
+ }
+
+ /**
+ * Minimal EventEmitter interface that is molded against the Node.js
+ * EventEmitter interface.
+ *
+ * @constructor
+ * @api public
+ */
+ function EventEmitter() { /* Nothing to set */ }
+
+ /**
+ * Hold the assigned EventEmitters by name.
+ *
+ * @type {Object}
+ * @private
+ */
+ EventEmitter.prototype._events = undefined;
+
+ /**
+ * Return an array listing the events for which the emitter has registered
+ * listeners.
+ *
+ * @returns {Array}
+ * @api public
+ */
+ EventEmitter.prototype.eventNames = function eventNames() {
+ var events = this._events
+ , names = []
+ , name;
+
+ if (!events) return names;
+
+ for (name in events) {
+ if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
+ }
+
+ if (Object.getOwnPropertySymbols) {
+ return names.concat(Object.getOwnPropertySymbols(events));
+ }
+
+ return names;
+ };
+
+ /**
+ * Return a list of assigned event listeners.
+ *
+ * @param {String} event The events that should be listed.
+ * @param {Boolean} exists We only need to know if there are listeners.
+ * @returns {Array|Boolean}
+ * @api public
+ */
+ EventEmitter.prototype.listeners = function listeners(event, exists) {
+ var evt = prefix ? prefix + event : event
+ , available = this._events && this._events[evt];
+
+ if (exists) return !!available;
+ if (!available) return [];
+ if (available.fn) return [available.fn];
+
+ for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
+ ee[i] = available[i].fn;
+ }
+
+ return ee;
+ };
+
+ /**
+ * Emit an event to all registered event listeners.
+ *
+ * @param {String} event The name of the event.
+ * @returns {Boolean} Indication if we've emitted an event.
+ * @api public
+ */
+ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
+ var evt = prefix ? prefix + event : event;
+
+ if (!this._events || !this._events[evt]) return false;
+
+ var listeners = this._events[evt]
+ , len = arguments.length
+ , args
+ , i;
+
+ if ('function' === typeof listeners.fn) {
+ if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
+
+ switch (len) {
+ case 1: return listeners.fn.call(listeners.context), true;
+ case 2: return listeners.fn.call(listeners.context, a1), true;
+ case 3: return listeners.fn.call(listeners.context, a1, a2), true;
+ case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
+ case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
+ case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
+ }
+
+ for (i = 1, args = new Array(len -1); i < len; i++) {
+ args[i - 1] = arguments[i];
+ }
+
+ listeners.fn.apply(listeners.context, args);
+ } else {
+ var length = listeners.length
+ , j;
+
+ for (i = 0; i < length; i++) {
+ if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
+
+ switch (len) {
+ case 1: listeners[i].fn.call(listeners[i].context); break;
+ case 2: listeners[i].fn.call(listeners[i].context, a1); break;
+ case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
+ default:
+ if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
+ args[j - 1] = arguments[j];
+ }
+
+ listeners[i].fn.apply(listeners[i].context, args);
+ }
+ }
+ }
+
+ return true;
+ };
+
+ /**
+ * Register a new EventListener for the given event.
+ *
+ * @param {String} event Name of the event.
+ * @param {Function} fn Callback function.
+ * @param {Mixed} [context=this] The context of the function.
+ * @api public
+ */
+ EventEmitter.prototype.on = function on(event, fn, context) {
+ var listener = new EE(fn, context || this)
+ , evt = prefix ? prefix + event : event;
+
+ if (!this._events) this._events = prefix ? {} : Object.create(null);
+ if (!this._events[evt]) this._events[evt] = listener;
+ else {
+ if (!this._events[evt].fn) this._events[evt].push(listener);
+ else this._events[evt] = [
+ this._events[evt], listener
+ ];
+ }
+
+ return this;
+ };
+
+ /**
+ * Add an EventListener that's only called once.
+ *
+ * @param {String} event Name of the event.
+ * @param {Function} fn Callback function.
+ * @param {Mixed} [context=this] The context of the function.
+ * @api public
+ */
+ EventEmitter.prototype.once = function once(event, fn, context) {
+ var listener = new EE(fn, context || this, true)
+ , evt = prefix ? prefix + event : event;
+
+ if (!this._events) this._events = prefix ? {} : Object.create(null);
+ if (!this._events[evt]) this._events[evt] = listener;
+ else {
+ if (!this._events[evt].fn) this._events[evt].push(listener);
+ else this._events[evt] = [
+ this._events[evt], listener
+ ];
+ }
+
+ return this;
+ };
+
+ /**
+ * Remove event listeners.
+ *
+ * @param {String} event The event we want to remove.
+ * @param {Function} fn The listener that we need to find.
+ * @param {Mixed} context Only remove listeners matching this context.
+ * @param {Boolean} once Only remove once listeners.
+ * @api public
+ */
+ EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
+ var evt = prefix ? prefix + event : event;
+
+ if (!this._events || !this._events[evt]) return this;
+
+ var listeners = this._events[evt]
+ , events = [];
+
+ if (fn) {
+ if (listeners.fn) {
+ if (
+ listeners.fn !== fn
+ || (once && !listeners.once)
+ || (context && listeners.context !== context)
+ ) {
+ events.push(listeners);
+ }
+ } else {
+ for (var i = 0, length = listeners.length; i < length; i++) {
+ if (
+ listeners[i].fn !== fn
+ || (once && !listeners[i].once)
+ || (context && listeners[i].context !== context)
+ ) {
+ events.push(listeners[i]);
+ }
+ }
+ }
+ }
+
+ //
+ // Reset the array, or remove it completely if we have no more listeners.
+ //
+ if (events.length) {
+ this._events[evt] = events.length === 1 ? events[0] : events;
+ } else {
+ delete this._events[evt];
+ }
+
+ return this;
+ };
+
+ /**
+ * Remove all listeners or only the listeners for the specified event.
+ *
+ * @param {String} event The event want to remove all listeners for.
+ * @api public
+ */
+ EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
+ if (!this._events) return this;
+
+ if (event) delete this._events[prefix ? prefix + event : event];
+ else this._events = prefix ? {} : Object.create(null);
+
+ return this;
+ };
+
+ //
+ // Alias methods names because people roll like that.
+ //
+ EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+ //
+ // This function doesn't apply anymore.
+ //
+ EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
+ return this;
+ };
+
+ //
+ // Expose the prefix.
+ //
+ EventEmitter.prefixed = prefix;
+
+ //
+ // Expose the module.
+ //
+ if (true) {
+ module.exports = EventEmitter;
+ }
+
+
+/***/ },
+/* 6 */
+/***/ function(module, exports, __webpack_require__) {
+
+ /**
+ * lodash (Custom Build)
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors
+ * Released under MIT license
+ * Based on Underscore.js 1.8.3
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+ var keys = __webpack_require__(7),
+ rest = __webpack_require__(8);
+
+ /** Used as references for various `Number` constants. */
+ var MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** `Object#toString` result references. */
+ var funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]';
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /** Used for built-in method references. */
+ var objectProto = Object.prototype;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Built-in value references. */
+ var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+ /** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */
+ var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');
+
+ /**
+ * Assigns `value` to `key` of `object` if the existing value is not equivalent
+ * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * for equality comparisons.
+ *
+ * @private
+ * @param {Object} object The object to modify.
+ * @param {string} key The key of the property to assign.
+ * @param {*} value The value to assign.
+ */
+ function assignValue(object, key, value) {
+ var objValue = object[key];
+ if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
+ (value === undefined && !(key in object))) {
+ object[key] = value;
+ }
+ }
+
+ /**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property identifiers to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @param {Function} [customizer] The function to customize copied values.
+ * @returns {Object} Returns `object`.
+ */
+ function copyObject(source, props, object, customizer) {
+ object || (object = {});
+
+ var index = -1,
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+
+ var newValue = customizer
+ ? customizer(object[key], source[key], key, object, source)
+ : source[key];
+
+ assignValue(object, key, newValue);
+ }
+ return object;
+ }
+
+ /**
+ * Creates a function like `_.assign`.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+ function createAssigner(assigner) {
+ return rest(function(object, sources) {
+ var index = -1,
+ length = sources.length,
+ customizer = length > 1 ? sources[length - 1] : undefined,
+ guard = length > 2 ? sources[2] : undefined;
+
+ customizer = (assigner.length > 3 && typeof customizer == 'function')
+ ? (length--, customizer)
+ : undefined;
+
+ if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+ customizer = length < 3 ? undefined : customizer;
+ length = 1;
+ }
+ object = Object(object);
+ while (++index < length) {
+ var source = sources[index];
+ if (source) {
+ assigner(object, source, index, customizer);
+ }
+ }
+ return object;
+ });
+ }
+
+ /**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a
+ * [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects
+ * Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+ var getLength = baseProperty('length');
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if the given arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+ * else `false`.
+ */
+ function isIterateeCall(value, index, object) {
+ if (!isObject(object)) {
+ return false;
+ }
+ var type = typeof index;
+ if (type == 'number'
+ ? (isArrayLike(object) && isIndex(index, object.length))
+ : (type == 'string' && index in object)
+ ) {
+ return eq(object[index], value);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * Performs a
+ * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
+ * comparison between two values to determine if they are equivalent.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * _.eq(object, object);
+ * // => true
+ *
+ * _.eq(object, other);
+ * // => false
+ *
+ * _.eq('a', 'a');
+ * // => true
+ *
+ * _.eq('a', Object('a'));
+ * // => false
+ *
+ * _.eq(NaN, NaN);
+ * // => true
+ */
+ function eq(value, other) {
+ return value === other || (value !== value && other !== other);
+ }
+
+ /**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(getLength(value)) && !isFunction(value);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8 which returns 'object' for typed array and weak map constructors,
+ // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length,
+ * else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+ function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Assigns own enumerable string keyed properties of source objects to the
+ * destination object. Source objects are applied from left to right.
+ * Subsequent sources overwrite property assignments of previous sources.
+ *
+ * **Note:** This method mutates `object` and is loosely based on
+ * [`Object.assign`](https://mdn.io/Object/assign).
+ *
+ * @static
+ * @memberOf _
+ * @since 0.10.0
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @returns {Object} Returns `object`.
+ * @see _.assignIn
+ * @example
+ *
+ * function Foo() {
+ * this.c = 3;
+ * }
+ *
+ * function Bar() {
+ * this.e = 5;
+ * }
+ *
+ * Foo.prototype.d = 4;
+ * Bar.prototype.f = 6;
+ *
+ * _.assign({ 'a': 1 }, new Foo, new Bar);
+ * // => { 'a': 1, 'c': 3, 'e': 5 }
+ */
+ var assign = createAssigner(function(object, source) {
+ if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
+ copyObject(source, keys(source), object);
+ return;
+ }
+ for (var key in source) {
+ if (hasOwnProperty.call(source, key)) {
+ assignValue(object, key, source[key]);
+ }
+ }
+ });
+
+ module.exports = assign;
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports) {
+
+ /**
+ * lodash (Custom Build)
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors
+ * Released under MIT license
+ * Based on Underscore.js 1.8.3
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as references for various `Number` constants. */
+ var MAX_SAFE_INTEGER = 9007199254740991;
+
+ /** `Object#toString` result references. */
+ var argsTag = '[object Arguments]',
+ funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ stringTag = '[object String]';
+
+ /** Used to detect unsigned integer values. */
+ var reIsUint = /^(?:0|[1-9]\d*)$/;
+
+ /**
+ * The base implementation of `_.times` without support for iteratee shorthands
+ * or max array length checks.
+ *
+ * @private
+ * @param {number} n The number of times to invoke `iteratee`.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns the array of results.
+ */
+ function baseTimes(n, iteratee) {
+ var index = -1,
+ result = Array(n);
+
+ while (++index < n) {
+ result[index] = iteratee(index);
+ }
+ return result;
+ }
+
+ /** Used for built-in method references. */
+ var objectProto = Object.prototype;
+
+ /** Used to check objects for own properties. */
+ var hasOwnProperty = objectProto.hasOwnProperty;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /** Built-in value references. */
+ var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeGetPrototype = Object.getPrototypeOf,
+ nativeKeys = Object.keys;
+
+ /**
+ * The base implementation of `_.has` without support for deep paths.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {Array|string} key The key to check.
+ * @returns {boolean} Returns `true` if `key` exists, else `false`.
+ */
+ function baseHas(object, key) {
+ // Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`,
+ // that are composed entirely of index properties, return `false` for
+ // `hasOwnProperty` checks of them.
+ return hasOwnProperty.call(object, key) ||
+ (typeof object == 'object' && key in object && getPrototype(object) === null);
+ }
+
+ /**
+ * The base implementation of `_.keys` which doesn't skip the constructor
+ * property of prototypes or treat sparse arrays as dense.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+ function baseKeys(object) {
+ return nativeKeys(Object(object));
+ }
+
+ /**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new accessor function.
+ */
+ function baseProperty(key) {
+ return function(object) {
+ return object == null ? undefined : object[key];
+ };
+ }
+
+ /**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a
+ * [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects
+ * Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+ var getLength = baseProperty('length');
+
+ /**
+ * Gets the `[[Prototype]]` of `value`.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {null|Object} Returns the `[[Prototype]]`.
+ */
+ function getPrototype(value) {
+ return nativeGetPrototype(Object(value));
+ }
+
+ /**
+ * Creates an array of index keys for `object` values of arrays,
+ * `arguments` objects, and strings, otherwise `null` is returned.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array|null} Returns index keys, else `null`.
+ */
+ function indexKeys(object) {
+ var length = object ? object.length : undefined;
+ if (isLength(length) &&
+ (isArray(object) || isString(object) || isArguments(object))) {
+ return baseTimes(length, String);
+ }
+ return null;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+ function isIndex(value, length) {
+ length = length == null ? MAX_SAFE_INTEGER : length;
+ return !!length &&
+ (typeof value == 'number' || reIsUint.test(value)) &&
+ (value > -1 && value % 1 == 0 && value < length);
+ }
+
+ /**
+ * Checks if `value` is likely a prototype object.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+ */
+ function isPrototype(value) {
+ var Ctor = value && value.constructor,
+ proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
+
+ return value === proto;
+ }
+
+ /**
+ * Checks if `value` is likely an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+ function isArguments(value) {
+ // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode.
+ return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
+ (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
+ }
+
+ /**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @type {Function}
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(document.body.children);
+ * // => false
+ *
+ * _.isArray('abc');
+ * // => false
+ *
+ * _.isArray(_.noop);
+ * // => false
+ */
+ var isArray = Array.isArray;
+
+ /**
+ * Checks if `value` is array-like. A value is considered array-like if it's
+ * not a function and has a `value.length` that's an integer greater than or
+ * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @example
+ *
+ * _.isArrayLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLike(document.body.children);
+ * // => true
+ *
+ * _.isArrayLike('abc');
+ * // => true
+ *
+ * _.isArrayLike(_.noop);
+ * // => false
+ */
+ function isArrayLike(value) {
+ return value != null && isLength(getLength(value)) && !isFunction(value);
+ }
+
+ /**
+ * This method is like `_.isArrayLike` except that it also checks if `value`
+ * is an object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an array-like object,
+ * else `false`.
+ * @example
+ *
+ * _.isArrayLikeObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isArrayLikeObject(document.body.children);
+ * // => true
+ *
+ * _.isArrayLikeObject('abc');
+ * // => false
+ *
+ * _.isArrayLikeObject(_.noop);
+ * // => false
+ */
+ function isArrayLikeObject(value) {
+ return isObjectLike(value) && isArrayLike(value);
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8 which returns 'object' for typed array and weak map constructors,
+ // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is loosely based on
+ * [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length,
+ * else `false`.
+ * @example
+ *
+ * _.isLength(3);
+ * // => true
+ *
+ * _.isLength(Number.MIN_VALUE);
+ * // => false
+ *
+ * _.isLength(Infinity);
+ * // => false
+ *
+ * _.isLength('3');
+ * // => false
+ */
+ function isLength(value) {
+ return typeof value == 'number' &&
+ value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a `String` primitive or object.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isString('abc');
+ * // => true
+ *
+ * _.isString(1);
+ * // => false
+ */
+ function isString(value) {
+ return typeof value == 'string' ||
+ (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag);
+ }
+
+ /**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @since 0.1.0
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ * this.a = 1;
+ * this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+ function keys(object) {
+ var isProto = isPrototype(object);
+ if (!(isProto || isArrayLike(object))) {
+ return baseKeys(object);
+ }
+ var indexes = indexKeys(object),
+ skipIndexes = !!indexes,
+ result = indexes || [],
+ length = result.length;
+
+ for (var key in object) {
+ if (baseHas(object, key) &&
+ !(skipIndexes && (key == 'length' || isIndex(key, length))) &&
+ !(isProto && key == 'constructor')) {
+ result.push(key);
+ }
+ }
+ return result;
+ }
+
+ module.exports = keys;
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports) {
+
+ /**
+ * lodash (Custom Build)
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors
+ * Released under MIT license
+ * Based on Underscore.js 1.8.3
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+ /** Used as the `TypeError` message for "Functions" methods. */
+ var FUNC_ERROR_TEXT = 'Expected a function';
+
+ /** Used as references for various `Number` constants. */
+ var INFINITY = 1 / 0,
+ MAX_INTEGER = 1.7976931348623157e+308,
+ NAN = 0 / 0;
+
+ /** `Object#toString` result references. */
+ var funcTag = '[object Function]',
+ genTag = '[object GeneratorFunction]',
+ symbolTag = '[object Symbol]';
+
+ /** Used to match leading and trailing whitespace. */
+ var reTrim = /^\s+|\s+$/g;
+
+ /** Used to detect bad signed hexadecimal string values. */
+ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+ /** Used to detect binary string values. */
+ var reIsBinary = /^0b[01]+$/i;
+
+ /** Used to detect octal string values. */
+ var reIsOctal = /^0o[0-7]+$/i;
+
+ /** Built-in method references without a dependency on `root`. */
+ var freeParseInt = parseInt;
+
+ /**
+ * A faster alternative to `Function#apply`, this function invokes `func`
+ * with the `this` binding of `thisArg` and the arguments of `args`.
+ *
+ * @private
+ * @param {Function} func The function to invoke.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {Array} args The arguments to invoke `func` with.
+ * @returns {*} Returns the result of `func`.
+ */
+ function apply(func, thisArg, args) {
+ var length = args.length;
+ switch (length) {
+ case 0: return func.call(thisArg);
+ case 1: return func.call(thisArg, args[0]);
+ case 2: return func.call(thisArg, args[0], args[1]);
+ case 3: return func.call(thisArg, args[0], args[1], args[2]);
+ }
+ return func.apply(thisArg, args);
+ }
+
+ /** Used for built-in method references. */
+ var objectProto = Object.prototype;
+
+ /**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+ var objectToString = objectProto.toString;
+
+ /* Built-in method references for those with the same name as other `lodash` methods. */
+ var nativeMax = Math.max;
+
+ /**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * created function and arguments from `start` and beyond provided as
+ * an array.
+ *
+ * **Note:** This method is based on the
+ * [rest parameter](https://mdn.io/rest_parameters).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Function
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.rest(function(what, names) {
+ * return what + ' ' + _.initial(names).join(', ') +
+ * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+ * });
+ *
+ * say('hello', 'fred', 'barney', 'pebbles');
+ * // => 'hello fred, barney, & pebbles'
+ */
+ function rest(func, start) {
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ start = nativeMax(start === undefined ? (func.length - 1) : toInteger(start), 0);
+ return function() {
+ var args = arguments,
+ index = -1,
+ length = nativeMax(args.length - start, 0),
+ array = Array(length);
+
+ while (++index < length) {
+ array[index] = args[start + index];
+ }
+ switch (start) {
+ case 0: return func.call(this, array);
+ case 1: return func.call(this, args[0], array);
+ case 2: return func.call(this, args[0], args[1], array);
+ }
+ var otherArgs = Array(start + 1);
+ index = -1;
+ while (++index < start) {
+ otherArgs[index] = args[index];
+ }
+ otherArgs[start] = array;
+ return apply(func, this, otherArgs);
+ };
+ }
+
+ /**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+ function isFunction(value) {
+ // The use of `Object#toString` avoids issues with the `typeof` operator
+ // in Safari 8 which returns 'object' for typed array and weak map constructors,
+ // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
+ var tag = isObject(value) ? objectToString.call(value) : '';
+ return tag == funcTag || tag == genTag;
+ }
+
+ /**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+ function isObject(value) {
+ var type = typeof value;
+ return !!value && (type == 'object' || type == 'function');
+ }
+
+ /**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+ function isObjectLike(value) {
+ return !!value && typeof value == 'object';
+ }
+
+ /**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified,
+ * else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+ function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike(value) && objectToString.call(value) == symbolTag);
+ }
+
+ /**
+ * Converts `value` to a finite number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.12.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted number.
+ * @example
+ *
+ * _.toFinite(3.2);
+ * // => 3.2
+ *
+ * _.toFinite(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toFinite(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toFinite('3.2');
+ * // => 3.2
+ */
+ function toFinite(value) {
+ if (!value) {
+ return value === 0 ? value : 0;
+ }
+ value = toNumber(value);
+ if (value === INFINITY || value === -INFINITY) {
+ var sign = (value < 0 ? -1 : 1);
+ return sign * MAX_INTEGER;
+ }
+ return value === value ? value : 0;
+ }
+
+ /**
+ * Converts `value` to an integer.
+ *
+ * **Note:** This function is loosely based on
+ * [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger).
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to convert.
+ * @returns {number} Returns the converted integer.
+ * @example
+ *
+ * _.toInteger(3.2);
+ * // => 3
+ *
+ * _.toInteger(Number.MIN_VALUE);
+ * // => 0
+ *
+ * _.toInteger(Infinity);
+ * // => 1.7976931348623157e+308
+ *
+ * _.toInteger('3.2');
+ * // => 3
+ */
+ function toInteger(value) {
+ var result = toFinite(value),
+ remainder = result % 1;
+
+ return result === result ? (remainder ? result - remainder : result) : 0;
+ }
+
+ /**
+ * Converts `value` to a number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ * @example
+ *
+ * _.toNumber(3.2);
+ * // => 3.2
+ *
+ * _.toNumber(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toNumber(Infinity);
+ * // => Infinity
+ *
+ * _.toNumber('3.2');
+ * // => 3.2
+ */
+ function toNumber(value) {
+ if (typeof value == 'number') {
+ return value;
+ }
+ if (isSymbol(value)) {
+ return NAN;
+ }
+ if (isObject(value)) {
+ var other = isFunction(value.valueOf) ? value.valueOf() : value;
+ value = isObject(other) ? (other + '') : other;
+ }
+ if (typeof value != 'string') {
+ return value === 0 ? value : +value;
+ }
+ value = value.replace(reTrim, '');
+ var isBinary = reIsBinary.test(value);
+ return (isBinary || reIsOctal.test(value))
+ ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+ : (reIsBadHex.test(value) ? NAN : +value);
+ }
+
+ module.exports = rest;
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ module.exports = __webpack_require__(10);
+
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var alphabet = __webpack_require__(11);
+ var encode = __webpack_require__(13);
+ var decode = __webpack_require__(15);
+ var isValid = __webpack_require__(16);
+
+ // Ignore all milliseconds before a certain time to reduce the size of the date entropy without sacrificing uniqueness.
+ // This number should be updated every year or so to keep the generated id short.
+ // To regenerate `new Date() - 0` and bump the version. Always bump the version!
+ var REDUCE_TIME = 1459707606518;
+
+ // don't change unless we change the algos or REDUCE_TIME
+ // must be an integer and less than 16
+ var version = 6;
+
+ // if you are using cluster or multiple servers use this to make each instance
+ // has a unique value for worker
+ // Note: I don't know if this is automatically set when using third
+ // party cluster solutions such as pm2.
+ var clusterWorkerId = __webpack_require__(17) || 0;
+
+ // Counter is used when shortid is called multiple times in one second.
+ var counter;
+
+ // Remember the last time shortid was called in case counter is needed.
+ var previousSeconds;
+
+ /**
+ * Generate unique id
+ * Returns string id
+ */
+ function generate() {
+
+ var str = '';
+
+ var seconds = Math.floor((Date.now() - REDUCE_TIME) * 0.001);
+
+ if (seconds === previousSeconds) {
+ counter++;
+ } else {
+ counter = 0;
+ previousSeconds = seconds;
+ }
+
+ str = str + encode(alphabet.lookup, version);
+ str = str + encode(alphabet.lookup, clusterWorkerId);
+ if (counter > 0) {
+ str = str + encode(alphabet.lookup, counter);
+ }
+ str = str + encode(alphabet.lookup, seconds);
+
+ return str;
+ }
+
+
+ /**
+ * Set the seed.
+ * Highly recommended if you don't want people to try to figure out your id schema.
+ * exposed as shortid.seed(int)
+ * @param seed Integer value to seed the random alphabet. ALWAYS USE THE SAME SEED or you might get overlaps.
+ */
+ function seed(seedValue) {
+ alphabet.seed(seedValue);
+ return module.exports;
+ }
+
+ /**
+ * Set the cluster worker or machine id
+ * exposed as shortid.worker(int)
+ * @param workerId worker must be positive integer. Number less than 16 is recommended.
+ * returns shortid module so it can be chained.
+ */
+ function worker(workerId) {
+ clusterWorkerId = workerId;
+ return module.exports;
+ }
+
+ /**
+ *
+ * sets new characters to use in the alphabet
+ * returns the shuffled alphabet
+ */
+ function characters(newCharacters) {
+ if (newCharacters !== undefined) {
+ alphabet.characters(newCharacters);
+ }
+
+ return alphabet.shuffled();
+ }
+
+
+ // Export all other functions as properties of the generate function
+ module.exports = generate;
+ module.exports.generate = generate;
+ module.exports.seed = seed;
+ module.exports.worker = worker;
+ module.exports.characters = characters;
+ module.exports.decode = decode;
+ module.exports.isValid = isValid;
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var randomFromSeed = __webpack_require__(12);
+
+ var ORIGINAL = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
+ var alphabet;
+ var previousSeed;
+
+ var shuffled;
+
+ function reset() {
+ shuffled = false;
+ }
+
+ function setCharacters(_alphabet_) {
+ if (!_alphabet_) {
+ if (alphabet !== ORIGINAL) {
+ alphabet = ORIGINAL;
+ reset();
+ }
+ return;
+ }
+
+ if (_alphabet_ === alphabet) {
+ return;
+ }
+
+ if (_alphabet_.length !== ORIGINAL.length) {
+ throw new Error('Custom alphabet for shortid must be ' + ORIGINAL.length + ' unique characters. You submitted ' + _alphabet_.length + ' characters: ' + _alphabet_);
+ }
+
+ var unique = _alphabet_.split('').filter(function(item, ind, arr){
+ return ind !== arr.lastIndexOf(item);
+ });
+
+ if (unique.length) {
+ throw new Error('Custom alphabet for shortid must be ' + ORIGINAL.length + ' unique characters. These characters were not unique: ' + unique.join(', '));
+ }
+
+ alphabet = _alphabet_;
+ reset();
+ }
+
+ function characters(_alphabet_) {
+ setCharacters(_alphabet_);
+ return alphabet;
+ }
+
+ function setSeed(seed) {
+ randomFromSeed.seed(seed);
+ if (previousSeed !== seed) {
+ reset();
+ previousSeed = seed;
+ }
+ }
+
+ function shuffle() {
+ if (!alphabet) {
+ setCharacters(ORIGINAL);
+ }
+
+ var sourceArray = alphabet.split('');
+ var targetArray = [];
+ var r = randomFromSeed.nextValue();
+ var characterIndex;
+
+ while (sourceArray.length > 0) {
+ r = randomFromSeed.nextValue();
+ characterIndex = Math.floor(r * sourceArray.length);
+ targetArray.push(sourceArray.splice(characterIndex, 1)[0]);
+ }
+ return targetArray.join('');
+ }
+
+ function getShuffled() {
+ if (shuffled) {
+ return shuffled;
+ }
+ shuffled = shuffle();
+ return shuffled;
+ }
+
+ /**
+ * lookup shuffled letter
+ * @param index
+ * @returns {string}
+ */
+ function lookup(index) {
+ var alphabetShuffled = getShuffled();
+ return alphabetShuffled[index];
+ }
+
+ module.exports = {
+ characters: characters,
+ seed: setSeed,
+ lookup: lookup,
+ shuffled: getShuffled
+ };
+
+
+/***/ },
+/* 12 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ // Found this seed-based random generator somewhere
+ // Based on The Central Randomizer 1.3 (C) 1997 by Paul Houle (houle@msc.cornell.edu)
+
+ var seed = 1;
+
+ /**
+ * return a random number based on a seed
+ * @param seed
+ * @returns {number}
+ */
+ function getNextValue() {
+ seed = (seed * 9301 + 49297) % 233280;
+ return seed/(233280.0);
+ }
+
+ function setSeed(_seed_) {
+ seed = _seed_;
+ }
+
+ module.exports = {
+ nextValue: getNextValue,
+ seed: setSeed
+ };
+
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var randomByte = __webpack_require__(14);
+
+ function encode(lookup, number) {
+ var loopCounter = 0;
+ var done;
+
+ var str = '';
+
+ while (!done) {
+ str = str + lookup( ( (number >> (4 * loopCounter)) & 0x0f ) | randomByte() );
+ done = number < (Math.pow(16, loopCounter + 1 ) );
+ loopCounter++;
+ }
+ return str;
+ }
+
+ module.exports = encode;
+
+
+/***/ },
+/* 14 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ var crypto = typeof window === 'object' && (window.crypto || window.msCrypto); // IE 11 uses window.msCrypto
+
+ function randomByte() {
+ if (!crypto || !crypto.getRandomValues) {
+ return Math.floor(Math.random() * 256) & 0x30;
+ }
+ var dest = new Uint8Array(1);
+ crypto.getRandomValues(dest);
+ return dest[0] & 0x30;
+ }
+
+ module.exports = randomByte;
+
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ var alphabet = __webpack_require__(11);
+
+ /**
+ * Decode the id to get the version and worker
+ * Mainly for debugging and testing.
+ * @param id - the shortid-generated id.
+ */
+ function decode(id) {
+ var characters = alphabet.shuffled();
+ return {
+ version: characters.indexOf(id.substr(0, 1)) & 0x0f,
+ worker: characters.indexOf(id.substr(1, 1)) & 0x0f
+ };
+ }
+
+ module.exports = decode;
+
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+ var alphabet = __webpack_require__(11);
+
+ function isShortId(id) {
+ if (!id || typeof id !== 'string' || id.length < 6 ) {
+ return false;
+ }
+
+ var characters = alphabet.characters();
+ var len = id.length;
+ for(var i = 0; i < len;i++) {
+ if (characters.indexOf(id[i]) === -1) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ module.exports = isShortId;
+
+
+/***/ },
+/* 17 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ module.exports = 0;
+
+
+/***/ },
+/* 18 */
+/***/ function(module, exports) {
+
+ module.exports = __WEBPACK_EXTERNAL_MODULE_18__;
+
+/***/ },
+/* 19 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ var _three = __webpack_require__(18);
+
+ var _three2 = _interopRequireDefault(_three);
+
+ // This can be imported from anywhere and will still reference the same scene,
+ // though there is a helper reference in Engine.scene
+
+ exports['default'] = (function () {
+ var scene = new _three2['default'].Scene();
+
+ // TODO: Re-enable when this works with the skybox
+ // scene.fog = new THREE.Fog(0xffffff, 1, 15000);
+ return scene;
+ })();
+
+ module.exports = exports['default'];
+
+/***/ },
+/* 20 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ // jscs:disable
+ /* eslint-disable */
+
+ /**
+ * Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+ var _three = __webpack_require__(18);
+
+ var _three2 = _interopRequireDefault(_three);
+
+ var CSS3DObject = function CSS3DObject(element) {
+
+ _three2['default'].Object3D.call(this);
+
+ this.element = element;
+ this.element.style.position = 'absolute';
+
+ this.addEventListener('removed', function (event) {
+
+ if (this.element.parentNode !== null) {
+
+ this.element.parentNode.removeChild(this.element);
+ }
+ });
+ };
+
+ CSS3DObject.prototype = Object.create(_three2['default'].Object3D.prototype);
+ CSS3DObject.prototype.constructor = CSS3DObject;
+
+ var CSS3DSprite = function CSS3DSprite(element) {
+
+ CSS3DObject.call(this, element);
+ };
+
+ CSS3DSprite.prototype = Object.create(CSS3DObject.prototype);
+ CSS3DSprite.prototype.constructor = CSS3DSprite;
+
+ //
+
+ var CSS3DRenderer = function CSS3DRenderer() {
+
+ console.log('THREE.CSS3DRenderer', _three2['default'].REVISION);
+
+ var _width, _height;
+ var _widthHalf, _heightHalf;
+
+ var matrix = new _three2['default'].Matrix4();
+
+ var cache = {
+ camera: { fov: 0, style: '' },
+ objects: {}
+ };
+
+ var domElement = document.createElement('div');
+ domElement.style.overflow = 'hidden';
+
+ domElement.style.WebkitTransformStyle = 'preserve-3d';
+ domElement.style.MozTransformStyle = 'preserve-3d';
+ domElement.style.oTransformStyle = 'preserve-3d';
+ domElement.style.transformStyle = 'preserve-3d';
+
+ this.domElement = domElement;
+
+ var cameraElement = document.createElement('div');
+
+ cameraElement.style.WebkitTransformStyle = 'preserve-3d';
+ cameraElement.style.MozTransformStyle = 'preserve-3d';
+ cameraElement.style.oTransformStyle = 'preserve-3d';
+ cameraElement.style.transformStyle = 'preserve-3d';
+
+ domElement.appendChild(cameraElement);
+
+ this.setClearColor = function () {};
+
+ this.getSize = function () {
+
+ return {
+ width: _width,
+ height: _height
+ };
+ };
+
+ this.setSize = function (width, height) {
+
+ _width = width;
+ _height = height;
+
+ _widthHalf = _width / 2;
+ _heightHalf = _height / 2;
+
+ domElement.style.width = width + 'px';
+ domElement.style.height = height + 'px';
+
+ cameraElement.style.width = width + 'px';
+ cameraElement.style.height = height + 'px';
+ };
+
+ var epsilon = function epsilon(value) {
+
+ return Math.abs(value) < Number.EPSILON ? 0 : value;
+ };
+
+ var getCameraCSSMatrix = function getCameraCSSMatrix(matrix) {
+
+ var elements = matrix.elements;
+
+ return 'matrix3d(' + epsilon(elements[0]) + ',' + epsilon(-elements[1]) + ',' + epsilon(elements[2]) + ',' + epsilon(elements[3]) + ',' + epsilon(elements[4]) + ',' + epsilon(-elements[5]) + ',' + epsilon(elements[6]) + ',' + epsilon(elements[7]) + ',' + epsilon(elements[8]) + ',' + epsilon(-elements[9]) + ',' + epsilon(elements[10]) + ',' + epsilon(elements[11]) + ',' + epsilon(elements[12]) + ',' + epsilon(-elements[13]) + ',' + epsilon(elements[14]) + ',' + epsilon(elements[15]) + ')';
+ };
+
+ var getObjectCSSMatrix = function getObjectCSSMatrix(matrix) {
+
+ var elements = matrix.elements;
+
+ return 'translate3d(-50%,-50%,0) matrix3d(' + epsilon(elements[0]) + ',' + epsilon(elements[1]) + ',' + epsilon(elements[2]) + ',' + epsilon(elements[3]) + ',' + epsilon(-elements[4]) + ',' + epsilon(-elements[5]) + ',' + epsilon(-elements[6]) + ',' + epsilon(-elements[7]) + ',' + epsilon(elements[8]) + ',' + epsilon(elements[9]) + ',' + epsilon(elements[10]) + ',' + epsilon(elements[11]) + ',' + epsilon(elements[12]) + ',' + epsilon(elements[13]) + ',' + epsilon(elements[14]) + ',' + epsilon(elements[15]) + ')';
+ };
+
+ var renderObject = function renderObject(object, camera) {
+
+ if (object instanceof CSS3DObject) {
+
+ var style;
+
+ if (object instanceof CSS3DSprite) {
+
+ // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/
+
+ matrix.copy(camera.matrixWorldInverse);
+ matrix.transpose();
+ matrix.copyPosition(object.matrixWorld);
+ matrix.scale(object.scale);
+
+ matrix.elements[3] = 0;
+ matrix.elements[7] = 0;
+ matrix.elements[11] = 0;
+ matrix.elements[15] = 1;
+
+ style = getObjectCSSMatrix(matrix);
+ } else {
+
+ style = getObjectCSSMatrix(object.matrixWorld);
+ }
+
+ var element = object.element;
+ var cachedStyle = cache.objects[object.id];
+
+ if (cachedStyle === undefined || cachedStyle !== style) {
+
+ element.style.WebkitTransform = style;
+ element.style.MozTransform = style;
+ element.style.oTransform = style;
+ element.style.transform = style;
+
+ cache.objects[object.id] = style;
+ }
+
+ if (element.parentNode !== cameraElement) {
+
+ cameraElement.appendChild(element);
+ }
+ }
+
+ for (var i = 0, l = object.children.length; i < l; i++) {
+
+ renderObject(object.children[i], camera);
+ }
+ };
+
+ this.render = function (scene, camera) {
+
+ var fov = 0.5 / Math.tan(_three2['default'].Math.degToRad(camera.fov * 0.5)) * _height;
+
+ if (cache.camera.fov !== fov) {
+
+ domElement.style.WebkitPerspective = fov + 'px';
+ domElement.style.MozPerspective = fov + 'px';
+ domElement.style.oPerspective = fov + 'px';
+ domElement.style.perspective = fov + 'px';
+
+ cache.camera.fov = fov;
+ }
+
+ scene.updateMatrixWorld();
+
+ if (camera.parent === null) camera.updateMatrixWorld();
+
+ camera.matrixWorldInverse.getInverse(camera.matrixWorld);
+
+ var style = 'translate3d(0,0,' + fov + 'px)' + getCameraCSSMatrix(camera.matrixWorldInverse) + ' translate3d(' + _widthHalf + 'px,' + _heightHalf + 'px, 0)';
+
+ if (cache.camera.style !== style) {
+
+ cameraElement.style.WebkitTransform = style;
+ cameraElement.style.MozTransform = style;
+ cameraElement.style.oTransform = style;
+ cameraElement.style.transform = style;
+
+ cache.camera.style = style;
+ }
+
+ renderObject(scene, camera);
+ };
+ };
+
+ exports.CSS3DObject = CSS3DObject;
+ exports.CSS3DSprite = CSS3DSprite;
+ exports.CSS3DRenderer = CSS3DRenderer;
+
+ _three2['default'].CSS3DObject = CSS3DObject;
+ _three2['default'].CSS3DSprite = CSS3DSprite;
+ _three2['default'].CSS3DRenderer = CSS3DRenderer;
+
+/***/ },
+/* 21 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ // jscs:disable
+ /* eslint-disable */
+
+ /**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+ var _three = __webpack_require__(18);
+
+ var _three2 = _interopRequireDefault(_three);
+
+ var CSS2DObject = function CSS2DObject(element) {
+
+ _three2['default'].Object3D.call(this);
+
+ this.element = element;
+ this.element.style.position = 'absolute';
+
+ this.addEventListener('removed', function (event) {
+
+ if (this.element.parentNode !== null) {
+
+ this.element.parentNode.removeChild(this.element);
+ }
+ });
+ };
+
+ CSS2DObject.prototype = Object.create(_three2['default'].Object3D.prototype);
+ CSS2DObject.prototype.constructor = CSS2DObject;
+
+ //
+
+ var CSS2DRenderer = function CSS2DRenderer() {
+
+ console.log('THREE.CSS2DRenderer', _three2['default'].REVISION);
+
+ var _width, _height;
+ var _widthHalf, _heightHalf;
+
+ var vector = new _three2['default'].Vector3();
+ var viewMatrix = new _three2['default'].Matrix4();
+ var viewProjectionMatrix = new _three2['default'].Matrix4();
+
+ var frustum = new _three2['default'].Frustum();
+
+ var domElement = document.createElement('div');
+ domElement.style.overflow = 'hidden';
+
+ this.domElement = domElement;
+
+ this.setSize = function (width, height) {
+
+ _width = width;
+ _height = height;
+
+ _widthHalf = _width / 2;
+ _heightHalf = _height / 2;
+
+ domElement.style.width = width + 'px';
+ domElement.style.height = height + 'px';
+ };
+
+ var renderObject = function renderObject(object, camera) {
+
+ if (object instanceof CSS2DObject) {
+
+ vector.setFromMatrixPosition(object.matrixWorld);
+ vector.applyProjection(viewProjectionMatrix);
+
+ var element = object.element;
+ var style = 'translate(-50%,-50%) translate(' + (vector.x * _widthHalf + _widthHalf) + 'px,' + (-vector.y * _heightHalf + _heightHalf) + 'px)';
+
+ element.style.WebkitTransform = style;
+ element.style.MozTransform = style;
+ element.style.oTransform = style;
+ element.style.transform = style;
+
+ if (element.parentNode !== domElement) {
+
+ domElement.appendChild(element);
+ }
+
+ // Hide if outside view frustum
+ if (!frustum.containsPoint(object.position)) {
+ element.style.display = 'none';
+ } else {
+ element.style.display = 'block';
+ }
+ }
+
+ for (var i = 0, l = object.children.length; i < l; i++) {
+
+ renderObject(object.children[i], camera);
+ }
+ };
+
+ this.render = function (scene, camera) {
+
+ scene.updateMatrixWorld();
+
+ if (camera.parent === null) camera.updateMatrixWorld();
+
+ camera.matrixWorldInverse.getInverse(camera.matrixWorld);
+
+ viewMatrix.copy(camera.matrixWorldInverse.getInverse(camera.matrixWorld));
+ viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, viewMatrix);
+
+ frustum.setFromMatrix(new _three2['default'].Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
+
+ renderObject(scene, camera);
+ };
+ };
+
+ exports.CSS2DObject = CSS2DObject;
+ exports.CSS2DRenderer = CSS2DRenderer;
+
+ _three2['default'].CSS2DObject = CSS2DObject;
+ _three2['default'].CSS2DRenderer = CSS2DRenderer;
+
+/***/ },
+/* 22 */
+/***/ function(module, exports, __webpack_require__) {
+
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+
+ var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
+
+ var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+ var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
+
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+ function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+ var _Layer2 = __webpack_require__(4);
+
+ var _Layer3 = _interopRequireDefault(_Layer2);
+
+ var _lodashAssign = __webpack_require__(6);
+
+ var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
+
+ var _reqwest = __webpack_require__(23);
+
+ var _reqwest2 = _interopRequireDefault(_reqwest);
+
+ var _utilGeoJSON = __webpack_require__(25);
+
+ var _utilGeoJSON2 = _interopRequireDefault(_utilGeoJSON);
+
+ var _utilWorker = __webpack_require__(31);
+
+ var _utilWorker2 = _interopRequireDefault(_utilWorker);
+
+ var _utilBuffer = __webpack_require__(34);
+
+ var _utilBuffer2 = _interopRequireDefault(_utilBuffer);
+
+ var _utilStringify = __webpack_require__(35);
+
+ var _utilStringify2 = _interopRequireDefault(_utilStringify);
+
+ var _geometryPolygonLayer = __webpack_require__(36);
+
+ var _geometryPolygonLayer2 = _interopRequireDefault(_geometryPolygonLayer);
+
+ var _geometryPolylineLayer = __webpack_require__(39);
+
+ var _geometryPolylineLayer2 = _interopRequireDefault(_geometryPolylineLayer);
+
+ var _geometryPointLayer = __webpack_require__(40);
+
+ var _geometryPointLayer2 = _interopRequireDefault(_geometryPointLayer);
+
+ var _geoLatLon = __webpack_require__(2);
+
+ var _geoPoint = __webpack_require__(3);
+
+ var _geoGeo = __webpack_require__(1);
+
+ var _geoGeo2 = _interopRequireDefault(_geoGeo);
+
+ var _enginePickingMaterial = __webpack_require__(37);
+
+ var _enginePickingMaterial2 = _interopRequireDefault(_enginePickingMaterial);
+
+ // TODO: Allow filter method to be run inside a worker to improve performance
+ // TODO: Allow onEachFeature method to be run inside a worker to improve performance
+
+ var GeoJSONWorkerLayer = (function (_Layer) {
+ _inherits(GeoJSONWorkerLayer, _Layer);
+
+ function GeoJSONWorkerLayer(geojson, options) {
+ _classCallCheck(this, GeoJSONWorkerLayer);
+
+ var defaults = {
+ topojson: false,
+ style: _utilGeoJSON2['default'].defaultStyle,
+ onEachFeature: null,
+ onEachFeatureWorker: null,
+ onAddAttributes: null,
+ interactive: false,
+ pointGeometry: null,
+ onClick: null,
+ headers: {}
+ };
+
+ var _options = (0, _lodashAssign2['default'])({}, defaults, options);
+
+ if (typeof options.style === 'object') {
+ _options.style = (0, _lodashAssign2['default'])({}, defaults.style, options.style);
+ }
+
+ _get(Object.getPrototypeOf(GeoJSONWorkerLayer.prototype), 'constructor', this).call(this, _options);
+
+ this._aborted = false;
+ this._geojson = geojson;
+ }
+
+ _createClass(GeoJSONWorkerLayer, [{
+ key: '_onAdd',
+ value: function _onAdd(world) {
+ if (this._options.interactive) {
+ // Worker layer always controls output to add a picking mesh
+ this._pickingMesh = new THREE.Object3D();
+ }
+
+ // Process GeoJSON
+ return this._process(this._geojson);
+ }
+
+ // Use workers to request and process GeoJSON, returning data structure
+ // containing geometry and any supplementary data for output
+ }, {
+ key: '_process',
+ value: function _process(_geojson) {
+ var _this = this;
+
+ return new Promise(function (resolve, reject) {
+ var style = _this._options.style;
+
+ // TODO: Convert to buffer and use transferrable objects
+ if (typeof _this._options.style === 'function') {
+ style = _utilStringify2['default'].functionToString(_this._options.style);
+ }
+
+ var pointGeometry = _this._options.pointGeometry;
+
+ // TODO: Convert to buffer and use transferrable objects
+ if (typeof _this._options.pointGeometry === 'function') {
+ pointGeometry = _utilStringify2['default'].functionToString(_this._options.pointGeometry);
+ }
+
+ var geojson = _geojson;
+ var transferrables = [];
+
+ if (typeof geojson !== 'string') {
+ _this._geojson = geojson = _utilBuffer2['default'].stringToUint8Array(JSON.stringify(geojson));
+ transferrables.push(geojson.buffer);
+ _this._execWorker(geojson, _this._options.topojson, _this._world._originPoint, style, _this._options.interactive, pointGeometry, transferrables).then(function () {
+ resolve();
+ })['catch'](reject);
+ } else if (typeof _this._options.filter === 'function' || typeof _this._options.onEachFeature === 'function') {
+ GeoJSONWorkerLayer.RequestGeoJSON(geojson).then(function (res) {
+ // if (this._aborted) {
+ // resolve();
+ // return;
+ // }
+
+ var fc = _utilGeoJSON2['default'].collectFeatures(res, _this._options.topojson);
+ var features = fc.features;
+
+ // Run filter, if provided
+ if (_this._options.filter) {
+ fc.features = features.filter(_this._options.filter);
+ }
+
+ if (_this._options.onEachFeature) {
+ var feature;
+ for (var i = 0; i < features.length; i++) {
+ feature = features[i];
+ _this._options.onEachFeature(feature);
+ };
+ }
+
+ _this._geojson = geojson = _utilBuffer2['default'].stringToUint8Array(JSON.stringify(fc));
+ transferrables.push(geojson.buffer);
+
+ _this._execWorker(geojson, false, _this._options.headers, _this._world._originPoint, style, _this._options.interactive, pointGeometry, transferrables).then(function () {
+ resolve();
+ })['catch'](reject);
+ });
+ } else {
+ _this._execWorker(geojson, _this._options.topojson, _this._options.headers, _this._world._originPoint, style, _this._options.interactive, pointGeometry, transferrables).then(function () {
+ resolve();
+ })['catch'](reject);
+ }
+ });
+ }
+ }, {
+ key: '_execWorker',
+ value: function _execWorker(geojson, topojson, headers, originPoint, style, interactive, pointGeometry, transferrables) {
+ var _this2 = this;
+
+ return new Promise(function (resolve, reject) {
+ console.time('Worker round trip');
+
+ _utilWorker2['default'].exec('GeoJSONWorkerLayer.Process', [geojson, topojson, headers, originPoint, style, interactive, pointGeometry], transferrables).then(function (results) {
+ console.timeEnd('Worker round trip');
+
+ // if (this._aborted) {
+ // resolve();
+ // return;
+ // }
+
+ var processPromises = [];
+
+ if (results.polygons) {
+ processPromises.push(_this2._processPolygonResults(results.polygons));
+ }
+
+ if (results.polylines) {
+ processPromises.push(_this2._processPolylineResults(results.polylines));
+ }
+
+ if (results.points) {
+ processPromises.push(_this2._processPointResults(results.points));
+ }
+
+ if (processPromises.length > 0) {
+ Promise.all(processPromises).then(function () {
+ resolve();
+ })['catch'](reject);
+ } else {
+ resolve();
+ }
+ });
+ });
+ }
+
+ // TODO: Dedupe with polyline method
+ }, {
+ key: '_processPolygonResults',
+ value: function _processPolygonResults(results) {
+ var _this3 = this;
+
+ return new Promise(function (resolve, reject) {
+ var splitPositions = _utilBuffer2['default'].splitFloat32Array(results.attributes.positions);
+ var splitNormals = _utilBuffer2['default'].splitFloat32Array(results.attributes.normals);
+ var splitColors = _utilBuffer2['default'].splitFloat32Array(results.attributes.colors);
+ var splitTops = _utilBuffer2['default'].splitFloat32Array(results.attributes.tops);
+
+ var splitOutlinePositions;
+ var splitOutlineColors;
+
+ if (results.outlineAttributes) {
+ splitOutlinePositions = _utilBuffer2['default'].splitFloat32Array(results.outlineAttributes.positions);
+ splitOutlineColors = _utilBuffer2['default'].splitFloat32Array(results.outlineAttributes.colors);
+ }
+
+ var splitProperties;
+ if (results.properties) {
+ splitProperties = _utilBuffer2['default'].splitUint8Array(results.properties);
+ }
+
+ var flats = results.flats;
+
+ var objects = [];
+ var outlineObjects = [];
+
+ var obj;
+ var pickingId;
+ var pickingIds;
+ var properties;
+
+ var polygonAttributeLengths = {
+ positions: 3,
+ normals: 3,
+ colors: 3,
+ tops: 1
+ };
+
+ var polygonOutlineAttributeLengths = {
+ positions: 3,
+ colors: 3
+ };
+
+ for (var i = 0; i < splitPositions.length; i++) {
+ if (splitProperties && splitProperties[i]) {
+ properties = JSON.parse(_utilBuffer2['default'].uint8ArrayToString(splitProperties[i]));
+ } else {
+ properties = {};
+ }
+
+ // WORKERS: obj.attributes should actually an array of polygons for
+ // the feature, though the current logic isn't aware of that
+ obj = {
+ attributes: [{
+ positions: splitPositions[i],
+ normals: splitNormals[i],
+ colors: splitColors[i],
+ tops: splitTops[i]
+ }],
+ properties: properties,
+ flat: flats[i]
+ };
+
+ // WORKERS: If interactive, generate unique ID for each feature, create
+ // the buffer attributes and set up event listeners
+ if (_this3._options.interactive) {
+ pickingId = _this3.getPickingId();
+
+ pickingIds = new Float32Array(splitPositions[i].length / 3);
+ pickingIds.fill(pickingId);
+
+ obj.attributes[0].pickingIds = pickingIds;
+
+ polygonAttributeLengths.pickingIds = 1;
+
+ _this3._addPicking(pickingId, properties);
+ }
+
+ // TODO: Make this specific to polygon attributes
+ if (typeof _this3._options.onAddAttributes === 'function') {
+ var customAttributes = _this3._options.onAddAttributes(obj.attributes[0], properties);
+ var customAttribute;
+ for (var key in customAttributes) {
+ customAttribute = customAttributes[key];
+ obj.attributes[0][key] = customAttribute.value;
+ polygonAttributeLengths[key] = customAttribute.length;
+ }
+ }
+
+ objects.push(obj);
+ }
+
+ for (var i = 0; i < splitOutlinePositions.length; i++) {
+ obj = {
+ attributes: [{
+ positions: splitOutlinePositions[i],
+ colors: splitOutlineColors[i]
+ }],
+ flat: true
+ };
+
+ outlineObjects.push(obj);
+ }
+
+ var polygonAttributes = [];
+ var polygonOutlineAttributes = [];
+
+ var polygonFlat = true;
+
+ for (var i = 0; i < objects.length; i++) {
+ obj = objects[i];
+
+ // TODO: Work out why obj.flat is rarely set to something other than
+ // true or false. Potentially undefined.
+ if (polygonFlat && obj.flat === false) {
+ polygonFlat = false;
+ }
+
+ var bufferAttributes = _utilBuffer2['default'].mergeAttributes(obj.attributes);
+ polygonAttributes.push(bufferAttributes);
+ };
+
+ for (var i = 0; i < outlineObjects.length; i++) {
+ obj = outlineObjects[i];
+
+ var bufferAttributes = _utilBuffer2['default'].mergeAttributes(obj.attributes);
+ polygonOutlineAttributes.push(bufferAttributes);
+ };
+
+ var outputPromises = [];
+
+ var style;
+
+ if (polygonAttributes.length > 0) {
+ var mergedPolygonAttributes = _utilBuffer2['default'].mergeAttributes(polygonAttributes);
+
+ // TODO: Make this work when style is a function per feature
+ style = typeof _this3._options.style === 'function' ? _this3._options.style(objects[0]) : _this3._options.style;
+ style = (0, _lodashAssign2['default'])({}, _utilGeoJSON2['default'].defaultStyle, style);
+
+ outputPromises.push(_this3._setPolygonMesh(mergedPolygonAttributes, polygonAttributeLengths, style, polygonFlat));
+ }
+
+ if (polygonOutlineAttributes.length > 0) {
+ var mergedPolygonOutlineAttributes = _utilBuffer2['default'].mergeAttributes(polygonOutlineAttributes);
+
+ style = typeof _this3._options.style === 'function' ? _this3._options.style(objects[0]) : _this3._options.style;
+ style = (0, _lodashAssign2['default'])({}, _utilGeoJSON2['default'].defaultStyle, style);
+
+ if (style.outlineRenderOrder !== undefined) {
+ style.lineRenderOrder = style.outlineRenderOrder;
+ } else {
+ style.lineRenderOrder = style.renderOrder ? style.renderOrder + 1 : 4;
+ }
+
+ if (style.outlineWidth) {
+ style.lineWidth = style.outlineWidth;
+ }
+
+ outputPromises.push(_this3._setPolylineMesh(mergedPolygonOutlineAttributes, polygonOutlineAttributeLengths, style, true));
+ }
+
+ Promise.all(outputPromises).then(function (results) {
+ var _results = _slicedToArray(results, 2);
+
+ var polygonResult = _results[0];
+ var outlineResult = _results[1];
+
+ if (polygonResult) {
+ _this3._polygonMesh = polygonResult.mesh;
+ _this3.add(_this3._polygonMesh);
+
+ if (polygonResult.pickingMesh) {
+ _this3._pickingMesh.add(polygonResult.pickingMesh);
+ }
+ }
+
+ if (outlineResult) {
+ _this3.add(outlineResult.mesh);
+ }
+
+ resolve();
+ })['catch'](reject);
+ });
+ }
+
+ // TODO: Dedupe with polygon method
+ }, {
+ key: '_processPolylineResults',
+ value: function _processPolylineResults(results) {
+ var _this4 = this;
+
+ return new Promise(function (resolve, reject) {
+ var splitPositions = _utilBuffer2['default'].splitFloat32Array(results.attributes.positions);
+ var splitColors = _utilBuffer2['default'].splitFloat32Array(results.attributes.colors);
+
+ var splitProperties;
+ if (results.properties) {
+ splitProperties = _utilBuffer2['default'].splitUint8Array(results.properties);
+ }
+
+ var flats = results.flats;
+
+ var objects = [];
+ var obj;
+ var pickingId;
+ var pickingIds;
+ var properties;
+
+ var polylineAttributeLengths = {
+ positions: 3,
+ colors: 3
+ };
+
+ for (var i = 0; i < splitPositions.length; i++) {
+ if (splitProperties && splitProperties[i]) {
+ properties = JSON.parse(_utilBuffer2['default'].uint8ArrayToString(splitProperties[i]));
+ } else {
+ properties = {};
+ }
+
+ // WORKERS: obj.attributes should actually an array of polygons for
+ // the feature, though the current logic isn't aware of that
+ obj = {
+ attributes: [{
+ positions: splitPositions[i],
+ colors: splitColors[i]
+ }],
+ properties: properties,
+ flat: flats[i]
+ };
+
+ // WORKERS: If interactive, generate unique ID for each feature, create
+ // the buffer attributes and set up event listeners
+ if (_this4._options.interactive) {
+ pickingId = _this4.getPickingId();
+
+ pickingIds = new Float32Array(splitPositions[i].length / 3);
+ pickingIds.fill(pickingId);
+
+ obj.attributes[0].pickingIds = pickingIds;
+
+ polylineAttributeLengths.pickingIds = 1;
+
+ _this4._addPicking(pickingId, properties);
+ }
+
+ // TODO: Make this specific to polyline attributes
+ if (typeof _this4._options.onAddAttributes === 'function') {
+ var customAttributes = _this4._options.onAddAttributes(obj.attributes[0], properties);
+ var customAttribute;
+ for (var key in customAttributes) {
+ customAttribute = customAttributes[key];
+ obj.attributes[0][key] = customAttribute.value;
+ polylineAttributeLengths[key] = customAttribute.length;
+ }
+ }
+
+ objects.push(obj);
+ }
+
+ var polylineAttributes = [];
+
+ var polylineFlat = true;
+
+ for (var i = 0; i < objects.length; i++) {
+ obj = objects[i];
+
+ if (polylineFlat && !obj.flat) {
+ polylineFlat = false;
+ }
+
+ var bufferAttributes = _utilBuffer2['default'].mergeAttributes(obj.attributes);
+ polylineAttributes.push(bufferAttributes);
+ };
+
+ if (polylineAttributes.length > 0) {
+ var mergedPolylineAttributes = _utilBuffer2['default'].mergeAttributes(polylineAttributes);
+
+ // TODO: Make this work when style is a function per feature
+ var style = typeof _this4._options.style === 'function' ? _this4._options.style(objects[0]) : _this4._options.style;
+ style = (0, _lodashAssign2['default'])({}, _utilGeoJSON2['default'].defaultStyle, style);
+
+ _this4._setPolylineMesh(mergedPolylineAttributes, polylineAttributeLengths, style, polylineFlat).then(function (result) {
+ _this4._polylineMesh = result.mesh;
+ _this4.add(_this4._polylineMesh);
+
+ if (result.pickingMesh) {
+ _this4._pickingMesh.add(result.pickingMesh);
+ }
+
+ resolve();
+ })['catch'](reject);
+ } else {
+ resolve();
+ }
+ });
+ }
+ }, {
+ key: '_processPointResults',
+ value: function _processPointResults(results) {
+ var _this5 = this;
+
+ return new Promise(function (resolve, reject) {
+ var splitPositions = _utilBuffer2['default'].splitFloat32Array(results.attributes.positions);
+ var splitNormals = _utilBuffer2['default'].splitFloat32Array(results.attributes.normals);
+ var splitColors = _utilBuffer2['default'].splitFloat32Array(results.attributes.colors);
+
+ var splitProperties;
+ if (results.properties) {
+ splitProperties = _utilBuffer2['default'].splitUint8Array(results.properties);
+ }
+
+ var flats = results.flats;
+
+ var objects = [];
+ var obj;
+ var pickingId;
+ var pickingIds;
+ var properties;
+
+ var pointAttributeLengths = {
+ positions: 3,
+ normals: 3,
+ colors: 3
+ };
+
+ for (var i = 0; i < splitPositions.length; i++) {
+ if (splitProperties && splitProperties[i]) {
+ properties = JSON.parse(_utilBuffer2['default'].uint8ArrayToString(splitProperties[i]));
+ } else {
+ properties = {};
+ }
+
+ // WORKERS: obj.attributes should actually an array of polygons for
+ // the feature, though the current logic isn't aware of that
+ obj = {
+ attributes: [{
+ positions: splitPositions[i],
+ normals: splitNormals[i],
+ colors: splitColors[i]
+ }],
+ properties: properties,
+ flat: flats[i]
+ };
+
+ // WORKERS: If interactive, generate unique ID for each feature, create
+ // the buffer attributes and set up event listeners
+ if (_this5._options.interactive) {
+ pickingId = _this5.getPickingId();
+
+ pickingIds = new Float32Array(splitPositions[i].length / 3);
+ pickingIds.fill(pickingId);
+
+ obj.attributes[0].pickingIds = pickingIds;
+
+ pointAttributeLengths.pickingIds = 1;
+
+ _this5._addPicking(pickingId, properties);
+ }
+
+ // TODO: Make this specific to polygon attributes
+ if (typeof _this5._options.onAddAttributes === 'function') {
+ var customAttributes = _this5._options.onAddAttributes(obj.attributes[0], properties);
+ var customAttribute;
+ for (var key in customAttributes) {
+ customAttribute = customAttributes[key];
+ obj.attributes[0][key] = customAttribute.value;
+ pointAttributeLengths[key] = customAttribute.length;
+ }
+ }
+
+ objects.push(obj);
+ }
+
+ var pointAttributes = [];
+
+ var pointFlat = true;
+
+ for (var i = 0; i < objects.length; i++) {
+ obj = objects[i];
+
+ if (pointFlat && !obj.flat) {
+ pointFlat = false;
+ }
+
+ var bufferAttributes = _utilBuffer2['default'].mergeAttributes(obj.attributes);
+ pointAttributes.push(bufferAttributes);
+ };
+
+ if (pointAttributes.length > 0) {
+ var mergedPointAttributes = _utilBuffer2['default'].mergeAttributes(pointAttributes);
+
+ // TODO: Make this work when style is a function per feature
+ var style = typeof _this5._options.style === 'function' ? _this5._options.style(objects[0]) : _this5._options.style;
+ style = (0, _lodashAssign2['default'])({}, _utilGeoJSON2['default'].defaultStyle, style);
+
+ _this5._setPointMesh(mergedPointAttributes, pointAttributeLengths, style, pointFlat).then(function (result) {
+ _this5._pointMesh = result.mesh;
+ _this5.add(_this5._pointMesh);
+
+ if (result.pickingMesh) {
+ _this5._pickingMesh.add(result.pickingMesh);
+ }
+
+ resolve();
+ })['catch'](reject);
+ } else {
+ resolve();
+ }
+ });
+ }
+
+ // TODO: At some point this needs to return all the features to the main thread
+ // so it can generate meshes and output to the scene, as well as perhaps creating
+ // individual layers / components for each feature to track things like picking
+ // and properties
+ //
+ // TODO: Find a way so the origin point isn't needed to be passed in as it
+ // feels a bit messy and against the idea of a static Geo class
+ //
+ // TODO: Support passing custom geometry for point layers
+ }, {
+ key: '_setPolygonMesh',
+
+ // Create and store mesh from buffer attributes
+ //
+ // Could make this an abstract method for each geometry layer
+ value: function _setPolygonMesh(attributes, attributeLengths, style, flat) {
+ if (!this._world) {
+ return Promise.reject();
+ }
+
+ return _geometryPolygonLayer2['default'].SetMesh(attributes, attributeLengths, flat, style, this._options, this._world._environment._skybox);
+ }
+ }, {
+ key: '_setPolylineMesh',
+ value: function _setPolylineMesh(attributes, attributeLengths, style, flat) {
+ if (!this._world) {
+ return Promise.reject();
+ }
+
+ return _geometryPolylineLayer2['default'].SetMesh(attributes, attributeLengths, flat, style, this._options);
+ }
+ }, {
+ key: '_setPointMesh',
+ value: function _setPointMesh(attributes, attributeLengths, style, flat) {
+ if (!this._world) {
+ return Promise.reject();
+ }
+
+ return _geometryPointLayer2['default'].SetMesh(attributes, attributeLengths, flat, style, this._options, this._world._environment._skybox);
+ }
+
+ // Set up and re-emit interaction events
+ }, {
+ key: '_addPicking',
+ value: function _addPicking(pickingId, properties) {
+ var _this6 = this;
+
+ this._world.on('pick-click-' + pickingId, function (pickingId, point2d, point3d, intersects) {
+ _this6._world.emit('click', _this6, properties, point2d, point3d);
+ });
+
+ this._world.on('pick-hover-' + pickingId, function (pickingId, point2d, point3d, intersects) {
+ _this6._world.emit('hover', _this6, properties, point2d, point3d);
+ });
+ }
+
+ // TODO: Finish cleanup
+ }, {
+ key: 'destroy',
+ value: function destroy() {
+ // Run common destruction logic from parent
+ _get(Object.getPrototypeOf(GeoJSONWorkerLayer.prototype), 'destroy', this).call(this);
+ }
+ }], [{
+ key: 'Process',
+ value: function Process(geojson, topojson, headers, originPoint, _style, _properties, _pointGeometry) {
+ return new Promise(function (resolve, reject) {
+ GeoJSONWorkerLayer.ProcessGeoJSON(geojson, headers).then(function (res) {
+ // Collects features into a single FeatureCollection
+ //
+ // Also converts TopoJSON to GeoJSON if instructed
+ var geojson = _utilGeoJSON2['default'].collectFeatures(res, topojson);
+
+ // TODO: Check that GeoJSON is valid / usable
+
+ var features = geojson.features;
+
+ // TODO: Run filter, if provided (must be static)
+
+ var pointScale;
+ var polygons = [];
+ var polylines = [];
+ var points = [];
+
+ // Deserialise style function if provided
+ if (typeof _style === 'string') {
+ _style = _utilStringify2['default'].stringToFunction(_style);
+ }
+
+ // Assume that a style won't be set per feature
+ var style = _style;
+
+ var pointGeometry;
+ // Deserialise pointGeometry function if provided
+ if (typeof _pointGeometry === 'string') {
+ pointGeometry = _utilStringify2['default'].stringToFunction(_pointGeometry);
+ }
+
+ var feature;
+ for (var i = 0; i < features.length; i++) {
+ feature = features[i];
+
+ var geometry = feature.geometry;
+ var coordinates = geometry.coordinates ? geometry.coordinates : null;
+
+ if (!coordinates || !geometry) {
+ return;
+ }
+
+ // Get per-feature style object, if provided
+ if (typeof _style === 'function') {
+ style = (0, _lodashAssign2['default'])({}, _utilGeoJSON2['default'].defaultStyle, _style(feature));
+ // console.log(feature, style);
+ }
+
+ if (geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
+ coordinates = _geometryPolygonLayer2['default'].isSingle(coordinates) ? [coordinates] : coordinates;
+
+ var converted = coordinates.map(function (_coordinates) {
+ return _coordinates.map(function (ring) {
+ return ring.map(function (coordinate) {
+ return (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
+ });
+ });
+ });
+
+ var point;
+ var projected = converted.map(function (_coordinates) {
+ return _coordinates.map(function (ring) {
+ return ring.map(function (latlon) {
+ point = _geoGeo2['default'].latLonToPoint(latlon)._subtract(originPoint);
+
+ if (!pointScale) {
+ pointScale = _geoGeo2['default'].pointScale(latlon);
+ }
+
+ return point;
+ });
+ });
+ });
+
+ var polygon = {
+ projected: projected,
+ options: {
+ pointScale: pointScale,
+ style: style
+ }
+ };
+
+ if (_properties) {
+ polygon.properties = feature.properties;
+ }
+
+ polygons.push(polygon);
+ }
+
+ if (geometry.type === 'LineString' || geometry.type === 'MultiLineString') {
+ coordinates = _geometryPolylineLayer2['default'].isSingle(coordinates) ? [coordinates] : coordinates;
+
+ var converted = coordinates.map(function (_coordinates) {
+ return _coordinates.map(function (coordinate) {
+ return (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
+ });
+ });
+
+ var point;
+ var projected = converted.map(function (_coordinates) {
+ return _coordinates.map(function (latlon) {
+ point = _geoGeo2['default'].latLonToPoint(latlon)._subtract(originPoint);
+
+ if (!pointScale) {
+ pointScale = _geoGeo2['default'].pointScale(latlon);
+ }
+
+ return point;
+ });
+ });
+
+ var polyline = {
+ projected: projected,
+ options: {
+ pointScale: pointScale,
+ style: style
+ }
+ };
+
+ if (_properties) {
+ polyline.properties = feature.properties;
+ }
+
+ polylines.push(polyline);
+ }
+
+ if (geometry.type === 'Point' || geometry.type === 'MultiPoint') {
+ coordinates = _geometryPointLayer2['default'].isSingle(coordinates) ? [coordinates] : coordinates;
+
+ var converted = coordinates.map(function (coordinate) {
+ return (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
+ });
+
+ var point;
+ var projected = converted.map(function (latlon) {
+ point = _geoGeo2['default'].latLonToPoint(latlon)._subtract(originPoint);
+
+ if (!pointScale) {
+ pointScale = _geoGeo2['default'].pointScale(latlon);
+ }
+
+ return point;
+ });
+
+ var point = {
+ projected: projected,
+ options: {
+ pointGeometry: pointGeometry(feature),
+ pointScale: pointScale,
+ style: style
+ }
+ };
+
+ if (_properties) {
+ point.properties = feature.properties;
+ }
+
+ points.push(point);
+ }
+ };
+
+ var polygonBufferPromises = [];
+ var polylineBufferPromises = [];
+ var pointBufferPromises = [];
+
+ var polygon;
+ for (var i = 0; i < polygons.length; i++) {
+ polygon = polygons[i];
+ polygonBufferPromises.push(_geometryPolygonLayer2['default'].SetBufferAttributes(polygon.projected, polygon.options));
+ };
+
+ var polyline;
+ for (var i = 0; i < polylines.length; i++) {
+ polyline = polylines[i];
+ polylineBufferPromises.push(_geometryPolylineLayer2['default'].SetBufferAttributes(polyline.projected, polyline.options));
+ };
+
+ var point;
+ for (var i = 0; i < points.length; i++) {
+ point = points[i];
+ pointBufferPromises.push(_geometryPointLayer2['default'].SetBufferAttributes(point.projected, point.options));
+ };
+
+ var data = {};
+ var transferrables = [];
+
+ // TODO: Make this work with polylines too
+ // TODO: Make this so it's not a nest of promises
+ GeoJSONWorkerLayer.ProcessPolygons(polygonBufferPromises, polygons, _properties).then(function (result) {
+ data.polygons = result.data;
+ transferrables = transferrables.concat(result.transferrables);
+
+ GeoJSONWorkerLayer.ProcessPolylines(polylineBufferPromises, polylines, _properties).then(function (result) {
+ data.polylines = result.data;
+ transferrables = transferrables.concat(result.transferrables);
+
+ GeoJSONWorkerLayer.ProcessPoints(pointBufferPromises, points, _properties).then(function (result) {
+ data.points = result.data;
+ transferrables = transferrables.concat(result.transferrables);
+
+ resolve({
+ data: data,
+ transferrables: transferrables
+ });
+ });
+ });
+ });
+ });
+ });
+ }
+ }, {
+ key: 'ProcessPolygons',
+ value: function ProcessPolygons(polygonPromises, polygons, _properties) {
+ return new Promise(function (resolve, reject) {
+ Promise.all(polygonPromises).then(function (results) {
+ var transferrables = [];
+
+ var positions = [];
+ var normals = [];
+ var colors = [];
+ var tops = [];
+
+ var outlinePositions = [];
+ var outlineColors = [];
+
+ var properties = [];
+
+ var flats = [];
+ var polygon;
+
+ var result;
+ for (var i = 0; i < results.length; i++) {
+ result = results[i];
+
+ polygon = polygons[i];
+
+ // WORKERS: Making this a typed array will speed up transfer time
+ // As things stand this adds on a few milliseconds
+ flats.push(result.flat);
+
+ // WORKERS: result.attributes is actually an array of polygons for each
+ // feature, though the current logic isn't keeping these all together
+
+ var attributes;
+ for (var j = 0; j < result.attributes.length; j++) {
+ attributes = result.attributes[j];
+
+ positions.push(attributes.positions);
+ normals.push(attributes.normals);
+ colors.push(attributes.colors);
+ tops.push(attributes.tops);
+
+ if (_properties) {
+ properties.push(_utilBuffer2['default'].stringToUint8Array(JSON.stringify(polygon.properties)));
+ }
+ };
+
+ var outlineAttributes;
+ for (var j = 0; j < result.outlineAttributes.length; j++) {
+ outlineAttributes = result.outlineAttributes[j];
+
+ outlinePositions.push(outlineAttributes.positions);
+ outlineColors.push(outlineAttributes.colors);
+ };
+ };
+
+ var mergedAttributes = {
+ positions: _utilBuffer2['default'].mergeFloat32Arrays(positions),
+ normals: _utilBuffer2['default'].mergeFloat32Arrays(normals),
+ colors: _utilBuffer2['default'].mergeFloat32Arrays(colors),
+ tops: _utilBuffer2['default'].mergeFloat32Arrays(tops)
+ };
+
+ var mergedOutlineAttributes = {
+ positions: _utilBuffer2['default'].mergeFloat32Arrays(outlinePositions),
+ colors: _utilBuffer2['default'].mergeFloat32Arrays(outlineColors)
+ };
+
+ transferrables.push(mergedAttributes.positions[0].buffer);
+ transferrables.push(mergedAttributes.positions[1].buffer);
+
+ transferrables.push(mergedAttributes.normals[0].buffer);
+ transferrables.push(mergedAttributes.normals[1].buffer);
+
+ transferrables.push(mergedAttributes.colors[0].buffer);
+ transferrables.push(mergedAttributes.colors[1].buffer);
+
+ transferrables.push(mergedAttributes.tops[0].buffer);
+ transferrables.push(mergedAttributes.tops[1].buffer);
+
+ transferrables.push(mergedOutlineAttributes.positions[0].buffer);
+ transferrables.push(mergedOutlineAttributes.positions[1].buffer);
+
+ transferrables.push(mergedOutlineAttributes.colors[0].buffer);
+ transferrables.push(mergedOutlineAttributes.colors[1].buffer);
+
+ var mergedProperties;
+ if (_properties) {
+ mergedProperties = _utilBuffer2['default'].mergeUint8Arrays(properties);
+
+ transferrables.push(mergedProperties[0].buffer);
+ transferrables.push(mergedProperties[1].buffer);
+ }
+
+ var output = {
+ attributes: mergedAttributes,
+ outlineAttributes: mergedOutlineAttributes,
+ flats: flats
+ };
+
+ if (_properties) {
+ output.properties = mergedProperties;
+ }
+
+ // TODO: Also return GeoJSON features that can be mapped to objects on
+ // the main thread. Allow user to provide filter / toggles to only return
+ // properties from the GeoJSON that they need (eg. don't return geometry,
+ // or don't return properties.height)
+ resolve({
+ data: output,
+ transferrables: transferrables
+ });
+ })['catch'](reject);
+ });
+ }
+ }, {
+ key: 'ProcessPolylines',
+ value: function ProcessPolylines(polylinePromises, polylines, _properties) {
+ return new Promise(function (resolve, reject) {
+ Promise.all(polylinePromises).then(function (results) {
+ var transferrables = [];
+
+ var positions = [];
+ var colors = [];
+
+ var properties = [];
+
+ var flats = [];
+ var polyline;
+
+ var result;
+ for (var i = 0; i < results.length; i++) {
+ result = results[i];
+
+ polyline = polylines[i];
+
+ // WORKERS: Making this a typed array will speed up transfer time
+ // As things stand this adds on a few milliseconds
+ flats.push(result.flat);
+
+ // WORKERS: result.attributes is actually an array of polygons for each
+ // feature, though the current logic isn't keeping these all together
+
+ var attributes;
+ for (var j = 0; j < result.attributes.length; j++) {
+ attributes = result.attributes[j];
+
+ positions.push(attributes.positions);
+ colors.push(attributes.colors);
+
+ if (_properties) {
+ properties.push(_utilBuffer2['default'].stringToUint8Array(JSON.stringify(polyline.properties)));
+ }
+ };
+ };
+
+ var mergedAttributes = {
+ positions: _utilBuffer2['default'].mergeFloat32Arrays(positions),
+ colors: _utilBuffer2['default'].mergeFloat32Arrays(colors)
+ };
+
+ transferrables.push(mergedAttributes.positions[0].buffer);
+ transferrables.push(mergedAttributes.positions[1].buffer);
+
+ transferrables.push(mergedAttributes.colors[0].buffer);
+ transferrables.push(mergedAttributes.colors[1].buffer);
+
+ var mergedProperties;
+ if (_properties) {
+ mergedProperties = _utilBuffer2['default'].mergeUint8Arrays(properties);
+
+ transferrables.push(mergedProperties[0].buffer);
+ transferrables.push(mergedProperties[1].buffer);
+ }
+
+ var output = {
+ attributes: mergedAttributes,
+ flats: flats
+ };
+
+ if (_properties) {
+ output.properties = mergedProperties;
+ }
+
+ // TODO: Also return GeoJSON features that can be mapped to objects on
+ // the main thread. Allow user to provide filter / toggles to only return
+ // properties from the GeoJSON that they need (eg. don't return geometry,
+ // or don't return properties.height)
+ resolve({
+ data: output,
+ transferrables: transferrables
+ });
+ })['catch'](reject);
+ });
+ }
+
+ // TODO: Dedupe with ProcessPolygons as they are identical
+ }, {
+ key: 'ProcessPoints',
+ value: function ProcessPoints(pointPromises, points, _properties) {
+ return new Promise(function (resolve, reject) {
+ Promise.all(pointPromises).then(function (results) {
+ var transferrables = [];
+
+ var positions = [];
+ var normals = [];
+ var colors = [];
+
+ var properties = [];
+
+ var flats = [];
+ var point;
+
+ var result;
+ for (var i = 0; i < results.length; i++) {
+ result = results[i];
+
+ point = points[i];
+
+ // WORKERS: Making this a typed array will speed up transfer time
+ // As things stand this adds on a few milliseconds
+ flats.push(result.flat);
+
+ // WORKERS: result.attributes is actually an array of polygons for each
+ // feature, though the current logic isn't keeping these all together
+
+ var attributes;
+ for (var j = 0; j < result.attributes.length; j++) {
+ attributes = result.attributes[j];
+
+ positions.push(attributes.positions);
+ normals.push(attributes.normals);
+ colors.push(attributes.colors);
+
+ if (_properties) {
+ properties.push(_utilBuffer2['default'].stringToUint8Array(JSON.stringify(polygon.properties)));
+ }
+ };
+ };
+
+ var mergedAttributes = {
+ positions: _utilBuffer2['default'].mergeFloat32Arrays(positions),
+ normals: _utilBuffer2['default'].mergeFloat32Arrays(normals),
+ colors: _utilBuffer2['default'].mergeFloat32Arrays(colors)
+ };
+
+ transferrables.push(mergedAttributes.positions[0].buffer);
+ transferrables.push(mergedAttributes.positions[1].buffer);
+
+ transferrables.push(mergedAttributes.normals[0].buffer);
+ transferrables.push(mergedAttributes.normals[1].buffer);
+
+ transferrables.push(mergedAttributes.colors[0].buffer);
+ transferrables.push(mergedAttributes.colors[1].buffer);
+
+ var mergedProperties;
+ if (_properties) {
+ mergedProperties = _utilBuffer2['default'].mergeUint8Arrays(properties);
+
+ transferrables.push(mergedProperties[0].buffer);
+ transferrables.push(mergedProperties[1].buffer);
+ }
+
+ var output = {
+ attributes: mergedAttributes,
+ flats: flats
+ };
+
+ if (_properties) {
+ output.properties = mergedProperties;
+ }
+
+ // TODO: Also return GeoJSON features that can be mapped to objects on
+ // the main thread. Allow user to provide filter / toggles to only return
+ // properties from the GeoJSON that they need (eg. don't return geometry,
+ // or don't return properties.height)
+ resolve({
+ data: output,
+ transferrables: transferrables
+ });
+ })['catch'](reject);
+ });
+ }
+ }, {
+ key: 'ProcessGeoJSON',
+ value: function ProcessGeoJSON(geojson, headers) {
+ if (typeof geojson === 'string') {
+ return GeoJSONWorkerLayer.RequestGeoJSON(geojson, headers);
+ } else {
+ return Promise.resolve(JSON.parse(_utilBuffer2['default'].uint8ArrayToString(geojson)));
+ }
+ }
+ }, {
+ key: 'RequestGeoJSON',
+ value: function RequestGeoJSON(path, headers) {
+ return (0, _reqwest2['default'])({
+ url: path,
+ type: 'json',
+ crossOrigin: true,
+ headers: headers
+ });
+ }
+ }]);
+
+ return GeoJSONWorkerLayer;
+ })(_Layer3['default']);
+
+ exports['default'] = GeoJSONWorkerLayer;
+
+ var noNew = function noNew(geojson, options) {
+ return new GeoJSONWorkerLayer(geojson, options);
+ };
+
+ exports.geoJSONWorkerLayer = noNew;
+
+/***/ },
+/* 23 */
+/***/ function(module, exports, __webpack_require__) {
+
+ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
+ * Reqwest! A general purpose XHR connection manager
+ * license MIT (c) Dustin Diaz 2015
+ * https://github.com/ded/reqwest
+ */
+
+ !function (name, context, definition) {
+ if (typeof module != 'undefined' && module.exports) module.exports = definition()
+ else 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 context[name] = definition()
+ }('reqwest', this, function () {
+
+ var context = this
+
+ if ('window' in context) {
+ var doc = document
+ , byTag = 'getElementsByTagName'
+ , head = doc[byTag]('head')[0]
+ } else {
+ var XHR2
+ try {
+ XHR2 = __webpack_require__(24)
+ } catch (ex) {
+ throw new Error('Peer dependency `xhr2` required! Please npm install xhr2')
+ }
+ }
+
+
+ var httpsRe = /^http/
+ , protocolRe = /(^\w+):\/\//
+ , twoHundo = /^(20\d|1223)$/ //http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
+ , readyState = 'readyState'
+ , contentType = 'Content-Type'
+ , requestedWith = 'X-Requested-With'
+ , uniqid = 0
+ , callbackPrefix = 'reqwest_' + (+new Date())
+ , lastValue // data stored by the most recent JSONP callback
+ , xmlHttpRequest = 'XMLHttpRequest'
+ , xDomainRequest = 'XDomainRequest'
+ , noop = function () {}
+
+ , isArray = typeof Array.isArray == 'function'
+ ? Array.isArray
+ : function (a) {
+ return a instanceof Array
+ }
+
+ , defaultHeaders = {
+ 'contentType': 'application/x-www-form-urlencoded'
+ , 'requestedWith': xmlHttpRequest
+ , 'accept': {
+ '*': 'text/javascript, text/html, application/xml, text/xml, */*'
+ , 'xml': 'application/xml, text/xml'
+ , 'html': 'text/html'
+ , 'text': 'text/plain'
+ , 'json': 'application/json, text/javascript'
+ , 'js': 'application/javascript, text/javascript'
+ }
+ }
+
+ , xhr = function(o) {
+ // is it x-domain
+ if (o['crossOrigin'] === true) {
+ var xhr = context[xmlHttpRequest] ? new XMLHttpRequest() : null
+ if (xhr && 'withCredentials' in xhr) {
+ return xhr
+ } else if (context[xDomainRequest]) {
+ return new XDomainRequest()
+ } else {
+ throw new Error('Browser does not support cross-origin requests')
+ }
+ } else if (context[xmlHttpRequest]) {
+ return new XMLHttpRequest()
+ } else if (XHR2) {
+ return new XHR2()
+ } else {
+ return new ActiveXObject('Microsoft.XMLHTTP')
+ }
+ }
+ , globalSetupOptions = {
+ dataFilter: function (data) {
+ return data
+ }
+ }
+
+ function succeed(r) {
+ var protocol = protocolRe.exec(r.url)
+ protocol = (protocol && protocol[1]) || context.location.protocol
+ return httpsRe.test(protocol) ? twoHundo.test(r.request.status) : !!r.request.response
+ }
+
+ function handleReadyState(r, success, error) {
+ return function () {
+ // use _aborted to mitigate against IE err c00c023f
+ // (can't read props on aborted request objects)
+ if (r._aborted) return error(r.request)
+ if (r._timedOut) return error(r.request, 'Request is aborted: timeout')
+ if (r.request && r.request[readyState] == 4) {
+ r.request.onreadystatechange = noop
+ if (succeed(r)) success(r.request)
+ else
+ error(r.request)
+ }
+ }
+ }
+
+ function setHeaders(http, o) {
+ var headers = o['headers'] || {}
+ , h
+
+ headers['Accept'] = headers['Accept']
+ || defaultHeaders['accept'][o['type']]
+ || defaultHeaders['accept']['*']
+
+ var isAFormData = typeof FormData !== 'undefined' && (o['data'] instanceof FormData);
+ // breaks cross-origin requests with legacy browsers
+ if (!o['crossOrigin'] && !headers[requestedWith]) headers[requestedWith] = defaultHeaders['requestedWith']
+ if (!headers[contentType] && !isAFormData) headers[contentType] = o['contentType'] || defaultHeaders['contentType']
+ for (h in headers)
+ headers.hasOwnProperty(h) && 'setRequestHeader' in http && http.setRequestHeader(h, headers[h])
+ }
+
+ function setCredentials(http, o) {
+ if (typeof o['withCredentials'] !== 'undefined' && typeof http.withCredentials !== 'undefined') {
+ http.withCredentials = !!o['withCredentials']
+ }
+ }
+
+ function generalCallback(data) {
+ lastValue = data
+ }
+
+ function urlappend (url, s) {
+ return url + (/\?/.test(url) ? '&' : '?') + s
+ }
+
+ function handleJsonp(o, fn, err, url) {
+ var reqId = uniqid++
+ , cbkey = o['jsonpCallback'] || 'callback' // the 'callback' key
+ , cbval = o['jsonpCallbackName'] || reqwest.getcallbackPrefix(reqId)
+ , cbreg = new RegExp('((^|\\?|&)' + cbkey + ')=([^&]+)')
+ , match = url.match(cbreg)
+ , script = doc.createElement('script')
+ , loaded = 0
+ , isIE10 = navigator.userAgent.indexOf('MSIE 10.0') !== -1
+
+ if (match) {
+ if (match[3] === '?') {
+ url = url.replace(cbreg, '$1=' + cbval) // wildcard callback func name
+ } else {
+ cbval = match[3] // provided callback func name
+ }
+ } else {
+ url = urlappend(url, cbkey + '=' + cbval) // no callback details, add 'em
+ }
+
+ context[cbval] = generalCallback
+
+ script.type = 'text/javascript'
+ script.src = url
+ script.async = true
+ if (typeof script.onreadystatechange !== 'undefined' && !isIE10) {
+ // need this for IE due to out-of-order onreadystatechange(), binding script
+ // execution to an event listener gives us control over when the script
+ // is executed. See http://jaubourg.net/2010/07/loading-script-as-onclick-handler-of.html
+ script.htmlFor = script.id = '_reqwest_' + reqId
+ }
+
+ script.onload = script.onreadystatechange = function () {
+ if ((script[readyState] && script[readyState] !== 'complete' && script[readyState] !== 'loaded') || loaded) {
+ return false
+ }
+ script.onload = script.onreadystatechange = null
+ script.onclick && script.onclick()
+ // Call the user callback with the last value stored and clean up values and scripts.
+ fn(lastValue)
+ lastValue = undefined
+ head.removeChild(script)
+ loaded = 1
+ }
+
+ // Add the script to the DOM head
+ head.appendChild(script)
+
+ // Enable JSONP timeout
+ return {
+ abort: function () {
+ script.onload = script.onreadystatechange = null
+ err({}, 'Request is aborted: timeout', {})
+ lastValue = undefined
+ head.removeChild(script)
+ loaded = 1
+ }
+ }
+ }
+
+ function getRequest(fn, err) {
+ var o = this.o
+ , method = (o['method'] || 'GET').toUpperCase()
+ , url = typeof o === 'string' ? o : o['url']
+ // convert non-string objects to query-string form unless o['processData'] is false
+ , data = (o['processData'] !== false && o['data'] && typeof o['data'] !== 'string')
+ ? reqwest.toQueryString(o['data'])
+ : (o['data'] || null)
+ , http
+ , sendWait = false
+
+ // if we're working on a GET request and we have data then we should append
+ // query string to end of URL and not post data
+ if ((o['type'] == 'jsonp' || method == 'GET') && data) {
+ url = urlappend(url, data)
+ data = null
+ }
+
+ if (o['type'] == 'jsonp') return handleJsonp(o, fn, err, url)
+
+ // get the xhr from the factory if passed
+ // if the factory returns null, fall-back to ours
+ http = (o.xhr && o.xhr(o)) || xhr(o)
+
+ http.open(method, url, o['async'] === false ? false : true)
+ setHeaders(http, o)
+ setCredentials(http, o)
+ if (context[xDomainRequest] && http instanceof context[xDomainRequest]) {
+ http.onload = fn
+ http.onerror = err
+ // NOTE: see
+ // http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/30ef3add-767c-4436-b8a9-f1ca19b4812e
+ http.onprogress = function() {}
+ sendWait = true
+ } else {
+ http.onreadystatechange = handleReadyState(this, fn, err)
+ }
+ o['before'] && o['before'](http)
+ if (sendWait) {
+ setTimeout(function () {
+ http.send(data)
+ }, 200)
+ } else {
+ http.send(data)
+ }
+ return http
+ }
+
+ function Reqwest(o, fn) {
+ this.o = o
+ this.fn = fn
+
+ init.apply(this, arguments)
+ }
+
+ function setType(header) {
+ // json, javascript, text/plain, text/html, xml
+ if (header === null) return undefined; //In case of no content-type.
+ if (header.match('json')) return 'json'
+ if (header.match('javascript')) return 'js'
+ if (header.match('text')) return 'html'
+ if (header.match('xml')) return 'xml'
+ }
+
+ function init(o, fn) {
+
+ this.url = typeof o == 'string' ? o : o['url']
+ this.timeout = null
+
+ // whether request has been fulfilled for purpose
+ // of tracking the Promises
+ this._fulfilled = false
+ // success handlers
+ this._successHandler = function(){}
+ this._fulfillmentHandlers = []
+ // error handlers
+ this._errorHandlers = []
+ // complete (both success and fail) handlers
+ this._completeHandlers = []
+ this._erred = false
+ this._responseArgs = {}
+
+ var self = this
+
+ fn = fn || function () {}
+
+ if (o['timeout']) {
+ this.timeout = setTimeout(function () {
+ timedOut()
+ }, o['timeout'])
+ }
+
+ if (o['success']) {
+ this._successHandler = function () {
+ o['success'].apply(o, arguments)
+ }
+ }
+
+ if (o['error']) {
+ this._errorHandlers.push(function () {
+ o['error'].apply(o, arguments)
+ })
+ }
+
+ if (o['complete']) {
+ this._completeHandlers.push(function () {
+ o['complete'].apply(o, arguments)
+ })
+ }
+
+ function complete (resp) {
+ o['timeout'] && clearTimeout(self.timeout)
+ self.timeout = null
+ while (self._completeHandlers.length > 0) {
+ self._completeHandlers.shift()(resp)
+ }
+ }
+
+ function success (resp) {
+ var type = o['type'] || resp && setType(resp.getResponseHeader('Content-Type')) // resp can be undefined in IE
+ resp = (type !== 'jsonp') ? self.request : resp
+ // use global data filter on response text
+ var filteredResponse = globalSetupOptions.dataFilter(resp.responseText, type)
+ , r = filteredResponse
+ try {
+ resp.responseText = r
+ } catch (e) {
+ // can't assign this in IE<=8, just ignore
+ }
+ if (r) {
+ switch (type) {
+ case 'json':
+ try {
+ resp = context.JSON ? context.JSON.parse(r) : eval('(' + r + ')')
+ } catch (err) {
+ return error(resp, 'Could not parse JSON in response', err)
+ }
+ break
+ case 'js':
+ resp = eval(r)
+ break
+ case 'html':
+ resp = r
+ break
+ case 'xml':
+ resp = resp.responseXML
+ && resp.responseXML.parseError // IE trololo
+ && resp.responseXML.parseError.errorCode
+ && resp.responseXML.parseError.reason
+ ? null
+ : resp.responseXML
+ break
+ }
+ }
+
+ self._responseArgs.resp = resp
+ self._fulfilled = true
+ fn(resp)
+ self._successHandler(resp)
+ while (self._fulfillmentHandlers.length > 0) {
+ resp = self._fulfillmentHandlers.shift()(resp)
+ }
+
+ complete(resp)
+ }
+
+ function timedOut() {
+ self._timedOut = true
+ self.request.abort()
+ }
+
+ function error(resp, msg, t) {
+ resp = self.request
+ self._responseArgs.resp = resp
+ self._responseArgs.msg = msg
+ self._responseArgs.t = t
+ self._erred = true
+ while (self._errorHandlers.length > 0) {
+ self._errorHandlers.shift()(resp, msg, t)
+ }
+ complete(resp)
+ }
+
+ this.request = getRequest.call(this, success, error)
+ }
+
+ Reqwest.prototype = {
+ abort: function () {
+ this._aborted = true
+ this.request.abort()
+ }
+
+ , retry: function () {
+ init.call(this, this.o, this.fn)
+ }
+
+ /**
+ * Small deviation from the Promises A CommonJs specification
+ * http://wiki.commonjs.org/wiki/Promises/A
+ */
+
+ /**
+ * `then` will execute upon successful requests
+ */
+ , then: function (success, fail) {
+ success = success || function () {}
+ fail = fail || function () {}
+ if (this._fulfilled) {
+ this._responseArgs.resp = success(this._responseArgs.resp)
+ } else if (this._erred) {
+ fail(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
+ } else {
+ this._fulfillmentHandlers.push(success)
+ this._errorHandlers.push(fail)
+ }
+ return this
+ }
+
+ /**
+ * `always` will execute whether the request succeeds or fails
+ */
+ , always: function (fn) {
+ if (this._fulfilled || this._erred) {
+ fn(this._responseArgs.resp)
+ } else {
+ this._completeHandlers.push(fn)
+ }
+ return this
+ }
+
+ /**
+ * `fail` will execute when the request fails
+ */
+ , fail: function (fn) {
+ if (this._erred) {
+ fn(this._responseArgs.resp, this._responseArgs.msg, this._responseArgs.t)
+ } else {
+ this._errorHandlers.push(fn)
+ }
+ return this
+ }
+ , 'catch': function (fn) {
+ return this.fail(fn)
+ }
+ }
+
+ function reqwest(o, fn) {
+ return new Reqwest(o, fn)
+ }
+
+ // normalize newline variants according to spec -> CRLF
+ function normalize(s) {
+ return s ? s.replace(/\r?\n/g, '\r\n') : ''
+ }
+
+ function serial(el, cb) {
+ var n = el.name
+ , t = el.tagName.toLowerCase()
+ , optCb = function (o) {
+ // IE gives value="" even where there is no value attribute
+ // 'specified' ref: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-862529273
+ if (o && !o['disabled'])
+ cb(n, normalize(o['attributes']['value'] && o['attributes']['value']['specified'] ? o['value'] : o['text']))
+ }
+ , ch, ra, val, i
+
+ // don't serialize elements that are disabled or without a name
+ if (el.disabled || !n) return
+
+ switch (t) {
+ case 'input':
+ if (!/reset|button|image|file/i.test(el.type)) {
+ ch = /checkbox/i.test(el.type)
+ ra = /radio/i.test(el.type)
+ val = el.value
+ // WebKit gives us "" instead of "on" if a checkbox has no value, so correct it here
+ ;(!(ch || ra) || el.checked) && cb(n, normalize(ch && val === '' ? 'on' : val))
+ }
+ break
+ case 'textarea':
+ cb(n, normalize(el.value))
+ break
+ case 'select':
+ if (el.type.toLowerCase() === 'select-one') {
+ optCb(el.selectedIndex >= 0 ? el.options[el.selectedIndex] : null)
+ } else {
+ for (i = 0; el.length && i < el.length; i++) {
+ el.options[i].selected && optCb(el.options[i])
+ }
+ }
+ break
+ }
+ }
+
+ // collect up all form elements found from the passed argument elements all
+ // the way down to child elements; pass a '