}\n * @constant\n */\nMarkerClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90];\n\n/**\n * @name MarkerWithLabel for V3\n * @version 1.1.10 [April 8, 2014]\n * @author Gary Little (inspired by code from Marc Ridey of Google).\n * @copyright Copyright 2012 Gary Little [gary at luxcentral.com]\n * @fileoverview MarkerWithLabel extends the Google Maps JavaScript API V3\n * google.maps.Marker
class.\n * \n * MarkerWithLabel allows you to define markers with associated labels. As you would expect,\n * if the marker is draggable, so too will be the label. In addition, a marker with a label\n * responds to all mouse events in the same manner as a regular marker. It also fires mouse\n * events and \"property changed\" events just as a regular marker would. Version 1.1 adds\n * support for the raiseOnDrag feature introduced in API V3.3.\n *
\n * If you drag a marker by its label, you can cancel the drag and return the marker to its\n * original position by pressing the Esc
key. This doesn't work if you drag the marker\n * itself because this feature is not (yet) supported in the google.maps.Marker
class.\n */\n\n/*!\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*jslint browser:true */\n/*global document,google */\n\n/**\n * @param {Function} childCtor Child class.\n * @param {Function} parentCtor Parent class.\n * @private\n */\nfunction inherits(childCtor, parentCtor) {\n /* @constructor */\n function tempCtor() {}\n tempCtor.prototype = parentCtor.prototype;\n childCtor.superClass_ = parentCtor.prototype;\n childCtor.prototype = new tempCtor();\n /* @override */\n childCtor.prototype.constructor = childCtor;\n}\n\n/**\n * This constructor creates a label and associates it with a marker.\n * It is for the private use of the MarkerWithLabel class.\n * @constructor\n * @param {Marker} marker The marker with which the label is to be associated.\n * @param {string} crossURL The URL of the cross image =.\n * @param {string} handCursor The URL of the hand cursor.\n * @private\n */\nfunction MarkerLabel_(marker, crossURL, handCursorURL) {\n this.marker_ = marker;\n this.handCursorURL_ = marker.handCursorURL;\n\n this.labelDiv_ = document.createElement(\"div\");\n this.labelDiv_.style.cssText = \"position: absolute; overflow: hidden;\";\n\n // Set up the DIV for handling mouse events in the label. This DIV forms a transparent veil\n // in the \"overlayMouseTarget\" pane, a veil that covers just the label. This is done so that\n // events can be captured even if the label is in the shadow of a google.maps.InfoWindow.\n // Code is included here to ensure the veil is always exactly the same size as the label.\n this.eventDiv_ = document.createElement(\"div\");\n this.eventDiv_.style.cssText = this.labelDiv_.style.cssText;\n\n // This is needed for proper behavior on MSIE:\n this.eventDiv_.setAttribute(\"onselectstart\", \"return false;\");\n this.eventDiv_.setAttribute(\"ondragstart\", \"return false;\");\n\n // Get the DIV for the \"X\" to be displayed when the marker is raised.\n this.crossDiv_ = MarkerLabel_.getSharedCross(crossURL);\n}\n\ninherits(MarkerLabel_, google.maps.OverlayView);\n\n/**\n * Returns the DIV for the cross used when dragging a marker when the\n * raiseOnDrag parameter set to true. One cross is shared with all markers.\n * @param {string} crossURL The URL of the cross image =.\n * @private\n */\nMarkerLabel_.getSharedCross = function (crossURL) {\n var div;\n if (typeof MarkerLabel_.getSharedCross.crossDiv === \"undefined\") {\n div = document.createElement(\"img\");\n div.style.cssText = \"position: absolute; z-index: 1000002; display: none;\";\n // Hopefully Google never changes the standard \"X\" attributes:\n div.style.marginLeft = \"-8px\";\n div.style.marginTop = \"-9px\";\n div.src = crossURL;\n MarkerLabel_.getSharedCross.crossDiv = div;\n }\n return MarkerLabel_.getSharedCross.crossDiv;\n};\n\n/**\n * Adds the DIV representing the label to the DOM. This method is called\n * automatically when the marker's setMap
method is called.\n * @private\n */\nMarkerLabel_.prototype.onAdd = function () {\n var me = this;\n var cMouseIsDown = false;\n var cDraggingLabel = false;\n var cSavedZIndex;\n var cLatOffset, cLngOffset;\n var cIgnoreClick;\n var cRaiseEnabled;\n var cStartPosition;\n var cStartCenter;\n // Constants:\n var cRaiseOffset = 20;\n var cDraggingCursor = \"url(\" + this.handCursorURL_ + \")\";\n\n // Stops all processing of an event.\n //\n var cAbortEvent = function (e) {\n if (e.preventDefault) {\n e.preventDefault();\n }\n e.cancelBubble = true;\n if (e.stopPropagation) {\n e.stopPropagation();\n }\n };\n\n var cStopBounce = function () {\n me.marker_.setAnimation(null);\n };\n\n this.getPanes().overlayImage.appendChild(this.labelDiv_);\n this.getPanes().overlayMouseTarget.appendChild(this.eventDiv_);\n // One cross is shared with all markers, so only add it once:\n if (typeof MarkerLabel_.getSharedCross.processed === \"undefined\") {\n this.getPanes().overlayImage.appendChild(this.crossDiv_);\n MarkerLabel_.getSharedCross.processed = true;\n }\n\n this.listeners_ = [\n google.maps.event.addDomListener(this.eventDiv_, \"mouseover\", function (e) {\n if (me.marker_.getDraggable() || me.marker_.getClickable()) {\n this.style.cursor = \"pointer\";\n google.maps.event.trigger(me.marker_, \"mouseover\", e);\n }\n }),\n google.maps.event.addDomListener(this.eventDiv_, \"mouseout\", function (e) {\n if ((me.marker_.getDraggable() || me.marker_.getClickable()) && !cDraggingLabel) {\n this.style.cursor = me.marker_.getCursor();\n google.maps.event.trigger(me.marker_, \"mouseout\", e);\n }\n }),\n google.maps.event.addDomListener(this.eventDiv_, \"mousedown\", function (e) {\n cDraggingLabel = false;\n if (me.marker_.getDraggable()) {\n cMouseIsDown = true;\n this.style.cursor = cDraggingCursor;\n }\n if (me.marker_.getDraggable() || me.marker_.getClickable()) {\n google.maps.event.trigger(me.marker_, \"mousedown\", e);\n cAbortEvent(e); // Prevent map pan when starting a drag on a label\n }\n }),\n google.maps.event.addDomListener(document, \"mouseup\", function (mEvent) {\n var position;\n if (cMouseIsDown) {\n cMouseIsDown = false;\n me.eventDiv_.style.cursor = \"pointer\";\n google.maps.event.trigger(me.marker_, \"mouseup\", mEvent);\n }\n if (cDraggingLabel) {\n if (cRaiseEnabled) { // Lower the marker & label\n position = me.getProjection().fromLatLngToDivPixel(me.marker_.getPosition());\n position.y += cRaiseOffset;\n me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position));\n // This is not the same bouncing style as when the marker portion is dragged,\n // but it will have to do:\n try { // Will fail if running Google Maps API earlier than V3.3\n me.marker_.setAnimation(google.maps.Animation.BOUNCE);\n setTimeout(cStopBounce, 1406);\n } catch (e) {}\n }\n me.crossDiv_.style.display = \"none\";\n me.marker_.setZIndex(cSavedZIndex);\n cIgnoreClick = true; // Set flag to ignore the click event reported after a label drag\n cDraggingLabel = false;\n mEvent.latLng = me.marker_.getPosition();\n google.maps.event.trigger(me.marker_, \"dragend\", mEvent);\n }\n }),\n google.maps.event.addListener(me.marker_.getMap(), \"mousemove\", function (mEvent) {\n var position;\n if (cMouseIsDown) {\n if (cDraggingLabel) {\n // Change the reported location from the mouse position to the marker position:\n mEvent.latLng = new google.maps.LatLng(mEvent.latLng.lat() - cLatOffset, mEvent.latLng.lng() - cLngOffset);\n position = me.getProjection().fromLatLngToDivPixel(mEvent.latLng);\n if (cRaiseEnabled) {\n me.crossDiv_.style.left = position.x + \"px\";\n me.crossDiv_.style.top = position.y + \"px\";\n me.crossDiv_.style.display = \"\";\n position.y -= cRaiseOffset;\n }\n me.marker_.setPosition(me.getProjection().fromDivPixelToLatLng(position));\n if (cRaiseEnabled) { // Don't raise the veil; this hack needed to make MSIE act properly\n me.eventDiv_.style.top = (position.y + cRaiseOffset) + \"px\";\n }\n google.maps.event.trigger(me.marker_, \"drag\", mEvent);\n } else {\n // Calculate offsets from the click point to the marker position:\n cLatOffset = mEvent.latLng.lat() - me.marker_.getPosition().lat();\n cLngOffset = mEvent.latLng.lng() - me.marker_.getPosition().lng();\n cSavedZIndex = me.marker_.getZIndex();\n cStartPosition = me.marker_.getPosition();\n cStartCenter = me.marker_.getMap().getCenter();\n cRaiseEnabled = me.marker_.get(\"raiseOnDrag\");\n cDraggingLabel = true;\n me.marker_.setZIndex(1000000); // Moves the marker & label to the foreground during a drag\n mEvent.latLng = me.marker_.getPosition();\n google.maps.event.trigger(me.marker_, \"dragstart\", mEvent);\n }\n }\n }),\n google.maps.event.addDomListener(document, \"keydown\", function (e) {\n if (cDraggingLabel) {\n if (e.keyCode === 27) { // Esc key\n cRaiseEnabled = false;\n me.marker_.setPosition(cStartPosition);\n me.marker_.getMap().setCenter(cStartCenter);\n google.maps.event.trigger(document, \"mouseup\", e);\n }\n }\n }),\n google.maps.event.addDomListener(this.eventDiv_, \"click\", function (e) {\n if (me.marker_.getDraggable() || me.marker_.getClickable()) {\n if (cIgnoreClick) { // Ignore the click reported when a label drag ends\n cIgnoreClick = false;\n } else {\n google.maps.event.trigger(me.marker_, \"click\", e);\n cAbortEvent(e); // Prevent click from being passed on to map\n }\n }\n }),\n google.maps.event.addDomListener(this.eventDiv_, \"dblclick\", function (e) {\n if (me.marker_.getDraggable() || me.marker_.getClickable()) {\n google.maps.event.trigger(me.marker_, \"dblclick\", e);\n cAbortEvent(e); // Prevent map zoom when double-clicking on a label\n }\n }),\n google.maps.event.addListener(this.marker_, \"dragstart\", function (mEvent) {\n if (!cDraggingLabel) {\n cRaiseEnabled = this.get(\"raiseOnDrag\");\n }\n }),\n google.maps.event.addListener(this.marker_, \"drag\", function (mEvent) {\n if (!cDraggingLabel) {\n if (cRaiseEnabled) {\n me.setPosition(cRaiseOffset);\n // During a drag, the marker's z-index is temporarily set to 1000000 to\n // ensure it appears above all other markers. Also set the label's z-index\n // to 1000000 (plus or minus 1 depending on whether the label is supposed\n // to be above or below the marker).\n me.labelDiv_.style.zIndex = 1000000 + (this.get(\"labelInBackground\") ? -1 : +1);\n }\n }\n }),\n google.maps.event.addListener(this.marker_, \"dragend\", function (mEvent) {\n if (!cDraggingLabel) {\n if (cRaiseEnabled) {\n me.setPosition(0); // Also restores z-index of label\n }\n }\n }),\n google.maps.event.addListener(this.marker_, \"position_changed\", function () {\n me.setPosition();\n }),\n google.maps.event.addListener(this.marker_, \"zindex_changed\", function () {\n me.setZIndex();\n }),\n google.maps.event.addListener(this.marker_, \"visible_changed\", function () {\n me.setVisible();\n }),\n google.maps.event.addListener(this.marker_, \"labelvisible_changed\", function () {\n me.setVisible();\n }),\n google.maps.event.addListener(this.marker_, \"title_changed\", function () {\n me.setTitle();\n }),\n google.maps.event.addListener(this.marker_, \"labelcontent_changed\", function () {\n me.setContent();\n }),\n google.maps.event.addListener(this.marker_, \"labelanchor_changed\", function () {\n me.setAnchor();\n }),\n google.maps.event.addListener(this.marker_, \"labelclass_changed\", function () {\n me.setStyles();\n }),\n google.maps.event.addListener(this.marker_, \"labelstyle_changed\", function () {\n me.setStyles();\n })\n ];\n};\n\n/**\n * Removes the DIV for the label from the DOM. It also removes all event handlers.\n * This method is called automatically when the marker's setMap(null)
\n * method is called.\n * @private\n */\nMarkerLabel_.prototype.onRemove = function () {\n var i;\n this.labelDiv_.parentNode.removeChild(this.labelDiv_);\n this.eventDiv_.parentNode.removeChild(this.eventDiv_);\n\n // Remove event listeners:\n for (i = 0; i < this.listeners_.length; i++) {\n google.maps.event.removeListener(this.listeners_[i]);\n }\n};\n\n/**\n * Draws the label on the map.\n * @private\n */\nMarkerLabel_.prototype.draw = function () {\n this.setContent();\n this.setTitle();\n this.setStyles();\n};\n\n/**\n * Sets the content of the label.\n * The content can be plain text or an HTML DOM node.\n * @private\n */\nMarkerLabel_.prototype.setContent = function () {\n var content = this.marker_.get(\"labelContent\");\n if (typeof content.nodeType === \"undefined\") {\n this.labelDiv_.innerHTML = content;\n this.eventDiv_.innerHTML = this.labelDiv_.innerHTML;\n } else {\n this.labelDiv_.innerHTML = \"\"; // Remove current content\n this.labelDiv_.appendChild(content);\n content = content.cloneNode(true);\n this.eventDiv_.innerHTML = \"\"; // Remove current content\n this.eventDiv_.appendChild(content);\n }\n};\n\n/**\n * Sets the content of the tool tip for the label. It is\n * always set to be the same as for the marker itself.\n * @private\n */\nMarkerLabel_.prototype.setTitle = function () {\n this.eventDiv_.title = this.marker_.getTitle() || \"\";\n};\n\n/**\n * Sets the style of the label by setting the style sheet and applying\n * other specific styles requested.\n * @private\n */\nMarkerLabel_.prototype.setStyles = function () {\n var i, labelStyle;\n\n // Apply style values from the style sheet defined in the labelClass parameter:\n this.labelDiv_.className = this.marker_.get(\"labelClass\");\n this.eventDiv_.className = this.labelDiv_.className;\n\n // Clear existing inline style values:\n this.labelDiv_.style.cssText = \"\";\n this.eventDiv_.style.cssText = \"\";\n // Apply style values defined in the labelStyle parameter:\n labelStyle = this.marker_.get(\"labelStyle\");\n for (i in labelStyle) {\n if (labelStyle.hasOwnProperty(i)) {\n this.labelDiv_.style[i] = labelStyle[i];\n this.eventDiv_.style[i] = labelStyle[i];\n }\n }\n this.setMandatoryStyles();\n};\n\n/**\n * Sets the mandatory styles to the DIV representing the label as well as to the\n * associated event DIV. This includes setting the DIV position, z-index, and visibility.\n * @private\n */\nMarkerLabel_.prototype.setMandatoryStyles = function () {\n this.labelDiv_.style.position = \"absolute\";\n this.labelDiv_.style.overflow = \"hidden\";\n // Make sure the opacity setting causes the desired effect on MSIE:\n if (typeof this.labelDiv_.style.opacity !== \"undefined\" && this.labelDiv_.style.opacity !== \"\") {\n this.labelDiv_.style.MsFilter = \"\\\"progid:DXImageTransform.Microsoft.Alpha(opacity=\" + (this.labelDiv_.style.opacity * 100) + \")\\\"\";\n this.labelDiv_.style.filter = \"alpha(opacity=\" + (this.labelDiv_.style.opacity * 100) + \")\";\n }\n\n this.eventDiv_.style.position = this.labelDiv_.style.position;\n this.eventDiv_.style.overflow = this.labelDiv_.style.overflow;\n this.eventDiv_.style.opacity = 0.01; // Don't use 0; DIV won't be clickable on MSIE\n this.eventDiv_.style.MsFilter = \"\\\"progid:DXImageTransform.Microsoft.Alpha(opacity=1)\\\"\";\n this.eventDiv_.style.filter = \"alpha(opacity=1)\"; // For MSIE\n\n this.setAnchor();\n this.setPosition(); // This also updates z-index, if necessary.\n this.setVisible();\n};\n\n/**\n * Sets the anchor point of the label.\n * @private\n */\nMarkerLabel_.prototype.setAnchor = function () {\n var anchor = this.marker_.get(\"labelAnchor\");\n this.labelDiv_.style.marginLeft = -anchor.x + \"px\";\n this.labelDiv_.style.marginTop = -anchor.y + \"px\";\n this.eventDiv_.style.marginLeft = -anchor.x + \"px\";\n this.eventDiv_.style.marginTop = -anchor.y + \"px\";\n};\n\n/**\n * Sets the position of the label. The z-index is also updated, if necessary.\n * @private\n */\nMarkerLabel_.prototype.setPosition = function (yOffset) {\n var position = this.getProjection().fromLatLngToDivPixel(this.marker_.getPosition());\n if (typeof yOffset === \"undefined\") {\n yOffset = 0;\n }\n this.labelDiv_.style.left = Math.round(position.x) + \"px\";\n this.labelDiv_.style.top = Math.round(position.y - yOffset) + \"px\";\n this.eventDiv_.style.left = this.labelDiv_.style.left;\n this.eventDiv_.style.top = this.labelDiv_.style.top;\n\n this.setZIndex();\n};\n\n/**\n * Sets the z-index of the label. If the marker's z-index property has not been defined, the z-index\n * of the label is set to the vertical coordinate of the label. This is in keeping with the default\n * stacking order for Google Maps: markers to the south are in front of markers to the north.\n * @private\n */\nMarkerLabel_.prototype.setZIndex = function () {\n var zAdjust = (this.marker_.get(\"labelInBackground\") ? -1 : +1);\n if (typeof this.marker_.getZIndex() === \"undefined\") {\n this.labelDiv_.style.zIndex = parseInt(this.labelDiv_.style.top, 10) + zAdjust;\n this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex;\n } else {\n this.labelDiv_.style.zIndex = this.marker_.getZIndex() + zAdjust;\n this.eventDiv_.style.zIndex = this.labelDiv_.style.zIndex;\n }\n};\n\n/**\n * Sets the visibility of the label. The label is visible only if the marker itself is\n * visible (i.e., its visible property is true) and the labelVisible property is true.\n * @private\n */\nMarkerLabel_.prototype.setVisible = function () {\n if (this.marker_.get(\"labelVisible\")) {\n this.labelDiv_.style.display = this.marker_.getVisible() ? \"block\" : \"none\";\n } else {\n this.labelDiv_.style.display = \"none\";\n }\n this.eventDiv_.style.display = this.labelDiv_.style.display;\n};\n\n/**\n * @name MarkerWithLabelOptions\n * @class This class represents the optional parameter passed to the {@link MarkerWithLabel} constructor.\n * The properties available are the same as for google.maps.Marker
with the addition\n * of the properties listed below. To change any of these additional properties after the labeled\n * marker has been created, call google.maps.Marker.set(propertyName, propertyValue)
.\n *
\n * When any of these properties changes, a property changed event is fired. The names of these\n * events are derived from the name of the property and are of the form propertyname_changed
.\n * For example, if the content of the label changes, a labelcontent_changed
event\n * is fired.\n *
\n * @property {string|Node} [labelContent] The content of the label (plain text or an HTML DOM node).\n * @property {Point} [labelAnchor] By default, a label is drawn with its anchor point at (0,0) so\n * that its top left corner is positioned at the anchor point of the associated marker. Use this\n * property to change the anchor point of the label. For example, to center a 50px-wide label\n * beneath a marker, specify a labelAnchor
of google.maps.Point(25, 0)
.\n * (Note: x-values increase to the right and y-values increase to the top.)\n * @property {string} [labelClass] The name of the CSS class defining the styles for the label.\n * Note that style values for position
, overflow
, top
,\n * left
, zIndex
, display
, marginLeft
, and\n * marginTop
are ignored; these styles are for internal use only.\n * @property {Object} [labelStyle] An object literal whose properties define specific CSS\n * style values to be applied to the label. Style values defined here override those that may\n * be defined in the labelClass
style sheet. If this property is changed after the\n * label has been created, all previously set styles (except those defined in the style sheet)\n * are removed from the label before the new style values are applied.\n * Note that style values for position
, overflow
, top
,\n * left
, zIndex
, display
, marginLeft
, and\n * marginTop
are ignored; these styles are for internal use only.\n * @property {boolean} [labelInBackground] A flag indicating whether a label that overlaps its\n * associated marker should appear in the background (i.e., in a plane below the marker).\n * The default is false
, which causes the label to appear in the foreground.\n * @property {boolean} [labelVisible] A flag indicating whether the label is to be visible.\n * The default is true
. Note that even if labelVisible
is\n * true
, the label will not be visible unless the associated marker is also\n * visible (i.e., unless the marker's visible
property is true
).\n * @property {boolean} [raiseOnDrag] A flag indicating whether the label and marker are to be\n * raised when the marker is dragged. The default is true
. If a draggable marker is\n * being created and a version of Google Maps API earlier than V3.3 is being used, this property\n * must be set to false
.\n * @property {boolean} [optimized] A flag indicating whether rendering is to be optimized for the\n * marker. Important: The optimized rendering technique is not supported by MarkerWithLabel,\n * so the value of this parameter is always forced to false
.\n * @property {string} [crossImage=\"http://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png\"]\n * The URL of the cross image to be displayed while dragging a marker.\n * @property {string} [handCursor=\"http://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur\"]\n * The URL of the cursor to be displayed while dragging a marker.\n */\n/**\n * Creates a MarkerWithLabel with the options specified in {@link MarkerWithLabelOptions}.\n * @constructor\n * @param {MarkerWithLabelOptions} [opt_options] The optional parameters.\n */\nfunction MarkerWithLabel(opt_options) {\n opt_options = opt_options || {};\n opt_options.labelContent = opt_options.labelContent || \"\";\n opt_options.labelAnchor = opt_options.labelAnchor || new google.maps.Point(0, 0);\n opt_options.labelClass = opt_options.labelClass || \"markerLabels\";\n opt_options.labelStyle = opt_options.labelStyle || {};\n opt_options.labelInBackground = opt_options.labelInBackground || false;\n if (typeof opt_options.labelVisible === \"undefined\") {\n opt_options.labelVisible = true;\n }\n if (typeof opt_options.raiseOnDrag === \"undefined\") {\n opt_options.raiseOnDrag = true;\n }\n if (typeof opt_options.clickable === \"undefined\") {\n opt_options.clickable = true;\n }\n if (typeof opt_options.draggable === \"undefined\") {\n opt_options.draggable = false;\n }\n if (typeof opt_options.optimized === \"undefined\") {\n opt_options.optimized = false;\n }\n opt_options.crossImage = opt_options.crossImage || \"http\" + (document.location.protocol === \"https:\" ? \"s\" : \"\") + \"://maps.gstatic.com/intl/en_us/mapfiles/drag_cross_67_16.png\";\n opt_options.handCursor = opt_options.handCursor || \"http\" + (document.location.protocol === \"https:\" ? \"s\" : \"\") + \"://maps.gstatic.com/intl/en_us/mapfiles/closedhand_8_8.cur\";\n opt_options.optimized = false; // Optimized rendering is not supported\n\n this.label = new MarkerLabel_(this, opt_options.crossImage, opt_options.handCursor); // Bind the label to the marker\n\n // Call the parent constructor. It calls Marker.setValues to initialize, so all\n // the new parameters are conveniently saved and can be accessed with get/set.\n // Marker.set triggers a property changed event (called \"propertyname_changed\")\n // that the marker label listens for in order to react to state changes.\n google.maps.Marker.apply(this, arguments);\n}\n\ninherits(MarkerWithLabel, google.maps.Marker);\n\n/**\n * Overrides the standard Marker setMap function.\n * @param {Map} theMap The map to which the marker is to be added.\n * @private\n */\nMarkerWithLabel.prototype.setMap = function (theMap) {\n\n // Call the inherited function...\n google.maps.Marker.prototype.setMap.apply(this, arguments);\n\n // ... then deal with the label:\n this.label.setMap(theMap);\n};\n\n// ==ClosureCompiler==\n// @compilation_level ADVANCED_OPTIMIZATIONS\n// @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3.js\n// @output_wrapper (function() {%output%})();\n// ==/ClosureCompiler==\n\n/**\n * @license\n * Copyright 2013 Google Inc. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * A RichMarker that allows any HTML/DOM to be added to a map and be draggable.\n *\n * @param {Object.=} opt_options Optional properties to set.\n * @extends {google.maps.OverlayView}\n * @constructor\n */\nfunction RichMarker(opt_options) {\n var options = opt_options || {};\n\n /**\n * @type {boolean}\n * @private\n */\n this.ready_ = false;\n\n /**\n * @type {boolean}\n * @private\n */\n this.dragging_ = false;\n\n if (opt_options['visible'] == undefined) {\n opt_options['visible'] = true;\n }\n\n if (opt_options['shadow'] == undefined) {\n opt_options['shadow'] = '7px -3px 5px rgba(88,88,88,0.7)';\n }\n\n if (opt_options['anchor'] == undefined) {\n opt_options['anchor'] = RichMarkerPosition['BOTTOM'];\n }\n\n this.setValues(options);\n}\nRichMarker.prototype = new google.maps.OverlayView();\nwindow['RichMarker'] = RichMarker;\n\n\n/**\n * Returns the current visibility state of the marker.\n *\n * @return {boolean} The visiblity of the marker.\n */\nRichMarker.prototype.getVisible = function() {\n return /** @type {boolean} */ (this.get('visible'));\n};\nRichMarker.prototype['getVisible'] = RichMarker.prototype.getVisible;\n\n\n/**\n * Sets the visiblility state of the marker.\n *\n * @param {boolean} visible The visiblilty of the marker.\n */\nRichMarker.prototype.setVisible = function(visible) {\n this.set('visible', visible);\n};\nRichMarker.prototype['setVisible'] = RichMarker.prototype.setVisible;\n\n\n/**\n * The visible changed event.\n */\nRichMarker.prototype.visible_changed = function() {\n if (this.ready_) {\n this.markerWrapper_.style['display'] = this.getVisible() ? '' : 'none';\n this.draw();\n }\n};\nRichMarker.prototype['visible_changed'] = RichMarker.prototype.visible_changed;\n\n\n/**\n * Sets the marker to be flat.\n *\n * @param {boolean} flat If the marker is to be flat or not.\n */\nRichMarker.prototype.setFlat = function(flat) {\n this.set('flat', !!flat);\n};\nRichMarker.prototype['setFlat'] = RichMarker.prototype.setFlat;\n\n\n/**\n * If the makrer is flat or not.\n *\n * @return {boolean} True the marker is flat.\n */\nRichMarker.prototype.getFlat = function() {\n return /** @type {boolean} */ (this.get('flat'));\n};\nRichMarker.prototype['getFlat'] = RichMarker.prototype.getFlat;\n\n\n/**\n * Get the width of the marker.\n *\n * @return {Number} The width of the marker.\n */\nRichMarker.prototype.getWidth = function() {\n return /** @type {Number} */ (this.get('width'));\n};\nRichMarker.prototype['getWidth'] = RichMarker.prototype.getWidth;\n\n\n/**\n * Get the height of the marker.\n *\n * @return {Number} The height of the marker.\n */\nRichMarker.prototype.getHeight = function() {\n return /** @type {Number} */ (this.get('height'));\n};\nRichMarker.prototype['getHeight'] = RichMarker.prototype.getHeight;\n\n\n/**\n * Sets the marker's box shadow.\n *\n * @param {string} shadow The box shadow to set.\n */\nRichMarker.prototype.setShadow = function(shadow) {\n this.set('shadow', shadow);\n this.flat_changed();\n};\nRichMarker.prototype['setShadow'] = RichMarker.prototype.setShadow;\n\n\n/**\n * Gets the marker's box shadow.\n *\n * @return {string} The box shadow.\n */\nRichMarker.prototype.getShadow = function() {\n return /** @type {string} */ (this.get('shadow'));\n};\nRichMarker.prototype['getShadow'] = RichMarker.prototype.getShadow;\n\n\n/**\n * Flat changed event.\n */\nRichMarker.prototype.flat_changed = function() {\n if (!this.ready_) {\n return;\n }\n\n this.markerWrapper_.style['boxShadow'] =\n this.markerWrapper_.style['webkitBoxShadow'] =\n this.markerWrapper_.style['MozBoxShadow'] =\n this.getFlat() ? '' : this.getShadow();\n};\nRichMarker.prototype['flat_changed'] = RichMarker.prototype.flat_changed;\n\n\n/**\n * Sets the zIndex of the marker.\n *\n * @param {Number} index The index to set.\n */\nRichMarker.prototype.setZIndex = function(index) {\n this.set('zIndex', index);\n};\nRichMarker.prototype['setZIndex'] = RichMarker.prototype.setZIndex;\n\n\n/**\n * Gets the zIndex of the marker.\n *\n * @return {Number} The zIndex of the marker.\n */\nRichMarker.prototype.getZIndex = function() {\n return /** @type {Number} */ (this.get('zIndex'));\n};\nRichMarker.prototype['getZIndex'] = RichMarker.prototype.getZIndex;\n\n\n/**\n * zIndex changed event.\n */\nRichMarker.prototype.zIndex_changed = function() {\n if (this.getZIndex() && this.ready_) {\n this.markerWrapper_.style.zIndex = this.getZIndex();\n }\n};\nRichMarker.prototype['zIndex_changed'] = RichMarker.prototype.zIndex_changed;\n\n/**\n * Whether the marker is draggable or not.\n *\n * @return {boolean} True if the marker is draggable.\n */\nRichMarker.prototype.getDraggable = function() {\n return /** @type {boolean} */ (this.get('draggable'));\n};\nRichMarker.prototype['getDraggable'] = RichMarker.prototype.getDraggable;\n\n\n/**\n * Sets the marker to be draggable or not.\n *\n * @param {boolean} draggable If the marker is draggable or not.\n */\nRichMarker.prototype.setDraggable = function(draggable) {\n this.set('draggable', !!draggable);\n};\nRichMarker.prototype['setDraggable'] = RichMarker.prototype.setDraggable;\n\n\n/**\n * Draggable property changed callback.\n */\nRichMarker.prototype.draggable_changed = function() {\n if (this.ready_) {\n if (this.getDraggable()) {\n this.addDragging_(this.markerWrapper_);\n } else {\n this.removeDragListeners_();\n }\n }\n};\nRichMarker.prototype['draggable_changed'] =\n RichMarker.prototype.draggable_changed;\n\n\n/**\n * Gets the postiton of the marker.\n *\n * @return {google.maps.LatLng} The position of the marker.\n */\nRichMarker.prototype.getPosition = function() {\n return /** @type {google.maps.LatLng} */ (this.get('position'));\n};\nRichMarker.prototype['getPosition'] = RichMarker.prototype.getPosition;\n\n\n/**\n * Sets the position of the marker.\n *\n * @param {google.maps.LatLng} position The position to set.\n */\nRichMarker.prototype.setPosition = function(position) {\n this.set('position', position);\n};\nRichMarker.prototype['setPosition'] = RichMarker.prototype.setPosition;\n\n\n/**\n * Position changed event.\n */\nRichMarker.prototype.position_changed = function() {\n this.draw();\n};\nRichMarker.prototype['position_changed'] =\n RichMarker.prototype.position_changed;\n\n\n/**\n * Gets the anchor.\n *\n * @return {google.maps.Size} The position of the anchor.\n */\nRichMarker.prototype.getAnchor = function() {\n return /** @type {google.maps.Size} */ (this.get('anchor'));\n};\nRichMarker.prototype['getAnchor'] = RichMarker.prototype.getAnchor;\n\n\n/**\n * Sets the anchor.\n *\n * @param {RichMarkerPosition|google.maps.Size} anchor The anchor to set.\n */\nRichMarker.prototype.setAnchor = function(anchor) {\n this.set('anchor', anchor);\n};\nRichMarker.prototype['setAnchor'] = RichMarker.prototype.setAnchor;\n\n\n/**\n * Anchor changed event.\n */\nRichMarker.prototype.anchor_changed = function() {\n this.draw();\n};\nRichMarker.prototype['anchor_changed'] = RichMarker.prototype.anchor_changed;\n\n\n/**\n * Converts a HTML string to a document fragment.\n *\n * @param {string} htmlString The HTML string to convert.\n * @return {Node} A HTML document fragment.\n * @private\n */\nRichMarker.prototype.htmlToDocumentFragment_ = function(htmlString) {\n var tempDiv = document.createElement('DIV');\n tempDiv.innerHTML = htmlString;\n if (tempDiv.childNodes.length == 1) {\n return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild));\n } else {\n var fragment = document.createDocumentFragment();\n while (tempDiv.firstChild) {\n fragment.appendChild(tempDiv.firstChild);\n }\n return fragment;\n }\n};\n\n\n/**\n * Removes all children from the node.\n *\n * @param {Node} node The node to remove all children from.\n * @private\n */\nRichMarker.prototype.removeChildren_ = function(node) {\n if (!node) {\n return;\n }\n\n var child;\n while (child = node.firstChild) {\n node.removeChild(child);\n }\n};\n\n\n/**\n * Sets the content of the marker.\n *\n * @param {string|Node} content The content to set.\n */\nRichMarker.prototype.setContent = function(content) {\n this.set('content', content);\n};\nRichMarker.prototype['setContent'] = RichMarker.prototype.setContent;\n\n\n/**\n * Get the content of the marker.\n *\n * @return {string|Node} The marker content.\n */\nRichMarker.prototype.getContent = function() {\n return /** @type {Node|string} */ (this.get('content'));\n};\nRichMarker.prototype['getContent'] = RichMarker.prototype.getContent;\n\n\n/**\n * Sets the marker content and adds loading events to images\n */\nRichMarker.prototype.content_changed = function() {\n if (!this.markerContent_) {\n // Marker content area doesnt exist.\n return;\n }\n\n this.removeChildren_(this.markerContent_);\n var content = this.getContent();\n if (content) {\n if (typeof content == 'string') {\n content = content.replace(/^\\s*([\\S\\s]*)\\b\\s*$/, '$1');\n content = this.htmlToDocumentFragment_(content);\n }\n this.markerContent_.appendChild(content);\n\n var that = this;\n var images = this.markerContent_.getElementsByTagName('IMG');\n for (var i = 0, image; image = images[i]; i++) {\n // By default, a browser lets a image be dragged outside of the browser,\n // so by calling preventDefault we stop this behaviour and allow the image\n // to be dragged around the map and now out of the browser and onto the\n // desktop.\n google.maps.event.addDomListener(image, 'mousedown', function(e) {\n if (that.getDraggable()) {\n if (e.preventDefault) {\n e.preventDefault();\n }\n e.returnValue = false;\n }\n });\n\n // Because we don't know the size of an image till it loads, add a\n // listener to the image load so the marker can resize and reposition\n // itself to be the correct height.\n google.maps.event.addDomListener(image, 'load', function() {\n that.draw();\n });\n }\n\n google.maps.event.trigger(this, 'domready');\n }\n\n if (this.ready_) {\n this.draw();\n }\n};\nRichMarker.prototype['content_changed'] = RichMarker.prototype.content_changed;\n\n/**\n * Sets the cursor.\n *\n * @param {string} whichCursor What cursor to show.\n * @private\n */\nRichMarker.prototype.setCursor_ = function(whichCursor) {\n if (!this.ready_) {\n return;\n }\n\n var cursor = '';\n if (navigator.userAgent.indexOf('Gecko/') !== -1) {\n // Moz has some nice cursors :)\n if (whichCursor == 'dragging') {\n cursor = '-moz-grabbing';\n }\n\n if (whichCursor == 'dragready') {\n cursor = '-moz-grab';\n }\n\n if (whichCursor == 'draggable') {\n cursor = 'pointer';\n }\n } else {\n if (whichCursor == 'dragging' || whichCursor == 'dragready') {\n cursor = 'move';\n }\n\n if (whichCursor == 'draggable') {\n cursor = 'pointer';\n }\n }\n\n if (this.markerWrapper_.style.cursor != cursor) {\n this.markerWrapper_.style.cursor = cursor;\n }\n};\n\n/**\n * Start dragging.\n *\n * @param {Event} e The event.\n */\nRichMarker.prototype.startDrag = function(e) {\n if (!this.getDraggable()) {\n return;\n }\n\n if (!this.dragging_) {\n this.dragging_ = true;\n var map = this.getMap();\n this.mapDraggable_ = map.get('draggable');\n map.set('draggable', false);\n\n // Store the current mouse position\n this.mouseX_ = e.clientX;\n this.mouseY_ = e.clientY;\n\n this.setCursor_('dragready');\n\n // Stop the text from being selectable while being dragged\n this.markerWrapper_.style['MozUserSelect'] = 'none';\n this.markerWrapper_.style['KhtmlUserSelect'] = 'none';\n this.markerWrapper_.style['WebkitUserSelect'] = 'none';\n\n this.markerWrapper_['unselectable'] = 'on';\n this.markerWrapper_['onselectstart'] = function() {\n return false;\n };\n\n this.addDraggingListeners_();\n\n google.maps.event.trigger(this, 'dragstart');\n }\n};\n\n\n/**\n * Stop dragging.\n */\nRichMarker.prototype.stopDrag = function() {\n if (!this.getDraggable()) {\n return;\n }\n\n if (this.dragging_) {\n this.dragging_ = false;\n this.getMap().set('draggable', this.mapDraggable_);\n this.mouseX_ = this.mouseY_ = this.mapDraggable_ = null;\n\n // Allow the text to be selectable again\n this.markerWrapper_.style['MozUserSelect'] = '';\n this.markerWrapper_.style['KhtmlUserSelect'] = '';\n this.markerWrapper_.style['WebkitUserSelect'] = '';\n this.markerWrapper_['unselectable'] = 'off';\n this.markerWrapper_['onselectstart'] = function() {};\n\n this.removeDraggingListeners_();\n\n this.setCursor_('draggable');\n google.maps.event.trigger(this, 'dragend');\n\n this.draw();\n }\n};\n\n\n/**\n * Handles the drag event.\n *\n * @param {Event} e The event.\n */\nRichMarker.prototype.drag = function(e) {\n if (!this.getDraggable() || !this.dragging_) {\n // This object isn't draggable or we have stopped dragging\n this.stopDrag();\n return;\n }\n\n var dx = this.mouseX_ - e.clientX;\n var dy = this.mouseY_ - e.clientY;\n\n this.mouseX_ = e.clientX;\n this.mouseY_ = e.clientY;\n\n var left = parseInt(this.markerWrapper_.style['left'], 10) - dx;\n var top = parseInt(this.markerWrapper_.style['top'], 10) - dy;\n\n this.markerWrapper_.style['left'] = left + 'px';\n this.markerWrapper_.style['top'] = top + 'px';\n\n var offset = this.getOffset_();\n\n // Set the position property and adjust for the anchor offset\n var point = new google.maps.Point(left - offset.width, top - offset.height);\n var projection = this.getProjection();\n this.setPosition(projection.fromDivPixelToLatLng(point));\n\n this.setCursor_('dragging');\n google.maps.event.trigger(this, 'drag');\n};\n\n\n/**\n * Removes the drag listeners associated with the marker.\n *\n * @private\n */\nRichMarker.prototype.removeDragListeners_ = function() {\n if (this.draggableListener_) {\n google.maps.event.removeListener(this.draggableListener_);\n delete this.draggableListener_;\n }\n this.setCursor_('');\n};\n\n\n/**\n * Add dragability events to the marker.\n *\n * @param {Node} node The node to apply dragging to.\n * @private\n */\nRichMarker.prototype.addDragging_ = function(node) {\n if (!node) {\n return;\n }\n\n var that = this;\n this.draggableListener_ =\n google.maps.event.addDomListener(node, 'mousedown', function(e) {\n that.startDrag(e);\n });\n\n this.setCursor_('draggable');\n};\n\n\n/**\n * Add dragging listeners.\n *\n * @private\n */\nRichMarker.prototype.addDraggingListeners_ = function() {\n var that = this;\n if (this.markerWrapper_.setCapture) {\n this.markerWrapper_.setCapture(true);\n this.draggingListeners_ = [\n google.maps.event.addDomListener(this.markerWrapper_, 'mousemove', function(e) {\n that.drag(e);\n }, true),\n google.maps.event.addDomListener(this.markerWrapper_, 'mouseup', function() {\n that.stopDrag();\n that.markerWrapper_.releaseCapture();\n }, true)\n ];\n } else {\n this.draggingListeners_ = [\n google.maps.event.addDomListener(window, 'mousemove', function(e) {\n that.drag(e);\n }, true),\n google.maps.event.addDomListener(window, 'mouseup', function() {\n that.stopDrag();\n }, true)\n ];\n }\n};\n\n\n/**\n * Remove dragging listeners.\n *\n * @private\n */\nRichMarker.prototype.removeDraggingListeners_ = function() {\n if (this.draggingListeners_) {\n for (var i = 0, listener; listener = this.draggingListeners_[i]; i++) {\n google.maps.event.removeListener(listener);\n }\n this.draggingListeners_.length = 0;\n }\n};\n\n\n/**\n * Get the anchor offset.\n *\n * @return {google.maps.Size} The size offset.\n * @private\n */\nRichMarker.prototype.getOffset_ = function() {\n var anchor = this.getAnchor();\n if (typeof anchor == 'object') {\n return /** @type {google.maps.Size} */ (anchor);\n }\n\n var offset = new google.maps.Size(0, 0);\n if (!this.markerContent_) {\n return offset;\n }\n\n var width = this.markerContent_.offsetWidth;\n var height = this.markerContent_.offsetHeight;\n\n switch (anchor) {\n case RichMarkerPosition['TOP_LEFT']:\n break;\n case RichMarkerPosition['TOP']:\n offset.width = -width / 2;\n break;\n case RichMarkerPosition['TOP_RIGHT']:\n offset.width = -width;\n break;\n case RichMarkerPosition['LEFT']:\n offset.height = -height / 2;\n break;\n case RichMarkerPosition['MIDDLE']:\n offset.width = -width / 2;\n offset.height = -height / 2;\n break;\n case RichMarkerPosition['RIGHT']:\n offset.width = -width;\n offset.height = -height / 2;\n break;\n case RichMarkerPosition['BOTTOM_LEFT']:\n offset.height = -height;\n break;\n case RichMarkerPosition['BOTTOM']:\n offset.width = -width / 2;\n offset.height = -height;\n break;\n case RichMarkerPosition['BOTTOM_RIGHT']:\n offset.width = -width;\n offset.height = -height;\n break;\n }\n\n return offset;\n};\n\n\n/**\n * Adding the marker to a map.\n * Implementing the interface.\n */\nRichMarker.prototype.onAdd = function() {\n if (!this.markerWrapper_) {\n this.markerWrapper_ = document.createElement('DIV');\n this.markerWrapper_.style['position'] = 'absolute';\n }\n\n if (this.getZIndex()) {\n this.markerWrapper_.style['zIndex'] = this.getZIndex();\n }\n\n this.markerWrapper_.style['display'] = this.getVisible() ? '' : 'none';\n\n if (!this.markerContent_) {\n this.markerContent_ = document.createElement('DIV');\n this.markerWrapper_.appendChild(this.markerContent_);\n\n var that = this;\n google.maps.event.addDomListener(this.markerContent_, 'click', function(e) {\n google.maps.event.trigger(that, 'click');\n });\n google.maps.event.addDomListener(this.markerContent_, 'mouseover', function(e) {\n google.maps.event.trigger(that, 'mouseover');\n });\n google.maps.event.addDomListener(this.markerContent_, 'mouseout', function(e) {\n google.maps.event.trigger(that, 'mouseout');\n });\n }\n\n this.ready_ = true;\n this.content_changed();\n this.flat_changed();\n this.draggable_changed();\n\n var panes = this.getPanes();\n if (panes) {\n panes.overlayMouseTarget.appendChild(this.markerWrapper_);\n }\n\n google.maps.event.trigger(this, 'ready');\n};\nRichMarker.prototype['onAdd'] = RichMarker.prototype.onAdd;\n\n\n/**\n * Impelementing the interface.\n */\nRichMarker.prototype.draw = function() {\n if (!this.ready_ || this.dragging_) {\n return;\n }\n\n var projection = this.getProjection();\n\n if (!projection) {\n // The map projection is not ready yet so do nothing\n return;\n }\n\n var latLng = /** @type {google.maps.LatLng} */ (this.get('position'));\n var pos = projection.fromLatLngToDivPixel(latLng);\n\n var offset = this.getOffset_();\n this.markerWrapper_.style['top'] = (pos.y + offset.height) + 'px';\n this.markerWrapper_.style['left'] = (pos.x + offset.width) + 'px';\n\n var height = this.markerContent_.offsetHeight;\n var width = this.markerContent_.offsetWidth;\n\n if (width != this.get('width')) {\n this.set('width', width);\n }\n\n if (height != this.get('height')) {\n this.set('height', height);\n }\n};\nRichMarker.prototype['draw'] = RichMarker.prototype.draw;\n\n\n/**\n * Removing a marker from the map.\n * Implementing the interface.\n */\nRichMarker.prototype.onRemove = function() {\n if (this.markerWrapper_ && this.markerWrapper_.parentNode) {\n this.markerWrapper_.parentNode.removeChild(this.markerWrapper_);\n }\n this.removeDragListeners_();\n};\nRichMarker.prototype['onRemove'] = RichMarker.prototype.onRemove;\n\n\n/**\n * RichMarker Anchor positions\n * @enum {number}\n */\nvar RichMarkerPosition = {\n 'TOP_LEFT': 1,\n 'TOP': 2,\n 'TOP_RIGHT': 3,\n 'LEFT': 4,\n 'MIDDLE': 5,\n 'RIGHT': 6,\n 'BOTTOM_LEFT': 7,\n 'BOTTOM': 8,\n 'BOTTOM_RIGHT': 9\n};\nwindow['RichMarkerPosition'] = RichMarkerPosition;\n\n\n //TODO: export / passthese on in the service instead of window\n window.InfoBox = InfoBox;\n window.Cluster = Cluster;\n window.ClusterIcon = ClusterIcon;\n window.MarkerClusterer = MarkerClusterer;\n window.MarkerLabel_ = MarkerLabel_;\n window.MarkerWithLabel = MarkerWithLabel;\n window.RichMarker = RichMarker;\n }();\n //END REPLACE\n })\n };\n});\n;/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/* istanbul ignore next */\n\tangular.module('uiGmapgoogle-maps.wrapped')\n\t.service('uiGmapDataStructures', function() {\n\treturn {\n\t Graph: __webpack_require__(1).Graph,\n\t Queue: __webpack_require__(1).Queue\n\t};\n\t});\n\n\n/***/ },\n/* 1 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t(function() {\n\t module.exports = {\n\t Graph: __webpack_require__(2),\n\t Heap: __webpack_require__(3),\n\t LinkedList: __webpack_require__(4),\n\t Map: __webpack_require__(5),\n\t Queue: __webpack_require__(6),\n\t RedBlackTree: __webpack_require__(7),\n\t Trie: __webpack_require__(8)\n\t };\n\n\t}).call(this);\n\n\n/***/ },\n/* 2 */\n/***/ function(module, exports) {\n\n\t/*\n\tGraph implemented as a modified incidence list. O(1) for every typical\n\toperation except `removeNode()` at O(E) where E is the number of edges.\n\n\t## Overview example:\n\n\t```js\n\tvar graph = new Graph;\n\tgraph.addNode('A'); // => a node object. For more info, log the output or check\n\t // the documentation for addNode\n\tgraph.addNode('B');\n\tgraph.addNode('C');\n\tgraph.addEdge('A', 'C'); // => an edge object\n\tgraph.addEdge('A', 'B');\n\tgraph.getEdge('B', 'A'); // => undefined. Directed edge!\n\tgraph.getEdge('A', 'B'); // => the edge object previously added\n\tgraph.getEdge('A', 'B').weight = 2 // weight is the only built-in handy property\n\t // of an edge object. Feel free to attach\n\t // other properties\n\tgraph.getInEdgesOf('B'); // => array of edge objects, in this case only one;\n\t // connecting A to B\n\tgraph.getOutEdgesOf('A'); // => array of edge objects, one to B and one to C\n\tgraph.getAllEdgesOf('A'); // => all the in and out edges. Edge directed toward\n\t // the node itself are only counted once\n\tforEachNode(function(nodeObject) {\n\t console.log(node);\n\t});\n\tforEachEdge(function(edgeObject) {\n\t console.log(edgeObject);\n\t});\n\tgraph.removeNode('C'); // => 'C'. The edge between A and C also removed\n\tgraph.removeEdge('A', 'B'); // => the edge object removed\n\t```\n\n\t## Properties:\n\n\t- nodeSize: total number of nodes.\n\t- edgeSize: total number of edges.\n\t*/\n\n\n\t(function() {\n\t var Graph,\n\t __hasProp = {}.hasOwnProperty;\n\n\t Graph = (function() {\n\t function Graph() {\n\t this._nodes = {};\n\t this.nodeSize = 0;\n\t this.edgeSize = 0;\n\t }\n\n\t Graph.prototype.addNode = function(id) {\n\t /*\n\t The `id` is a unique identifier for the node, and should **not** change\n\t after it's added. It will be used for adding, retrieving and deleting\n\t related edges too.\n\t \n\t **Note** that, internally, the ids are kept in an object. JavaScript's\n\t object hashes the id `'2'` and `2` to the same key, so please stick to a\n\t simple id data type such as number or string.\n\t \n\t _Returns:_ the node object. Feel free to attach additional custom properties\n\t on it for graph algorithms' needs. **Undefined if node id already exists**,\n\t as to avoid accidental overrides.\n\t */\n\n\t if (!this._nodes[id]) {\n\t this.nodeSize++;\n\t return this._nodes[id] = {\n\t _outEdges: {},\n\t _inEdges: {}\n\t };\n\t }\n\t };\n\n\t Graph.prototype.getNode = function(id) {\n\t /*\n\t _Returns:_ the node object. Feel free to attach additional custom properties\n\t on it for graph algorithms' needs.\n\t */\n\n\t return this._nodes[id];\n\t };\n\n\t Graph.prototype.removeNode = function(id) {\n\t /*\n\t _Returns:_ the node object removed, or undefined if it didn't exist in the\n\t first place.\n\t */\n\n\t var inEdgeId, nodeToRemove, outEdgeId, _ref, _ref1;\n\t nodeToRemove = this._nodes[id];\n\t if (!nodeToRemove) {\n\t return;\n\t } else {\n\t _ref = nodeToRemove._outEdges;\n\t for (outEdgeId in _ref) {\n\t if (!__hasProp.call(_ref, outEdgeId)) continue;\n\t this.removeEdge(id, outEdgeId);\n\t }\n\t _ref1 = nodeToRemove._inEdges;\n\t for (inEdgeId in _ref1) {\n\t if (!__hasProp.call(_ref1, inEdgeId)) continue;\n\t this.removeEdge(inEdgeId, id);\n\t }\n\t this.nodeSize--;\n\t delete this._nodes[id];\n\t }\n\t return nodeToRemove;\n\t };\n\n\t Graph.prototype.addEdge = function(fromId, toId, weight) {\n\t var edgeToAdd, fromNode, toNode;\n\t if (weight == null) {\n\t weight = 1;\n\t }\n\t /*\n\t `fromId` and `toId` are the node id specified when it was created using\n\t `addNode()`. `weight` is optional and defaults to 1. Ignoring it effectively\n\t makes this an unweighted graph. Under the hood, `weight` is just a normal\n\t property of the edge object.\n\t \n\t _Returns:_ the edge object created. Feel free to attach additional custom\n\t properties on it for graph algorithms' needs. **Or undefined** if the nodes\n\t of id `fromId` or `toId` aren't found, or if an edge already exists between\n\t the two nodes.\n\t */\n\n\t if (this.getEdge(fromId, toId)) {\n\t return;\n\t }\n\t fromNode = this._nodes[fromId];\n\t toNode = this._nodes[toId];\n\t if (!fromNode || !toNode) {\n\t return;\n\t }\n\t edgeToAdd = {\n\t weight: weight\n\t };\n\t fromNode._outEdges[toId] = edgeToAdd;\n\t toNode._inEdges[fromId] = edgeToAdd;\n\t this.edgeSize++;\n\t return edgeToAdd;\n\t };\n\n\t Graph.prototype.getEdge = function(fromId, toId) {\n\t /*\n\t _Returns:_ the edge object, or undefined if the nodes of id `fromId` or\n\t `toId` aren't found.\n\t */\n\n\t var fromNode, toNode;\n\t fromNode = this._nodes[fromId];\n\t toNode = this._nodes[toId];\n\t if (!fromNode || !toNode) {\n\n\t } else {\n\t return fromNode._outEdges[toId];\n\t }\n\t };\n\n\t Graph.prototype.removeEdge = function(fromId, toId) {\n\t /*\n\t _Returns:_ the edge object removed, or undefined of edge wasn't found.\n\t */\n\n\t var edgeToDelete, fromNode, toNode;\n\t fromNode = this._nodes[fromId];\n\t toNode = this._nodes[toId];\n\t edgeToDelete = this.getEdge(fromId, toId);\n\t if (!edgeToDelete) {\n\t return;\n\t }\n\t delete fromNode._outEdges[toId];\n\t delete toNode._inEdges[fromId];\n\t this.edgeSize--;\n\t return edgeToDelete;\n\t };\n\n\t Graph.prototype.getInEdgesOf = function(nodeId) {\n\t /*\n\t _Returns:_ an array of edge objects that are directed toward the node, or\n\t empty array if no such edge or node exists.\n\t */\n\n\t var fromId, inEdges, toNode, _ref;\n\t toNode = this._nodes[nodeId];\n\t inEdges = [];\n\t _ref = toNode != null ? toNode._inEdges : void 0;\n\t for (fromId in _ref) {\n\t if (!__hasProp.call(_ref, fromId)) continue;\n\t inEdges.push(this.getEdge(fromId, nodeId));\n\t }\n\t return inEdges;\n\t };\n\n\t Graph.prototype.getOutEdgesOf = function(nodeId) {\n\t /*\n\t _Returns:_ an array of edge objects that go out of the node, or empty array\n\t if no such edge or node exists.\n\t */\n\n\t var fromNode, outEdges, toId, _ref;\n\t fromNode = this._nodes[nodeId];\n\t outEdges = [];\n\t _ref = fromNode != null ? fromNode._outEdges : void 0;\n\t for (toId in _ref) {\n\t if (!__hasProp.call(_ref, toId)) continue;\n\t outEdges.push(this.getEdge(nodeId, toId));\n\t }\n\t return outEdges;\n\t };\n\n\t Graph.prototype.getAllEdgesOf = function(nodeId) {\n\t /*\n\t **Note:** not the same as concatenating `getInEdgesOf()` and\n\t `getOutEdgesOf()`. Some nodes might have an edge pointing toward itself.\n\t This method solves that duplication.\n\t \n\t _Returns:_ an array of edge objects linked to the node, no matter if they're\n\t outgoing or coming. Duplicate edge created by self-pointing nodes are\n\t removed. Only one copy stays. Empty array if node has no edge.\n\t */\n\n\t var i, inEdges, outEdges, selfEdge, _i, _ref, _ref1;\n\t inEdges = this.getInEdgesOf(nodeId);\n\t outEdges = this.getOutEdgesOf(nodeId);\n\t if (inEdges.length === 0) {\n\t return outEdges;\n\t }\n\t selfEdge = this.getEdge(nodeId, nodeId);\n\t for (i = _i = 0, _ref = inEdges.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {\n\t if (inEdges[i] === selfEdge) {\n\t _ref1 = [inEdges[inEdges.length - 1], inEdges[i]], inEdges[i] = _ref1[0], inEdges[inEdges.length - 1] = _ref1[1];\n\t inEdges.pop();\n\t break;\n\t }\n\t }\n\t return inEdges.concat(outEdges);\n\t };\n\n\t Graph.prototype.forEachNode = function(operation) {\n\t /*\n\t Traverse through the graph in an arbitrary manner, visiting each node once.\n\t Pass a function of the form `fn(nodeObject, nodeId)`.\n\t \n\t _Returns:_ undefined.\n\t */\n\n\t var nodeId, nodeObject, _ref;\n\t _ref = this._nodes;\n\t for (nodeId in _ref) {\n\t if (!__hasProp.call(_ref, nodeId)) continue;\n\t nodeObject = _ref[nodeId];\n\t operation(nodeObject, nodeId);\n\t }\n\t };\n\n\t Graph.prototype.forEachEdge = function(operation) {\n\t /*\n\t Traverse through the graph in an arbitrary manner, visiting each edge once.\n\t Pass a function of the form `fn(edgeObject)`.\n\t \n\t _Returns:_ undefined.\n\t */\n\n\t var edgeObject, nodeId, nodeObject, toId, _ref, _ref1;\n\t _ref = this._nodes;\n\t for (nodeId in _ref) {\n\t if (!__hasProp.call(_ref, nodeId)) continue;\n\t nodeObject = _ref[nodeId];\n\t _ref1 = nodeObject._outEdges;\n\t for (toId in _ref1) {\n\t if (!__hasProp.call(_ref1, toId)) continue;\n\t edgeObject = _ref1[toId];\n\t operation(edgeObject);\n\t }\n\t }\n\t };\n\n\t return Graph;\n\n\t })();\n\n\t module.exports = Graph;\n\n\t}).call(this);\n\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t/*\n\tMinimum heap, i.e. smallest node at root.\n\n\t**Note:** does not accept null or undefined. This is by design. Those values\n\tcause comparison problems and might report false negative during extraction.\n\n\t## Overview example:\n\n\t```js\n\tvar heap = new Heap([5, 6, 3, 4]);\n\theap.add(10); // => 10\n\theap.removeMin(); // => 3\n\theap.peekMin(); // => 4\n\t```\n\n\t## Properties:\n\n\t- size: total number of items.\n\t*/\n\n\n\t(function() {\n\t var Heap, _leftChild, _parent, _rightChild;\n\n\t Heap = (function() {\n\t function Heap(dataToHeapify) {\n\t var i, item, _i, _j, _len, _ref;\n\t if (dataToHeapify == null) {\n\t dataToHeapify = [];\n\t }\n\t /*\n\t Pass an optional array to be heapified. Takes only O(n) time.\n\t */\n\n\t this._data = [void 0];\n\t for (_i = 0, _len = dataToHeapify.length; _i < _len; _i++) {\n\t item = dataToHeapify[_i];\n\t if (item != null) {\n\t this._data.push(item);\n\t }\n\t }\n\t if (this._data.length > 1) {\n\t for (i = _j = 2, _ref = this._data.length; 2 <= _ref ? _j < _ref : _j > _ref; i = 2 <= _ref ? ++_j : --_j) {\n\t this._upHeap(i);\n\t }\n\t }\n\t this.size = this._data.length - 1;\n\t }\n\n\t Heap.prototype.add = function(value) {\n\t /*\n\t **Remember:** rejects null and undefined for mentioned reasons.\n\t \n\t _Returns:_ the value added.\n\t */\n\n\t if (value == null) {\n\t return;\n\t }\n\t this._data.push(value);\n\t this._upHeap(this._data.length - 1);\n\t this.size++;\n\t return value;\n\t };\n\n\t Heap.prototype.removeMin = function() {\n\t /*\n\t _Returns:_ the smallest item (the root).\n\t */\n\n\t var min;\n\t if (this._data.length === 1) {\n\t return;\n\t }\n\t this.size--;\n\t if (this._data.length === 2) {\n\t return this._data.pop();\n\t }\n\t min = this._data[1];\n\t this._data[1] = this._data.pop();\n\t this._downHeap();\n\t return min;\n\t };\n\n\t Heap.prototype.peekMin = function() {\n\t /*\n\t Check the smallest item without removing it.\n\t \n\t _Returns:_ the smallest item (the root).\n\t */\n\n\t return this._data[1];\n\t };\n\n\t Heap.prototype._upHeap = function(index) {\n\t var valueHolder, _ref;\n\t valueHolder = this._data[index];\n\t while (this._data[index] < this._data[_parent(index)] && index > 1) {\n\t _ref = [this._data[_parent(index)], this._data[index]], this._data[index] = _ref[0], this._data[_parent(index)] = _ref[1];\n\t index = _parent(index);\n\t }\n\t };\n\n\t Heap.prototype._downHeap = function() {\n\t var currentIndex, smallerChildIndex, _ref;\n\t currentIndex = 1;\n\t while (_leftChild(currentIndex < this._data.length)) {\n\t smallerChildIndex = _leftChild(currentIndex);\n\t if (smallerChildIndex < this._data.length - 1) {\n\t if (this._data[_rightChild(currentIndex)] < this._data[smallerChildIndex]) {\n\t smallerChildIndex = _rightChild(currentIndex);\n\t }\n\t }\n\t if (this._data[smallerChildIndex] < this._data[currentIndex]) {\n\t _ref = [this._data[currentIndex], this._data[smallerChildIndex]], this._data[smallerChildIndex] = _ref[0], this._data[currentIndex] = _ref[1];\n\t currentIndex = smallerChildIndex;\n\t } else {\n\t break;\n\t }\n\t }\n\t };\n\n\t return Heap;\n\n\t })();\n\n\t _parent = function(index) {\n\t return index >> 1;\n\t };\n\n\t _leftChild = function(index) {\n\t return index << 1;\n\t };\n\n\t _rightChild = function(index) {\n\t return (index << 1) + 1;\n\t };\n\n\t module.exports = Heap;\n\n\t}).call(this);\n\n\n/***/ },\n/* 4 */\n/***/ function(module, exports) {\n\n\t/*\n\tDoubly Linked.\n\n\t## Overview example:\n\n\t```js\n\tvar list = new LinkedList([5, 4, 9]);\n\tlist.add(12); // => 12\n\tlist.head.next.value; // => 4\n\tlist.tail.value; // => 12\n\tlist.at(-1); // => 12\n\tlist.removeAt(2); // => 9\n\tlist.remove(4); // => 4\n\tlist.indexOf(5); // => 0\n\tlist.add(5, 1); // => 5. Second 5 at position 1.\n\tlist.indexOf(5, 1); // => 1\n\t```\n\n\t## Properties:\n\n\t- head: first item.\n\t- tail: last item.\n\t- size: total number of items.\n\t- item.value: value passed to the item when calling `add()`.\n\t- item.prev: previous item.\n\t- item.next: next item.\n\t*/\n\n\n\t(function() {\n\t var LinkedList;\n\n\t LinkedList = (function() {\n\t function LinkedList(valuesToAdd) {\n\t var value, _i, _len;\n\t if (valuesToAdd == null) {\n\t valuesToAdd = [];\n\t }\n\t /*\n\t Can pass an array of elements to link together during `new LinkedList()`\n\t initiation.\n\t */\n\n\t this.head = {\n\t prev: void 0,\n\t value: void 0,\n\t next: void 0\n\t };\n\t this.tail = {\n\t prev: void 0,\n\t value: void 0,\n\t next: void 0\n\t };\n\t this.size = 0;\n\t for (_i = 0, _len = valuesToAdd.length; _i < _len; _i++) {\n\t value = valuesToAdd[_i];\n\t this.add(value);\n\t }\n\t }\n\n\t LinkedList.prototype.at = function(position) {\n\t /*\n\t Get the item at `position` (optional). Accepts negative index:\n\t \n\t ```js\n\t myList.at(-1); // Returns the last element.\n\t ```\n\t However, passing a negative index that surpasses the boundary will return\n\t undefined:\n\t \n\t ```js\n\t myList = new LinkedList([2, 6, 8, 3])\n\t myList.at(-5); // Undefined.\n\t myList.at(-4); // 2.\n\t ```\n\t _Returns:_ item gotten, or undefined if not found.\n\t */\n\n\t var currentNode, i, _i, _j, _ref;\n\t if (!((-this.size <= position && position < this.size))) {\n\t return;\n\t }\n\t position = this._adjust(position);\n\t if (position * 2 < this.size) {\n\t currentNode = this.head;\n\t for (i = _i = 1; _i <= position; i = _i += 1) {\n\t currentNode = currentNode.next;\n\t }\n\t } else {\n\t currentNode = this.tail;\n\t for (i = _j = 1, _ref = this.size - position - 1; _j <= _ref; i = _j += 1) {\n\t currentNode = currentNode.prev;\n\t }\n\t }\n\t return currentNode;\n\t };\n\n\t LinkedList.prototype.add = function(value, position) {\n\t var currentNode, nodeToAdd, _ref, _ref1, _ref2;\n\t if (position == null) {\n\t position = this.size;\n\t }\n\t /*\n\t Add a new item at `position` (optional). Defaults to adding at the end.\n\t `position`, just like in `at()`, can be negative (within the negative\n\t boundary). Position specifies the place the value's going to be, and the old\n\t node will be pushed higher. `add(-2)` on list of size 7 is the same as\n\t `add(5)`.\n\t \n\t _Returns:_ item added.\n\t */\n\n\t if (!((-this.size <= position && position <= this.size))) {\n\t return;\n\t }\n\t nodeToAdd = {\n\t value: value\n\t };\n\t position = this._adjust(position);\n\t if (this.size === 0) {\n\t this.head = nodeToAdd;\n\t } else {\n\t if (position === 0) {\n\t _ref = [nodeToAdd, this.head, nodeToAdd], this.head.prev = _ref[0], nodeToAdd.next = _ref[1], this.head = _ref[2];\n\t } else {\n\t currentNode = this.at(position - 1);\n\t _ref1 = [currentNode.next, nodeToAdd, nodeToAdd, currentNode], nodeToAdd.next = _ref1[0], (_ref2 = currentNode.next) != null ? _ref2.prev = _ref1[1] : void 0, currentNode.next = _ref1[2], nodeToAdd.prev = _ref1[3];\n\t }\n\t }\n\t if (position === this.size) {\n\t this.tail = nodeToAdd;\n\t }\n\t this.size++;\n\t return value;\n\t };\n\n\t LinkedList.prototype.removeAt = function(position) {\n\t var currentNode, valueToReturn, _ref;\n\t if (position == null) {\n\t position = this.size - 1;\n\t }\n\t /*\n\t Remove an item at index `position` (optional). Defaults to the last item.\n\t Index can be negative (within the boundary).\n\t \n\t _Returns:_ item removed.\n\t */\n\n\t if (!((-this.size <= position && position < this.size))) {\n\t return;\n\t }\n\t if (this.size === 0) {\n\t return;\n\t }\n\t position = this._adjust(position);\n\t if (this.size === 1) {\n\t valueToReturn = this.head.value;\n\t this.head.value = this.tail.value = void 0;\n\t } else {\n\t if (position === 0) {\n\t valueToReturn = this.head.value;\n\t this.head = this.head.next;\n\t this.head.prev = void 0;\n\t } else {\n\t currentNode = this.at(position);\n\t valueToReturn = currentNode.value;\n\t currentNode.prev.next = currentNode.next;\n\t if ((_ref = currentNode.next) != null) {\n\t _ref.prev = currentNode.prev;\n\t }\n\t if (position === this.size - 1) {\n\t this.tail = currentNode.prev;\n\t }\n\t }\n\t }\n\t this.size--;\n\t return valueToReturn;\n\t };\n\n\t LinkedList.prototype.remove = function(value) {\n\t /*\n\t Remove the item using its value instead of position. **Will remove the fist\n\t occurrence of `value`.**\n\t \n\t _Returns:_ the value, or undefined if value's not found.\n\t */\n\n\t var currentNode;\n\t if (value == null) {\n\t return;\n\t }\n\t currentNode = this.head;\n\t while (currentNode && currentNode.value !== value) {\n\t currentNode = currentNode.next;\n\t }\n\t if (!currentNode) {\n\t return;\n\t }\n\t if (this.size === 1) {\n\t this.head.value = this.tail.value = void 0;\n\t } else if (currentNode === this.head) {\n\t this.head = this.head.next;\n\t this.head.prev = void 0;\n\t } else if (currentNode === this.tail) {\n\t this.tail = this.tail.prev;\n\t this.tail.next = void 0;\n\t } else {\n\t currentNode.prev.next = currentNode.next;\n\t currentNode.next.prev = currentNode.prev;\n\t }\n\t this.size--;\n\t return value;\n\t };\n\n\t LinkedList.prototype.indexOf = function(value, startingPosition) {\n\t var currentNode, position;\n\t if (startingPosition == null) {\n\t startingPosition = 0;\n\t }\n\t /*\n\t Find the index of an item, similarly to `array.indexOf()`. Defaults to start\n\t searching from the beginning, by can start at another position by passing\n\t `startingPosition`. This parameter can also be negative; but unlike the\n\t other methods of this class, `startingPosition` (optional) can be as small\n\t as desired; a value of -999 for a list of size 5 will start searching\n\t normally, at the beginning.\n\t \n\t **Note:** searches forwardly, **not** backwardly, i.e:\n\t \n\t ```js\n\t var myList = new LinkedList([2, 3, 1, 4, 3, 5])\n\t myList.indexOf(3, -3); // Returns 4, not 1\n\t ```\n\t _Returns:_ index of item found, or -1 if not found.\n\t */\n\n\t if (((this.head.value == null) && !this.head.next) || startingPosition >= this.size) {\n\t return -1;\n\t }\n\t startingPosition = Math.max(0, this._adjust(startingPosition));\n\t currentNode = this.at(startingPosition);\n\t position = startingPosition;\n\t while (currentNode) {\n\t if (currentNode.value === value) {\n\t break;\n\t }\n\t currentNode = currentNode.next;\n\t position++;\n\t }\n\t if (position === this.size) {\n\t return -1;\n\t } else {\n\t return position;\n\t }\n\t };\n\n\t LinkedList.prototype._adjust = function(position) {\n\t if (position < 0) {\n\t return this.size + position;\n\t } else {\n\t return position;\n\t }\n\t };\n\n\t return LinkedList;\n\n\t })();\n\n\t module.exports = LinkedList;\n\n\t}).call(this);\n\n\n/***/ },\n/* 5 */\n/***/ function(module, exports) {\n\n\t/*\n\tKind of a stopgap measure for the upcoming [JavaScript\n\tMap](http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets)\n\n\t**Note:** due to JavaScript's limitations, hashing something other than Boolean,\n\tNumber, String, Undefined, Null, RegExp, Function requires a hack that inserts a\n\thidden unique property into the object. This means `set`, `get`, `has` and\n\t`delete` must employ the same object, and not a mere identical copy as in the\n\tcase of, say, a string.\n\n\t## Overview example:\n\n\t```js\n\tvar map = new Map({'alice': 'wonderland', 20: 'ok'});\n\tmap.set('20', 5); // => 5\n\tmap.get('20'); // => 5\n\tmap.has('alice'); // => true\n\tmap.delete(20) // => true\n\tvar arr = [1, 2];\n\tmap.add(arr, 'goody'); // => 'goody'\n\tmap.has(arr); // => true\n\tmap.has([1, 2]); // => false. Needs to compare by reference\n\tmap.forEach(function(key, value) {\n\t console.log(key, value);\n\t});\n\t```\n\n\t## Properties:\n\n\t- size: The total number of `(key, value)` pairs.\n\t*/\n\n\n\t(function() {\n\t var Map, SPECIAL_TYPE_KEY_PREFIX, _extractDataType, _isSpecialType,\n\t __hasProp = {}.hasOwnProperty;\n\n\t SPECIAL_TYPE_KEY_PREFIX = '_mapId_';\n\n\t Map = (function() {\n\t Map._mapIdTracker = 0;\n\n\t Map._newMapId = function() {\n\t return this._mapIdTracker++;\n\t };\n\n\t function Map(objectToMap) {\n\t /*\n\t Pass an optional object whose (key, value) pair will be hashed. **Careful**\n\t not to pass something like {5: 'hi', '5': 'hello'}, since JavaScript's\n\t native object behavior will crush the first 5 property before it gets to\n\t constructor.\n\t */\n\n\t var key, value;\n\t this._content = {};\n\t this._itemId = 0;\n\t this._id = Map._newMapId();\n\t this.size = 0;\n\t for (key in objectToMap) {\n\t if (!__hasProp.call(objectToMap, key)) continue;\n\t value = objectToMap[key];\n\t this.set(key, value);\n\t }\n\t }\n\n\t Map.prototype.hash = function(key, makeHash) {\n\t var propertyForMap, type;\n\t if (makeHash == null) {\n\t makeHash = false;\n\t }\n\t /*\n\t The hash function for hashing keys is public. Feel free to replace it with\n\t your own. The `makeHash` parameter is optional and accepts a boolean\n\t (defaults to `false`) indicating whether or not to produce a new hash (for\n\t the first use, naturally).\n\t \n\t _Returns:_ the hash.\n\t */\n\n\t type = _extractDataType(key);\n\t if (_isSpecialType(key)) {\n\t propertyForMap = SPECIAL_TYPE_KEY_PREFIX + this._id;\n\t if (makeHash && !key[propertyForMap]) {\n\t key[propertyForMap] = this._itemId++;\n\t }\n\t return propertyForMap + '_' + key[propertyForMap];\n\t } else {\n\t return type + '_' + key;\n\t }\n\t };\n\n\t Map.prototype.set = function(key, value) {\n\t /*\n\t _Returns:_ value.\n\t */\n\n\t if (!this.has(key)) {\n\t this.size++;\n\t }\n\t this._content[this.hash(key, true)] = [value, key];\n\t return value;\n\t };\n\n\t Map.prototype.get = function(key) {\n\t /*\n\t _Returns:_ value corresponding to the key, or undefined if not found.\n\t */\n\n\t var _ref;\n\t return (_ref = this._content[this.hash(key)]) != null ? _ref[0] : void 0;\n\t };\n\n\t Map.prototype.has = function(key) {\n\t /*\n\t Check whether a value exists for the key.\n\t \n\t _Returns:_ true or false.\n\t */\n\n\t return this.hash(key) in this._content;\n\t };\n\n\t Map.prototype[\"delete\"] = function(key) {\n\t /*\n\t Remove the (key, value) pair.\n\t \n\t _Returns:_ **true or false**. Unlike most of this library, this method\n\t doesn't return the deleted value. This is so that it conforms to the future\n\t JavaScript `map.delete()`'s behavior.\n\t */\n\n\t var hashedKey;\n\t hashedKey = this.hash(key);\n\t if (hashedKey in this._content) {\n\t delete this._content[hashedKey];\n\t if (_isSpecialType(key)) {\n\t delete key[SPECIAL_TYPE_KEY_PREFIX + this._id];\n\t }\n\t this.size--;\n\t return true;\n\t }\n\t return false;\n\t };\n\n\t Map.prototype.forEach = function(operation) {\n\t /*\n\t Traverse through the map. Pass a function of the form `fn(key, value)`.\n\t \n\t _Returns:_ undefined.\n\t */\n\n\t var key, value, _ref;\n\t _ref = this._content;\n\t for (key in _ref) {\n\t if (!__hasProp.call(_ref, key)) continue;\n\t value = _ref[key];\n\t operation(value[1], value[0]);\n\t }\n\t };\n\n\t return Map;\n\n\t })();\n\n\t _isSpecialType = function(key) {\n\t var simpleHashableTypes, simpleType, type, _i, _len;\n\t simpleHashableTypes = ['Boolean', 'Number', 'String', 'Undefined', 'Null', 'RegExp', 'Function'];\n\t type = _extractDataType(key);\n\t for (_i = 0, _len = simpleHashableTypes.length; _i < _len; _i++) {\n\t simpleType = simpleHashableTypes[_i];\n\t if (type === simpleType) {\n\t return false;\n\t }\n\t }\n\t return true;\n\t };\n\n\t _extractDataType = function(type) {\n\t return Object.prototype.toString.apply(type).match(/\\[object (.+)\\]/)[1];\n\t };\n\n\t module.exports = Map;\n\n\t}).call(this);\n\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t/*\n\tAmortized O(1) dequeue!\n\n\t## Overview example:\n\n\t```js\n\tvar queue = new Queue([1, 6, 4]);\n\tqueue.enqueue(10); // => 10\n\tqueue.dequeue(); // => 1\n\tqueue.dequeue(); // => 6\n\tqueue.dequeue(); // => 4\n\tqueue.peek(); // => 10\n\tqueue.dequeue(); // => 10\n\tqueue.peek(); // => undefined\n\t```\n\n\t## Properties:\n\n\t- size: The total number of items.\n\t*/\n\n\n\t(function() {\n\t var Queue;\n\n\t Queue = (function() {\n\t function Queue(initialArray) {\n\t if (initialArray == null) {\n\t initialArray = [];\n\t }\n\t /*\n\t Pass an optional array to be transformed into a queue. The item at index 0\n\t is the first to be dequeued.\n\t */\n\n\t this._content = initialArray;\n\t this._dequeueIndex = 0;\n\t this.size = this._content.length;\n\t }\n\n\t Queue.prototype.enqueue = function(item) {\n\t /*\n\t _Returns:_ the item.\n\t */\n\n\t this.size++;\n\t this._content.push(item);\n\t return item;\n\t };\n\n\t Queue.prototype.dequeue = function() {\n\t /*\n\t _Returns:_ the dequeued item.\n\t */\n\n\t var itemToDequeue;\n\t if (this.size === 0) {\n\t return;\n\t }\n\t this.size--;\n\t itemToDequeue = this._content[this._dequeueIndex];\n\t this._dequeueIndex++;\n\t if (this._dequeueIndex * 2 > this._content.length) {\n\t this._content = this._content.slice(this._dequeueIndex);\n\t this._dequeueIndex = 0;\n\t }\n\t return itemToDequeue;\n\t };\n\n\t Queue.prototype.peek = function() {\n\t /*\n\t Check the next item to be dequeued, without removing it.\n\t \n\t _Returns:_ the item.\n\t */\n\n\t return this._content[this._dequeueIndex];\n\t };\n\n\t return Queue;\n\n\t })();\n\n\t module.exports = Queue;\n\n\t}).call(this);\n\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t/*\n\tCredit to Wikipedia's article on [Red-black\n\ttree](http://en.wikipedia.org/wiki/Red–black_tree)\n\n\t**Note:** doesn't handle duplicate entries, undefined and null. This is by\n\tdesign.\n\n\t## Overview example:\n\n\t```js\n\tvar rbt = new RedBlackTree([7, 5, 1, 8]);\n\trbt.add(2); // => 2\n\trbt.add(10); // => 10\n\trbt.has(5); // => true\n\trbt.peekMin(); // => 1\n\trbt.peekMax(); // => 10\n\trbt.removeMin(); // => 1\n\trbt.removeMax(); // => 10\n\trbt.remove(8); // => 8\n\t```\n\n\t## Properties:\n\n\t- size: The total number of items.\n\t*/\n\n\n\t(function() {\n\t var BLACK, NODE_FOUND, NODE_TOO_BIG, NODE_TOO_SMALL, RED, RedBlackTree, STOP_SEARCHING, _findNode, _grandParentOf, _isLeft, _leftOrRight, _peekMaxNode, _peekMinNode, _siblingOf, _uncleOf;\n\n\t NODE_FOUND = 0;\n\n\t NODE_TOO_BIG = 1;\n\n\t NODE_TOO_SMALL = 2;\n\n\t STOP_SEARCHING = 3;\n\n\t RED = 1;\n\n\t BLACK = 2;\n\n\t RedBlackTree = (function() {\n\t function RedBlackTree(valuesToAdd) {\n\t var value, _i, _len;\n\t if (valuesToAdd == null) {\n\t valuesToAdd = [];\n\t }\n\t /*\n\t Pass an optional array to be turned into binary tree. **Note:** does not\n\t accept duplicate, undefined and null.\n\t */\n\n\t this._root;\n\t this.size = 0;\n\t for (_i = 0, _len = valuesToAdd.length; _i < _len; _i++) {\n\t value = valuesToAdd[_i];\n\t if (value != null) {\n\t this.add(value);\n\t }\n\t }\n\t }\n\n\t RedBlackTree.prototype.add = function(value) {\n\t /*\n\t Again, make sure to not pass a value already in the tree, or undefined, or\n\t null.\n\t \n\t _Returns:_ value added.\n\t */\n\n\t var currentNode, foundNode, nodeToInsert, _ref;\n\t if (value == null) {\n\t return;\n\t }\n\t this.size++;\n\t nodeToInsert = {\n\t value: value,\n\t _color: RED\n\t };\n\t if (!this._root) {\n\t this._root = nodeToInsert;\n\t } else {\n\t foundNode = _findNode(this._root, function(node) {\n\t if (value === node.value) {\n\t return NODE_FOUND;\n\t } else {\n\t if (value < node.value) {\n\t if (node._left) {\n\t return NODE_TOO_BIG;\n\t } else {\n\t nodeToInsert._parent = node;\n\t node._left = nodeToInsert;\n\t return STOP_SEARCHING;\n\t }\n\t } else {\n\t if (node._right) {\n\t return NODE_TOO_SMALL;\n\t } else {\n\t nodeToInsert._parent = node;\n\t node._right = nodeToInsert;\n\t return STOP_SEARCHING;\n\t }\n\t }\n\t }\n\t });\n\t if (foundNode != null) {\n\t return;\n\t }\n\t }\n\t currentNode = nodeToInsert;\n\t while (true) {\n\t if (currentNode === this._root) {\n\t currentNode._color = BLACK;\n\t break;\n\t }\n\t if (currentNode._parent._color === BLACK) {\n\t break;\n\t }\n\t if (((_ref = _uncleOf(currentNode)) != null ? _ref._color : void 0) === RED) {\n\t currentNode._parent._color = BLACK;\n\t _uncleOf(currentNode)._color = BLACK;\n\t _grandParentOf(currentNode)._color = RED;\n\t currentNode = _grandParentOf(currentNode);\n\t continue;\n\t }\n\t if (!_isLeft(currentNode) && _isLeft(currentNode._parent)) {\n\t this._rotateLeft(currentNode._parent);\n\t currentNode = currentNode._left;\n\t } else if (_isLeft(currentNode) && !_isLeft(currentNode._parent)) {\n\t this._rotateRight(currentNode._parent);\n\t currentNode = currentNode._right;\n\t }\n\t currentNode._parent._color = BLACK;\n\t _grandParentOf(currentNode)._color = RED;\n\t if (_isLeft(currentNode)) {\n\t this._rotateRight(_grandParentOf(currentNode));\n\t } else {\n\t this._rotateLeft(_grandParentOf(currentNode));\n\t }\n\t break;\n\t }\n\t return value;\n\t };\n\n\t RedBlackTree.prototype.has = function(value) {\n\t /*\n\t _Returns:_ true or false.\n\t */\n\n\t var foundNode;\n\t foundNode = _findNode(this._root, function(node) {\n\t if (value === node.value) {\n\t return NODE_FOUND;\n\t } else if (value < node.value) {\n\t return NODE_TOO_BIG;\n\t } else {\n\t return NODE_TOO_SMALL;\n\t }\n\t });\n\t if (foundNode) {\n\t return true;\n\t } else {\n\t return false;\n\t }\n\t };\n\n\t RedBlackTree.prototype.peekMin = function() {\n\t /*\n\t Check the minimum value without removing it.\n\t \n\t _Returns:_ the minimum value.\n\t */\n\n\t var _ref;\n\t return (_ref = _peekMinNode(this._root)) != null ? _ref.value : void 0;\n\t };\n\n\t RedBlackTree.prototype.peekMax = function() {\n\t /*\n\t Check the maximum value without removing it.\n\t \n\t _Returns:_ the maximum value.\n\t */\n\n\t var _ref;\n\t return (_ref = _peekMaxNode(this._root)) != null ? _ref.value : void 0;\n\t };\n\n\t RedBlackTree.prototype.remove = function(value) {\n\t /*\n\t _Returns:_ the value removed, or undefined if the value's not found.\n\t */\n\n\t var foundNode;\n\t foundNode = _findNode(this._root, function(node) {\n\t if (value === node.value) {\n\t return NODE_FOUND;\n\t } else if (value < node.value) {\n\t return NODE_TOO_BIG;\n\t } else {\n\t return NODE_TOO_SMALL;\n\t }\n\t });\n\t if (!foundNode) {\n\t return;\n\t }\n\t this._removeNode(this._root, foundNode);\n\t this.size--;\n\t return value;\n\t };\n\n\t RedBlackTree.prototype.removeMin = function() {\n\t /*\n\t _Returns:_ smallest item removed, or undefined if tree's empty.\n\t */\n\n\t var nodeToRemove, valueToReturn;\n\t nodeToRemove = _peekMinNode(this._root);\n\t if (!nodeToRemove) {\n\t return;\n\t }\n\t valueToReturn = nodeToRemove.value;\n\t this._removeNode(this._root, nodeToRemove);\n\t return valueToReturn;\n\t };\n\n\t RedBlackTree.prototype.removeMax = function() {\n\t /*\n\t _Returns:_ biggest item removed, or undefined if tree's empty.\n\t */\n\n\t var nodeToRemove, valueToReturn;\n\t nodeToRemove = _peekMaxNode(this._root);\n\t if (!nodeToRemove) {\n\t return;\n\t }\n\t valueToReturn = nodeToRemove.value;\n\t this._removeNode(this._root, nodeToRemove);\n\t return valueToReturn;\n\t };\n\n\t RedBlackTree.prototype._removeNode = function(root, node) {\n\t var sibling, successor, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;\n\t if (node._left && node._right) {\n\t successor = _peekMinNode(node._right);\n\t node.value = successor.value;\n\t node = successor;\n\t }\n\t successor = node._left || node._right;\n\t if (!successor) {\n\t successor = {\n\t color: BLACK,\n\t _right: void 0,\n\t _left: void 0,\n\t isLeaf: true\n\t };\n\t }\n\t successor._parent = node._parent;\n\t if ((_ref = node._parent) != null) {\n\t _ref[_leftOrRight(node)] = successor;\n\t }\n\t if (node._color === BLACK) {\n\t if (successor._color === RED) {\n\t successor._color = BLACK;\n\t if (!successor._parent) {\n\t this._root = successor;\n\t }\n\t } else {\n\t while (true) {\n\t if (!successor._parent) {\n\t if (!successor.isLeaf) {\n\t this._root = successor;\n\t } else {\n\t this._root = void 0;\n\t }\n\t break;\n\t }\n\t sibling = _siblingOf(successor);\n\t if ((sibling != null ? sibling._color : void 0) === RED) {\n\t successor._parent._color = RED;\n\t sibling._color = BLACK;\n\t if (_isLeft(successor)) {\n\t this._rotateLeft(successor._parent);\n\t } else {\n\t this._rotateRight(successor._parent);\n\t }\n\t }\n\t sibling = _siblingOf(successor);\n\t if (successor._parent._color === BLACK && (!sibling || (sibling._color === BLACK && (!sibling._left || sibling._left._color === BLACK) && (!sibling._right || sibling._right._color === BLACK)))) {\n\t if (sibling != null) {\n\t sibling._color = RED;\n\t }\n\t if (successor.isLeaf) {\n\t successor._parent[_leftOrRight(successor)] = void 0;\n\t }\n\t successor = successor._parent;\n\t continue;\n\t }\n\t if (successor._parent._color === RED && (!sibling || (sibling._color === BLACK && (!sibling._left || ((_ref1 = sibling._left) != null ? _ref1._color : void 0) === BLACK) && (!sibling._right || ((_ref2 = sibling._right) != null ? _ref2._color : void 0) === BLACK)))) {\n\t if (sibling != null) {\n\t sibling._color = RED;\n\t }\n\t successor._parent._color = BLACK;\n\t break;\n\t }\n\t if ((sibling != null ? sibling._color : void 0) === BLACK) {\n\t if (_isLeft(successor) && (!sibling._right || sibling._right._color === BLACK) && ((_ref3 = sibling._left) != null ? _ref3._color : void 0) === RED) {\n\t sibling._color = RED;\n\t if ((_ref4 = sibling._left) != null) {\n\t _ref4._color = BLACK;\n\t }\n\t this._rotateRight(sibling);\n\t } else if (!_isLeft(successor) && (!sibling._left || sibling._left._color === BLACK) && ((_ref5 = sibling._right) != null ? _ref5._color : void 0) === RED) {\n\t sibling._color = RED;\n\t if ((_ref6 = sibling._right) != null) {\n\t _ref6._color = BLACK;\n\t }\n\t this._rotateLeft(sibling);\n\t }\n\t break;\n\t }\n\t sibling = _siblingOf(successor);\n\t sibling._color = successor._parent._color;\n\t if (_isLeft(successor)) {\n\t sibling._right._color = BLACK;\n\t this._rotateRight(successor._parent);\n\t } else {\n\t sibling._left._color = BLACK;\n\t this._rotateLeft(successor._parent);\n\t }\n\t }\n\t }\n\t }\n\t if (successor.isLeaf) {\n\t return (_ref7 = successor._parent) != null ? _ref7[_leftOrRight(successor)] = void 0 : void 0;\n\t }\n\t };\n\n\t RedBlackTree.prototype._rotateLeft = function(node) {\n\t var _ref, _ref1;\n\t if ((_ref = node._parent) != null) {\n\t _ref[_leftOrRight(node)] = node._right;\n\t }\n\t node._right._parent = node._parent;\n\t node._parent = node._right;\n\t node._right = node._right._left;\n\t node._parent._left = node;\n\t if ((_ref1 = node._right) != null) {\n\t _ref1._parent = node;\n\t }\n\t if (node._parent._parent == null) {\n\t return this._root = node._parent;\n\t }\n\t };\n\n\t RedBlackTree.prototype._rotateRight = function(node) {\n\t var _ref, _ref1;\n\t if ((_ref = node._parent) != null) {\n\t _ref[_leftOrRight(node)] = node._left;\n\t }\n\t node._left._parent = node._parent;\n\t node._parent = node._left;\n\t node._left = node._left._right;\n\t node._parent._right = node;\n\t if ((_ref1 = node._left) != null) {\n\t _ref1._parent = node;\n\t }\n\t if (node._parent._parent == null) {\n\t return this._root = node._parent;\n\t }\n\t };\n\n\t return RedBlackTree;\n\n\t })();\n\n\t _isLeft = function(node) {\n\t return node === node._parent._left;\n\t };\n\n\t _leftOrRight = function(node) {\n\t if (_isLeft(node)) {\n\t return '_left';\n\t } else {\n\t return '_right';\n\t }\n\t };\n\n\t _findNode = function(startingNode, comparator) {\n\t var comparisonResult, currentNode, foundNode;\n\t currentNode = startingNode;\n\t foundNode = void 0;\n\t while (currentNode) {\n\t comparisonResult = comparator(currentNode);\n\t if (comparisonResult === NODE_FOUND) {\n\t foundNode = currentNode;\n\t break;\n\t }\n\t if (comparisonResult === NODE_TOO_BIG) {\n\t currentNode = currentNode._left;\n\t } else if (comparisonResult === NODE_TOO_SMALL) {\n\t currentNode = currentNode._right;\n\t } else if (comparisonResult === STOP_SEARCHING) {\n\t break;\n\t }\n\t }\n\t return foundNode;\n\t };\n\n\t _peekMinNode = function(startingNode) {\n\t return _findNode(startingNode, function(node) {\n\t if (node._left) {\n\t return NODE_TOO_BIG;\n\t } else {\n\t return NODE_FOUND;\n\t }\n\t });\n\t };\n\n\t _peekMaxNode = function(startingNode) {\n\t return _findNode(startingNode, function(node) {\n\t if (node._right) {\n\t return NODE_TOO_SMALL;\n\t } else {\n\t return NODE_FOUND;\n\t }\n\t });\n\t };\n\n\t _grandParentOf = function(node) {\n\t var _ref;\n\t return (_ref = node._parent) != null ? _ref._parent : void 0;\n\t };\n\n\t _uncleOf = function(node) {\n\t if (!_grandParentOf(node)) {\n\t return;\n\t }\n\t if (_isLeft(node._parent)) {\n\t return _grandParentOf(node)._right;\n\t } else {\n\t return _grandParentOf(node)._left;\n\t }\n\t };\n\n\t _siblingOf = function(node) {\n\t if (_isLeft(node)) {\n\t return node._parent._right;\n\t } else {\n\t return node._parent._left;\n\t }\n\t };\n\n\t module.exports = RedBlackTree;\n\n\t}).call(this);\n\n\n/***/ },\n/* 8 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/*\n\tGood for fast insertion/removal/lookup of strings.\n\n\t## Overview example:\n\n\t```js\n\tvar trie = new Trie(['bear', 'beer']);\n\ttrie.add('hello'); // => 'hello'\n\ttrie.add('helloha!'); // => 'helloha!'\n\ttrie.has('bears'); // => false\n\ttrie.longestPrefixOf('beatrice'); // => 'bea'\n\ttrie.wordsWithPrefix('hel'); // => ['hello', 'helloha!']\n\ttrie.remove('beers'); // => undefined. 'beer' still exists\n\ttrie.remove('Beer') // => undefined. Case-sensitive\n\ttrie.remove('beer') // => 'beer'. Removed\n\t```\n\n\t## Properties:\n\n\t- size: The total number of words.\n\t*/\n\n\n\t(function() {\n\t var Queue, Trie, WORD_END, _hasAtLeastNChildren,\n\t __hasProp = {}.hasOwnProperty;\n\n\t Queue = __webpack_require__(6);\n\n\t WORD_END = 'end';\n\n\t Trie = (function() {\n\t function Trie(words) {\n\t var word, _i, _len;\n\t if (words == null) {\n\t words = [];\n\t }\n\t /*\n\t Pass an optional array of strings to be inserted initially.\n\t */\n\n\t this._root = {};\n\t this.size = 0;\n\t for (_i = 0, _len = words.length; _i < _len; _i++) {\n\t word = words[_i];\n\t this.add(word);\n\t }\n\t }\n\n\t Trie.prototype.add = function(word) {\n\t /*\n\t Add a whole string to the trie.\n\t \n\t _Returns:_ the word added. Will return undefined (without adding the value)\n\t if the word passed is null or undefined.\n\t */\n\n\t var currentNode, letter, _i, _len;\n\t if (word == null) {\n\t return;\n\t }\n\t this.size++;\n\t currentNode = this._root;\n\t for (_i = 0, _len = word.length; _i < _len; _i++) {\n\t letter = word[_i];\n\t if (currentNode[letter] == null) {\n\t currentNode[letter] = {};\n\t }\n\t currentNode = currentNode[letter];\n\t }\n\t currentNode[WORD_END] = true;\n\t return word;\n\t };\n\n\t Trie.prototype.has = function(word) {\n\t /*\n\t __Returns:_ true or false.\n\t */\n\n\t var currentNode, letter, _i, _len;\n\t if (word == null) {\n\t return false;\n\t }\n\t currentNode = this._root;\n\t for (_i = 0, _len = word.length; _i < _len; _i++) {\n\t letter = word[_i];\n\t if (currentNode[letter] == null) {\n\t return false;\n\t }\n\t currentNode = currentNode[letter];\n\t }\n\t if (currentNode[WORD_END]) {\n\t return true;\n\t } else {\n\t return false;\n\t }\n\t };\n\n\t Trie.prototype.longestPrefixOf = function(word) {\n\t /*\n\t Find all words containing the prefix. The word itself counts as a prefix.\n\t \n\t ```js\n\t var trie = new Trie;\n\t trie.add('hello');\n\t trie.longestPrefixOf('he'); // 'he'\n\t trie.longestPrefixOf('hello'); // 'hello'\n\t trie.longestPrefixOf('helloha!'); // 'hello'\n\t ```\n\t \n\t _Returns:_ the prefix string, or empty string if no prefix found.\n\t */\n\n\t var currentNode, letter, prefix, _i, _len;\n\t if (word == null) {\n\t return '';\n\t }\n\t currentNode = this._root;\n\t prefix = '';\n\t for (_i = 0, _len = word.length; _i < _len; _i++) {\n\t letter = word[_i];\n\t if (currentNode[letter] == null) {\n\t break;\n\t }\n\t prefix += letter;\n\t currentNode = currentNode[letter];\n\t }\n\t return prefix;\n\t };\n\n\t Trie.prototype.wordsWithPrefix = function(prefix) {\n\t /*\n\t Find all words containing the prefix. The word itself counts as a prefix.\n\t **Watch out for edge cases.**\n\t \n\t ```js\n\t var trie = new Trie;\n\t trie.wordsWithPrefix(''); // []. Check later case below.\n\t trie.add('');\n\t trie.wordsWithPrefix(''); // ['']\n\t trie.add('he');\n\t trie.add('hello');\n\t trie.add('hell');\n\t trie.add('bear');\n\t trie.add('z');\n\t trie.add('zebra');\n\t trie.wordsWithPrefix('hel'); // ['hell', 'hello']\n\t ```\n\t \n\t _Returns:_ an array of strings, or empty array if no word found.\n\t */\n\n\t var accumulatedLetters, currentNode, letter, node, queue, subNode, words, _i, _len, _ref;\n\t if (prefix == null) {\n\t return [];\n\t }\n\t (prefix != null) || (prefix = '');\n\t words = [];\n\t currentNode = this._root;\n\t for (_i = 0, _len = prefix.length; _i < _len; _i++) {\n\t letter = prefix[_i];\n\t currentNode = currentNode[letter];\n\t if (currentNode == null) {\n\t return [];\n\t }\n\t }\n\t queue = new Queue();\n\t queue.enqueue([currentNode, '']);\n\t while (queue.size !== 0) {\n\t _ref = queue.dequeue(), node = _ref[0], accumulatedLetters = _ref[1];\n\t if (node[WORD_END]) {\n\t words.push(prefix + accumulatedLetters);\n\t }\n\t for (letter in node) {\n\t if (!__hasProp.call(node, letter)) continue;\n\t subNode = node[letter];\n\t queue.enqueue([subNode, accumulatedLetters + letter]);\n\t }\n\t }\n\t return words;\n\t };\n\n\t Trie.prototype.remove = function(word) {\n\t /*\n\t _Returns:_ the string removed, or undefined if the word in its whole doesn't\n\t exist. **Note:** this means removing `beers` when only `beer` exists will\n\t return undefined and conserve `beer`.\n\t */\n\n\t var currentNode, i, letter, prefix, _i, _j, _len, _ref;\n\t if (word == null) {\n\t return;\n\t }\n\t currentNode = this._root;\n\t prefix = [];\n\t for (_i = 0, _len = word.length; _i < _len; _i++) {\n\t letter = word[_i];\n\t if (currentNode[letter] == null) {\n\t return;\n\t }\n\t currentNode = currentNode[letter];\n\t prefix.push([letter, currentNode]);\n\t }\n\t if (!currentNode[WORD_END]) {\n\t return;\n\t }\n\t this.size--;\n\t delete currentNode[WORD_END];\n\t if (_hasAtLeastNChildren(currentNode, 1)) {\n\t return word;\n\t }\n\t for (i = _j = _ref = prefix.length - 1; _ref <= 1 ? _j <= 1 : _j >= 1; i = _ref <= 1 ? ++_j : --_j) {\n\t if (!_hasAtLeastNChildren(prefix[i][1], 1)) {\n\t delete prefix[i - 1][1][prefix[i][0]];\n\t } else {\n\t break;\n\t }\n\t }\n\t if (!_hasAtLeastNChildren(this._root[prefix[0][0]], 1)) {\n\t delete this._root[prefix[0][0]];\n\t }\n\t return word;\n\t };\n\n\t return Trie;\n\n\t })();\n\n\t _hasAtLeastNChildren = function(node, n) {\n\t var child, childCount;\n\t if (n === 0) {\n\t return true;\n\t }\n\t childCount = 0;\n\t for (child in node) {\n\t if (!__hasProp.call(node, child)) continue;\n\t childCount++;\n\t if (childCount >= n) {\n\t return true;\n\t }\n\t }\n\t return false;\n\t };\n\n\t module.exports = Trie;\n\n\t}).call(this);\n\n\n/***/ }\n/******/ ]);;angular.module('uiGmapgoogle-maps.wrapped')\n.service('uiGmapMarkerSpiderfier', [ 'uiGmapGoogleMapApi', function(GoogleMapApi) {\n var self = this;\n /* istanbul ignore next */\n +function(){\n \n/** @preserve OverlappingMarkerSpiderfier\nhttps://github.com/jawj/OverlappingMarkerSpiderfier\nCopyright (c) 2011 - 2013 George MacKerron\nReleased under the MIT licence: http://opensource.org/licenses/mit-license\nNote: The Google Maps API v3 must be included *before* this code\n */\nvar hasProp = {}.hasOwnProperty,\n slice = [].slice;\n\nthis['OverlappingMarkerSpiderfier'] = (function() {\n var ge, gm, j, lcH, lcU, len, mt, p, ref, twoPi, x;\n\n p = _Class.prototype;\n\n ref = [_Class, p];\n for (j = 0, len = ref.length; j < len; j++) {\n x = ref[j];\n x['VERSION'] = '0.3.3';\n }\n\n gm = void 0;\n\n ge = void 0;\n\n mt = void 0;\n\n twoPi = Math.PI * 2;\n\n p['keepSpiderfied'] = false;\n\n p['markersWontHide'] = false;\n\n p['markersWontMove'] = false;\n\n p['nearbyDistance'] = 20;\n\n p['circleSpiralSwitchover'] = 9;\n\n p['circleFootSeparation'] = 23;\n\n p['circleStartAngle'] = twoPi / 12;\n\n p['spiralFootSeparation'] = 26;\n\n p['spiralLengthStart'] = 11;\n\n p['spiralLengthFactor'] = 4;\n\n p['spiderfiedZIndex'] = 1000;\n\n p['usualLegZIndex'] = 10;\n\n p['highlightedLegZIndex'] = 20;\n\n p['event'] = 'click';\n\n p['minZoomLevel'] = false;\n\n p['legWeight'] = 1.5;\n\n p['legColors'] = {\n 'usual': {},\n 'highlighted': {}\n };\n\n lcU = p['legColors']['usual'];\n\n lcH = p['legColors']['highlighted'];\n\n _Class['initializeGoogleMaps'] = function(google) {\n gm = google.maps;\n ge = gm.event;\n mt = gm.MapTypeId;\n lcU[mt.HYBRID] = lcU[mt.SATELLITE] = '#fff';\n lcH[mt.HYBRID] = lcH[mt.SATELLITE] = '#f00';\n lcU[mt.TERRAIN] = lcU[mt.ROADMAP] = '#444';\n lcH[mt.TERRAIN] = lcH[mt.ROADMAP] = '#f00';\n this.ProjHelper = function(map) {\n return this.setMap(map);\n };\n this.ProjHelper.prototype = new gm.OverlayView();\n return this.ProjHelper.prototype['draw'] = function() {};\n };\n\n function _Class(map1, opts) {\n var e, k, l, len1, ref1, v;\n this.map = map1;\n if (opts == null) {\n opts = {};\n }\n for (k in opts) {\n if (!hasProp.call(opts, k)) continue;\n v = opts[k];\n this[k] = v;\n }\n this.projHelper = new this.constructor.ProjHelper(this.map);\n this.initMarkerArrays();\n this.listeners = {};\n ref1 = ['click', 'zoom_changed', 'maptypeid_changed'];\n for (l = 0, len1 = ref1.length; l < len1; l++) {\n e = ref1[l];\n ge.addListener(this.map, e, (function(_this) {\n return function() {\n return _this['unspiderfy']();\n };\n })(this));\n }\n }\n\n p.initMarkerArrays = function() {\n this.markers = [];\n return this.markerListenerRefs = [];\n };\n\n p['addMarker'] = function(marker) {\n var listenerRefs;\n if (marker['_oms'] != null) {\n return this;\n }\n marker['_oms'] = true;\n listenerRefs = [\n ge.addListener(marker, this['event'], (function(_this) {\n return function(event) {\n return _this.spiderListener(marker, event);\n };\n })(this))\n ];\n if (!this['markersWontHide']) {\n listenerRefs.push(ge.addListener(marker, 'visible_changed', (function(_this) {\n return function() {\n return _this.markerChangeListener(marker, false);\n };\n })(this)));\n }\n if (!this['markersWontMove']) {\n listenerRefs.push(ge.addListener(marker, 'position_changed', (function(_this) {\n return function() {\n return _this.markerChangeListener(marker, true);\n };\n })(this)));\n }\n this.markerListenerRefs.push(listenerRefs);\n this.markers.push(marker);\n return this;\n };\n\n p.markerChangeListener = function(marker, positionChanged) {\n if ((marker['_omsData'] != null) && (positionChanged || !marker.getVisible()) && !((this.spiderfying != null) || (this.unspiderfying != null))) {\n return this['unspiderfy'](positionChanged ? marker : null);\n }\n };\n\n p['getMarkers'] = function() {\n return this.markers.slice(0);\n };\n\n p['removeMarker'] = function(marker) {\n var i, l, len1, listenerRef, listenerRefs;\n if (marker['_omsData'] != null) {\n this['unspiderfy']();\n }\n i = this.arrIndexOf(this.markers, marker);\n if (i < 0) {\n return this;\n }\n listenerRefs = this.markerListenerRefs.splice(i, 1)[0];\n for (l = 0, len1 = listenerRefs.length; l < len1; l++) {\n listenerRef = listenerRefs[l];\n ge.removeListener(listenerRef);\n }\n delete marker['_oms'];\n this.markers.splice(i, 1);\n return this;\n };\n\n p['clearMarkers'] = function() {\n var i, l, len1, len2, listenerRef, listenerRefs, marker, n, ref1;\n this['unspiderfy']();\n ref1 = this.markers;\n for (i = l = 0, len1 = ref1.length; l < len1; i = ++l) {\n marker = ref1[i];\n listenerRefs = this.markerListenerRefs[i];\n for (n = 0, len2 = listenerRefs.length; n < len2; n++) {\n listenerRef = listenerRefs[n];\n ge.removeListener(listenerRef);\n }\n delete marker['_oms'];\n }\n this.initMarkerArrays();\n return this;\n };\n\n p['addListener'] = function(event, func) {\n var base;\n ((base = this.listeners)[event] != null ? base[event] : base[event] = []).push(func);\n return this;\n };\n\n p['removeListener'] = function(event, func) {\n var i;\n i = this.arrIndexOf(this.listeners[event], func);\n if (!(i < 0)) {\n this.listeners[event].splice(i, 1);\n }\n return this;\n };\n\n p['clearListeners'] = function(event) {\n this.listeners[event] = [];\n return this;\n };\n\n p.trigger = function() {\n var args, event, func, l, len1, ref1, ref2, results;\n event = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];\n ref2 = (ref1 = this.listeners[event]) != null ? ref1 : [];\n results = [];\n for (l = 0, len1 = ref2.length; l < len1; l++) {\n func = ref2[l];\n results.push(func.apply(null, args));\n }\n return results;\n };\n\n p.generatePtsCircle = function(count, centerPt) {\n var angle, angleStep, circumference, i, l, legLength, ref1, results;\n circumference = this['circleFootSeparation'] * (2 + count);\n legLength = circumference / twoPi;\n angleStep = twoPi / count;\n results = [];\n for (i = l = 0, ref1 = count; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {\n angle = this['circleStartAngle'] + i * angleStep;\n results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle)));\n }\n return results;\n };\n\n p.generatePtsSpiral = function(count, centerPt) {\n var angle, i, l, legLength, pt, ref1, results;\n legLength = this['spiralLengthStart'];\n angle = 0;\n results = [];\n for (i = l = 0, ref1 = count; 0 <= ref1 ? l < ref1 : l > ref1; i = 0 <= ref1 ? ++l : --l) {\n angle += this['spiralFootSeparation'] / legLength + i * 0.0005;\n pt = new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));\n legLength += twoPi * this['spiralLengthFactor'] / angle;\n results.push(pt);\n }\n return results;\n };\n\n p.spiderListener = function(marker, event) {\n var $this, clear, l, len1, m, mPt, markerPt, markerSpiderfied, nDist, nearbyMarkerData, nonNearbyMarkers, pxSq, ref1;\n markerSpiderfied = marker['_omsData'] != null;\n if (!(markerSpiderfied && this['keepSpiderfied'])) {\n if (this['event'] === 'mouseover') {\n $this = this;\n clear = function() {\n return $this['unspiderfy']();\n };\n window.clearTimeout(p.timeout);\n p.timeout = setTimeout(clear, 3000);\n } else {\n this['unspiderfy']();\n }\n }\n if (markerSpiderfied || this.map.getStreetView().getVisible() || this.map.getMapTypeId() === 'GoogleEarthAPI') {\n return this.trigger('click', marker, event);\n } else {\n nearbyMarkerData = [];\n nonNearbyMarkers = [];\n nDist = this['nearbyDistance'];\n pxSq = nDist * nDist;\n markerPt = this.llToPt(marker.position);\n ref1 = this.markers;\n for (l = 0, len1 = ref1.length; l < len1; l++) {\n m = ref1[l];\n if (!((m.map != null) && m.getVisible())) {\n continue;\n }\n mPt = this.llToPt(m.position);\n if (this.ptDistanceSq(mPt, markerPt) < pxSq) {\n nearbyMarkerData.push({\n marker: m,\n markerPt: mPt\n });\n } else {\n nonNearbyMarkers.push(m);\n }\n }\n if (nearbyMarkerData.length === 1) {\n return this.trigger('click', marker, event);\n } else {\n return this.spiderfy(nearbyMarkerData, nonNearbyMarkers);\n }\n }\n };\n\n p['markersNearMarker'] = function(marker, firstOnly) {\n var l, len1, m, mPt, markerPt, markers, nDist, pxSq, ref1, ref2, ref3;\n if (firstOnly == null) {\n firstOnly = false;\n }\n if (this.projHelper.getProjection() == null) {\n throw \"Must wait for 'idle' event on map before calling markersNearMarker\";\n }\n nDist = this['nearbyDistance'];\n pxSq = nDist * nDist;\n markerPt = this.llToPt(marker.position);\n markers = [];\n ref1 = this.markers;\n for (l = 0, len1 = ref1.length; l < len1; l++) {\n m = ref1[l];\n if (m === marker || (m.map == null) || !m.getVisible()) {\n continue;\n }\n mPt = this.llToPt((ref2 = (ref3 = m['_omsData']) != null ? ref3.usualPosition : void 0) != null ? ref2 : m.position);\n if (this.ptDistanceSq(mPt, markerPt) < pxSq) {\n markers.push(m);\n if (firstOnly) {\n break;\n }\n }\n }\n return markers;\n };\n\n p['markersNearAnyOtherMarker'] = function() {\n var i, i1, i2, l, len1, len2, len3, m, m1, m1Data, m2, m2Data, mData, n, nDist, pxSq, q, ref1, ref2, ref3, results;\n if (this.projHelper.getProjection() == null) {\n throw \"Must wait for 'idle' event on map before calling markersNearAnyOtherMarker\";\n }\n nDist = this['nearbyDistance'];\n pxSq = nDist * nDist;\n mData = (function() {\n var l, len1, ref1, ref2, ref3, results;\n ref1 = this.markers;\n results = [];\n for (l = 0, len1 = ref1.length; l < len1; l++) {\n m = ref1[l];\n results.push({\n pt: this.llToPt((ref2 = (ref3 = m['_omsData']) != null ? ref3.usualPosition : void 0) != null ? ref2 : m.position),\n willSpiderfy: false\n });\n }\n return results;\n }).call(this);\n ref1 = this.markers;\n for (i1 = l = 0, len1 = ref1.length; l < len1; i1 = ++l) {\n m1 = ref1[i1];\n if (!((m1.map != null) && m1.getVisible())) {\n continue;\n }\n m1Data = mData[i1];\n if (m1Data.willSpiderfy) {\n continue;\n }\n ref2 = this.markers;\n for (i2 = n = 0, len2 = ref2.length; n < len2; i2 = ++n) {\n m2 = ref2[i2];\n if (i2 === i1) {\n continue;\n }\n if (!((m2.map != null) && m2.getVisible())) {\n continue;\n }\n m2Data = mData[i2];\n if (i2 < i1 && !m2Data.willSpiderfy) {\n continue;\n }\n if (this.ptDistanceSq(m1Data.pt, m2Data.pt) < pxSq) {\n m1Data.willSpiderfy = m2Data.willSpiderfy = true;\n break;\n }\n }\n }\n ref3 = this.markers;\n results = [];\n for (i = q = 0, len3 = ref3.length; q < len3; i = ++q) {\n m = ref3[i];\n if (mData[i].willSpiderfy) {\n results.push(m);\n }\n }\n return results;\n };\n\n p.makeHighlightListenerFuncs = function(marker) {\n return {\n highlight: (function(_this) {\n return function() {\n return marker['_omsData'].leg.setOptions({\n strokeColor: _this['legColors']['highlighted'][_this.map.mapTypeId],\n zIndex: _this['highlightedLegZIndex']\n });\n };\n })(this),\n unhighlight: (function(_this) {\n return function() {\n return marker['_omsData'].leg.setOptions({\n strokeColor: _this['legColors']['usual'][_this.map.mapTypeId],\n zIndex: _this['usualLegZIndex']\n });\n };\n })(this)\n };\n };\n\n p.spiderfy = function(markerData, nonNearbyMarkers) {\n var bodyPt, footLl, footPt, footPts, highlightListenerFuncs, leg, marker, md, nearestMarkerDatum, numFeet, spiderfiedMarkers;\n if (this['minZoomLevel'] && this.map.getZoom() < this['minZoomLevel']) {\n return false;\n }\n this.spiderfying = true;\n numFeet = markerData.length;\n bodyPt = this.ptAverage((function() {\n var l, len1, results;\n results = [];\n for (l = 0, len1 = markerData.length; l < len1; l++) {\n md = markerData[l];\n results.push(md.markerPt);\n }\n return results;\n })());\n footPts = numFeet >= this['circleSpiralSwitchover'] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt);\n spiderfiedMarkers = (function() {\n var l, len1, results;\n results = [];\n for (l = 0, len1 = footPts.length; l < len1; l++) {\n footPt = footPts[l];\n footLl = this.ptToLl(footPt);\n nearestMarkerDatum = this.minExtract(markerData, (function(_this) {\n return function(md) {\n return _this.ptDistanceSq(md.markerPt, footPt);\n };\n })(this));\n marker = nearestMarkerDatum.marker;\n leg = new gm.Polyline({\n map: this.map,\n path: [marker.position, footLl],\n strokeColor: this['legColors']['usual'][this.map.mapTypeId],\n strokeWeight: this['legWeight'],\n zIndex: this['usualLegZIndex']\n });\n marker['_omsData'] = {\n usualPosition: marker.position,\n leg: leg\n };\n if (this['legColors']['highlighted'][this.map.mapTypeId] !== this['legColors']['usual'][this.map.mapTypeId]) {\n highlightListenerFuncs = this.makeHighlightListenerFuncs(marker);\n marker['_omsData'].hightlightListeners = {\n highlight: ge.addListener(marker, 'mouseover', highlightListenerFuncs.highlight),\n unhighlight: ge.addListener(marker, 'mouseout', highlightListenerFuncs.unhighlight)\n };\n }\n marker.setPosition(footLl);\n marker.setZIndex(Math.round(this['spiderfiedZIndex'] + footPt.y));\n results.push(marker);\n }\n return results;\n }).call(this);\n delete this.spiderfying;\n this.spiderfied = true;\n return this.trigger('spiderfy', spiderfiedMarkers, nonNearbyMarkers);\n };\n\n p['unspiderfy'] = function(markerNotToMove) {\n var l, len1, listeners, marker, nonNearbyMarkers, ref1, unspiderfiedMarkers;\n if (markerNotToMove == null) {\n markerNotToMove = null;\n }\n if (this.spiderfied == null) {\n return this;\n }\n this.unspiderfying = true;\n unspiderfiedMarkers = [];\n nonNearbyMarkers = [];\n ref1 = this.markers;\n for (l = 0, len1 = ref1.length; l < len1; l++) {\n marker = ref1[l];\n if (marker['_omsData'] != null) {\n marker['_omsData'].leg.setMap(null);\n if (marker !== markerNotToMove) {\n marker.setPosition(marker['_omsData'].usualPosition);\n }\n marker.setZIndex(null);\n listeners = marker['_omsData'].hightlightListeners;\n if (listeners != null) {\n ge.removeListener(listeners.highlight);\n ge.removeListener(listeners.unhighlight);\n }\n delete marker['_omsData'];\n unspiderfiedMarkers.push(marker);\n } else {\n nonNearbyMarkers.push(marker);\n }\n }\n delete this.unspiderfying;\n delete this.spiderfied;\n this.trigger('unspiderfy', unspiderfiedMarkers, nonNearbyMarkers);\n return this;\n };\n\n p.ptDistanceSq = function(pt1, pt2) {\n var dx, dy;\n dx = pt1.x - pt2.x;\n dy = pt1.y - pt2.y;\n return dx * dx + dy * dy;\n };\n\n p.ptAverage = function(pts) {\n var l, len1, numPts, pt, sumX, sumY;\n sumX = sumY = 0;\n for (l = 0, len1 = pts.length; l < len1; l++) {\n pt = pts[l];\n sumX += pt.x;\n sumY += pt.y;\n }\n numPts = pts.length;\n return new gm.Point(sumX / numPts, sumY / numPts);\n };\n\n p.llToPt = function(ll) {\n return this.projHelper.getProjection().fromLatLngToDivPixel(ll);\n };\n\n p.ptToLl = function(pt) {\n return this.projHelper.getProjection().fromDivPixelToLatLng(pt);\n };\n\n p.minExtract = function(set, func) {\n var bestIndex, bestVal, index, item, l, len1, val;\n for (index = l = 0, len1 = set.length; l < len1; index = ++l) {\n item = set[index];\n val = func(item);\n if ((typeof bestIndex === \"undefined\" || bestIndex === null) || val < bestVal) {\n bestVal = val;\n bestIndex = index;\n }\n }\n return set.splice(bestIndex, 1)[0];\n };\n\n p.arrIndexOf = function(arr, obj) {\n var i, l, len1, o;\n if (arr.indexOf != null) {\n return arr.indexOf(obj);\n }\n for (i = l = 0, len1 = arr.length; l < len1; i = ++l) {\n o = arr[i];\n if (o === obj) {\n return i;\n }\n }\n return -1;\n };\n\n return _Class;\n\n})();\n\n }.apply(self);\n\n GoogleMapApi.then(function(){\n self.OverlappingMarkerSpiderfier.initializeGoogleMaps(window.google);\n });\n return this.OverlappingMarkerSpiderfier;\n}]);\n;/**\n * Performance overrides on MarkerClusterer custom to Angular Google Maps\n *\n * Created by Petr Bruna ccg1415 and Nick McCready on 7/13/14.\n */\nangular.module('uiGmapgoogle-maps.extensions')\n.service('uiGmapExtendMarkerClusterer',['uiGmapLodash', 'uiGmapPropMap', function (uiGmapLodash, PropMap) {\n return {\n init: _.once(function () {\n (function () {\n var __hasProp = {}.hasOwnProperty,\n __extends = function (child, parent) {\n for (var key in parent) {\n if (__hasProp.call(parent, key)) child[key] = parent[key];\n }\n function ctor() {\n this.constructor = child;\n }\n\n ctor.prototype = parent.prototype;\n child.prototype = new ctor();\n child.__super__ = parent.prototype;\n return child;\n };\n\n window.NgMapCluster = (function (_super) {\n __extends(NgMapCluster, _super);\n\n function NgMapCluster(opts) {\n NgMapCluster.__super__.constructor.call(this, opts);\n this.markers_ = new PropMap();\n }\n\n /**\n * Adds a marker to the cluster.\n *\n * @param {google.maps.Marker} marker The marker to be added.\n * @return {boolean} True if the marker was added.\n * @ignore\n */\n NgMapCluster.prototype.addMarker = function (marker) {\n var i;\n var mCount;\n var mz;\n\n if (this.isMarkerAlreadyAdded_(marker)) {\n var oldMarker = this.markers_.get(marker.key);\n if (oldMarker.getPosition().lat() == marker.getPosition().lat() && oldMarker.getPosition().lon() == marker.getPosition().lon()) //if nothing has changed\n return false;\n }\n\n if (!this.center_) {\n this.center_ = marker.getPosition();\n this.calculateBounds_();\n } else {\n if (this.averageCenter_) {\n var l = this.markers_.length + 1;\n var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l;\n var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l;\n this.center_ = new google.maps.LatLng(lat, lng);\n this.calculateBounds_();\n }\n }\n marker.isAdded = true;\n this.markers_.push(marker);\n\n mCount = this.markers_.length;\n mz = this.markerClusterer_.getMaxZoom();\n if (mz !== null && this.map_.getZoom() > mz) {\n // Zoomed in past max zoom, so show the marker.\n if (marker.getMap() !== this.map_) {\n marker.setMap(this.map_);\n }\n } else if (mCount < this.minClusterSize_) {\n // Min cluster size not reached so show the marker.\n if (marker.getMap() !== this.map_) {\n marker.setMap(this.map_);\n }\n } else if (mCount === this.minClusterSize_) {\n // Hide the markers that were showing.\n this.markers_.each(function (m) {\n m.setMap(null);\n });\n } else {\n marker.setMap(null);\n }\n\n //this.updateIcon_();\n return true;\n };\n\n /**\n * Determines if a marker has already been added to the cluster.\n *\n * @param {google.maps.Marker} marker The marker to check.\n * @return {boolean} True if the marker has already been added.\n */\n NgMapCluster.prototype.isMarkerAlreadyAdded_ = function (marker) {\n return uiGmapLodash.isNullOrUndefined(this.markers_.get(marker.key));\n };\n\n\n /**\n * Returns the bounds of the cluster.\n *\n * @return {google.maps.LatLngBounds} the cluster bounds.\n * @ignore\n */\n NgMapCluster.prototype.getBounds = function () {\n var i;\n var bounds = new google.maps.LatLngBounds(this.center_, this.center_);\n this.getMarkers().each(function(m){\n bounds.extend(m.getPosition());\n });\n return bounds;\n };\n\n\n /**\n * Removes the cluster from the map.\n *\n * @ignore\n */\n NgMapCluster.prototype.remove = function () {\n this.clusterIcon_.setMap(null);\n this.markers_ = new PropMap();\n delete this.markers_;\n };\n\n\n return NgMapCluster;\n\n })(Cluster);\n\n\n window.NgMapMarkerClusterer = (function (_super) {\n __extends(NgMapMarkerClusterer, _super);\n\n function NgMapMarkerClusterer(map, opt_markers, opt_options) {\n NgMapMarkerClusterer.__super__.constructor.call(this, map, opt_markers, opt_options);\n this.markers_ = new PropMap();\n }\n\n /**\n * Removes all clusters and markers from the map and also removes all markers\n * managed by the clusterer.\n */\n NgMapMarkerClusterer.prototype.clearMarkers = function () {\n this.resetViewport_(true);\n this.markers_ = new PropMap();\n };\n /**\n * Removes a marker and returns true if removed, false if not.\n *\n * @param {google.maps.Marker} marker The marker to remove\n * @return {boolean} Whether the marker was removed or not\n */\n NgMapMarkerClusterer.prototype.removeMarker_ = function (marker) {\n if (!this.markers_.get(marker.key)) {\n return false;\n }\n marker.setMap(null);\n this.markers_.remove(marker.key); // Remove the marker from the list of managed markers\n return true;\n };\n\n /**\n * Creates the clusters. This is done in batches to avoid timeout errors\n * in some browsers when there is a huge number of markers.\n *\n * @param {number} iFirst The index of the first marker in the batch of\n * markers to be added to clusters.\n */\n NgMapMarkerClusterer.prototype.createClusters_ = function (iFirst) {\n var i, marker;\n var mapBounds;\n var cMarkerClusterer = this;\n if (!this.ready_) {\n return;\n }\n\n // Cancel previous batch processing if we're working on the first batch:\n if (iFirst === 0) {\n /**\n * This event is fired when the MarkerClusterer
begins\n * clustering markers.\n * @name MarkerClusterer#clusteringbegin\n * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.\n * @event\n */\n google.maps.event.trigger(this, 'clusteringbegin', this);\n\n if (typeof this.timerRefStatic !== 'undefined') {\n clearTimeout(this.timerRefStatic);\n delete this.timerRefStatic;\n }\n }\n\n // Get our current map view bounds.\n // Create a new bounds object so we don't affect the map.\n //\n // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:\n if (this.getMap().getZoom() > 3) {\n mapBounds = new google.maps.LatLngBounds(this.getMap().getBounds().getSouthWest(),\n this.getMap().getBounds().getNorthEast());\n } else {\n mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));\n }\n var bounds = this.getExtendedBounds(mapBounds);\n\n var iLast = Math.min(iFirst + this.batchSize_, this.markers_.length);\n\n var _ms = this.markers_.values();\n for (i = iFirst; i < iLast; i++) {\n marker = _ms[i];\n if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {\n if (!this.ignoreHidden_ || (this.ignoreHidden_ && marker.getVisible())) {\n this.addToClosestCluster_(marker);\n }\n }\n }\n\n if (iLast < this.markers_.length) {\n this.timerRefStatic = setTimeout(function () {\n cMarkerClusterer.createClusters_(iLast);\n }, 0);\n } else {\n // custom addition by ui-gmap\n // update icon for all clusters\n for (i = 0; i < this.clusters_.length; i++) {\n this.clusters_[i].updateIcon_();\n }\n\n delete this.timerRefStatic;\n\n /**\n * This event is fired when the MarkerClusterer
stops\n * clustering markers.\n * @name MarkerClusterer#clusteringend\n * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.\n * @event\n */\n google.maps.event.trigger(this, 'clusteringend', this);\n }\n };\n\n /**\n * Adds a marker to a cluster, or creates a new cluster.\n *\n * @param {google.maps.Marker} marker The marker to add.\n */\n NgMapMarkerClusterer.prototype.addToClosestCluster_ = function (marker) {\n var i, d, cluster, center;\n var distance = 40000; // Some large number\n var clusterToAddTo = null;\n for (i = 0; i < this.clusters_.length; i++) {\n cluster = this.clusters_[i];\n center = cluster.getCenter();\n if (center) {\n d = this.distanceBetweenPoints_(center, marker.getPosition());\n if (d < distance) {\n distance = d;\n clusterToAddTo = cluster;\n }\n }\n }\n\n if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {\n clusterToAddTo.addMarker(marker);\n } else {\n cluster = new NgMapCluster(this);\n cluster.addMarker(marker);\n this.clusters_.push(cluster);\n }\n };\n\n /**\n * Redraws all the clusters.\n */\n NgMapMarkerClusterer.prototype.redraw_ = function () {\n this.createClusters_(0);\n };\n\n\n /**\n * Removes all clusters from the map. The markers are also removed from the map\n * if opt_hide
is set to true
.\n *\n * @param {boolean} [opt_hide] Set to true
to also remove the markers\n * from the map.\n */\n NgMapMarkerClusterer.prototype.resetViewport_ = function (opt_hide) {\n var i, marker;\n // Remove all the clusters\n for (i = 0; i < this.clusters_.length; i++) {\n this.clusters_[i].remove();\n }\n this.clusters_ = [];\n\n // Reset the markers to not be added and to be removed from the map.\n this.markers_.each(function (marker) {\n marker.isAdded = false;\n if (opt_hide) {\n marker.setMap(null);\n }\n });\n };\n\n /**\n * Extends an object's prototype by another's.\n *\n * @param {Object} obj1 The object to be extended.\n * @param {Object} obj2 The object to extend with.\n * @return {Object} The new extended object.\n * @ignore\n */\n NgMapMarkerClusterer.prototype.extend = function (obj1, obj2) {\n return (function (object) {\n var property;\n for (property in object.prototype) {\n if (property !== 'constructor')\n this.prototype[property] = object.prototype[property];\n }\n return this;\n }).apply(obj1, [obj2]);\n };\n ////////////////////////////////////////////////////////////////////////////////\n /*\n Other overrides relevant to MarkerClusterPlus\n */\n ////////////////////////////////////////////////////////////////////////////////\n /**\n * Positions and shows the icon.\n */\n ClusterIcon.prototype.show = function () {\n if (this.div_) {\n var img = \"\";\n // NOTE: values must be specified in px units\n var bp = this.backgroundPosition_.split(\" \");\n var spriteH = parseInt(bp[0].trim(), 10);\n var spriteV = parseInt(bp[1].trim(), 10);\n var pos = this.getPosFromLatLng_(this.center_);\n this.div_.style.cssText = this.createCss(pos);\n img = \"
\";\n this.div_.innerHTML = img + \"\" + this.sums_.text + \"
\";\n if (typeof this.sums_.title === \"undefined\" || this.sums_.title === \"\") {\n this.div_.title = this.cluster_.getMarkerClusterer().getTitle();\n } else {\n this.div_.title = this.sums_.title;\n }\n this.div_.style.display = \"\";\n }\n this.visible_ = true;\n };\n //END OTHER OVERRIDES\n ////////////////////////////////////////////////////////////////////////////////\n\n return NgMapMarkerClusterer;\n\n })(MarkerClusterer);\n }).call(this);\n })\n };\n}]);\n}( window,angular));","/* commonjs package manager support (eg componentjs) */\nif (typeof module !== \"undefined\" && typeof exports !== \"undefined\" && module.exports === exports){\n module.exports = 'angularSpinners';\n}\n\n(function (window, angular, undefined) {\nangular.module('angularSpinners', [])\n .factory('spinnerService', function () {\n var spinners = {};\n return {\n _register: function (data) {\n if (!data.hasOwnProperty('name')) {\n throw new Error(\"Spinner must specify a name when registering with the spinner service.\");\n }\n if (spinners.hasOwnProperty(data.name)) {\n throw new Error(\"A spinner with the name '\" + data.name + \"' has already been registered.\");\n }\n spinners[data.name] = data;\n },\n _unregister: function (name) {\n if (spinners.hasOwnProperty(name)) {\n delete spinners[name];\n }\n },\n _unregisterGroup: function (group) {\n for (var name in spinners) {\n if (spinners[name].group === group) {\n delete spinners[name];\n }\n }\n },\n _unregisterAll: function () {\n for (var name in spinners) {\n delete spinners[name];\n }\n },\n show: function (name) {\n var spinner = spinners[name];\n if (!spinner) {\n throw new Error(\"No spinner named '\" + name + \"' is registered.\");\n }\n spinner.show();\n },\n hide: function (name) {\n var spinner = spinners[name];\n if (!spinner) {\n throw new Error(\"No spinner named '\" + name + \"' is registered.\");\n }\n spinner.hide();\n },\n showGroup: function (group) {\n var groupExists = false;\n for (var name in spinners) {\n var spinner = spinners[name];\n if (spinner.group === group) {\n spinner.show();\n groupExists = true;\n }\n }\n if (!groupExists) {\n throw new Error(\"No spinners found with group '\" + group + \"'.\")\n }\n },\n hideGroup: function (group) {\n var groupExists = false;\n for (var name in spinners) {\n var spinner = spinners[name];\n if (spinner.group === group) {\n spinner.hide();\n groupExists = true;\n }\n }\n if (!groupExists) {\n throw new Error(\"No spinners found with group '\" + group + \"'.\")\n }\n },\n showAll: function () {\n for (var name in spinners) {\n spinners[name].show();\n }\n },\n hideAll: function () {\n for (var name in spinners) {\n spinners[name].hide();\n }\n }\n };\n });\n\nangular.module('angularSpinners')\n .directive('spinner', function () {\n return {\n restrict: 'EA',\n replace: true,\n transclude: true,\n scope: {\n name: '@?',\n group: '@?',\n show: '=?',\n imgSrc: '@?',\n register: '@?',\n onLoaded: '&?',\n onShow: '&?',\n onHide: '&?'\n },\n template: [\n '',\n '
![]()
',\n '
',\n '
'\n ].join(''),\n controller: [\"$scope\", \"spinnerService\", function ($scope, spinnerService) {\n\n // register should be true by default if not specified.\n if (!$scope.hasOwnProperty('register')) {\n $scope.register = true;\n } else {\n $scope.register = $scope.register.toLowerCase() === 'false' ? false : true;\n }\n\n // Declare a mini-API to hand off to our service so the service\n // doesn't have a direct reference to this directive's scope.\n var api = {\n name: $scope.name,\n group: $scope.group,\n show: function () {\n $scope.show = true;\n },\n hide: function () {\n $scope.show = false;\n },\n toggle: function () {\n $scope.show = !$scope.show;\n }\n };\n\n // Register this spinner with the spinner service.\n if ($scope.register === true) {\n spinnerService._register(api);\n }\n\n // If an onShow or onHide expression was provided, register a watcher\n // that will fire the relevant expression when show's value changes.\n if ($scope.onShow || $scope.onHide) {\n $scope.$watch('show', function (show) {\n if (show && $scope.onShow) {\n $scope.onShow({ spinnerService: spinnerService, spinnerApi: api });\n } else if (!show && $scope.onHide) {\n $scope.onHide({ spinnerService: spinnerService, spinnerApi: api });\n }\n });\n }\n\n // This spinner is good to go. Fire the onLoaded expression.\n if ($scope.onLoaded) {\n $scope.onLoaded({ spinnerService: spinnerService, spinnerApi: api });\n }\n\n // Unregister this spinner if the $destroy event is emitted on scope.\n $scope.$on('$destroy', function () {\n spinnerService._unregister($scope.name);\n });\n }]\n };\n });\n})(window, window.angular);","var angular = require('angular');\n\nmodule.exports = angular.module('fyn.configs', [])\n .service(\"$previousState\",\n function($rootScope, $state) {\n var previous = null;\n var memos = {};\n\n var lastPrevious = null;\n\n $rootScope.$on('$stateChangeSuccess', function() {\n document.body.scrollTop = document.documentElement.scrollTop = 0;\n });\n\n $rootScope.$on(\"$stateChangeStart\", function(evt, toState, toStateParams, fromState, fromStateParams) {\n lastPrevious = previous;\n previous = { state: fromState, params: fromStateParams };\n });\n\n $rootScope.$on(\"$stateChangeError\", function() {\n previous = lastPrevious;\n lastPrevious = null;\n });\n\n $rootScope.$on(\"$stateChangeSuccess\", function() {\n lastPrevious = null;\n });\n\n var $previousState = {\n get: function(memoName) {\n return memoName ? memos[memoName] : previous;\n },\n go: function(memoName) {\n var to = $previousState.get(memoName);\n return $state.go(to.state, to.params)\n },\n memo: function(memoName) {\n memos[memoName] = previous;\n }\n };\n\n return $previousState;\n })\n .run(function($previousState) {\n // Inject in .run so it can register $rootScope.$on.\n })\n .factory('localeHttpInterceptor',\n function($q, $location) {\n return {\n request: function(config){\n if(!config.params) config.params = {};\n config.params.locale = angular.locale;\n return config || $q.when(config);\n }\n }\n }\n ).config(function($httpProvider) {\n $httpProvider.interceptors.push('localeHttpInterceptor');\n })\n .config(function ($compileProvider){\n $compileProvider.debugInfoEnabled(true)\n }).config(function(uiGmapGoogleMapApiProvider) {\n uiGmapGoogleMapApiProvider.configure({\n key: 'AIzaSyDQ0XkWrssKgUKx0ISde_6IPSkPwFY2ClQ',\n v: '3', //defaults to latest 3.X anyhow\n libraries: 'geometry,visualization'\n });\n });\n","var angular = require('angular');\n\nrequire(\"angular-ui-router\");\n\nvar _ = require('lodash');\n\nmodule.exports = angular.module('fyn.routes', ['ui.router'])\n .config(function ($locationProvider, $urlRouterProvider, $stateProvider){\n\n $locationProvider.html5Mode({\n enabled: true\n });\n\n $urlRouterProvider.when('/en',function ($state) {\n window.location.reload();\n });\n $urlRouterProvider.when('/fr',function ($state) {\n window.location.reload();\n });\n $urlRouterProvider.when('/es',function ($state) {\n window.location.reload();\n });\n\n // $urlRouterProvider.when('/store',function ($state) {\n // if($state.current.name == 'fyn.store.genome') return false;\n // $state.go('fyn.store.genome', { location: 'replace' })\n // });\n\n $urlRouterProvider.otherwise('/');\n\n $stateProvider.state('accueil', {\n url: '/',\n templateUrl: '/templates/accueil.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/accueil-controller')\n });\n\n $stateProvider.state('fyn.dynamic', {\n url: '/dynamic',\n templateUrl: '/templates/fyn/pages/dynamic.html'\n });\n\n $stateProvider.state('fyn.static', {\n url: '/static',\n templateUrl: '/templates/fyn/pages/static.html'\n });\n\n $stateProvider.state('fyn', {\n abstract: true,\n url: '',\n templateUrl: '/templates/fyn/base.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/base-controller')\n });\n\n $stateProvider.state('fyn.resources', {\n url: '/resources',\n templateUrl: '/templates/fyn/pages/resources.html'\n });\n\n $stateProvider.state('fyn.designer', {\n url: '/designer',\n templateUrl: '/templates/fyn/pages/designer.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/designer-controller'),\n onExit: function(){\n var body = angular.element(document).find('body');\n body.removeClass('modal-open', 'modal-backdrop');\n }\n });\n\n $stateProvider.state('fyn.aboutus', {\n url: '/aboutus',\n templateUrl: '/templates/fyn/pages/aboutus.html'\n });\n\n $stateProvider.state('fyn.adac', {\n url: '/adac',\n templateUrl: '/templates/fyn/pages/adac.html'\n });\n\n $stateProvider.state('fyn.shaper', {\n url: '/shaper',\n templateUrl: '/templates/fyn/pages/shaper.html'\n });\n\n $stateProvider.state('fyn.retailers', {\n url: '/retailers',\n templateUrl: '/templates/fyn/pages/retailers.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/retailers-controller')\n });\n\n $stateProvider.state('fyn.store', {\n abstract: true,\n url: '/store',\n templateUrl: '/templates/fyn/store/store.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/store-controller')\n });\n\n $stateProvider.state('fyn.store.all', {\n url: '',\n templateUrl: '/templates/fyn/store/all.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/store-all-controller')\n });\n\n $stateProvider.state('fyn.store.product', {\n url: '/{option:longboardset|newfish|thrusterclassic|quadpuissant|summersecure|longboarddynamic|classic2|pro2|static|static2|staticpro|staticpro2|longboard}',\n templateUrl: '/templates/fyn/store/product.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/store-product-controller'),\n onEnter: function($state, $stateParams) {\n if (!_.includes(['longboardset', 'newfish', 'thrusterclassic', 'quadpuissant', 'summersecure', 'longboarddynamic', 'classic2', 'pro2', 'static', 'static2', 'staticpro', 'staticpro2', 'longboard'], $stateParams.option))\n $state.go('fyn.store.all', {location: 'replace'});\n }\n });\n\n $stateProvider.state('fyn.cart', {\n url: '/cart',\n templateUrl: '/templates/fyn/cart/cart.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/cart-controller')\n });\n\n $stateProvider.state('fyn.checkout', {\n abstract: true,\n url: '/checkout/:id',\n template: '',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-controller'),\n resolve: require('fyn/controllers/checkout-controller').resolve\n });\n\n $stateProvider.state('fyn.checkout.steps', {\n abstract: true,\n url: '',\n templateUrl: '/templates/fyn/checkout/checkout_steps_base.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-steps'),\n data: {\n checkoutData: {\n countryForms: {}\n }\n }\n });\n\n $stateProvider.state('fyn.checkout.steps.infos', {\n url: '/information',\n templateUrl: '/templates/fyn/checkout/infos.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-infos-controller'),\n resolve:require('fyn/controllers/checkout-infos-controller').resolve,\n onEnter: checkOrderState\n });\n\n $stateProvider.state('fyn.checkout.steps.payment', {\n url: '/payment?error',\n templateUrl: '/templates/fyn/checkout/payment.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-payment-controller'),\n resolve:require('fyn/controllers/checkout-payment-controller').resolve,\n onEnter: checkOrderState\n });\n\n $stateProvider.state('fyn.checkout.process', {\n url: '/process',\n templateUrl: '/templates/fyn/checkout/process.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-process-controller'),\n onEnter: checkOrderState\n });\n\n $stateProvider.state('fyn.checkout.success', {\n url: '/success',\n templateUrl: '/templates/fyn/checkout/success.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/checkout-success-controller'),\n onEnter: checkOrderState\n });\n\n function /*@ngInject*/ checkOrderState($state, order) {\n if ((order.state == 'ready') && this.name != 'fyn.checkout.success') {\n $state.go('fyn.checkout.success', {id: order.id}, {location: 'replace'});\n } else if (order.state == 'processing' && this.name != 'fyn.checkout.process') {\n $state.go('fyn.checkout.process', {id: order.id}, {location: 'replace'});\n } else if ((order.state == 'pending' || order.state == 'failed') && this.name != 'fyn.checkout.steps.payment') {\n $state.go('fyn.checkout.steps.payment', {id: order.id}, {location: 'replace'});\n } else if (order.state == 'initialized' && (this.name != 'fyn.checkout.steps.infos' && this.name != 'fyn.checkout.steps.payment')) {\n $state.go('fyn.checkout.steps.infos', {id: order.id});\n }\n }\n\n $stateProvider.state('fyn.order', {\n url: '/orders/:id/:token',\n templateUrl: '/templates/fyn/orders/show.html',\n controllerAs: 'vm',\n controller: require('fyn/controllers/orders-controller'),\n resolve: require('fyn/controllers/orders-controller').resolve\n });\n }\n);\n","/**\n * State-based routing for AngularJS\n * @version v0.2.15\n * @link http://angular-ui.github.com/\n * @license MIT License, http://www.opensource.org/licenses/MIT\n */\n\n/* commonjs package manager support (eg componentjs) */\nif (typeof module !== \"undefined\" && typeof exports !== \"undefined\" && module.exports === exports){\n module.exports = 'ui.router';\n}\n\n(function (window, angular, undefined) {\n/*jshint globalstrict:true*/\n/*global angular:false*/\n'use strict';\n\nvar isDefined = angular.isDefined,\n isFunction = angular.isFunction,\n isString = angular.isString,\n isObject = angular.isObject,\n isArray = angular.isArray,\n forEach = angular.forEach,\n extend = angular.extend,\n copy = angular.copy;\n\nfunction inherit(parent, extra) {\n return extend(new (extend(function() {}, { prototype: parent }))(), extra);\n}\n\nfunction merge(dst) {\n forEach(arguments, function(obj) {\n if (obj !== dst) {\n forEach(obj, function(value, key) {\n if (!dst.hasOwnProperty(key)) dst[key] = value;\n });\n }\n });\n return dst;\n}\n\n/**\n * Finds the common ancestor path between two states.\n *\n * @param {Object} first The first state.\n * @param {Object} second The second state.\n * @return {Array} Returns an array of state names in descending order, not including the root.\n */\nfunction ancestors(first, second) {\n var path = [];\n\n for (var n in first.path) {\n if (first.path[n] !== second.path[n]) break;\n path.push(first.path[n]);\n }\n return path;\n}\n\n/**\n * IE8-safe wrapper for `Object.keys()`.\n *\n * @param {Object} object A JavaScript object.\n * @return {Array} Returns the keys of the object as an array.\n */\nfunction objectKeys(object) {\n if (Object.keys) {\n return Object.keys(object);\n }\n var result = [];\n\n forEach(object, function(val, key) {\n result.push(key);\n });\n return result;\n}\n\n/**\n * IE8-safe wrapper for `Array.prototype.indexOf()`.\n *\n * @param {Array} array A JavaScript array.\n * @param {*} value A value to search the array for.\n * @return {Number} Returns the array index value of `value`, or `-1` if not present.\n */\nfunction indexOf(array, value) {\n if (Array.prototype.indexOf) {\n return array.indexOf(value, Number(arguments[2]) || 0);\n }\n var len = array.length >>> 0, from = Number(arguments[2]) || 0;\n from = (from < 0) ? Math.ceil(from) : Math.floor(from);\n\n if (from < 0) from += len;\n\n for (; from < len; from++) {\n if (from in array && array[from] === value) return from;\n }\n return -1;\n}\n\n/**\n * Merges a set of parameters with all parameters inherited between the common parents of the\n * current state and a given destination state.\n *\n * @param {Object} currentParams The value of the current state parameters ($stateParams).\n * @param {Object} newParams The set of parameters which will be composited with inherited params.\n * @param {Object} $current Internal definition of object representing the current state.\n * @param {Object} $to Internal definition of object representing state to transition to.\n */\nfunction inheritParams(currentParams, newParams, $current, $to) {\n var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = [];\n\n for (var i in parents) {\n if (!parents[i].params) continue;\n parentParams = objectKeys(parents[i].params);\n if (!parentParams.length) continue;\n\n for (var j in parentParams) {\n if (indexOf(inheritList, parentParams[j]) >= 0) continue;\n inheritList.push(parentParams[j]);\n inherited[parentParams[j]] = currentParams[parentParams[j]];\n }\n }\n return extend({}, inherited, newParams);\n}\n\n/**\n * Performs a non-strict comparison of the subset of two objects, defined by a list of keys.\n *\n * @param {Object} a The first object.\n * @param {Object} b The second object.\n * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified,\n * it defaults to the list of keys in `a`.\n * @return {Boolean} Returns `true` if the keys match, otherwise `false`.\n */\nfunction equalForKeys(a, b, keys) {\n if (!keys) {\n keys = [];\n for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility\n }\n\n for (var i=0; i\n * \n * \n * \n * \n * \n * \n * \n * \n * \n * \n * \n * \n */\nangular.module('ui.router', ['ui.router.state']);\n\nangular.module('ui.router.compat', ['ui.router']);\n\n/**\n * @ngdoc object\n * @name ui.router.util.$resolve\n *\n * @requires $q\n * @requires $injector\n *\n * @description\n * Manages resolution of (acyclic) graphs of promises.\n */\n$Resolve.$inject = ['$q', '$injector'];\nfunction $Resolve( $q, $injector) {\n \n var VISIT_IN_PROGRESS = 1,\n VISIT_DONE = 2,\n NOTHING = {},\n NO_DEPENDENCIES = [],\n NO_LOCALS = NOTHING,\n NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });\n \n\n /**\n * @ngdoc function\n * @name ui.router.util.$resolve#study\n * @methodOf ui.router.util.$resolve\n *\n * @description\n * Studies a set of invocables that are likely to be used multiple times.\n * \n * $resolve.study(invocables)(locals, parent, self)\n *
\n * is equivalent to\n * \n * $resolve.resolve(invocables, locals, parent, self)\n *
\n * but the former is more efficient (in fact `resolve` just calls `study` \n * internally).\n *\n * @param {object} invocables Invocable objects\n * @return {function} a function to pass in locals, parent and self\n */\n this.study = function (invocables) {\n if (!isObject(invocables)) throw new Error(\"'invocables' must be an object\");\n var invocableKeys = objectKeys(invocables || {});\n \n // Perform a topological sort of invocables to build an ordered plan\n var plan = [], cycle = [], visited = {};\n function visit(value, key) {\n if (visited[key] === VISIT_DONE) return;\n \n cycle.push(key);\n if (visited[key] === VISIT_IN_PROGRESS) {\n cycle.splice(0, indexOf(cycle, key));\n throw new Error(\"Cyclic dependency: \" + cycle.join(\" -> \"));\n }\n visited[key] = VISIT_IN_PROGRESS;\n \n if (isString(value)) {\n plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);\n } else {\n var params = $injector.annotate(value);\n forEach(params, function (param) {\n if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);\n });\n plan.push(key, value, params);\n }\n \n cycle.pop();\n visited[key] = VISIT_DONE;\n }\n forEach(invocables, visit);\n invocables = cycle = visited = null; // plan is all that's required\n \n function isResolve(value) {\n return isObject(value) && value.then && value.$$promises;\n }\n \n return function (locals, parent, self) {\n if (isResolve(locals) && self === undefined) {\n self = parent; parent = locals; locals = null;\n }\n if (!locals) locals = NO_LOCALS;\n else if (!isObject(locals)) {\n throw new Error(\"'locals' must be an object\");\n } \n if (!parent) parent = NO_PARENT;\n else if (!isResolve(parent)) {\n throw new Error(\"'parent' must be a promise returned by $resolve.resolve()\");\n }\n \n // To complete the overall resolution, we have to wait for the parent\n // promise and for the promise for each invokable in our plan.\n var resolution = $q.defer(),\n result = resolution.promise,\n promises = result.$$promises = {},\n values = extend({}, locals),\n wait = 1 + plan.length/3,\n merged = false;\n \n function done() {\n // Merge parent values we haven't got yet and publish our own $$values\n if (!--wait) {\n if (!merged) merge(values, parent.$$values); \n result.$$values = values;\n result.$$promises = result.$$promises || true; // keep for isResolve()\n delete result.$$inheritedValues;\n resolution.resolve(values);\n }\n }\n \n function fail(reason) {\n result.$$failure = reason;\n resolution.reject(reason);\n }\n\n // Short-circuit if parent has already failed\n if (isDefined(parent.$$failure)) {\n fail(parent.$$failure);\n return result;\n }\n \n if (parent.$$inheritedValues) {\n merge(values, omit(parent.$$inheritedValues, invocableKeys));\n }\n\n // Merge parent values if the parent has already resolved, or merge\n // parent promises and wait if the parent resolve is still in progress.\n extend(promises, parent.$$promises);\n if (parent.$$values) {\n merged = merge(values, omit(parent.$$values, invocableKeys));\n result.$$inheritedValues = omit(parent.$$values, invocableKeys);\n done();\n } else {\n if (parent.$$inheritedValues) {\n result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys);\n } \n parent.then(done, fail);\n }\n \n // Process each invocable in the plan, but ignore any where a local of the same name exists.\n for (var i=0, ii=plan.length; i} The template html as a string, or a promise \n * for that string.\n */\n this.fromUrl = function (url, params) {\n if (isFunction(url)) url = url(params);\n if (url == null) return null;\n else return $http\n .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }})\n .then(function(response) { return response.data; });\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$templateFactory#fromProvider\n * @methodOf ui.router.util.$templateFactory\n *\n * @description\n * Creates a template by invoking an injectable provider function.\n *\n * @param {Function} provider Function to invoke via `$injector.invoke`\n * @param {Object} params Parameters for the template.\n * @param {Object} locals Locals to pass to `invoke`. Defaults to \n * `{ params: params }`.\n * @return {string|Promise.} The template html as a string, or a promise \n * for that string.\n */\n this.fromProvider = function (provider, params, locals) {\n return $injector.invoke(provider, null, locals || { params: params });\n };\n}\n\nangular.module('ui.router.util').service('$templateFactory', $TemplateFactory);\n\nvar $$UMFP; // reference to $UrlMatcherFactoryProvider\n\n/**\n * @ngdoc object\n * @name ui.router.util.type:UrlMatcher\n *\n * @description\n * Matches URLs against patterns and extracts named parameters from the path or the search\n * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list\n * of search parameters. Multiple search parameter names are separated by '&'. Search parameters\n * do not influence whether or not a URL is matched, but their values are passed through into\n * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}.\n *\n * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace\n * syntax, which optionally allows a regular expression for the parameter to be specified:\n *\n * * `':'` name - colon placeholder\n * * `'*'` name - catch-all placeholder\n * * `'{' name '}'` - curly placeholder\n * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the\n * regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash.\n *\n * Parameter names may contain only word characters (latin letters, digits, and underscore) and\n * must be unique within the pattern (across both path and search parameters). For colon\n * placeholders or curly placeholders without an explicit regexp, a path parameter matches any\n * number of characters other than '/'. For catch-all placeholders the path parameter matches\n * any number of characters.\n *\n * Examples:\n *\n * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for\n * trailing slashes, and patterns have to match the entire path, not just a prefix.\n * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or\n * '/user/bob/details'. The second path segment will be captured as the parameter 'id'.\n * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax.\n * * `'/user/{id:[^/]*}'` - Same as the previous example.\n * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id\n * parameter consists of 1 to 8 hex digits.\n * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the\n * path into the parameter 'path'.\n * * `'/files/*path'` - ditto.\n * * `'/calendar/{start:date}'` - Matches \"/calendar/2014-11-12\" (because the pattern defined\n * in the built-in `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start\n *\n * @param {string} pattern The pattern to compile into a matcher.\n * @param {Object} config A configuration object hash:\n * @param {Object=} parentMatcher Used to concatenate the pattern/config onto\n * an existing UrlMatcher\n *\n * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`.\n * * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`.\n *\n * @property {string} prefix A static prefix of this pattern. The matcher guarantees that any\n * URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns\n * non-null) will start with this prefix.\n *\n * @property {string} source The pattern that was passed into the constructor\n *\n * @property {string} sourcePath The path portion of the source property\n *\n * @property {string} sourceSearch The search portion of the source property\n *\n * @property {string} regex The constructed regex that will be used to match against the url when\n * it is time to determine which url will match.\n *\n * @returns {Object} New `UrlMatcher` object\n */\nfunction UrlMatcher(pattern, config, parentMatcher) {\n config = extend({ params: {} }, isObject(config) ? config : {});\n\n // Find all placeholders and create a compiled pattern, using either classic or curly syntax:\n // '*' name\n // ':' name\n // '{' name '}'\n // '{' name ':' regexp '}'\n // The regular expression is somewhat complicated due to the need to allow curly braces\n // inside the regular expression. The placeholder regexp breaks down as follows:\n // ([:*])([\\w\\[\\]]+) - classic placeholder ($1 / $2) (search version has - for snake-case)\n // \\{([\\w\\[\\]]+)(?:\\:( ... ))?\\} - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case\n // (?: ... | ... | ... )+ - the regexp consists of any number of atoms, an atom being either\n // [^{}\\\\]+ - anything other than curly braces or backslash\n // \\\\. - a backslash escape\n // \\{(?:[^{}\\\\]+|\\\\.)*\\} - a matched set of curly braces containing other atoms\n var placeholder = /([:*])([\\w\\[\\]]+)|\\{([\\w\\[\\]]+)(?:\\:((?:[^{}\\\\]+|\\\\.|\\{(?:[^{}\\\\]+|\\\\.)*\\})+))?\\}/g,\n searchPlaceholder = /([:]?)([\\w\\[\\]-]+)|\\{([\\w\\[\\]-]+)(?:\\:((?:[^{}\\\\]+|\\\\.|\\{(?:[^{}\\\\]+|\\\\.)*\\})+))?\\}/g,\n compiled = '^', last = 0, m,\n segments = this.segments = [],\n parentParams = parentMatcher ? parentMatcher.params : {},\n params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(),\n paramNames = [];\n\n function addParameter(id, type, config, location) {\n paramNames.push(id);\n if (parentParams[id]) return parentParams[id];\n if (!/^\\w+(-+\\w+)*(?:\\[\\])?$/.test(id)) throw new Error(\"Invalid parameter name '\" + id + \"' in pattern '\" + pattern + \"'\");\n if (params[id]) throw new Error(\"Duplicate parameter name '\" + id + \"' in pattern '\" + pattern + \"'\");\n params[id] = new $$UMFP.Param(id, type, config, location);\n return params[id];\n }\n\n function quoteRegExp(string, pattern, squash, optional) {\n var surroundPattern = ['',''], result = string.replace(/[\\\\\\[\\]\\^$*+?.()|{}]/g, \"\\\\$&\");\n if (!pattern) return result;\n switch(squash) {\n case false: surroundPattern = ['(', ')' + (optional ? \"?\" : \"\")]; break;\n case true: surroundPattern = ['?(', ')?']; break;\n default: surroundPattern = ['(' + squash + \"|\", ')?']; break;\n }\n return result + surroundPattern[0] + pattern + surroundPattern[1];\n }\n\n this.source = pattern;\n\n // Split into static segments separated by path parameter placeholders.\n // The number of segments is always 1 more than the number of parameters.\n function matchDetails(m, isSearch) {\n var id, regexp, segment, type, cfg, arrayMode;\n id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null\n cfg = config.params[id];\n segment = pattern.substring(last, m.index);\n regexp = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null);\n type = $$UMFP.type(regexp || \"string\") || inherit($$UMFP.type(\"string\"), { pattern: new RegExp(regexp, config.caseInsensitive ? 'i' : undefined) });\n return {\n id: id, regexp: regexp, segment: segment, type: type, cfg: cfg\n };\n }\n\n var p, param, segment;\n while ((m = placeholder.exec(pattern))) {\n p = matchDetails(m, false);\n if (p.segment.indexOf('?') >= 0) break; // we're into the search part\n\n param = addParameter(p.id, p.type, p.cfg, \"path\");\n compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash, param.isOptional);\n segments.push(p.segment);\n last = placeholder.lastIndex;\n }\n segment = pattern.substring(last);\n\n // Find any search parameter names and remove them from the last segment\n var i = segment.indexOf('?');\n\n if (i >= 0) {\n var search = this.sourceSearch = segment.substring(i);\n segment = segment.substring(0, i);\n this.sourcePath = pattern.substring(0, last + i);\n\n if (search.length > 0) {\n last = 0;\n while ((m = searchPlaceholder.exec(search))) {\n p = matchDetails(m, true);\n param = addParameter(p.id, p.type, p.cfg, \"search\");\n last = placeholder.lastIndex;\n // check if ?&\n }\n }\n } else {\n this.sourcePath = pattern;\n this.sourceSearch = '';\n }\n\n compiled += quoteRegExp(segment) + (config.strict === false ? '\\/?' : '') + '$';\n segments.push(segment);\n\n this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined);\n this.prefix = segments[0];\n this.$$paramNames = paramNames;\n}\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:UrlMatcher#concat\n * @methodOf ui.router.util.type:UrlMatcher\n *\n * @description\n * Returns a new matcher for a pattern constructed by appending the path part and adding the\n * search parameters of the specified pattern to this pattern. The current pattern is not\n * modified. This can be understood as creating a pattern for URLs that are relative to (or\n * suffixes of) the current pattern.\n *\n * @example\n * The following two matchers are equivalent:\n * \n * new UrlMatcher('/user/{id}?q').concat('/details?date');\n * new UrlMatcher('/user/{id}/details?q&date');\n *
\n *\n * @param {string} pattern The pattern to append.\n * @param {Object} config An object hash of the configuration for the matcher.\n * @returns {UrlMatcher} A matcher for the concatenated pattern.\n */\nUrlMatcher.prototype.concat = function (pattern, config) {\n // Because order of search parameters is irrelevant, we can add our own search\n // parameters to the end of the new pattern. Parse the new pattern by itself\n // and then join the bits together, but it's much easier to do this on a string level.\n var defaultConfig = {\n caseInsensitive: $$UMFP.caseInsensitive(),\n strict: $$UMFP.strictMode(),\n squash: $$UMFP.defaultSquashPolicy()\n };\n return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this);\n};\n\nUrlMatcher.prototype.toString = function () {\n return this.source;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:UrlMatcher#exec\n * @methodOf ui.router.util.type:UrlMatcher\n *\n * @description\n * Tests the specified path against this matcher, and returns an object containing the captured\n * parameter values, or null if the path does not match. The returned object contains the values\n * of any search parameters that are mentioned in the pattern, but their value may be null if\n * they are not present in `searchParams`. This means that search parameters are always treated\n * as optional.\n *\n * @example\n * \n * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {\n * x: '1', q: 'hello'\n * });\n * // returns { id: 'bob', q: 'hello', r: null }\n *
\n *\n * @param {string} path The URL path to match, e.g. `$location.path()`.\n * @param {Object} searchParams URL search parameters, e.g. `$location.search()`.\n * @returns {Object} The captured parameter values.\n */\nUrlMatcher.prototype.exec = function (path, searchParams) {\n var m = this.regexp.exec(path);\n if (!m) return null;\n searchParams = searchParams || {};\n\n var paramNames = this.parameters(), nTotal = paramNames.length,\n nPath = this.segments.length - 1,\n values = {}, i, j, cfg, paramName;\n\n if (nPath !== m.length - 1) throw new Error(\"Unbalanced capture group in route '\" + this.source + \"'\");\n\n function decodePathArray(string) {\n function reverseString(str) { return str.split(\"\").reverse().join(\"\"); }\n function unquoteDashes(str) { return str.replace(/\\\\-/g, \"-\"); }\n\n var split = reverseString(string).split(/-(?!\\\\)/);\n var allReversed = map(split, reverseString);\n return map(allReversed, unquoteDashes).reverse();\n }\n\n for (i = 0; i < nPath; i++) {\n paramName = paramNames[i];\n var param = this.params[paramName];\n var paramVal = m[i+1];\n // if the param value matches a pre-replace pair, replace the value before decoding.\n for (j = 0; j < param.replace; j++) {\n if (param.replace[j].from === paramVal) paramVal = param.replace[j].to;\n }\n if (paramVal && param.array === true) paramVal = decodePathArray(paramVal);\n values[paramName] = param.value(paramVal);\n }\n for (/**/; i < nTotal; i++) {\n paramName = paramNames[i];\n values[paramName] = this.params[paramName].value(searchParams[paramName]);\n }\n\n return values;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:UrlMatcher#parameters\n * @methodOf ui.router.util.type:UrlMatcher\n *\n * @description\n * Returns the names of all path and search parameters of this pattern in an unspecified order.\n *\n * @returns {Array.} An array of parameter names. Must be treated as read-only. If the\n * pattern has no parameters, an empty array is returned.\n */\nUrlMatcher.prototype.parameters = function (param) {\n if (!isDefined(param)) return this.$$paramNames;\n return this.params[param] || null;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:UrlMatcher#validate\n * @methodOf ui.router.util.type:UrlMatcher\n *\n * @description\n * Checks an object hash of parameters to validate their correctness according to the parameter\n * types of this `UrlMatcher`.\n *\n * @param {Object} params The object hash of parameters to validate.\n * @returns {boolean} Returns `true` if `params` validates, otherwise `false`.\n */\nUrlMatcher.prototype.validates = function (params) {\n return this.params.$$validates(params);\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:UrlMatcher#format\n * @methodOf ui.router.util.type:UrlMatcher\n *\n * @description\n * Creates a URL that matches this pattern by substituting the specified values\n * for the path and search parameters. Null values for path parameters are\n * treated as empty strings.\n *\n * @example\n * \n * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });\n * // returns '/user/bob?q=yes'\n *
\n *\n * @param {Object} values the values to substitute for the parameters in this pattern.\n * @returns {string} the formatted URL (path and optionally search part).\n */\nUrlMatcher.prototype.format = function (values) {\n values = values || {};\n var segments = this.segments, params = this.parameters(), paramset = this.params;\n if (!this.validates(values)) return null;\n\n var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0];\n\n function encodeDashes(str) { // Replace dashes with encoded \"\\-\"\n return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); });\n }\n\n for (i = 0; i < nTotal; i++) {\n var isPathParam = i < nPath;\n var name = params[i], param = paramset[name], value = param.value(values[name]);\n var isDefaultValue = param.isOptional && param.type.equals(param.value(), value);\n var squash = isDefaultValue ? param.squash : false;\n var encoded = param.type.encode(value);\n\n if (isPathParam) {\n var nextSegment = segments[i + 1];\n if (squash === false) {\n if (encoded != null) {\n if (isArray(encoded)) {\n result += map(encoded, encodeDashes).join(\"-\");\n } else {\n result += encodeURIComponent(encoded);\n }\n }\n result += nextSegment;\n } else if (squash === true) {\n var capture = result.match(/\\/$/) ? /\\/?(.*)/ : /(.*)/;\n result += nextSegment.match(capture)[1];\n } else if (isString(squash)) {\n result += squash + nextSegment;\n }\n } else {\n if (encoded == null || (isDefaultValue && squash !== false)) continue;\n if (!isArray(encoded)) encoded = [ encoded ];\n encoded = map(encoded, encodeURIComponent).join('&' + name + '=');\n result += (search ? '&' : '?') + (name + '=' + encoded);\n search = true;\n }\n }\n\n return result;\n};\n\n/**\n * @ngdoc object\n * @name ui.router.util.type:Type\n *\n * @description\n * Implements an interface to define custom parameter types that can be decoded from and encoded to\n * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`}\n * objects when matching or formatting URLs, or comparing or validating parameter values.\n *\n * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more\n * information on registering custom types.\n *\n * @param {Object} config A configuration object which contains the custom type definition. The object's\n * properties will override the default methods and/or pattern in `Type`'s public interface.\n * @example\n * \n * {\n * decode: function(val) { return parseInt(val, 10); },\n * encode: function(val) { return val && val.toString(); },\n * equals: function(a, b) { return this.is(a) && a === b; },\n * is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },\n * pattern: /\\d+/\n * }\n *
\n *\n * @property {RegExp} pattern The regular expression pattern used to match values of this type when\n * coming from a substring of a URL.\n *\n * @returns {Object} Returns a new `Type` object.\n */\nfunction Type(config) {\n extend(this, config);\n}\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:Type#is\n * @methodOf ui.router.util.type:Type\n *\n * @description\n * Detects whether a value is of a particular type. Accepts a native (decoded) value\n * and determines whether it matches the current `Type` object.\n *\n * @param {*} val The value to check.\n * @param {string} key Optional. If the type check is happening in the context of a specific\n * {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the\n * parameter in which `val` is stored. Can be used for meta-programming of `Type` objects.\n * @returns {Boolean} Returns `true` if the value matches the type, otherwise `false`.\n */\nType.prototype.is = function(val, key) {\n return true;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:Type#encode\n * @methodOf ui.router.util.type:Type\n *\n * @description\n * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the\n * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it\n * only needs to be a representation of `val` that has been coerced to a string.\n *\n * @param {*} val The value to encode.\n * @param {string} key The name of the parameter in which `val` is stored. Can be used for\n * meta-programming of `Type` objects.\n * @returns {string} Returns a string representation of `val` that can be encoded in a URL.\n */\nType.prototype.encode = function(val, key) {\n return val;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:Type#decode\n * @methodOf ui.router.util.type:Type\n *\n * @description\n * Converts a parameter value (from URL string or transition param) to a custom/native value.\n *\n * @param {string} val The URL parameter value to decode.\n * @param {string} key The name of the parameter in which `val` is stored. Can be used for\n * meta-programming of `Type` objects.\n * @returns {*} Returns a custom representation of the URL parameter value.\n */\nType.prototype.decode = function(val, key) {\n return val;\n};\n\n/**\n * @ngdoc function\n * @name ui.router.util.type:Type#equals\n * @methodOf ui.router.util.type:Type\n *\n * @description\n * Determines whether two decoded values are equivalent.\n *\n * @param {*} a A value to compare against.\n * @param {*} b A value to compare against.\n * @returns {Boolean} Returns `true` if the values are equivalent/equal, otherwise `false`.\n */\nType.prototype.equals = function(a, b) {\n return a == b;\n};\n\nType.prototype.$subPattern = function() {\n var sub = this.pattern.toString();\n return sub.substr(1, sub.length - 2);\n};\n\nType.prototype.pattern = /.*/;\n\nType.prototype.toString = function() { return \"{Type:\" + this.name + \"}\"; };\n\n/** Given an encoded string, or a decoded object, returns a decoded object */\nType.prototype.$normalize = function(val) {\n return this.is(val) ? val : this.decode(val);\n};\n\n/*\n * Wraps an existing custom Type as an array of Type, depending on 'mode'.\n * e.g.:\n * - urlmatcher pattern \"/path?{queryParam[]:int}\"\n * - url: \"/path?queryParam=1&queryParam=2\n * - $stateParams.queryParam will be [1, 2]\n * if `mode` is \"auto\", then\n * - url: \"/path?queryParam=1 will create $stateParams.queryParam: 1\n * - url: \"/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2]\n */\nType.prototype.$asArray = function(mode, isSearch) {\n if (!mode) return this;\n if (mode === \"auto\" && !isSearch) throw new Error(\"'auto' array mode is for query parameters only\");\n\n function ArrayType(type, mode) {\n function bindTo(type, callbackName) {\n return function() {\n return type[callbackName].apply(type, arguments);\n };\n }\n\n // Wrap non-array value as array\n function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); }\n // Unwrap array value for \"auto\" mode. Return undefined for empty array.\n function arrayUnwrap(val) {\n switch(val.length) {\n case 0: return undefined;\n case 1: return mode === \"auto\" ? val[0] : val;\n default: return val;\n }\n }\n function falsey(val) { return !val; }\n\n // Wraps type (.is/.encode/.decode) functions to operate on each value of an array\n function arrayHandler(callback, allTruthyMode) {\n return function handleArray(val) {\n val = arrayWrap(val);\n var result = map(val, callback);\n if (allTruthyMode === true)\n return filter(result, falsey).length === 0;\n return arrayUnwrap(result);\n };\n }\n\n // Wraps type (.equals) functions to operate on each value of an array\n function arrayEqualsHandler(callback) {\n return function handleArray(val1, val2) {\n var left = arrayWrap(val1), right = arrayWrap(val2);\n if (left.length !== right.length) return false;\n for (var i = 0; i < left.length; i++) {\n if (!callback(left[i], right[i])) return false;\n }\n return true;\n };\n }\n\n this.encode = arrayHandler(bindTo(type, 'encode'));\n this.decode = arrayHandler(bindTo(type, 'decode'));\n this.is = arrayHandler(bindTo(type, 'is'), true);\n this.equals = arrayEqualsHandler(bindTo(type, 'equals'));\n this.pattern = type.pattern;\n this.$normalize = arrayHandler(bindTo(type, '$normalize'));\n this.name = type.name;\n this.$arrayMode = mode;\n }\n\n return new ArrayType(this, mode);\n};\n\n\n\n/**\n * @ngdoc object\n * @name ui.router.util.$urlMatcherFactory\n *\n * @description\n * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory\n * is also available to providers under the name `$urlMatcherFactoryProvider`.\n */\nfunction $UrlMatcherFactory() {\n $$UMFP = this;\n\n var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false;\n\n function valToString(val) { return val != null ? val.toString().replace(/\\//g, \"%2F\") : val; }\n function valFromString(val) { return val != null ? val.toString().replace(/%2F/g, \"/\") : val; }\n\n var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = {\n string: {\n encode: valToString,\n decode: valFromString,\n // TODO: in 1.0, make string .is() return false if value is undefined/null by default.\n // In 0.2.x, string params are optional by default for backwards compat\n is: function(val) { return val == null || !isDefined(val) || typeof val === \"string\"; },\n pattern: /[^/]*/\n },\n int: {\n encode: valToString,\n decode: function(val) { return parseInt(val, 10); },\n is: function(val) { return isDefined(val) && this.decode(val.toString()) === val; },\n pattern: /\\d+/\n },\n bool: {\n encode: function(val) { return val ? 1 : 0; },\n decode: function(val) { return parseInt(val, 10) !== 0; },\n is: function(val) { return val === true || val === false; },\n pattern: /0|1/\n },\n date: {\n encode: function (val) {\n if (!this.is(val))\n return undefined;\n return [ val.getFullYear(),\n ('0' + (val.getMonth() + 1)).slice(-2),\n ('0' + val.getDate()).slice(-2)\n ].join(\"-\");\n },\n decode: function (val) {\n if (this.is(val)) return val;\n var match = this.capture.exec(val);\n return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;\n },\n is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); },\n equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); },\n pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/,\n capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/\n },\n json: {\n encode: angular.toJson,\n decode: angular.fromJson,\n is: angular.isObject,\n equals: angular.equals,\n pattern: /[^/]*/\n },\n any: { // does not encode/decode\n encode: angular.identity,\n decode: angular.identity,\n equals: angular.equals,\n pattern: /.*/\n }\n };\n\n function getDefaultConfig() {\n return {\n strict: isStrictMode,\n caseInsensitive: isCaseInsensitive\n };\n }\n\n function isInjectable(value) {\n return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1])));\n }\n\n /**\n * [Internal] Get the default value of a parameter, which may be an injectable function.\n */\n $UrlMatcherFactory.$$getDefaultValue = function(config) {\n if (!isInjectable(config.value)) return config.value;\n if (!injector) throw new Error(\"Injectable functions cannot be called at configuration time\");\n return injector.invoke(config.value);\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#caseInsensitive\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Defines whether URL matching should be case sensitive (the default behavior), or not.\n *\n * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`;\n * @returns {boolean} the current value of caseInsensitive\n */\n this.caseInsensitive = function(value) {\n if (isDefined(value))\n isCaseInsensitive = value;\n return isCaseInsensitive;\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#strictMode\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Defines whether URLs should match trailing slashes, or not (the default behavior).\n *\n * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`.\n * @returns {boolean} the current value of strictMode\n */\n this.strictMode = function(value) {\n if (isDefined(value))\n isStrictMode = value;\n return isStrictMode;\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Sets the default behavior when generating or matching URLs with default parameter values.\n *\n * @param {string} value A string that defines the default parameter URL squashing behavior.\n * `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL\n * `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the\n * parameter is surrounded by slashes, squash (remove) one slash from the URL\n * any other string, e.g. \"~\": When generating an href with a default parameter value, squash (remove)\n * the parameter value from the URL and replace it with this string.\n */\n this.defaultSquashPolicy = function(value) {\n if (!isDefined(value)) return defaultSquashPolicy;\n if (value !== true && value !== false && !isString(value))\n throw new Error(\"Invalid squash policy: \" + value + \". Valid policies: false, true, arbitrary-string\");\n defaultSquashPolicy = value;\n return value;\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#compile\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern.\n *\n * @param {string} pattern The URL pattern.\n * @param {Object} config The config object hash.\n * @returns {UrlMatcher} The UrlMatcher.\n */\n this.compile = function (pattern, config) {\n return new UrlMatcher(pattern, extend(getDefaultConfig(), config));\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#isMatcher\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Returns true if the specified object is a `UrlMatcher`, or false otherwise.\n *\n * @param {Object} object The object to perform the type check against.\n * @returns {Boolean} Returns `true` if the object matches the `UrlMatcher` interface, by\n * implementing all the same methods.\n */\n this.isMatcher = function (o) {\n if (!isObject(o)) return false;\n var result = true;\n\n forEach(UrlMatcher.prototype, function(val, name) {\n if (isFunction(val)) {\n result = result && (isDefined(o[name]) && isFunction(o[name]));\n }\n });\n return result;\n };\n\n /**\n * @ngdoc function\n * @name ui.router.util.$urlMatcherFactory#type\n * @methodOf ui.router.util.$urlMatcherFactory\n *\n * @description\n * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to\n * generate URLs with typed parameters.\n *\n * @param {string} name The type name.\n * @param {Object|Function} definition The type definition. See\n * {@link ui.router.util.type:Type `Type`} for information on the values accepted.\n * @param {Object|Function} definitionFn (optional) A function that is injected before the app\n * runtime starts. The result of this function is merged into the existing `definition`.\n * See {@link ui.router.util.type:Type `Type`} for information on the values accepted.\n *\n * @returns {Object} Returns `$urlMatcherFactoryProvider`.\n *\n * @example\n * This is a simple example of a custom type that encodes and decodes items from an\n * array, using the array index as the URL-encoded value:\n *\n * \n * var list = ['John', 'Paul', 'George', 'Ringo'];\n *\n * $urlMatcherFactoryProvider.type('listItem', {\n * encode: function(item) {\n * // Represent the list item in the URL using its corresponding index\n * return list.indexOf(item);\n * },\n * decode: function(item) {\n * // Look up the list item by index\n * return list[parseInt(item, 10)];\n * },\n * is: function(item) {\n * // Ensure the item is valid by checking to see that it appears\n * // in the list\n * return list.indexOf(item) > -1;\n * }\n * });\n *\n * $stateProvider.state('list', {\n * url: \"/list/{item:listItem}\",\n * controller: function($scope, $stateParams) {\n * console.log($stateParams.item);\n * }\n * });\n *\n * // ...\n *\n * // Changes URL to '/list/3', logs \"Ringo\" to the console\n * $state.go('list', { item: \"Ringo\" });\n *
\n *\n * This is a more complex example of a type that relies on dependency injection to\n * interact with services, and uses the parameter name from the URL to infer how to\n * handle encoding and decoding parameter values:\n *\n * \n * // Defines a custom type that gets a value from a service,\n * // where each service gets different types of values from\n * // a backend API:\n * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {\n *\n * // Matches up services to URL parameter names\n * var services = {\n * user: Users,\n * post: Posts\n * };\n *\n * return {\n * encode: function(object) {\n * // Represent the object in the URL using its unique ID\n * return object.id;\n * },\n * decode: function(value, key) {\n * // Look up the object by ID, using the parameter\n * // name (key) to call the correct service\n * return services[key].findById(value);\n * },\n * is: function(object, key) {\n * // Check that object is a valid dbObject\n * return angular.isObject(object) && object.id && services[key];\n * }\n * equals: function(a, b) {\n * // Check the equality of decoded objects by comparing\n * // their unique IDs\n * return a.id === b.id;\n * }\n * };\n * });\n *\n * // In a config() block, you can then attach URLs with\n * // type-annotated parameters:\n * $stateProvider.state('users', {\n * url: \"/users\",\n * // ...\n * }).state('users.item', {\n * url: \"/{user:dbObject}\",\n * controller: function($scope, $stateParams) {\n * // $stateParams.user will now be an object returned from\n * // the Users service\n * },\n * // ...\n * });\n *
\n */\n this.type = function (name, definition, definitionFn) {\n if (!isDefined(definition)) return $types[name];\n if ($types.hasOwnProperty(name)) throw new Error(\"A type named '\" + name + \"' has already been defined.\");\n\n $types[name] = new Type(extend({ name: name }, definition));\n if (definitionFn) {\n typeQueue.push({ name: name, def: definitionFn });\n if (!enqueue) flushTypeQueue();\n }\n return this;\n };\n\n // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s\n function flushTypeQueue() {\n while(typeQueue.length) {\n var type = typeQueue.shift();\n if (type.pattern) throw new Error(\"You cannot override a type's .pattern at runtime.\");\n angular.extend($types[type.name], injector.invoke(type.def));\n }\n }\n\n // Register default types. Store them in the prototype of $types.\n forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); });\n $types = inherit($types, {});\n\n /* No need to document $get, since it returns this */\n this.$get = ['$injector', function ($injector) {\n injector = $injector;\n enqueue = false;\n flushTypeQueue();\n\n forEach(defaultTypes, function(type, name) {\n if (!$types[name]) $types[name] = new Type(type);\n });\n return this;\n }];\n\n this.Param = function Param(id, type, config, location) {\n var self = this;\n config = unwrapShorthand(config);\n type = getType(config, type, location);\n var arrayMode = getArrayMode();\n type = arrayMode ? type.$asArray(arrayMode, location === \"search\") : type;\n if (type.name === \"string\" && !arrayMode && location === \"path\" && config.value === undefined)\n config.value = \"\"; // for 0.2.x; in 0.3.0+ do not automatically default to \"\"\n var isOptional = config.value !== undefined;\n var squash = getSquashPolicy(config, isOptional);\n var replace = getReplace(config, arrayMode, isOptional, squash);\n\n function unwrapShorthand(config) {\n var keys = isObject(config) ? objectKeys(config) : [];\n var isShorthand = indexOf(keys, \"value\") === -1 && indexOf(keys, \"type\") === -1 &&\n indexOf(keys, \"squash\") === -1 && indexOf(keys, \"array\") === -1;\n if (isShorthand) config = { value: config };\n config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; };\n return config;\n }\n\n function getType(config, urlType, location) {\n if (config.type && urlType) throw new Error(\"Param '\"+id+\"' has two type configurations.\");\n if (urlType) return urlType;\n if (!config.type) return (location === \"config\" ? $types.any : $types.string);\n return config.type instanceof Type ? config.type : new Type(config.type);\n }\n\n // array config: param name (param[]) overrides default settings. explicit config overrides param name.\n function getArrayMode() {\n var arrayDefaults = { array: (location === \"search\" ? \"auto\" : false) };\n var arrayParamNomenclature = id.match(/\\[\\]$/) ? { array: true } : {};\n return extend(arrayDefaults, arrayParamNomenclature, config).array;\n }\n\n /**\n * returns false, true, or the squash value to indicate the \"default parameter url squash policy\".\n */\n function getSquashPolicy(config, isOptional) {\n var squash = config.squash;\n if (!isOptional || squash === false) return false;\n if (!isDefined(squash) || squash == null) return defaultSquashPolicy;\n if (squash === true || isString(squash)) return squash;\n throw new Error(\"Invalid squash policy: '\" + squash + \"'. Valid policies: false, true, or arbitrary string\");\n }\n\n function getReplace(config, arrayMode, isOptional, squash) {\n var replace, configuredKeys, defaultPolicy = [\n { from: \"\", to: (isOptional || arrayMode ? undefined : \"\") },\n { from: null, to: (isOptional || arrayMode ? undefined : \"\") }\n ];\n replace = isArray(config.replace) ? config.replace : [];\n if (isString(squash))\n replace.push({ from: squash, to: undefined });\n configuredKeys = map(replace, function(item) { return item.from; } );\n return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace);\n }\n\n /**\n * [Internal] Get the default value of a parameter, which may be an injectable function.\n */\n function $$getDefaultValue() {\n if (!injector) throw new Error(\"Injectable functions cannot be called at configuration time\");\n var defaultValue = injector.invoke(config.$$fn);\n if (defaultValue !== null && defaultValue !== undefined && !self.type.is(defaultValue))\n throw new Error(\"Default value (\" + defaultValue + \") for parameter '\" + self.id + \"' is not an instance of Type (\" + self.type.name + \")\");\n return defaultValue;\n }\n\n /**\n * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the\n * default value, which may be the result of an injectable function.\n */\n function $value(value) {\n function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; }\n function $replace(value) {\n var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; });\n return replacement.length ? replacement[0] : value;\n }\n value = $replace(value);\n return !isDefined(value) ? $$getDefaultValue() : self.type.$normalize(value);\n }\n\n function toString() { return \"{Param:\" + id + \" \" + type + \" squash: '\" + squash + \"' optional: \" + isOptional + \"}\"; }\n\n extend(this, {\n id: id,\n type: type,\n location: location,\n array: arrayMode,\n squash: squash,\n replace: replace,\n isOptional: isOptional,\n value: $value,\n dynamic: undefined,\n config: config,\n toString: toString\n });\n };\n\n function ParamSet(params) {\n extend(this, params || {});\n }\n\n ParamSet.prototype = {\n $$new: function() {\n return inherit(this, extend(new ParamSet(), { $$parent: this}));\n },\n $$keys: function () {\n var keys = [], chain = [], parent = this,\n ignore = objectKeys(ParamSet.prototype);\n while (parent) { chain.push(parent); parent = parent.$$parent; }\n chain.reverse();\n forEach(chain, function(paramset) {\n forEach(objectKeys(paramset), function(key) {\n if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key);\n });\n });\n return keys;\n },\n $$values: function(paramValues) {\n var values = {}, self = this;\n forEach(self.$$keys(), function(key) {\n values[key] = self[key].value(paramValues && paramValues[key]);\n });\n return values;\n },\n $$equals: function(paramValues1, paramValues2) {\n var equal = true, self = this;\n forEach(self.$$keys(), function(key) {\n var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key];\n if (!self[key].type.equals(left, right)) equal = false;\n });\n return equal;\n },\n $$validates: function $$validate(paramValues) {\n var keys = this.$$keys(), i, param, rawVal, normalized, encoded;\n for (i = 0; i < keys.length; i++) {\n param = this[keys[i]];\n rawVal = paramValues[keys[i]];\n if ((rawVal === undefined || rawVal === null) && param.isOptional)\n break; // There was no parameter value, but the param is optional\n normalized = param.type.$normalize(rawVal);\n if (!param.type.is(normalized))\n return false; // The value was not of the correct Type, and could not be decoded to the correct Type\n encoded = param.type.encode(normalized);\n if (angular.isString(encoded) && !param.type.pattern.exec(encoded))\n return false; // The value was of the correct type, but when encoded, did not match the Type's regexp\n }\n return true;\n },\n $$parent: undefined\n };\n\n this.ParamSet = ParamSet;\n}\n\n// Register as a provider so it's available to other providers\nangular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory);\nangular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]);\n\n/**\n * @ngdoc object\n * @name ui.router.router.$urlRouterProvider\n *\n * @requires ui.router.util.$urlMatcherFactoryProvider\n * @requires $locationProvider\n *\n * @description\n * `$urlRouterProvider` has the responsibility of watching `$location`. \n * When `$location` changes it runs through a list of rules one by one until a \n * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify \n * a url in a state configuration. All urls are compiled into a UrlMatcher object.\n *\n * There are several methods on `$urlRouterProvider` that make it useful to use directly\n * in your module config.\n */\n$UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider'];\nfunction $UrlRouterProvider( $locationProvider, $urlMatcherFactory) {\n var rules = [], otherwise = null, interceptDeferred = false, listener;\n\n // Returns a string that is a prefix of all strings matching the RegExp\n function regExpPrefix(re) {\n var prefix = /^\\^((?:\\\\[^a-zA-Z0-9]|[^\\\\\\[\\]\\^$*+?.()|{}]+)*)/.exec(re.source);\n return (prefix != null) ? prefix[1].replace(/\\\\(.)/g, \"$1\") : '';\n }\n\n // Interpolates matched values into a String.replace()-style pattern\n function interpolate(pattern, match) {\n return pattern.replace(/\\$(\\$|\\d{1,2})/, function (m, what) {\n return match[what === '$' ? 0 : Number(what)];\n });\n }\n\n /**\n * @ngdoc function\n * @name ui.router.router.$urlRouterProvider#rule\n * @methodOf ui.router.router.$urlRouterProvider\n *\n * @description\n * Defines rules that are used by `$urlRouterProvider` to find matches for\n * specific URLs.\n *\n * @example\n * \n * var app = angular.module('app', ['ui.router.router']);\n *\n * app.config(function ($urlRouterProvider) {\n * // Here's an example of how you might allow case insensitive urls\n * $urlRouterProvider.rule(function ($injector, $location) {\n * var path = $location.path(),\n * normalized = path.toLowerCase();\n *\n * if (path !== normalized) {\n * return normalized;\n * }\n * });\n * });\n *
\n *\n * @param {object} rule Handler function that takes `$injector` and `$location`\n * services as arguments. You can use them to return a valid path as a string.\n *\n * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance\n */\n this.rule = function (rule) {\n if (!isFunction(rule)) throw new Error(\"'rule' must be a function\");\n rules.push(rule);\n return this;\n };\n\n /**\n * @ngdoc object\n * @name ui.router.router.$urlRouterProvider#otherwise\n * @methodOf ui.router.router.$urlRouterProvider\n *\n * @description\n * Defines a path that is used when an invalid route is requested.\n *\n * @example\n * \n * var app = angular.module('app', ['ui.router.router']);\n *\n * app.config(function ($urlRouterProvider) {\n * // if the path doesn't match any of the urls you configured\n * // otherwise will take care of routing the user to the\n * // specified url\n * $urlRouterProvider.otherwise('/index');\n *\n * // Example of using function rule as param\n * $urlRouterProvider.otherwise(function ($injector, $location) {\n * return '/a/valid/url';\n * });\n * });\n *
\n *\n * @param {string|object} rule The url path you want to redirect to or a function \n * rule that returns the url path. The function version is passed two params: \n * `$injector` and `$location` services, and must return a url string.\n *\n * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance\n */\n this.otherwise = function (rule) {\n if (isString(rule)) {\n var redirect = rule;\n rule = function () { return redirect; };\n }\n else if (!isFunction(rule)) throw new Error(\"'rule' must be a function\");\n otherwise = rule;\n return this;\n };\n\n\n function handleIfMatch($injector, handler, match) {\n if (!match) return false;\n var result = $injector.invoke(handler, handler, { $match: match });\n return isDefined(result) ? result : true;\n }\n\n /**\n * @ngdoc function\n * @name ui.router.router.$urlRouterProvider#when\n * @methodOf ui.router.router.$urlRouterProvider\n *\n * @description\n * Registers a handler for a given url matching. if handle is a string, it is\n * treated as a redirect, and is interpolated according to the syntax of match\n * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise).\n *\n * If the handler is a function, it is injectable. It gets invoked if `$location`\n * matches. You have the option of inject the match object as `$match`.\n *\n * The handler can return\n *\n * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter`\n * will continue trying to find another one that matches.\n * - **string** which is treated as a redirect and passed to `$location.url()`\n * - **void** or any **truthy** value tells `$urlRouter` that the url was handled.\n *\n * @example\n * \n * var app = angular.module('app', ['ui.router.router']);\n *\n * app.config(function ($urlRouterProvider) {\n * $urlRouterProvider.when($state.url, function ($match, $stateParams) {\n * if ($state.$current.navigable !== state ||\n * !equalForKeys($match, $stateParams) {\n * $state.transitionTo(state, $match, false);\n * }\n * });\n * });\n *
\n *\n * @param {string|object} what The incoming path that you want to redirect.\n * @param {string|object} handler The path you want to redirect your user to.\n */\n this.when = function (what, handler) {\n var redirect, handlerIsString = isString(handler);\n if (isString(what)) what = $urlMatcherFactory.compile(what);\n\n if (!handlerIsString && !isFunction(handler) && !isArray(handler))\n throw new Error(\"invalid 'handler' in when()\");\n\n var strategies = {\n matcher: function (what, handler) {\n if (handlerIsString) {\n redirect = $urlMatcherFactory.compile(handler);\n handler = ['$match', function ($match) { return redirect.format($match); }];\n }\n return extend(function ($injector, $location) {\n return handleIfMatch($injector, handler, what.exec($location.path(), $location.search()));\n }, {\n prefix: isString(what.prefix) ? what.prefix : ''\n });\n },\n regex: function (what, handler) {\n if (what.global || what.sticky) throw new Error(\"when() RegExp must not be global or sticky\");\n\n if (handlerIsString) {\n redirect = handler;\n handler = ['$match', function ($match) { return interpolate(redirect, $match); }];\n }\n return extend(function ($injector, $location) {\n return handleIfMatch($injector, handler, what.exec($location.path()));\n }, {\n prefix: regExpPrefix(what)\n });\n }\n };\n\n var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp };\n\n for (var n in check) {\n if (check[n]) return this.rule(strategies[n](what, handler));\n }\n\n throw new Error(\"invalid 'what' in when()\");\n };\n\n /**\n * @ngdoc function\n * @name ui.router.router.$urlRouterProvider#deferIntercept\n * @methodOf ui.router.router.$urlRouterProvider\n *\n * @description\n * Disables (or enables) deferring location change interception.\n *\n * If you wish to customize the behavior of syncing the URL (for example, if you wish to\n * defer a transition but maintain the current URL), call this method at configuration time.\n * Then, at run time, call `$urlRouter.listen()` after you have configured your own\n * `$locationChangeSuccess` event handler.\n *\n * @example\n * \n * var app = angular.module('app', ['ui.router.router']);\n *\n * app.config(function ($urlRouterProvider) {\n *\n * // Prevent $urlRouter from automatically intercepting URL changes;\n * // this allows you to configure custom behavior in between\n * // location changes and route synchronization:\n * $urlRouterProvider.deferIntercept();\n *\n * }).run(function ($rootScope, $urlRouter, UserService) {\n *\n * $rootScope.$on('$locationChangeSuccess', function(e) {\n * // UserService is an example service for managing user state\n * if (UserService.isLoggedIn()) return;\n *\n * // Prevent $urlRouter's default handler from firing\n * e.preventDefault();\n *\n * UserService.handleLogin().then(function() {\n * // Once the user has logged in, sync the current URL\n * // to the router:\n * $urlRouter.sync();\n * });\n * });\n *\n * // Configures $urlRouter's listener *after* your custom listener\n * $urlRouter.listen();\n * });\n *
\n *\n * @param {boolean} defer Indicates whether to defer location change interception. Passing\n no parameter is equivalent to `true`.\n */\n this.deferIntercept = function (defer) {\n if (defer === undefined) defer = true;\n interceptDeferred = defer;\n };\n\n /**\n * @ngdoc object\n * @name ui.router.router.$urlRouter\n *\n * @requires $location\n * @requires $rootScope\n * @requires $injector\n * @requires $browser\n *\n * @description\n *\n */\n this.$get = $get;\n $get.$inject = ['$location', '$rootScope', '$injector', '$browser'];\n function $get( $location, $rootScope, $injector, $browser) {\n\n var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl;\n\n function appendBasePath(url, isHtml5, absolute) {\n if (baseHref === '/') return url;\n if (isHtml5) return baseHref.slice(0, -1) + url;\n if (absolute) return baseHref.slice(1) + url;\n return url;\n }\n\n // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree\n function update(evt) {\n if (evt && evt.defaultPrevented) return;\n var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl;\n lastPushedUrl = undefined;\n // TODO: Re-implement this in 1.0 for https://github.com/angular-ui/ui-router/issues/1573\n //if (ignoreUpdate) return true;\n\n function check(rule) {\n var handled = rule($injector, $location);\n\n if (!handled) return false;\n if (isString(handled)) $location.replace().url(handled);\n return true;\n }\n var n = rules.length, i;\n\n for (i = 0; i < n; i++) {\n if (check(rules[i])) return;\n }\n // always check otherwise last to allow dynamic updates to the set of rules\n if (otherwise) check(otherwise);\n }\n\n function listen() {\n listener = listener || $rootScope.$on('$locationChangeSuccess', update);\n return listener;\n }\n\n if (!interceptDeferred) listen();\n\n return {\n /**\n * @ngdoc function\n * @name ui.router.router.$urlRouter#sync\n * @methodOf ui.router.router.$urlRouter\n *\n * @description\n * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`.\n * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event,\n * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed\n * with the transition by calling `$urlRouter.sync()`.\n *\n * @example\n * \n * angular.module('app', ['ui.router'])\n * .run(function($rootScope, $urlRouter) {\n * $rootScope.$on('$locationChangeSuccess', function(evt) {\n * // Halt state change from even starting\n * evt.preventDefault();\n * // Perform custom logic\n * var meetsRequirement = ...\n * // Continue with the update and state transition if logic allows\n * if (meetsRequirement) $urlRouter.sync();\n * });\n * });\n *
\n */\n sync: function() {\n update();\n },\n\n listen: function() {\n return listen();\n },\n\n update: function(read) {\n if (read) {\n location = $location.url();\n return;\n }\n if ($location.url() === location) return;\n\n $location.url(location);\n $location.replace();\n },\n\n push: function(urlMatcher, params, options) {\n var url = urlMatcher.format(params || {});\n\n // Handle the special hash param, if needed\n if (url !== null && params && params['#']) {\n url += '#' + params['#'];\n }\n\n $location.url(url);\n lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined;\n if (options && options.replace) $location.replace();\n },\n\n /**\n * @ngdoc function\n * @name ui.router.router.$urlRouter#href\n * @methodOf ui.router.router.$urlRouter\n *\n * @description\n * A URL generation method that returns the compiled URL for a given\n * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters.\n *\n * @example\n * \n * $bob = $urlRouter.href(new UrlMatcher(\"/about/:person\"), {\n * person: \"bob\"\n * });\n * // $bob == \"/about/bob\";\n *
\n *\n * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate.\n * @param {object=} params An object of parameter values to fill the matcher's required parameters.\n * @param {object=} options Options object. The options are:\n *\n * - **`absolute`** - {boolean=false}, If true will generate an absolute url, e.g. \"http://www.example.com/fullurl\".\n *\n * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher`\n */\n href: function(urlMatcher, params, options) {\n if (!urlMatcher.validates(params)) return null;\n\n var isHtml5 = $locationProvider.html5Mode();\n if (angular.isObject(isHtml5)) {\n isHtml5 = isHtml5.enabled;\n }\n \n var url = urlMatcher.format(params);\n options = options || {};\n\n if (!isHtml5 && url !== null) {\n url = \"#\" + $locationProvider.hashPrefix() + url;\n }\n\n // Handle special hash param, if needed\n if (url !== null && params && params['#']) {\n url += '#' + params['#'];\n }\n\n url = appendBasePath(url, isHtml5, options.absolute);\n\n if (!options.absolute || !url) {\n return url;\n }\n\n var slash = (!isHtml5 && url ? '/' : ''), port = $location.port();\n port = (port === 80 || port === 443 ? '' : ':' + port);\n\n return [$location.protocol(), '://', $location.host(), port, slash, url].join('');\n }\n };\n }\n}\n\nangular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider);\n\n/**\n * @ngdoc object\n * @name ui.router.state.$stateProvider\n *\n * @requires ui.router.router.$urlRouterProvider\n * @requires ui.router.util.$urlMatcherFactoryProvider\n *\n * @description\n * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely\n * on state.\n *\n * A state corresponds to a \"place\" in the application in terms of the overall UI and\n * navigation. A state describes (via the controller / template / view properties) what\n * the UI looks like and does at that place.\n *\n * States often have things in common, and the primary way of factoring out these\n * commonalities in this model is via the state hierarchy, i.e. parent/child states aka\n * nested states.\n *\n * The `$stateProvider` provides interfaces to declare these states for your app.\n */\n$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider'];\nfunction $StateProvider( $urlRouterProvider, $urlMatcherFactory) {\n\n var root, states = {}, $state, queue = {}, abstractKey = 'abstract';\n\n // Builds state properties from definition passed to registerState()\n var stateBuilder = {\n\n // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined.\n // state.children = [];\n // if (parent) parent.children.push(state);\n parent: function(state) {\n if (isDefined(state.parent) && state.parent) return findState(state.parent);\n // regex matches any valid composite state name\n // would match \"contact.list\" but not \"contacts\"\n var compositeName = /^(.+)\\.[^.]+$/.exec(state.name);\n return compositeName ? findState(compositeName[1]) : root;\n },\n\n // inherit 'data' from parent and override by own values (if any)\n data: function(state) {\n if (state.parent && state.parent.data) {\n state.data = state.self.data = extend({}, state.parent.data, state.data);\n }\n return state.data;\n },\n\n // Build a URLMatcher if necessary, either via a relative or absolute URL\n url: function(state) {\n var url = state.url, config = { params: state.params || {} };\n\n if (isString(url)) {\n if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config);\n return (state.parent.navigable || root).url.concat(url, config);\n }\n\n if (!url || $urlMatcherFactory.isMatcher(url)) return url;\n throw new Error(\"Invalid url '\" + url + \"' in state '\" + state + \"'\");\n },\n\n // Keep track of the closest ancestor state that has a URL (i.e. is navigable)\n navigable: function(state) {\n return state.url ? state : (state.parent ? state.parent.navigable : null);\n },\n\n // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params\n ownParams: function(state) {\n var params = state.url && state.url.params || new $$UMFP.ParamSet();\n forEach(state.params || {}, function(config, id) {\n if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, \"config\");\n });\n return params;\n },\n\n // Derive parameters for this state and ensure they're a super-set of parent's parameters\n params: function(state) {\n return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet();\n },\n\n // If there is no explicit multi-view configuration, make one up so we don't have\n // to handle both cases in the view directive later. Note that having an explicit\n // 'views' property will mean the default unnamed view properties are ignored. This\n // is also a good time to resolve view names to absolute names, so everything is a\n // straight lookup at link time.\n views: function(state) {\n var views = {};\n\n forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) {\n if (name.indexOf('@') < 0) name += '@' + state.parent.name;\n views[name] = view;\n });\n return views;\n },\n\n // Keep a full path from the root down to this state as this is needed for state activation.\n path: function(state) {\n return state.parent ? state.parent.path.concat(state) : []; // exclude root from path\n },\n\n // Speed up $state.contains() as it's used a lot\n includes: function(state) {\n var includes = state.parent ? extend({}, state.parent.includes) : {};\n includes[state.name] = true;\n return includes;\n },\n\n $delegates: {}\n };\n\n function isRelative(stateName) {\n return stateName.indexOf(\".\") === 0 || stateName.indexOf(\"^\") === 0;\n }\n\n function findState(stateOrName, base) {\n if (!stateOrName) return undefined;\n\n var isStr = isString(stateOrName),\n name = isStr ? stateOrName : stateOrName.name,\n path = isRelative(name);\n\n if (path) {\n if (!base) throw new Error(\"No reference point given for path '\" + name + \"'\");\n base = findState(base);\n \n var rel = name.split(\".\"), i = 0, pathLength = rel.length, current = base;\n\n for (; i < pathLength; i++) {\n if (rel[i] === \"\" && i === 0) {\n current = base;\n continue;\n }\n if (rel[i] === \"^\") {\n if (!current.parent) throw new Error(\"Path '\" + name + \"' not valid for state '\" + base.name + \"'\");\n current = current.parent;\n continue;\n }\n break;\n }\n rel = rel.slice(i).join(\".\");\n name = current.name + (current.name && rel ? \".\" : \"\") + rel;\n }\n var state = states[name];\n\n if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) {\n return state;\n }\n return undefined;\n }\n\n function queueState(parentName, state) {\n if (!queue[parentName]) {\n queue[parentName] = [];\n }\n queue[parentName].push(state);\n }\n\n function flushQueuedChildren(parentName) {\n var queued = queue[parentName] || [];\n while(queued.length) {\n registerState(queued.shift());\n }\n }\n\n function registerState(state) {\n // Wrap a new object around the state so we can store our private details easily.\n state = inherit(state, {\n self: state,\n resolve: state.resolve || {},\n toString: function() { return this.name; }\n });\n\n var name = state.name;\n if (!isString(name) || name.indexOf('@') >= 0) throw new Error(\"State must have a valid name\");\n if (states.hasOwnProperty(name)) throw new Error(\"State '\" + name + \"'' is already defined\");\n\n // Get parent name\n var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.'))\n : (isString(state.parent)) ? state.parent\n : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name\n : '';\n\n // If parent is not registered yet, add state to queue and register later\n if (parentName && !states[parentName]) {\n return queueState(parentName, state.self);\n }\n\n for (var key in stateBuilder) {\n if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]);\n }\n states[name] = state;\n\n // Register the state in the global state list and with $urlRouter if necessary.\n if (!state[abstractKey] && state.url) {\n $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {\n if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {\n $state.transitionTo(state, $match, { inherit: true, location: false });\n }\n }]);\n }\n\n // Register any queued children\n flushQueuedChildren(name);\n\n return state;\n }\n\n // Checks text to see if it looks like a glob.\n function isGlob (text) {\n return text.indexOf('*') > -1;\n }\n\n // Returns true if glob matches current $state name.\n function doesStateMatchGlob (glob) {\n var globSegments = glob.split('.'),\n segments = $state.$current.name.split('.');\n\n //match single stars\n for (var i = 0, l = globSegments.length; i < l; i++) {\n if (globSegments[i] === '*') {\n segments[i] = '*';\n }\n }\n\n //match greedy starts\n if (globSegments[0] === '**') {\n segments = segments.slice(indexOf(segments, globSegments[1]));\n segments.unshift('**');\n }\n //match greedy ends\n if (globSegments[globSegments.length - 1] === '**') {\n segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE);\n segments.push('**');\n }\n\n if (globSegments.length != segments.length) {\n return false;\n }\n\n return segments.join('') === globSegments.join('');\n }\n\n\n // Implicit root state that is always active\n root = registerState({\n name: '',\n url: '^',\n views: null,\n 'abstract': true\n });\n root.navigable = null;\n\n\n /**\n * @ngdoc function\n * @name ui.router.state.$stateProvider#decorator\n * @methodOf ui.router.state.$stateProvider\n *\n * @description\n * Allows you to extend (carefully) or override (at your own peril) the \n * `stateBuilder` object used internally by `$stateProvider`. This can be used \n * to add custom functionality to ui-router, for example inferring templateUrl \n * based on the state name.\n *\n * When passing only a name, it returns the current (original or decorated) builder\n * function that matches `name`.\n *\n * The builder functions that can be decorated are listed below. Though not all\n * necessarily have a good use case for decoration, that is up to you to decide.\n *\n * In addition, users can attach custom decorators, which will generate new \n * properties within the state's internal definition. There is currently no clear \n * use-case for this beyond accessing internal states (i.e. $state.$current), \n * however, expect this to become increasingly relevant as we introduce additional \n * meta-programming features.\n *\n * **Warning**: Decorators should not be interdependent because the order of \n * execution of the builder functions in non-deterministic. Builder functions \n * should only be dependent on the state definition object and super function.\n *\n *\n * Existing builder functions and current return values:\n *\n * - **parent** `{object}` - returns the parent state object.\n * - **data** `{object}` - returns state data, including any inherited data that is not\n * overridden by own values (if any).\n * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher}\n * or `null`.\n * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is \n * navigable).\n * - **params** `{object}` - returns an array of state params that are ensured to \n * be a super-set of parent's params.\n * - **views** `{object}` - returns a views object where each key is an absolute view \n * name (i.e. \"viewName@stateName\") and each value is the config object \n * (template, controller) for the view. Even when you don't use the views object \n * explicitly on a state config, one is still created for you internally.\n * So by decorating this builder function you have access to decorating template \n * and controller properties.\n * - **ownParams** `{object}` - returns an array of params that belong to the state, \n * not including any params defined by ancestor states.\n * - **path** `{string}` - returns the full path from the root down to this state. \n * Needed for state activation.\n * - **includes** `{object}` - returns an object that includes every state that \n * would pass a `$state.includes()` test.\n *\n * @example\n * \n * // Override the internal 'views' builder with a function that takes the state\n * // definition, and a reference to the internal function being overridden:\n * $stateProvider.decorator('views', function (state, parent) {\n * var result = {},\n * views = parent(state);\n *\n * angular.forEach(views, function (config, name) {\n * var autoName = (state.name + '.' + name).replace('.', '/');\n * config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';\n * result[name] = config;\n * });\n * return result;\n * });\n *\n * $stateProvider.state('home', {\n * views: {\n * 'contact.list': { controller: 'ListController' },\n * 'contact.item': { controller: 'ItemController' }\n * }\n * });\n *\n * // ...\n *\n * $state.go('home');\n * // Auto-populates list and item views with /partials/home/contact/list.html,\n * // and /partials/home/contact/item.html, respectively.\n *
\n *\n * @param {string} name The name of the builder function to decorate. \n * @param {object} func A function that is responsible for decorating the original \n * builder function. The function receives two parameters:\n *\n * - `{object}` - state - The state config object.\n * - `{object}` - super - The original builder function.\n *\n * @return {object} $stateProvider - $stateProvider instance\n */\n this.decorator = decorator;\n function decorator(name, func) {\n /*jshint validthis: true */\n if (isString(name) && !isDefined(func)) {\n return stateBuilder[name];\n }\n if (!isFunction(func) || !isString(name)) {\n return this;\n }\n if (stateBuilder[name] && !stateBuilder.$delegates[name]) {\n stateBuilder.$delegates[name] = stateBuilder[name];\n }\n stateBuilder[name] = func;\n return this;\n }\n\n /**\n * @ngdoc function\n * @name ui.router.state.$stateProvider#state\n * @methodOf ui.router.state.$stateProvider\n *\n * @description\n * Registers a state configuration under a given state name. The stateConfig object\n * has the following acceptable properties.\n *\n * @param {string} name A unique state name, e.g. \"home\", \"about\", \"contacts\".\n * To create a parent/child state use a dot, e.g. \"about.sales\", \"home.newest\".\n * @param {object} stateConfig State configuration object.\n * @param {string|function=} stateConfig.template\n * \n * html template as a string or a function that returns\n * an html template as a string which should be used by the uiView directives. This property \n * takes precedence over templateUrl.\n * \n * If `template` is a function, it will be called with the following parameters:\n *\n * - {array.<object>} - state parameters extracted from the current $location.path() by\n * applying the current state\n *\n * template:\n * \"inline template definition
\" +\n * \"\"
\n * template: function(params) {\n * return \"generated template
\"; }
\n *