PageSourceSearch

https://patentfsi.com/wp-content/plugins/wp-google-map-plugin/assets/js/frontend.js?ver=4.9.22

js patentfsi.com collected 2026-09-30 14:01:50 UTC 109,538 bytes, 3,077 lines download raw bytes

1/**
2 * This jQuery plugin displays pagination links inside the selected elements.
3 *
4 * @author Gabriel Birke (birke *at* d-scribe *dot* de)
5 * @version 1.2
6 * @param {int} maxentries Number of entries to paginate
7 * @param {Object} opts Several options (see README for documentation)
8 * @return {Object} jQuery Object
9 */
10jQuery.fn.pagination = function(maxentries, opts) {
11    opts = jQuery.extend({
12        items_per_page: 10,
13        num_display_entries: 10,
14        current_page: 0,
15        num_edge_entries: 0,
16        link_to: "#",
17        prev_text: "Prev",
18        next_text: "Next",
19        ellipse_text: "...",
20        prev_show_always: true,
21        next_show_always: true,
22        data_source: '',
23        listing_container: '',
24
25        callback: function() {
26            return false;
27        }
28    }, opts || {});
29
30    return this.each(function() {
31        /**
32         * Calculate the maximum number of pages
33         */
34        function numPages() {
35            return Math.ceil(maxentries / opts.items_per_page);
36        }
37
38        /**
39         * Calculate start and end point of pagination links depending on 
40         * current_page and num_display_entries.
41         * @return {Array}
42         */
43        function getInterval() {
44            var ne_half = Math.ceil(opts.num_display_entries / 2);
45            var np = numPages();
46            var upper_limit = np - opts.num_display_entries;
47            var start = current_page > ne_half ? Math.max(Math.min(current_page - ne_half, upper_limit), 0) : 0;
48            var end = current_page > ne_half ? Math.min(current_page + ne_half, np) : Math.min(opts.num_display_entries, np);
49            return [start, end];
50        }
51
52        /**
53         * This is the event handling function for the pagination links. 
54         * @param {int} page_id The new page number
55         */
56        function pageSelected(page_id, evt) {
57            current_page = page_id;
58            drawLinks();
59            var continuePropagation = opts.callback(page_id, panel);
60            if (!continuePropagation) {
61                if (evt.stopPropagation) {
62                    evt.stopPropagation();
63                } else {
64                    evt.cancelBubble = true;
65                }
66            }
67            return continuePropagation;
68        }
69
70        /**
71         * This function inserts the pagination links into the container element
72         */
73        function drawLinks() {
74            panel.empty();
75            var interval = getInterval();
76            var np = numPages();
77            // This helper function returns a handler function that calls pageSelected with the right page_id
78            var getClickHandler = function(page_id) {
79                    return function(evt) {
80                        return pageSelected(page_id, evt);
81                    }
82                }
83                // Helper function for generating a single link (or a span tag if it's the current page)
84            var appendItem = function(page_id, appendopts) {
85                    page_id = page_id < 0 ? 0 : (page_id < np ? page_id : np - 1); // Normalize page id to sane value
86                    appendopts = jQuery.extend({
87                        text: page_id + 1,
88                        classes: ""
89                    }, appendopts || {});
90                    if (page_id == current_page) {
91                        var lnk = jQuery("<span class='current'>" + (appendopts.text) + "</span>");
92                    } else {
93                        var lnk = jQuery("<a>" + (appendopts.text) + "</a>")
94                            .bind("click", getClickHandler(page_id))
95                            .attr('href', opts.link_to.replace(/__id__/, page_id));
96
97
98                    }
99                    if (appendopts.classes) {
100                        lnk.addClass(appendopts.classes);
101                    }
102                    panel.append(lnk);
103                }
104                // Generate "Previous"-Link
105            if (opts.prev_text && (current_page > 0 || opts.prev_show_always)) {
106                appendItem(current_page - 1, {
107                    text: opts.prev_text,
108                    classes: "prev"
109                });
110            }
111            // Generate starting points
112            if (interval[0] >
112 0 && opts.num_edge_entries > 0) {
113                var end = Math.min(opts.num_edge_entries, interval[0]);
114                for (var i = 0; i < end; i++) {
115                    appendItem(i);
116                }
117                if (opts.num_edge_entries < interval[0] && opts.ellipse_text) {
118                    jQuery("<span>" + opts.ellipse_text + "</span>").appendTo(panel);
119                }
120            }
121            // Generate interval links
122            for (var i = interval[0]; i < interval[1]; i++) {
123                appendItem(i);
124            }
125            // Generate ending points
126            if (interval[1] < np && opts.num_edge_entries > 0) {
127                if (np - opts.num_edge_entries > interval[1] && opts.ellipse_text) {
128                    jQuery("<span>" + opts.ellipse_text + "</span>").appendTo(panel);
129                }
130                var begin = Math.max(np - opts.num_edge_entries, interval[1]);
131                for (var i = begin; i < np; i++) {
132                    appendItem(i);
133                }
134
135            }
136            // Generate "Next"-Link
137            if (opts.next_text && (current_page < np - 1 || opts.next_show_always)) {
138                appendItem(current_page + 1, {
139                    text: opts.next_text,
140                    classes: "next"
141                });
142            }
143        }
144
145        // Extract current_page from options
146        var current_page = opts.current_page;
147        // Create a sane value for maxentries and items_per_page
148        maxentries = (!maxentries || maxentries < 0) ? 1 : maxentries;
149        opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0) ? 1 : opts.items_per_page;
150        // Store DOM element for easy access from all inner functions
151        var panel = jQuery(this);
152        // Attach control functions to the DOM element 
153        this.selectPage = function(page_id) {
154            pageSelected(page_id);
155        }
156        this.prevPage = function() {
157            if (current_page > 0) {
158                pageSelected(current_page - 1);
159                return true;
160            } else {
161                return false;
162            }
163        }
164        this.nextPage = function() {
165                if (current_page < numPages() - 1) {
166                    pageSelected(current_page + 1);
167                    return true;
168                } else {
169                    return false;
170                }
171            }
172            // When all initialisation is done, draw the links
173        drawLinks();
174        // call callback function
175        opts.callback(current_page, this);
176    });
177}
178
179
180/**
181 * @name MarkerClustererPlus for Google Maps V3
182 * @version 2.1.2 [May 28, 2014]
183 * @author Gary Little
184 * @fileoverview
185 * The library creates and manages per-zoom-level clusters for large amounts of markers.
186 * <p>
187 * This is an enhanced V3 implementation of the
188 * <a href="http://gmaps-utility-library-dev.googlecode.com/svn/tags/markerclusterer/"
189 * >V2 MarkerClusterer</a> by Xiaoxi Wu. It is based on the
190 * <a href="http://google-maps-utility-library-v3.googlecode.com/svn/tags/markerclusterer/"
191 * >V3 MarkerClusterer</a> port by Luke Mahe. MarkerClustererPlus was created by Gary Little.
192 * <p>
193 * v2.0 release: MarkerClustererPlus v2.0 is backward compatible with MarkerClusterer v1.0. It
194 *  adds support for the <code>ignoreHidden</code>, <code>title</code>, <code>batchSizeIE</code>,
195 *  and <code>calculator</code> properties as well as support for four more events. It also allows
196 *  greater control over the styling of the text that appears on the cluster marker. The
197 *  documentation has been significantly improved and the overall code has been simplified and
198 *  polished. Very large numbers of markers can now be managed without causing Javascript timeout
199 *  errors on Internet Explorer. Note that the name of the <code>clusterclick</code> event has been
200 *  deprecated. The new name is <code>click</code>, so please change your application code now.
201 */
202
203/**
204 * Licensed under the Apache License, Version 2.0 (the "License");
205 * you may not use this file except in compliance with the License.
206 * You may obtain a copy of the License at
207 *
208 *     http://www.apache.org/licenses/LICENSE-2.0
209 *
210 * Unless required by applicable law or agreed to in writing, softw
210are
211 * distributed under the License is distributed on an "AS IS" BASIS,
212 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
213 * See the License for the specific language governing permissions and
214 * limitations under the License.
215 */
216
217
218/**
219 * @name ClusterIconStyle
220 * @class This class represents the object for values in the <code>styles</code> array passed
221 *  to the {@link MarkerClusterer} constructor. The element in this array that is used to
222 *  style the cluster icon is determined by calling the <code>calculator</code> function.
223 *
224 * @property {string} url The URL of the cluster icon image file. Required.
225 * @property {number} height The display height (in pixels) of the cluster icon. Required.
226 * @property {number} width The display width (in pixels) of the cluster icon. Required.
227 * @property {Array} [anchorText] The position (in pixels) from the center of the cluster icon to
228 *  where the text label is to be centered and drawn. The format is <code>[yoffset, xoffset]</code>
229 *  where <code>yoffset</code> increases as you go down from center and <code>xoffset</code>
230 *  increases to the right of center. The default is <code>[0, 0]</code>.
231 * @property {Array} [anchorIcon] The anchor position (in pixels) of the cluster icon. This is the
232 *  spot on the cluster icon that is to be aligned with the cluster position. The format is
233 *  <code>[yoffset, xoffset]</code> where <code>yoffset</code> increases as you go down and
234 *  <code>xoffset</code> increases to the right of the top-left corner of the icon. The default
235 *  anchor position is the center of the cluster icon.
236 * @property {string} [textColor="black"] The color of the label text shown on the
237 *  cluster icon.
238 * @property {number} [textSize=11] The size (in pixels) of the label text shown on the
239 *  cluster icon.
240 * @property {string} [textDecoration="none"] The value of the CSS <code>text-decoration</code>
241 *  property for the label text shown on the cluster icon.
242 * @property {string} [fontWeight="bold"] The value of the CSS <code>font-weight</code>
243 *  property for the label text shown on the cluster icon.
244 * @property {string} [fontStyle="normal"] The value of the CSS <code>font-style</code>
245 *  property for the label text shown on the cluster icon.
246 * @property {string} [fontFamily="Arial,sans-serif"] The value of the CSS <code>font-family</code>
247 *  property for the label text shown on the cluster icon.
248 * @property {string} [backgroundPosition="0 0"] The position of the cluster icon image
249 *  within the image defined by <code>url</code>. The format is <code>"xpos ypos"</code>
250 *  (the same format as for the CSS <code>background-position</code> property). You must set
251 *  this property appropriately when the image defined by <code>url</code> represents a sprite
252 *  containing multiple images. Note that the position <i>must</i> be specified in px units.
253 */
254/**
255 * @name ClusterIconInfo
256 * @class This class is an object containing general information about a cluster icon. This is
257 *  the object that a <code>calculator</code> function returns.
258 *
259 * @property {string} text The text of the label to be shown on the cluster icon.
260 * @property {number} index The index plus 1 of the element in the <code>styles</code>
261 *  array to be used to style the cluster icon.
262 * @property {string} title The tooltip to display when the mouse moves over the cluster icon.
263 *  If this value is <code>undefined</code> or <code>""</code>, <code>title</code> is set to the
264 *  value of the <code>title</code> property passed to the MarkerClusterer.
265 */
266/**
267 * A cluster icon.
268 *
269 * @constructor
270 * @extends google.maps.OverlayView
271 * @param {Cluster} cluster The cluster with which the icon is to be associated.
272 * @param {Array} [styles] An array of {@link ClusterIconStyle} defining the cluster icons
273 *  to use for various cluster sizes.
274 * @private
275 */
276function ClusterIcon(cluster, styles) {
277    cluster.getMarkerClusterer().extend(ClusterIcon, google.maps.OverlayView);
278
279    this.cluster_ = cluster;
280    this.className_ = cluster.getMarkerClusterer().getClusterClass();
281    this.styles_ = styles;
282    this.center_ = null;
283    this.div_ = null;
284    this.sums_ = null;
285    this.visible_ = false;
286
287    this.setMap(cluster.getMap()); // Note: this causes onAdd to be called
288}
289
290
291/**
292 * Adds the icon to the DOM.
293 */
294ClusterIcon.prototype.onAdd = function() {
295    var cClusterIcon = this;
296    var cMouseDownInCluster;
297    var cDraggingMapByCluster;
298
299    this.div_ = document.createElement("div");
300    this.div_.className = this.className_;
301    if (this.visible_) {
302        this.show();
303    }
304
305    this.getPanes().overlayMouseTarget.appendChild(this.div_);
306
307    // Fix for Issue 157
308    this.boundsChangedListener_ = google.maps.event.addListener(this.getMap(), "bounds_changed", function() {
309        cDraggingMapByCluster = cMouseDownInCluster;
310    });
311
312    google.maps.event.addDomListener(this.div_, "mousedown", function() {
313        cMouseDownInCluster = true;
314        cDraggingMapByCluster = false;
315    });
316
317    google.maps.event.addDomListener(this.div_, "click", function(e) {
318        cMouseDownInCluster = false;
319        if (!cDraggingMapByCluster) {
320            var theBounds;
321            var mz;
322            var mc = cClusterIcon.cluster_.getMarkerClusterer();
323            /**
324             * This event is fired when a cluster marker is clicked.
325             * @name MarkerClusterer#click
326             * @param {Cluster} c The cluster that was clicked.
327             * @event
328             */
329            google.maps.event.trigger(mc, "click", cClusterIcon.cluster_);
330            google.maps.event.trigger(mc, "clusterclick", cClusterIcon.cluster_); // deprecated name
331
332            // The default click handler follows. Disable it by setting
333            // the zoomOnClick property to false.
334            if (mc.getZoomOnClick()) {
335                // Zoom into the cluster.
336                mz = mc.getMaxZoom();
337                theBounds = cClusterIcon.cluster_.getBounds();
338                mc.getMap().fitBounds(theBounds);
339                // There is a fix for Issue 170 here:
340                setTimeout(function() {
341                    mc.getMap().fitBounds(theBounds);
342                    // Don't zoom beyond the max zoom level
343                    if (mz !== null && (mc.getMap().getZoom() > mz)) {
344                        mc.getMap().setZoom(mz + 1);
345                    }
346                }, 100);
347            }
348
349            // Prevent event propagation to the map:
350            e.cancelBubble = true;
351            if (e.stopPropagation) {
352                e.stopPropagation();
353            }
354        }
355    });
356
357    google.maps.event.addDomListener(this.div_, "mouseover", function() {
358        var mc = cClusterIcon.cluster_.getMarkerClusterer();
359        /**
360         * This event is fired when the mouse moves over a cluster marker.
361         * @name MarkerClusterer#mouseover
362         * @param {Cluster} c The cluster that the mouse moved over.
363         * @event
364         */
365        google.maps.event.trigger(mc, "mouseover", cClusterIcon.cluster_);
366    });
367
368    google.maps.event.addDomListener(this.div_, "mouseout", function() {
369        var mc = cClusterIcon.cluster_.getMarkerClusterer();
370        /**
vendor: 14,931 bytes, lines 371-802
371         * This event is fired when the mouse moves out of a cluster marker.
372         * @name MarkerClusterer#mouseout
373         * @param {Cluster} c The cluster that the mouse moved out of.
374         * @event
375         */
376        google.maps.event.trigger(mc, "mouseout", cClusterIcon.cluster_);
377    });
378};
379
380
381/**
382 * Removes the icon from the DOM.
383 */
384ClusterIcon.prototype.onRemove = function() {
385    if (this.div_ && this.div_.parentNode) {
386        this.hide();
387        google.maps.event.removeListener(this.boundsChangedListener_);
388        google.maps.event.clearInstanceListeners(this.div_);
389        this.div_.parentNode.removeChild(this.div_);
390        this.div_ = null;
391    }
392};
393
394
395/**
396 * Draws the icon.
397 */
398ClusterIcon.prototype.draw = function() {
399    if (this.visible_) {
400        var pos = this.getPosFromLatLng_(this.center_);
401        this.div_.style.top = pos.y + "px";
402        this.div_.style.left = pos.x + "px";
403    }
404};
405
406
407/**
408 * Hides the icon.
409 */
410ClusterIcon.prototype.hide = function() {
411    if (this.div_) {
412        this.div_.style.display = "none";
413    }
414    this.visible_ = false;
415};
416
417
418/**
419 * Positions and shows the icon.
420 */
421ClusterIcon.prototype.show = function() {
422    if (this.div_) {
423        var img = "";
424        // NOTE: values must be specified in px units
425        var bp = this.backgroundPosition_.split(" ");
426        var spriteH = parseInt(bp[0].replace(/^\s+|\s+$/g, ""), 10);
427        var spriteV = parseInt(bp[1].replace(/^\s+|\s+$/g, ""), 10);
428        var pos = this.getPosFromLatLng_(this.center_);
429        this.div_.style.cssText = this.createCss(pos);
430        img = "<img src='" + this.url_ + "' style='position: absolute; top: " + spriteV + "px; left: " + spriteH + "px; ";
431        if (!this.cluster_.getMarkerClusterer().enableRetinaIcons_) {
432            img += "clip: rect(" + (-1 * spriteV) + "px, " + ((-1 * spriteH) + this.width_) + "px, " +
433                ((-1 * spriteV) + this.height_) + "px, " + (-1 * spriteH) + "px);";
434        }
435        img += "'>";
436        this.div_.innerHTML = img + "<div style='" +
437            "position: absolute;" +
438            "top: " + this.anchorText_[0] + "px;" +
439            "left: " + this.anchorText_[1] + "px;" +
440            "color: " + this.textColor_ + ";" +
441            "font-size: " + this.textSize_ + "px;" +
442            "font-family: " + this.fontFamily_ + ";" +
443            "font-weight: " + this.fontWeight_ + ";" +
444            "font-style: " + this.fontStyle_ + ";" +
445            "text-decoration: " + this.textDecoration_ + ";" +
446            "text-align: center;" +
447            "width: " + this.width_ + "px;" +
448            "line-height:" + this.height_ + "px;" +
449            "'>" + this.sums_.text + "</div>";
450        if (typeof this.sums_.title === "undefined" || this.sums_.title === "") {
451            this.div_.title = this.cluster_.getMarkerClusterer().getTitle();
452        } else {
453            this.div_.title = this.sums_.title;
454        }
455        this.div_.style.display = "";
456    }
457    this.visible_ = true;
458};
459
460
461/**
462 * Sets the icon styles to the appropriate element in the styles array.
463 *
464 * @param {ClusterIconInfo} sums The icon label text and styles index.
465 */
466ClusterIcon.prototype.useStyle = function(sums) {
467    this.sums_ = sums;
468    var index = Math.max(0, sums.index - 1);
469    index = Math.min(this.styles_.length - 1, index);
470    var style = this.styles_[index];
471    this.url_ = style.url;
472    this.height_ = style.height;
473    this.width_ = style.width;
474    this.anchorText_ = style.anchorText || [0, 0];
475    this.anchorIcon_ = style.anchorIcon || [parseInt(this.height_ / 2, 10), parseInt(this.width_ / 2, 10)];
476    this.textColor_ = style.textColor || "black";
477    this.textSize_ = style.textSize || 11;
478    this.textDecoration_ = style.textDecoration || "none";
479    this.fontWeight_ = style.fontWeight || "bold";
480    this.fontStyle_ = style.fontStyle || "normal";
481    this.fontFamily_ = style.fontFamily || "Arial,sans-serif";
482    this.backgroundPosition_ = style.backgroundPosition || "0 0";
483};
484
485
486/**
487 * Sets the position at which to center the icon.
488 *
489 * @param {google.maps.LatLng} center The latlng to set as the center.
490 */
491ClusterIcon.prototype.setCenter = function(center) {
492    this.center_ = center;
493};
494
495
496/**
497 * Creates the cssText style parameter based on the position of the icon.
498 *
499 * @param {google.maps.Point} pos The position of the icon.
500 * @return {string} The CSS style text.
501 */
502ClusterIcon.prototype.createCss = function(pos) {
503    var style = [];
504    style.push("cursor: pointer;");
505    style.push("position: absolute; top: " + pos.y + "px; left: " + pos.x + "px;");
506    style.push("width: " + this.width_ + "px; height: " + this.height_ + "px;");
507    return style.join("");
508};
509
510
511/**
512 * Returns the position at which to place the DIV depending on the latlng.
513 *
514 * @param {google.maps.LatLng} latlng The position in latlng.
515 * @return {google.maps.Point} The position in pixels.
516 */
517ClusterIcon.prototype.getPosFromLatLng_ = function(latlng) {
518    var pos = this.getProjection().fromLatLngToDivPixel(latlng);
519    pos.x -= this.anchorIcon_[1];
520    pos.y -= this.anchorIcon_[0];
521    pos.x = parseInt(pos.x, 10);
522    pos.y = parseInt(pos.y, 10);
523    return pos;
524};
525
526
527/**
528 * Creates a single cluster that manages a group of proximate markers.
529 *  Used internally, do not call this constructor directly.
530 * @constructor
531 * @param {MarkerClusterer} mc The <code>MarkerClusterer</code> object with which this
532 *  cluster is associated.
533 */
534function Cluster(mc) {
535    this.markerClusterer_ = mc;
536    this.map_ = mc.getMap();
537    this.gridSize_ = mc.getGridSize();
538    this.minClusterSize_ = mc.getMinimumClusterSize();
539    this.averageCenter_ = mc.getAverageCenter();
540    this.markers_ = [];
541    this.center_ = null;
542    this.bounds_ = null;
543    this.clusterIcon_ = new ClusterIcon(this, mc.getStyles());
544}
545
546
547/**
548 * Returns the number of markers managed by the cluster. You can call this from
549 * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
550 * for the <code>MarkerClusterer</code> object.
551 *
552 * @return {number} The number of markers in the cluster.
553 */
554Cluster.prototype.getSize = function() {
555    return this.markers_.length;
556};
557
558
559/**
560 * Returns the array of markers managed by the cluster. You can call this from
561 * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
562 * for the <code>MarkerClusterer</code> object.
563 *
564 * @return {Array} The array of markers in the cluster.
565 */
566Cluster.prototype.getMarkers = function() {
567    return this.markers_;
568};
569
570
571/**
572 * Returns the center of the cluster. You can call this from
573 * a <code>click</code>, <code>mouseover</code>, or <code>mouseout</code> event handler
574 * for the <code>MarkerClusterer</code> object.
575 *
576 * @return {google.maps.LatLng} The center of the cluster.
577 */
578Cluster.prototype.getCenter = function() {
579    return this.center_;
580};
581
582
583/**
584 * Returns the map with which the cluster is associated.
585 *
586 * @return {google.maps.Map} The map.
587 * @ignore
588 */
589Cluster.prototype.getMap = function() {
590    return this.map_;
591};
592
593
594/**
595 * Returns the <code>MarkerClusterer</code> object with which the cluster is associated.
596 *
597 * @return {MarkerClusterer} The associated marker clusterer.
598 * @ignore
599 */
600Cluster.prototype.getMarkerClusterer = function() {
601    return this.markerClusterer_;
602};
603
604
605/**
606 * Returns the bounds of the cluster.
607 *
608 * @return {google.maps.LatLngBounds} the cluster bounds.
609 * @ignore
610 */
611Cluster.prototype.getBounds = function() {
612    var i;
613    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
614    var markers = this.getMarkers();
615    for (i = 0; i < markers.length; i++) {
616        bounds.extend(markers[i].getPosition());
617    }
618    return bounds;
619};
620
621
622/**
623 * Removes the cluster from the map.
624 *
625 * @ignore
626 */
627Cluster.prototype.remove = function() {
628    this.clusterIcon_.setMap(null);
629    this.markers_ = [];
630    delete this.markers_;
631};
632
633
634/**
635 * Adds a marker to the cluster.
636 *
637 * @param {google.maps.Marker} marker The marker to be added.
638 * @return {boolean} True if the marker was added.
639 * @ignore
640 */
641Cluster.prototype.addMarker = function(marker) {
642    var i;
643    var mCount;
644    var mz;
645
646    if (this.isMarkerAlreadyAdded_(marker)) {
647        return false;
648    }
649
650    if (!this.center_) {
651        this.center_ = marker.getPosition();
652        this.calculateBounds_();
653    } else {
654        if (this.averageCenter_) {
655            var l = this.markers_.length + 1;
656            var lat = (this.center_.lat() * (l - 1) + marker.getPosition().lat()) / l;
657            var lng = (this.center_.lng() * (l - 1) + marker.getPosition().lng()) / l;
658            this.center_ = new google.maps.LatLng(lat, lng);
659            this.calculateBounds_();
660        }
661    }
662
663    marker.isAdded = true;
664    this.markers_.push(marker);
665
666    mCount = this.markers_.length;
667    mz = this.markerClusterer_.getMaxZoom();
668    if (mz !== null && this.map_.getZoom() > mz) {
669        // Zoomed in past max zoom, so show the marker.
670        if (marker.getMap() !== this.map_) {
671            marker.setMap(this.map_);
672        }
673    } else if (mCount < this.minClusterSize_) {
674        // Min cluster size not reached so show the marker.
675        if (marker.getMap() !== this.map_) {
676            marker.setMap(this.map_);
677        }
678    } else if (mCount === this.minClusterSize_) {
679        // Hide the markers that were showing.
680        for (i = 0; i < mCount; i++) {
681            this.markers_[i].setMap(null);
682        }
683    } else {
684        marker.setMap(null);
685    }
686
687    this.updateIcon_();
688    return true;
689};
690
691
692/**
693 * Determines if a marker lies within the cluster's bounds.
694 *
695 * @param {google.maps.Marker} marker The marker to check.
696 * @return {boolean} True if the marker lies in the bounds.
697 * @ignore
698 */
699Cluster.prototype.isMarkerInClusterBounds = function(marker) {
700    return this.bounds_.contains(marker.getPosition());
701};
702
703
704/**
705 * Calculates the extended bounds of the cluster with the grid.
706 */
707Cluster.prototype.calculateBounds_ = function() {
708    var bounds = new google.maps.LatLngBounds(this.center_, this.center_);
709    this.bounds_ = this.markerClusterer_.getExtendedBounds(bounds);
710};
711
712
713/**
714 * Updates the cluster icon.
715 */
716Cluster.prototype.updateIcon_ = function() {
717    var mCount = this.markers_.length;
718    var mz = this.markerClusterer_.getMaxZoom();
719
720    if (mz !== null && this.map_.getZoom() > mz) {
721        this.clusterIcon_.hide();
722        return;
723    }
724
725    if (mCount < this.minClusterSize_) {
726        // Min cluster size not yet reached.
727        this.clusterIcon_.hide();
728        return;
729    }
730
731    var numStyles = this.markerClusterer_.getStyles().length;
732    var sums = this.markerClusterer_.getCalculator()(this.markers_, numStyles);
733    this.clusterIcon_.setCenter(this.center_);
734    this.clusterIcon_.useStyle(sums);
735    this.clusterIcon_.show();
736};
737
738
739/**
740 * Determines if a marker has already been added to the cluster.
741 *
742 * @param {google.maps.Marker} marker The marker to check.
743 * @return {boolean} True if the marker has already been added.
744 */
745Cluster.prototype.isMarkerAlreadyAdded_ = function(marker) {
746    var i;
747    if (this.markers_.indexOf) {
748        return this.markers_.indexOf(marker) !== -1;
749    } else {
750        for (i = 0; i < this.markers_.length; i++) {
751            if (marker === this.markers_[i]) {
752                return true;
753            }
754        }
755    }
756    return false;
757};
758
759
760/**
761 * @name MarkerClustererOptions
762 * @class This class represents the optional parameter passed to
763 *  the {@link MarkerClusterer} constructor.
764 * @property {number} [gridSize=60] The grid size of a cluster in pixels. The grid is a square.
765 * @property {number} [maxZoom=null] The maximum zoom level at which clustering is enabled or
766 *  <code>null</code> if clustering is to be enabled at all zoom levels.
767 * @property {boolean} [zoomOnClick=true] Whether to zoom the map when a cluster marker is
768 *  clicked. You may want to set this to <code>false</code> if you have installed a handler
769 *  for the <code>click</code> event and it deals with zooming on its own.
770 * @property {boolean} [averageCenter=false] Whether the position of a cluster marker should be
771 *  the average position of all markers in the cluster. If set to <code>false</code>, the
772 *  cluster marker is positioned at the location of the first marker added to the cluster.
773 * @property {number} [minimumClusterSize=2] The minimum number of markers needed in a cluster
774 *  before the markers are hidden and a cluster marker appears.
775 * @property {boolean} [ignoreHidden=false] Whether to ignore hidden markers in clusters. You
776 *  may want to set this to <code>true</code> to ensure that hidden markers are not included
777 *  in the marker count that appears on a cluster marker (this count is the value of the
778 *  <code>text</code> property of the result returned by the default <code>calculator</code>).
779 *  If set to <code>true</code> and you change the visibility of a marker being clustered, be
780 *  sure to also call <code>MarkerClusterer.repaint()</code>.
781 * @property {string} [title=""] The tooltip to display when the mouse moves over a cluster
782 *  marker. (Alternatively, you can use a custom <code>calculator</code> function to specify a
783 *  different tooltip for each cluster marker.)
784 * @property {function} [calculator=MarkerClusterer.CALCULATOR] The function used to determine
785 *  the text to be displayed on a cluster marker and the index indicating which style to use
786 *  for the cluster marker. The input parameters for the function are (1) the array of markers
787 *  represented by a cluster marker and (2) the number of cluster icon styles. It returns a
788 *  {@link ClusterIconInfo} object. The default <code>calculator</code> returns a
789 *  <code>text</code> property which is the number of markers in the cluster and an
790 *  <code>index</code> property which is one higher than the lowest integer such that
791 *  <code>10^i</code> exceeds the number of markers in the cluster, or the size of the styles
792 *  array, whichever is less. The <code>styles</code> array element used has an index of
793 *  <code>index</code> minus 1. For example, the default <code>calculator</code> returns a
794 *  <code>text</code> value of <code>"125"</code> and an <code>index</code> of <code>3</code>
795 *  for a cluster icon representing 125 markers so the element used in the <code>styles</code>
796 *  array is <code>2</code>. A <code>calculator</code> may also return a <code>title</code>
797 *  property that contains the text of the tooltip to be used for the cluster marker. If
798 *   <code>title</code> is not defined, the tooltip is set to the value of the <code>title</code>
799 *   property for the MarkerClusterer.
800 * @property {string} [clusterClass="cluster"] The name of the CSS class defining general styles
801 *  for the cluster markers. Use this class to define CSS styles that are not set up by the code
802 *  that processes the <code>styles</code> array.
803 * @property {Array} [styles] An array of {@link ClusterIconStyle} elements defining the styles
804 *  of the cluster markers to be used. The element to be used to style a given cluster marker
805 *  is determined by the function defined by the <code>calculator</code> property.
806 *  The default is an array of {@link ClusterIconStyle} elements whose properties are derived
807 *  from the values for <code>imagePath</code>, <code>imageExtension</code>, and
808 *  <code>imageSizes</code>.
809 * @property {boolean} [enableRetinaIcons=false] Whether to allow the use of cluster icons that
810 * have sizes that are some multiple (typically double) of their actual display size. Icons such
811 * as these look better when viewed on high-resolution monitors such as Apple's Retina displays.
812 * Note: if this property is <code>true</code>, sprites cannot be used as cluster icons.
813 * @property {number} [batchSize=MarkerClusterer.BATCH_SIZE] Set this property to the
814 *  number of markers to be processed in a single batch when using a browser other than
815 *  Internet Explorer (for Internet Explorer, use the batchSizeIE property instead).
816 * @property {number} [batchSizeIE=MarkerClusterer.BATCH_SIZE_IE] When Internet Explorer is
817 *  being used, markers are processed in several batches with a small delay inserted between
818 *  each batch in an attempt to avoid Javascript timeout errors. Set this property to the
819 *  number of markers to be processed in a single batch; select as high a number as you can
820 *  without causing a timeout error in the browser. This number might need to be as low as 100
821 *  if 15,000 markers are being managed, for example.
822 * @property {string} [imagePath=MarkerClusterer.IMAGE_PATH]
823 *  The full URL of the root name of the group of image files to use for cluster icons.
824 *  The complete file name is of the form <code>imagePath</code>n.<code>imageExtension</code>
825 *  where n is the image file number (1, 2, etc.).
826 * @property {string} [imageExtension=MarkerClusterer.IMAGE_EXTENSION]
827 *  The extension name for the cluster icon image files (e.g., <code>"png"</code> or
828 *  <code>"jpg"</code>).
829 * @property {Array} [imageSizes=MarkerClusterer.IMAGE_SIZES]
830 *  An array of numbers containing the widths of the group of
831 *  <code>imagePath</code>n.<code>imageExtension</code> image files.
832 *  (The images are assumed to be square.)
833 */
834/**
835 * Creates a MarkerClusterer object with the options specified in {@link MarkerClustererOptions}.
836 * @constructor
837 * @extends google.maps.OverlayView
838 * @param {google.maps.Map} map The Google map to attach to.
839 * @param {Array.<google.maps.Marker>} [opt_markers] The markers to be added to the cluster.
840 * @param {MarkerClustererOptions} [opt_options] The optional parameters.
841 */
842function MarkerClusterer(map, opt_markers, opt_options) {
843    // MarkerClusterer implements google.maps.OverlayView interface. We use the
844    // extend function to extend MarkerClusterer with google.maps.OverlayView
845    // because it might not always be available when the code is defined so we
846    // look for it at the last possible moment. If it doesn't exist now then
847    // there is no point going ahead :)
848    this.extend(MarkerClusterer, google.maps.OverlayView);
849
850    opt_markers = opt_markers || [];
851    opt_options = opt_options || {};
852
853    this.markers_ = [];
854    this.clusters_ = [];
855    this.listeners_ = [];
856    this.activeMap_ = null;
857    this.ready_ = false;
858
859    this.gridSize_ = opt_options.gridSize || 60;
860    this.minClusterSize_ = opt_options.minimumClusterSize || 2;
861    this.maxZoom_ = opt_options.maxZoom || null;
862    this.styles_ = opt_options.styles || [];
863    this.title_ = opt_options.title || "";
864    this.zoomOnClick_ = true;
865    if (opt_options.zoomOnClick !== undefined) {
866        this.zoomOnClick_ = opt_options.zoomOnClick;
867    }
868    this.averageCenter_ = false;
869    if (opt_options.averageCenter !== undefined) {
870        this.averageCenter_ = opt_options.averageCenter;
871    }
872    this.ignoreHidden_ = false;
873    if (opt_options.ignoreHidden !== undefined) {
874        this.ignoreHidden_ = opt_options.ignoreHidden;
875    }
876    this.enableRetinaIcons_ = false;
vendor: 15,608 bytes, lines 877-1471
877    if (opt_options.enableRetinaIcons !== undefined) {
878        this.enableRetinaIcons_ = opt_options.enableRetinaIcons;
879    }
880    this.imagePath_ = opt_options.imagePath || MarkerClusterer.IMAGE_PATH;
881    this.imageExtension_ = opt_options.imageExtension || MarkerClusterer.IMAGE_EXTENSION;
882    this.imageSizes_ = opt_options.imageSizes || MarkerClusterer.IMAGE_SIZES;
883    this.calculator_ = opt_options.calculator || MarkerClusterer.CALCULATOR;
884    this.batchSize_ = opt_options.batchSize || MarkerClusterer.BATCH_SIZE;
885    this.batchSizeIE_ = opt_options.batchSizeIE || MarkerClusterer.BATCH_SIZE_IE;
886    this.clusterClass_ = opt_options.clusterClass || "cluster";
887
888    if (navigator.userAgent.toLowerCase().indexOf("msie") !== -1) {
889        // Try to avoid IE timeout when processing a huge number of markers:
890        this.batchSize_ = this.batchSizeIE_;
891    }
892
893    this.setupStyles_();
894
895    this.addMarkers(opt_markers, true);
896    this.setMap(map); // Note: this causes onAdd to be called
897}
898
899
900/**
901 * Implementation of the onAdd interface method.
902 * @ignore
903 */
904MarkerClusterer.prototype.onAdd = function() {
905    var cMarkerClusterer = this;
906
907    this.activeMap_ = this.getMap();
908    this.ready_ = true;
909
910    this.repaint();
911
912    // Add the map event listeners
913    this.listeners_ = [
914        google.maps.event.addListener(this.getMap(), "zoom_changed", function() {
915            cMarkerClusterer.resetViewport_(false);
916            // Workaround for this Google bug: when map is at level 0 and "-" of
917            // zoom slider is clicked, a "zoom_changed" event is fired even though
918            // the map doesn't zoom out any further. In this situation, no "idle"
919            // event is triggered so the cluster markers that have been removed
920            // do not get redrawn. Same goes for a zoom in at maxZoom.
921            if (this.getZoom() === (this.get("minZoom") || 0) || this.getZoom() === this.get("maxZoom")) {
922                google.maps.event.trigger(this, "idle");
923            }
924        }),
925        google.maps.event.addListener(this.getMap(), "idle", function() {
926            cMarkerClusterer.redraw_();
927        })
928    ];
929};
930
931
932/**
933 * Implementation of the onRemove interface method.
934 * Removes map event listeners and all cluster icons from the DOM.
935 * All managed markers are also put back on the map.
936 * @ignore
937 */
938MarkerClusterer.prototype.onRemove = function() {
939    var i;
940
941    // Put all the managed markers back on the map:
942    for (i = 0; i < this.markers_.length; i++) {
943        if (this.markers_[i].getMap() !== this.activeMap_) {
944            this.markers_[i].setMap(this.activeMap_);
945        }
946    }
947
948    // Remove all clusters:
949    for (i = 0; i < this.clusters_.length; i++) {
950        this.clusters_[i].remove();
951    }
952    this.clusters_ = [];
953
954    // Remove map event listeners:
955    for (i = 0; i < this.listeners_.length; i++) {
956        google.maps.event.removeListener(this.listeners_[i]);
957    }
958    this.listeners_ = [];
959
960    this.activeMap_ = null;
961    this.ready_ = false;
962};
963
964
965/**
966 * Implementation of the draw interface method.
967 * @ignore
968 */
969MarkerClusterer.prototype.draw = function() {};
970
971
972/**
973 * Sets up the styles object.
974 */
975MarkerClusterer.prototype.setupStyles_ = function() {
976    var i, size;
977    if (this.styles_.length > 0) {
978        return;
979    }
980
981    for (i = 0; i < this.imageSizes_.length; i++) {
982        size = this.imageSizes_[i];
983        this.styles_.push({
984            url: this.imagePath_ + (i + 1) + "." + this.imageExtension_,
985            height: size,
986            width: size
987        });
988    }
989};
990
991
992/**
993 *  Fits the map to the bounds of the markers managed by the clusterer.
994 */
995MarkerClusterer.prototype.fitMapToMarkers = function() {
996    var i;
997    var markers = this.getMarkers();
998    var bounds = new google.maps.LatLngBounds();
999    for (i = 0; i < markers.length; i++) {
1000        bounds.extend(markers[i].getPosition());
1001    }
1002
1003    this.getMap().fitBounds(bounds);
1004};
1005
1006
1007/**
1008 * Returns the value of the <code>gridSize</code> property.
1009 *
1010 * @return {number} The grid size.
1011 */
1012MarkerClusterer.prototype.getGridSize = function() {
1013    return this.gridSize_;
1014};
1015
1016
1017/**
1018 * Sets the value of the <code>gridSize</code> property.
1019 *
1020 * @param {number} gridSize The grid size.
1021 */
1022MarkerClusterer.prototype.setGridSize = function(gridSize) {
1023    this.gridSize_ = gridSize;
1024};
1025
1026
1027/**
1028 * Returns the value of the <code>minimumClusterSize</code> property.
1029 *
1030 * @return {number} The minimum cluster size.
1031 */
1032MarkerClusterer.prototype.getMinimumClusterSize = function() {
1033    return this.minClusterSize_;
1034};
1035
1036/**
1037 * Sets the value of the <code>minimumClusterSize</code> property.
1038 *
1039 * @param {number} minimumClusterSize The minimum cluster size.
1040 */
1041MarkerClusterer.prototype.setMinimumClusterSize = function(minimumClusterSize) {
1042    this.minClusterSize_ = minimumClusterSize;
1043};
1044
1045
1046/**
1047 *  Returns the value of the <code>maxZoom</code> property.
1048 *
1049 *  @return {number} The maximum zoom level.
1050 */
1051MarkerClusterer.prototype.getMaxZoom = function() {
1052    return this.maxZoom_;
1053};
1054
1055
1056/**
1057 *  Sets the value of the <code>maxZoom</code> property.
1058 *
1059 *  @param {number} maxZoom The maximum zoom level.
1060 */
1061MarkerClusterer.prototype.setMaxZoom = function(maxZoom) {
1062    this.maxZoom_ = maxZoom;
1063};
1064
1065
1066/**
1067 *  Returns the value of the <code>styles</code> property.
1068 *
1069 *  @return {Array} The array of styles defining the cluster markers to be used.
1070 */
1071MarkerClusterer.prototype.getStyles = function() {
1072    return this.styles_;
1073};
1074
1075
1076/**
1077 *  Sets the value of the <code>styles</code> property.
1078 *
1079 *  @param {Array.<ClusterIconStyle>} styles The array of styles to use.
1080 */
1081MarkerClusterer.prototype.setStyles = function(styles) {
1082    this.styles_ = styles;
1083};
1084
1085
1086/**
1087 * Returns the value of the <code>title</code> property.
1088 *
1089 * @return {string} The content of the title text.
1090 */
1091MarkerClusterer.prototype.getTitle = function() {
1092    return this.title_;
1093};
1094
1095
1096/**
1097 *  Sets the value of the <code>title</code> property.
1098 *
1099 *  @param {string} title The value of the title property.
1100 */
1101MarkerClusterer.prototype.setTitle = function(title) {
1102    this.title_ = title;
1103};
1104
1105
1106/**
1107 * Returns the value of the <code>zoomOnClick</code> property.
1108 *
1109 * @return {boolean} True if zoomOnClick property is set.
1110 */
1111MarkerClusterer.prototype.getZoomOnClick = function() {
1112    return this.zoomOnClick_;
1113};
1114
1115
1116/**
1117 *  Sets the value of the <code>zoomOnClick</code> property.
1118 *
1119 *  @param {boolean} zoomOnClick The value of the zoomOnClick property.
1120 */
1121MarkerClusterer.prototype.setZoomOnClick = function(zoomOnClick) {
1122    this.zoomOnClick_ = zoomOnClick;
1123};
1124
1125
1126/**
1127 * Returns the value of the <code>averageCenter</code> property.
1128 *
1129 * @return {boolean} True if averageCenter property is set.
1130 */
1131MarkerClusterer.prototype.getAverageCenter = function() {
1132    return this.averageCenter_;
1133};
1134
1135
1136/**
1137 *  Sets the value of the <code>averageCenter</code> property.
1138 *
1139 *  @param {boolean} averageCenter The value of the averageCenter property.
1140 */
1141MarkerClusterer.prototype.setAverageCenter = function(averageCenter) {
1142    this.averageCenter_ = averageCenter;
1143};
1144
1145
1146/**
1147 * Returns the value of the <code>ignoreHidden</code> property.
1148 *
1149 * @return {boolean} True if ignoreHidden property is set.
1150 */
1151MarkerClusterer.prototype.getIgnoreHidden = function() {
1152    return this.ignoreHidden_;
1153};
1154
1155
1156/**
1157 *  Sets the value of the <code>ignoreHidden</code> property.
1158 *
1159 *  @param {boolean} ignoreHidden The value of the ignoreHidden property.
1160 */
1161MarkerClusterer.prototype.setIgnoreHidden = function(ignoreHidden) {
1162    this.ignoreHidden_ = ignoreHidden;
1163};
1164
1165
1166/**
1167 * Returns the value of the <code>enableRetinaIcons</code> property.
1168 *
1169 * @return {boolean} True if enableRetinaIcons property is set.
1170 */
1171MarkerClusterer.prototype.getEnableRetinaIcons = function() {
1172    return this.enableRetinaIcons_;
1173};
1174
1175
1176/**
1177 *  Sets the value of the <code>enableRetinaIcons</code> property.
1178 *
1179 *  @param {boolean} enableRetinaIcons The value of the enableRetinaIcons property.
1180 */
1181MarkerClusterer.prototype.setEnableRetinaIcons = function(enableRetinaIcons) {
1182    this.enableRetinaIcons_ = enableRetinaIcons;
1183};
1184
1185
1186/**
1187 * Returns the value of the <code>imageExtension</code> property.
1188 *
1189 * @return {string} The value of the imageExtension property.
1190 */
1191MarkerClusterer.prototype.getImageExtension = function() {
1192    return this.imageExtension_;
1193};
1194
1195
1196/**
1197 *  Sets the value of the <code>imageExtension</code> property.
1198 *
1199 *  @param {string} imageExtension The value of the imageExtension property.
1200 */
1201MarkerClusterer.prototype.setImageExtension = function(imageExtension) {
1202    this.imageExtension_ = imageExtension;
1203};
1204
1205
1206/**
1207 * Returns the value of the <code>imagePath</code> property.
1208 *
1209 * @return {string} The value of the imagePath property.
1210 */
1211MarkerClusterer.prototype.getImagePath = function() {
1212    return this.imagePath_;
1213};
1214
1215
1216/**
1217 *  Sets the value of the <code>imagePath</code> property.
1218 *
1219 *  @param {string} imagePath The value of the imagePath property.
1220 */
1221MarkerClusterer.prototype.setImagePath = function(imagePath) {
1222    this.imagePath_ = imagePath;
1223};
1224
1225
1226/**
1227 * Returns the value of the <code>imageSizes</code> property.
1228 *
1229 * @return {Array} The value of the imageSizes property.
1230 */
1231MarkerClusterer.prototype.getImageSizes = function() {
1232    return this.imageSizes_;
1233};
1234
1235
1236/**
1237 *  Sets the value of the <code>imageSizes</code> property.
1238 *
1239 *  @param {Array} imageSizes The value of the imageSizes property.
1240 */
1241MarkerClusterer.prototype.setImageSizes = function(imageSizes) {
1242    this.imageSizes_ = imageSizes;
1243};
1244
1245
1246/**
1247 * Returns the value of the <code>calculator</code> property.
1248 *
1249 * @return {function} the value of the calculator property.
1250 */
1251MarkerClusterer.prototype.getCalculator = function() {
1252    return this.calculator_;
1253};
1254
1255
1256/**
1257 * Sets the value of the <code>calculator</code> property.
1258 *
1259 * @param {function(Array.<google.maps.Marker>, number)} calculator The value
1260 *  of the calculator property.
1261 */
1262MarkerClusterer.prototype.setCalculator = function(calculator) {
1263    this.calculator_ = calculator;
1264};
1265
1266
1267/**
1268 * Returns the value of the <code>batchSizeIE</code> property.
1269 *
1270 * @return {number} the value of the batchSizeIE property.
1271 */
1272MarkerClusterer.prototype.getBatchSizeIE = function() {
1273    return this.batchSizeIE_;
1274};
1275
1276
1277/**
1278 * Sets the value of the <code>batchSizeIE</code> property.
1279 *
1280 *  @param {number} batchSizeIE The value of the batchSizeIE property.
1281 */
1282MarkerClusterer.prototype.setBatchSizeIE = function(batchSizeIE) {
1283    this.batchSizeIE_ = batchSizeIE;
1284};
1285
1286
1287/**
1288 * Returns the value of the <code>clusterClass</code> property.
1289 *
1290 * @return {string} the value of the clusterClass property.
1291 */
1292MarkerClusterer.prototype.getClusterClass = function() {
1293    return this.clusterClass_;
1294};
1295
1296
1297/**
1298 * Sets the value of the <code>clusterClass</code> property.
1299 *
1300 *  @param {string} clusterClass The value of the clusterClass property.
1301 */
1302MarkerClusterer.prototype.setClusterClass = function(clusterClass) {
1303    this.clusterClass_ = clusterClass;
1304};
1305
1306
1307/**
1308 *  Returns the array of markers managed by the clusterer.
1309 *
1310 *  @return {Array} The array of markers managed by the clusterer.
1311 */
1312MarkerClusterer.prototype.getMarkers = function() {
1313    return this.markers_;
1314};
1315
1316
1317/**
1318 *  Returns the number of markers managed by the clusterer.
1319 *
1320 *  @return {number} The number of markers.
1321 */
1322MarkerClusterer.prototype.getTotalMarkers = function() {
1323    return this.markers_.length;
1324};
1325
1326
1327/**
1328 * Returns the current array of clusters formed by the clusterer.
1329 *
1330 * @return {Array} The array of clusters formed by the clusterer.
1331 */
1332MarkerClusterer.prototype.getClusters = function() {
1333    return this.clusters_;
1334};
1335
1336
1337/**
1338 * Returns the number of clusters formed by the clusterer.
1339 *
1340 * @return {number} The number of clusters formed by the clusterer.
1341 */
1342MarkerClusterer.prototype.getTotalClusters = function() {
1343    return this.clusters_.length;
1344};
1345
1346
1347/**
1348 * Adds a marker to the clusterer. The clusters are redrawn unless
1349 *  <code>opt_nodraw</code> is set to <code>true</code>.
1350 *
1351 * @param {google.maps.Marker} marker The marker to add.
1352 * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
1353 */
1354MarkerClusterer.prototype.addMarker = function(marker, opt_nodraw) {
1355    this.pushMarkerTo_(marker);
1356    if (!opt_nodraw) {
1357        this.redraw_();
1358    }
1359};
1360
1361
1362/**
1363 * Adds an array of markers to the clusterer. The clusters are redrawn unless
1364 *  <code>opt_nodraw</code> is set to <code>true</code>.
1365 *
1366 * @param {Array.<google.maps.Marker>} markers The markers to add.
1367 * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
1368 */
1369MarkerClusterer.prototype.addMarkers = function(markers, opt_nodraw) {
1370    var key;
1371    for (key in markers) {
1372        if (markers.hasOwnProperty(key)) {
1373            this.pushMarkerTo_(markers[key]);
1374        }
1375    }
1376    if (!opt_nodraw) {
1377        this.redraw_();
1378    }
1379};
1380
1381
1382/**
1383 * Pushes a marker to the clusterer.
1384 *
1385 * @param {google.maps.Marker} marker The marker to add.
1386 */
1387MarkerClusterer.prototype.pushMarkerTo_ = function(marker) {
1388    // If the marker is draggable add a listener so we can update the clusters on the dragend:
1389    if (marker.getDraggable()) {
1390        var cMarkerClusterer = this;
1391        google.maps.event.addListener(marker, "dragend", function() {
1392            if (cMarkerClusterer.ready_) {
1393                this.isAdded = false;
1394                cMarkerClusterer.repaint();
1395            }
1396        });
1397    }
1398    marker.isAdded = false;
1399    this.markers_.push(marker);
1400};
1401
1402
1403/**
1404 * Removes a marker from the cluster.  The clusters are redrawn unless
1405 *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if the
1406 *  marker was removed from the clusterer.
1407 *
1408 * @param {google.maps.Marker} marker The marker to remove.
1409 * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
1410 * @return {boolean} True if the marker was removed from the clusterer.
1411 */
1412MarkerClusterer.prototype.removeMarker = function(marker, opt_nodraw) {
1413    var removed = this.removeMarker_(marker);
1414
1415    if (!opt_nodraw && removed) {
1416        this.repaint();
1417    }
1418
1419    return removed;
1420};
1421
1422
1423/**
1424 * Removes an array of markers from the cluster. The clusters are redrawn unless
1425 *  <code>opt_nodraw</code> is set to <code>true</code>. Returns <code>true</code> if markers
1426 *  were removed from the clusterer.
1427 *
1428 * @param {Array.<google.maps.Marker>} markers The markers to remove.
1429 * @param {boolean} [opt_nodraw] Set to <code>true</code> to prevent redrawing.
1430 * @return {boolean} True if markers were removed from the clusterer.
1431 */
1432MarkerClusterer.prototype.removeMarkers = function(markers, opt_nodraw) {
1433    var i, r;
1434    var removed = false;
1435
1436    for (i = 0; i < markers.length; i++) {
1437        r = this.removeMarker_(markers[i]);
1438        removed = removed || r;
1439    }
1440
1441    if (!opt_nodraw && removed) {
1442        this.repaint();
1443    }
1444
1445    return removed;
1446};
1447
1448
1449/**
1450 * Removes a marker and returns true if removed, false if not.
1451 *
1452 * @param {google.maps.Marker} marker The marker to remove
1453 * @return {boolean} Whether the marker was removed or not
1454 */
1455MarkerClusterer.prototype.removeMarker_ = function(marker) {
1456    var i;
1457    var index = -1;
1458    if (this.markers_.indexOf) {
1459        index = this.markers_.indexOf(marker);
1460    } else {
1461        for (i = 0; i < this.markers_.length; i++) {
1462            if (marker === this.markers_[i]) {
1463                index = i;
1464                break;
1465            }
1466        }
1467    }
1468
1469    if (index === -1) {
1470        // Marker is not in our list of markers, so do nothing:
1471        return false;
1472    }
1473
1474    marker.setMap(null);
1475    this.markers_.splice(index, 1); // Remove the marker from the list of managed markers
1476    return true;
1477};
1478
1479
1480/**
1481 * Removes all clusters and markers from the map and also removes all markers
1482 *  managed by the clusterer.
1483 */
1484MarkerClusterer.prototype.clearMarkers = function() {
1485    this.resetViewport_(true);
1486    this.markers_ = [];
1487};
1488
1489
1490/**
1491 * Recalculates and redraws all the marker clusters from scratch.
1492 *  Call this after changing any properties.
1493 */
1494MarkerClusterer.prototype.repaint = function() {
1495    var oldClusters = this.clusters_.slice();
1496    this.clusters_ = [];
1497    this.resetViewport_(false);
1498    this.redraw_();
1499
1500    // Remove the old clusters.
1501    // Do it in a timeout to prevent blinking effect.
1502    setTimeout(function() {
1503        var i;
1504        for (i = 0; i < oldClusters.length; i++) {
1505            oldClusters[i].remove();
1506        }
1507    }, 0);
1508};
1509
1510
1511/**
1512 * Returns the current bounds extended by the grid size.
1513 *
1514 * @param {google.maps.LatLngBounds} bounds The bounds to extend.
1515 * @return {google.maps.LatLngBounds}
vendor: 5,340 bytes, lines 1515-1683
1515 The extended bounds.
1516 * @ignore
1517 */
1518MarkerClusterer.prototype.getExtendedBounds = function(bounds) {
1519    var projection = this.getProjection();
1520
1521    // Turn the bounds into latlng.
1522    var tr = new google.maps.LatLng(bounds.getNorthEast().lat(),
1523        bounds.getNorthEast().lng());
1524    var bl = new google.maps.LatLng(bounds.getSouthWest().lat(),
1525        bounds.getSouthWest().lng());
1526
1527    // Convert the points to pixels and the extend out by the grid size.
1528    var trPix = projection.fromLatLngToDivPixel(tr);
1529    trPix.x += this.gridSize_;
1530    trPix.y -= this.gridSize_;
1531
1532    var blPix = projection.fromLatLngToDivPixel(bl);
1533    blPix.x -= this.gridSize_;
1534    blPix.y += this.gridSize_;
1535
1536    // Convert the pixel points back to LatLng
1537    var ne = projection.fromDivPixelToLatLng(trPix);
1538    var sw = projection.fromDivPixelToLatLng(blPix);
1539
1540    // Extend the bounds to contain the new bounds.
1541    bounds.extend(ne);
1542    bounds.extend(sw);
1543
1544    return bounds;
1545};
1546
1547
1548/**
1549 * Redraws all the clusters.
1550 */
1551MarkerClusterer.prototype.redraw_ = function() {
1552    this.createClusters_(0);
1553};
1554
1555
1556/**
1557 * Removes all clusters from the map. The markers are also removed from the map
1558 *  if <code>opt_hide</code> is set to <code>true</code>.
1559 *
1560 * @param {boolean} [opt_hide] Set to <code>true</code> to also remove the markers
1561 *  from the map.
1562 */
1563MarkerClusterer.prototype.resetViewport_ = function(opt_hide) {
1564    var i, marker;
1565    // Remove all the clusters
1566    for (i = 0; i < this.clusters_.length; i++) {
1567        this.clusters_[i].remove();
1568    }
1569    this.clusters_ = [];
1570
1571    // Reset the markers to not be added and to be removed from the map.
1572    for (i = 0; i < this.markers_.length; i++) {
1573        marker = this.markers_[i];
1574        marker.isAdded = false;
1575        if (opt_hide) {
1576            marker.setMap(null);
1577        }
1578    }
1579};
1580
1581
1582/**
1583 * Calculates the distance between two latlng locations in km.
1584 *
1585 * @param {google.maps.LatLng} p1 The first lat lng point.
1586 * @param {google.maps.LatLng} p2 The second lat lng point.
1587 * @return {number} The distance between the two points in km.
1588 * @see http://www.movable-type.co.uk/scripts/latlong.html
1589 */
1590MarkerClusterer.prototype.distanceBetweenPoints_ = function(p1, p2) {
1591    var R = 6371; // Radius of the Earth in km
1592    var dLat = (p2.lat() - p1.lat()) * Math.PI / 180;
1593    var dLon = (p2.lng() - p1.lng()) * Math.PI / 180;
1594    var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
1595        Math.cos(p1.lat() * Math.PI / 180) * Math.cos(p2.lat() * Math.PI / 180) *
1596        Math.sin(dLon / 2) * Math.sin(dLon / 2);
1597    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1598    var d = R * c;
1599    return d;
1600};
1601
1602
1603/**
1604 * Determines if a marker is contained in a bounds.
1605 *
1606 * @param {google.maps.Marker} marker The marker to check.
1607 * @param {google.maps.LatLngBounds} bounds The bounds to check against.
1608 * @return {boolean} True if the marker is in the bounds.
1609 */
1610MarkerClusterer.prototype.isMarkerInBounds_ = function(marker, bounds) {
1611    return bounds.contains(marker.getPosition());
1612};
1613
1614
1615/**
1616 * Adds a marker to a cluster, or creates a new cluster.
1617 *
1618 * @param {google.maps.Marker} marker The marker to add.
1619 */
1620MarkerClusterer.prototype.addToClosestCluster_ = function(marker) {
1621    var i, d, cluster, center;
1622    var distance = 40000; // Some large number
1623    var clusterToAddTo = null;
1624    for (i = 0; i < this.clusters_.length; i++) {
1625        cluster = this.clusters_[i];
1626        center = cluster.getCenter();
1627        if (center) {
1628            d = this.distanceBetweenPoints_(center, marker.getPosition());
1629            if (d < distance) {
1630                distance = d;
1631                clusterToAddTo = cluster;
1632            }
1633        }
1634    }
1635
1636    if (clusterToAddTo && clusterToAddTo.isMarkerInClusterBounds(marker)) {
1637        clusterToAddTo.addMarker(marker);
1638    } else {
1639        cluster = new Cluster(this);
1640        cluster.addMarker(marker);
1641        this.clusters_.push(cluster);
1642    }
1643};
1644
1645
1646/**
1647 * Creates the clusters. This is done in batches to avoid timeout errors
1648 *  in some browsers when there is a huge number of markers.
1649 *
1650 * @param {number} iFirst The index of the first marker in the batch of
1651 *  markers to be added to clusters.
1652 */
1653MarkerClusterer.prototype.createClusters_ = function(iFirst) {
1654    var i, marker;
1655    var mapBounds;
1656    var cMarkerClusterer = this;
1657    if (!this.ready_) {
1658        return;
1659    }
1660
1661    // Cancel previous batch processing if we're working on the first batch:
1662    if (iFirst === 0) {
1663        /**
1664         * This event is fired when the <code>MarkerClusterer</code> begins
1665         *  clustering markers.
1666         * @name MarkerClusterer#clusteringbegin
1667         * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.
1668         * @event
1669         */
1670        google.maps.event.trigger(this, "clusteringbegin", this);
1671
1672        if (typeof this.timerRefStatic !== "undefined") {
1673            clearTimeout(this.timerRefStatic);
1674            delete this.timerRefStatic;
1675        }
1676    }
1677
1678    // Get our current map view bounds.
1679    // Create a new bounds object so we don't affect the map.
1680    //
1681    // See Comments 9 & 11 on Issue 3651 relating to this workaround for a Google Maps bug:
1682    if (this.getMap().getZoom() > 3) {
1683        mapBounds = new google.maps.LatLngBounds(this.getMap().getBounds().getSouthWest
1683(),
1684            this.getMap().getBounds().getNorthEast());
1685    } else {
1686        mapBounds = new google.maps.LatLngBounds(new google.maps.LatLng(85.02070771743472, -178.48388434375), new google.maps.LatLng(-85.08136444384544, 178.00048865625));
1687    }
1688    var bounds = this.getExtendedBounds(mapBounds);
1689
1690    var iLast = Math.min(iFirst + this.batchSize_, this.markers_.length);
1691
1692    for (i = iFirst; i < iLast; i++) {
1693        marker = this.markers_[i];
1694        if (!marker.isAdded && this.isMarkerInBounds_(marker, bounds)) {
1695            if (!this.ignoreHidden_ || (this.ignoreHidden_ && marker.getVisible())) {
1696                this.addToClosestCluster_(marker);
1697            }
1698        }
1699    }
1700
1701    if (iLast < this.markers_.length) {
1702        this.timerRefStatic = setTimeout(function() {
1703            cMarkerClusterer.createClusters_(iLast);
1704        }, 0);
1705    } else {
1706        delete this.timerRefStatic;
1707
1708        /**
1709         * This event is fired when the <code>MarkerClusterer</code> stops
1710         *  clustering markers.
1711         * @name MarkerClusterer#clusteringend
1712         * @param {MarkerClusterer} mc The MarkerClusterer whose markers are being clustered.
1713         * @event
1714         */
1715        google.maps.event.trigger(this, "clusteringend", this);
1716    }
1717};
1718
1719
1720/**
1721 * Extends an object's prototype by another's.
1722 *
1723 * @param {Object} obj1 The object to be extended.
1724 * @param {Object} obj2 The object to extend with.
1725 * @return {Object} The new extended object.
1726 * @ignore
1727 */
1728MarkerClusterer.prototype.extend = function(obj1, obj2) {
1729    return (function(object) {
1730        var property;
1731        for (property in object.prototype) {
1732            this.prototype[property] = object.prototype[property];
1733        }
1734        return this;
1735    }).apply(obj1, [obj2]);
1736};
1737
1738
1739/**
1740 * The default function for determining the label text and style
1741 * for a cluster icon.
1742 *
1743 * @param {Array.<google.maps.Marker>} markers The array of markers represented by the cluster.
1744 * @param {number} numStyles The number of marker styles available.
1745 * @return {ClusterIconInfo} The information resource for the cluster.
1746 * @constant
1747 * @ignore
1748 */
1749MarkerClusterer.CALCULATOR = function(markers, numStyles) {
1750    var index = 0;
1751    var title = "";
1752    var count = markers.length.toString();
1753
1754    var dv = count;
1755    while (dv !== 0) {
1756        dv = parseInt(dv / 10, 10);
1757        index++;
1758    }
1759
1760    index = Math.min(index, numStyles);
1761    return {
1762        text: count,
1763        index: index,
1764        title: title
1765    };
1766};
1767
1768
1769/**
1770 * The number of markers to process in one batch.
1771 *
1772 * @type {number}
1773 * @constant
1774 */
1775MarkerClusterer.BATCH_SIZE = 2000;
1776
1777
1778/**
1779 * The number of markers to process in one batch (IE only).
1780 *
1781 * @type {number}
1782 * @constant
1783 */
1784MarkerClusterer.BATCH_SIZE_IE = 500;
1785
1786
1787/**
1788 * The default root name for the marker cluster images.
1789 *
1790 * @type {string}
1791 * @constant
1792 */
1793MarkerClusterer.IMAGE_PATH = "http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclustererplus/images/m";
1794
1795
1796/**
1797 * The default extension name for the marker cluster images.
1798 *
1799 * @type {string}
1800 * @constant
1801 */
1802MarkerClusterer.IMAGE_EXTENSION = "png";
1803
1804
1805/**
1806 * The default array of sizes for the marker cluster images.
1807 *
1808 * @type {Array.<number>}
1809 * @constant
1810 */
1811MarkerClusterer.IMAGE_SIZES = [53, 56, 66, 78, 90];
1812
1813/**
1814 * Accordion, jQuery Plugin
1815 *
1816 * This plugin provides an accordion with cookie support.
1817 *
1818 * Copyright (c) 2011 John Snyder (snyderplace.com)
1819 * @license http://www.snyderplace.com/accordion/license.txt New BSD
1820 * @version 1.1
1821 */
1822(function($) {
1823    $.fn.accordion = function(options) {
1824
1825        //firewalling
1826        if (!this || this.length < 1) {
1827            return this;
1828        }
1829
1830        initialize(this, options);
1831
1832    };
1833
1834    //create the initial accordion
1835    function initialize(obj, options) {
1836
1837        //build main options before element iteration
1838        var opts = $.extend({}, $.fn.accordion.defaults, options);
1839
1840        //store any opened default values to set cookie later
1841        var opened = '';
1842
1843        //iterate each matched object, bind, and open/close
1844        obj.each(function() {
1845            var $this = $(this);
1846            saveOpts($this, opts);
1847
1848            //bind it to the event
1849            if (opts.bind == 'mouseenter') {
1850                $this.bind('mouseenter', function(e) {
1851                    e.preventDefault();
1852                    toggle($this, opts);
1853                });
1854            }
1855
1856            //bind it to the event
1857            if (opts.bind == 'mouseover') {
1858                $this.bind('mouseover', function(e) {
1859                    e.preventDefault();
1860                    toggle($this, opts);
1861                });
1862            }
1863
1864            //bind it to the event
1865            if (opts.bind == 'click') {
1866                $this.bind('click', function(e) {
1867                    e.preventDefault();
1868                    toggle($this, opts);
1869                });
1870            }
1871
1872            //bind it to the event
1873            if (opts.bind == 'dblclick') {
1874                $this.bind('dblclick', function(e) {
1875                    e.preventDefault();
1876                    toggle($this, opts);
1877                });
1878            }
1879
1880            //initialize the panels
1881            //get the id for this element
1882            id = $this.attr('id');
1883
1884            //if not using cookies, open defaults
1885            if (!useCookies(opts)) {
1886                //close it if not defaulted to open
1887                if (id != opts.defaultOpen) {
1888                    $this.addClass(opts.cssClose);
1889                    opts.loadClose($this, opts);
1890                } else { //its a default open, open it
1891                    $this.addClass(opts.cssOpen);
1892                    opts.loadOpen($this, opts);
1893                    opened = id;
1894                }
1895            } else { //can use cookies, use them now
1896                //has a cookie been set, this overrides default open
1897                if (issetCookie(opts)) {
1898                    if (inCookie(id, opts) === false) {
1899                        $this.addClass(opts.cssClose);
1900                        opts.loadClose($this, opts);
1901                    } else {
1902                        $this.addClass(opts.cssOpen);
1903                        opts.loadOpen($this, opts);
1904                        opened = id;
1905                    }
1906                } else { //a cookie hasn't been set open defaults
1907                    if (id != opts.defaultOpen) {
1908                        $this.addClass(opts.cssClose);
1909                        opts.loadClose($this, opts);
1910                    } else { //its a default open, open it
1911                        $this.addClass(opts.cssOpen);
1912                        opts.loadOpen($this, opts);
1913                        opened = id;
1914                    }
1915                }
1916            }
1917        });
1918
1919        //now that the loop is done, set the cookie
1920        if (opened.length > 0 && useCookies(opts)) {
1921            setCookie(opened, opts);
1922        } else { //there are none open, set cookie
1923            setCookie('', opts);
1924        }
1925
1926        return obj;
1927    };
1928
1929    //load opts from object
1930    function loadOpts($this) {
1931        return $this.data('accordion-opts');
1932    }
1933
1934    //save opts into object
1935    function saveOpts($this, opts) {
1936        return $this.data('accordion-opts', opts);
1937    }
1938
1939    //hides a accordion panel
1940    function close(opts) {
1941        opened = $(document).find('.' + opts.cssOpen);
1942        $.each(opened, function() {
1943            //give the proper class to the linked element
1944            $(this).addClass(opts.cssClose).removeClass(opts.cssOpen);
1945            opts.animateClose($(this), opts);
1946        });
1947    }
1948
1949    //opens a accordion panel
1950    function open($this, opts) {
1951        close(opts);
1952        //give the proper class to the linked element
1953        $this.removeClass(opts.cssClose).addClass(opts.cssOpen);
1954
1955        //open the element
1956        opts.animateOpen($this, opts);
1957
1958        //do cookies if plugin available
1959        if (useCookies(opts)) {
1960            // split the cookieOpen string by ","
1961            id = $this.attr('id');
1962            setCookie(id, opts);
1963        }
1964    }
1965
1966    //toggle a accordion on an event
1967    function toggle($this, opts) {
1968        // close the only open item
1969        if ($this.hasClass(opts.cssOpen)) {
1970            close(opts);
1971            //do cookies if plugin available
1972            if (useCookies(opts)) {
1973                // split the cookieOpen string by ","
1974                setCookie('', opts);
1975            }
1976            return false;
1977        }
1978        close(opts);
1979        //open a closed element
1980        open($this, opts);
1981        return false;
1982    }
1983
1984    //use cookies?
1985    function useCookies(opts) {
1986        //return false if cookie plugin not present or if a cookie name is not provided
1987        if (!$.cookie || opts.cookieName == '') {
1988            return false;
1989        }
1990
1991        //we can use cookies
1992        return true;
1993    }
1994
1995    //set a cookie
1996    function setCookie(value, opts) {
1997        //can use the cookie plugin
1998        if (!useCookies(opts)) { //no, quit here
1999            return false;
2000        }
2001
2002        //cookie plugin is available, lets set the cookie
2003        $.cookie(opts.cookieName, value, opts.cookieOptions);
2004    }
2005
2006    //check if a accordion is in the cookie
2007    function inCookie(value, opts) {
2008        //can use the cookie plugin
2009        if (!useCookies(opts)) {
2010            return false;
2011        }
2012
2013        //if its not there we don't need to remove from it
2014        if (!issetCookie(opts)) { //quit here, don't have a cookie
2015            return false;
2016        }
2017
2018        //unescape it
2019        cookie = unescape($.cookie(opts.cookieName));
2020
2021        //is this value in the cookie arrray
2022        if (cookie != value) { //no, quit here
2023            return false;
2024        }
2025
2026        return true;
2027    }
2028
2029    //check if a cookie is set
2030    function issetCookie(opts) {
2031        //can we use the cookie plugin
2032        if (!useCookies(opts)) { //no, quit here
2033            return false;
2034        }
2035
2036        //is the cookie set
2037        if ($.cookie(opts.cookieName) == null) { //no, quit here
2038            return false;
2039        }
2040
2041        return true;
2042    }
2043
2044    // settings
2045    $.fn.accordion.defaults = {
2046        cssClose: 'accordion-close', //class you want to assign to a closed accordion header
2047        cssOpen: 'accordion-open', //class you want to assign an opened accordion header
2048        cookieName: 'accordion', //name of the cookie you want to set for this accordion
2049        cookieOptions: { //cookie options, see cookie plugin for details
2050            path: '/',
2051            expires: 7,
2052            domain: '',
2053            secure: ''
2054        },
2055        defaultOpen: '', //id that you want opened by default
2056        speed: 'slow', //speed of the slide effect
2057        bind: 'click', //event to bind to, supports click, dblclick, mouseover and mouseenter
2058        animateOpen: function(elem, opts) { //replace the standard slideDown with custom function
2059            elem.next().stop(true, true).slideDown(opts.speed);
2060        },
2061        animateClose: function(elem, opts) { //replace the standard slideUp with custom function
vendor: 6,719 bytes, lines 2062-2262
2062            elem.next().stop(true, true).slideUp(opts.speed);
2063        },
2064        loadOpen: function(elem, opts) { //replace the default open state with custom function
2065            elem.next().show();
2066        },
2067        loadClose: function(elem, opts) { //replace the default close state with custom function
2068            elem.next().hide();
2069        }
2070    };
2071})(jQuery);
2072
2073/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
2074 * Licensed under the MIT License (LICENSE.txt).
2075 *
2076 * Version: 3.1.9
2077 *
2078 * Requires: jQuery 1.2.2+
2079 */
2080
2081(function(factory) {
2082    if (typeof define === 'function' && define.amd) {
2083        // AMD. Register as an anonymous module.
2084        define(['jquery'], factory);
2085    } else if (typeof exports === 'object') {
2086        // Node/CommonJS style for Browserify
2087        module.exports = factory;
2088    } else {
2089        // Browser globals
2090        factory(jQuery);
2091    }
2092}(function($) {
2093
2094    var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
2095        toBind = ('onwheel' in document || document.documentMode >= 9) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
2096        slice = Array.prototype.slice,
2097        nullLowestDeltaTimeout, lowestDelta;
2098
2099    if ($.event.fixHooks) {
2100        for (var i = toFix.length; i;) {
2101            $.event.fixHooks[toFix[--i]] = $.event.mouseHooks;
2102        }
2103    }
2104
2105    var special = $.event.special.mousewheel = {
2106        version: '3.1.9',
2107
2108        setup: function() {
2109            if (this.addEventListener) {
2110                for (var i = toBind.length; i;) {
2111                    this.addEventListener(toBind[--i], handler, false);
2112                }
2113            } else {
2114                this.onmousewheel = handler;
2115            }
2116            // Store the line height and page height for this particular element
2117            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
2118            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
2119        },
2120
2121        teardown: function() {
2122            if (this.removeEventListener) {
2123                for (var i = toBind.length; i;) {
2124                    this.removeEventListener(toBind[--i], handler, false);
2125                }
2126            } else {
2127                this.onmousewheel = null;
2128            }
2129        },
2130
2131        getLineHeight: function(elem) {
2132            return parseInt($(elem)['offsetParent' in $.fn ? 'offsetParent' : 'parent']().css('fontSize'), 10);
2133        },
2134
2135        getPageHeight: function(elem) {
2136            return $(elem).height();
2137        },
2138
2139        settings: {
2140            adjustOldDeltas: true
2141        }
2142    };
2143
2144    $.fn.extend({
2145        mousewheel: function(fn) {
2146            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
2147        },
2148
2149        unmousewheel: function(fn) {
2150            return this.unbind('mousewheel', fn);
2151        }
2152    });
2153
2154
2155    function handler(event) {
2156        var orgEvent = event || window.event,
2157            args = slice.call(arguments, 1),
2158            delta = 0,
2159            deltaX = 0,
2160            deltaY = 0,
2161            absDelta = 0;
2162        event = $.event.fix(orgEvent);
2163        event.type = 'mousewheel';
2164
2165        // Old school scrollwheel delta
2166        if ('detail' in orgEvent) {
2167            deltaY = orgEvent.detail * -1;
2168        }
2169        if ('wheelDelta' in orgEvent) {
2170            deltaY = orgEvent.wheelDelta;
2171        }
2172        if ('wheelDeltaY' in orgEvent) {
2173            deltaY = orgEvent.wheelDeltaY;
2174        }
2175        if ('wheelDeltaX' in orgEvent) {
2176            deltaX = orgEvent.wheelDeltaX * -1;
2177        }
2178
2179        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
2180        if ('axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS) {
2181            deltaX = deltaY * -1;
2182            deltaY = 0;
2183        }
2184
2185        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
2186        delta = deltaY === 0 ? deltaX : deltaY;
2187
2188        // New school wheel delta (wheel event)
2189        if ('deltaY' in orgEvent) {
2190            deltaY = orgEvent.deltaY * -1;
2191            delta = deltaY;
2192        }
2193        if ('deltaX' in orgEvent) {
2194            deltaX = orgEvent.deltaX;
2195            if (deltaY === 0) {
2196                delta = deltaX * -1;
2197            }
2198        }
2199
2200        // No change actually happened, no reason to go any further
2201        if (deltaY === 0 && deltaX === 0) {
2202            return;
2203        }
2204
2205        // Need to convert lines and pages to pixels if we aren't already in pixels
2206        // There are three delta modes:
2207        //   * deltaMode 0 is by pixels, nothing to do
2208        //   * deltaMode 1 is by lines
2209        //   * deltaMode 2 is by pages
2210        if (orgEvent.deltaMode === 1) {
2211            var lineHeight = $.data(this, 'mousewheel-line-height');
2212            delta *= lineHeight;
2213            deltaY *= lineHeight;
2214            deltaX *= lineHeight;
2215        } else if (orgEvent.deltaMode === 2) {
2216            var pageHeight = $.data(this, 'mousewheel-page-height');
2217            delta *= pageHeight;
2218            deltaY *= pageHeight;
2219            deltaX *= pageHeight;
2220        }
2221
2222        // Store lowest absolute delta to normalize the delta values
2223        absDelta = Math.max(Math.abs(deltaY), Math.abs(deltaX));
2224
2225        if (!lowestDelta || absDelta < lowestDelta) {
2226            lowestDelta = absDelta;
2227
2228            // Adjust older deltas if necessary
2229            if (shouldAdjustOldDeltas(orgEvent, absDelta)) {
2230                lowestDelta /= 40;
2231            }
2232        }
2233
2234        // Adjust older deltas if necessary
2235        if (shouldAdjustOldDeltas(orgEvent, absDelta)) {
2236            // Divide all the things by 40!
2237            delta /= 40;
2238            deltaX /= 40;
2239            deltaY /= 40;
2240        }
2241
2242        // Get a whole, normalized value for the deltas
2243        delta = Math[delta >= 1 ? 'floor' : 'ceil'](delta / lowestDelta);
2244        deltaX = Math[deltaX >= 1 ? 'floor' : 'ceil'](deltaX / lowestDelta);
2245        deltaY = Math[deltaY >= 1 ? 'floor' : 'ceil'](deltaY / lowestDelta);
2246
2247        // Add information to the event object
2248        event.deltaX = deltaX;
2249        event.deltaY = deltaY;
2250        event.deltaFactor = lowestDelta;
2251        // Go ahead and set deltaMode to 0 since we converted to pixels
2252        // Although this is a little odd since we overwrite the deltaX/Y
2253        // properties with normalized deltas.
2254        event.deltaMode = 0;
2255
2256        // Add event and delta to the front of the arguments
2257        args.unshift(event, delta, deltaX, deltaY);
2258
2259        // Clearout lowestDelta after sometime to better
2260        // handle multiple device types that give different
2261        // a different lowestDelta
2262        // Ex: trackpad = 3 and mouse wheel = 120
2263        if (nullLowestDeltaTimeout) {
2264            clearTimeout(nullLowestDeltaTimeout);
2265        }
2266        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
2267
2268        return ($.event.dispatch || $.event.handle).apply(this, args);
2269    }
2270
2271    function nullLowestDelta() {
2272        lowestDelta = null;
2273    }
2274
2275    function shouldAdjustOldDeltas(orgEvent, absDelta) {
2276        // If this is an older event and the delta is divisable by 120,
2277        // then we are assuming that the browser is treating this as an
2278        // older mouse wheel event and that we should divide the deltas
2279        // by 40 to try and get a more usable deltaFactor.
2280        // Side note, this actually impacts the reported scroll distance
2281        // in older browsers and can cause scrolling to be slower than native.
2282        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
2283        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
2284    }
2285
2286}));
2287
2288/*!
2289 * jScrollPane - v2.0.19 - 2013-11-16
2290 * http://jscrollpane.kelvinluck.com/
2291 *
2292 * Copyright (c) 2013 Kelvin Luck
2293 * Dual licensed under the MIT or GPL licenses.
2294 */
2295! function(a, b, c) {
2296    a.fn.jScrollPane = function(d) {
2297        function e(d, e) {
2298            function f(b) {
2299                var e, h, j, l, m, n, q = !1,
2300                    r = !1;
2301                if (P = b, Q === c) m = d.scrollTop(), n = d.scrollLeft(), d.css({
2302                    overflow: "hidden",
2303                    padding: 0
2304                }), R = d.innerWidth() + tb, S = d.innerHeight(), d.width(R), Q = a('<div class="jspPane" />').css("padding", sb).append(d.children()), T = a('<div class="jspContainer" />').css({
2305                    width: R + "px",
2306                    height: S + "px"
2307                }).append(Q).appendTo(d);
2308                else {
2309                    if (d.css("width", ""), q = P.stickToBottom && C(), r = P.stickToRight && D(), l = d.innerWidth() + tb != R || d.outerHeight() != S, l && (R = d.innerWidth() + tb, S = d.innerHeight(), T.css({
2310                            width: R + "px",
2311                            height: S + "px"
2312                        })), !l && ub == U && Q.outerHeight() == V) return d.width(R), void 0;
2313                    ub = U, Q.css("width", ""), d.width(R), T.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()
2314                }
2315                Q.css("overflow", "auto"), U = b.contentWidth ? b.contentWidth : Q[0].scrollWidth, V = Q[0].scrollHeight, Q.css("overflow", ""), W = U / R, X = V / S, Y = X > 1, Z = W > 1, Z || Y ? (d.addClass("jspScrollable"), e = P.maintainPosition && (ab || db), e && (h = A(), j = B()), g(), i(), k(), e && (y(r ? U - R : h, !1), x(q ? V - S : j, !1)), H(), E(), N(), P.enableKeyboardNavigation && J(), P.clickOnTrack && o(), L(), P.hijackInternalLinks && M()) : (d.removeClass("jspScrollable"), Q.css({
2316                    top: 0,
2317                    left: 0,
2318                    width: T.width() - tb
2319                }), F(), I(), K(), p()), P.autoReinitialise && !rb ? rb = setInterval(function() {
2320                    f(P)
2321                }, P.autoReinitialiseDelay) : !P.autoReinitialise && rb && clearInterval(rb), m && d.scrollTop(0) && x(m, !1), n && d.scrollLeft(0) && y(n, !1), d.trigger("jsp-initialised", [Z || Y])
2322            }
2323
2324            function g() {
2325                Y && (T.append(a('<div class="jspVerticalBar" />').append(a('<div class="jspCap jspCapTop" />'), a('<div class="jspTrack" />').append(a('<div class="jspDrag" />').append(a('<div class="jspDragTop" />'), a('<div class="jspDragBottom" />'))), a('<div class="jspCap jspCapBottom" />'))), eb = T.find(">.jspVerticalBar"), fb = eb.find(">.jspTrack"), $ = fb.find(">.jspDrag"), P.showArrows && (jb = a('<a class="jspArrow jspArrowUp" />').bind("mousedown.jsp", m(0, -1)).bind("click.jsp", G), kb = a('<a class="jspArrow jspArrowDown" />').bind("mousedown.jsp", m(0, 1)).bind("click.jsp", G), P.arrowScrollOnHover && (jb.bind("mouseover.jsp", m(0, -1, jb)), kb.bind("mouseover.jsp", m(0, 1, kb))), l(fb, P.verticalArrowPositions, jb, kb)), hb = S, T.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function() {
2326                    hb -= a(this).outerHeight()
2327                }), $.hover(function() {
2328                    $.addClass("jspHover")
2329                }, function() {
2330                    $.removeClass("jspHover")
2331                }).bind("mousedown.jsp", function(b) {
2332                    a("html").bind("dragstart.jsp selectstart.jsp", G), $.addClass("jspActive");
2333                    var c = b.pageY - $.position().top;
2334                    return a("html").bind("mousemove.jsp", function(a) {
2335                        r(a.pageY - c, !1)
2336                    }).bind("mouseup.jsp mouseleave.jsp", q), !1
2337                }), h())
2338            }
2339
2340            function h() {
2341                fb.height(hb + "px"), ab = 0, gb = P.verticalGutter + fb.outerWidth(), Q.width(R - gb - tb);
2342                try {
2343                    0 === eb.position().left && Q.css("margin-left", gb + "px")
2344                } catch (a) {}
2345            }
2346
2347            function i() {
2348                Z && (T.append(a('<div class="jspHorizontalBar" />').append(a('<div class="jspCap jspCapLeft" />'), a('<div class="jspTrack" />').append(a('<div class="jspDrag" />').append(a('<div class="jspDragLeft" />'), a('<div class="jspDragRight" />'))), a('<div class="jspCap jspCapRight" />'))), lb = T.find(">.jspHorizontalBar"), mb = lb.find(">.jspTrack"), bb = mb.find(">.jspDrag"), P.showArrows && (pb = a('<a class="jspArrow jspArrowLeft" />').bind("mousedown.jsp", m(-1, 0)).bind("click.jsp", G), qb = a('<a class="jspArrow jspArrowRight" />').bind("mousedown.jsp", m(1, 0)).bind("click.jsp", G), P.arrowScrollOnHover && (pb.bind("mouseover.jsp", m(-1, 0, pb)), qb.bind("mouseover.jsp", m(1, 0, qb))), l(mb, P.horizontalArrowPositions, pb, qb)), bb.hover(function() {
2349                    bb.addClass("jspHover")
2350                }, function() {
2351                    bb.removeClass("jspHover")
2352                }).bind("mousedown.jsp", function(b) {
2353                    a("html").bind("dragstart.jsp selectstart.jsp", G), bb.addClass("jspActive");
2354                    var c = b.pageX - bb.position().left;
2355                    return a("html").bind("mousemove.jsp", function(a) {
2356                        t(a.pageX - c, !1)
2357                    }).bind("mouseup.jsp mouseleave.jsp", q), !1
2358                }), nb = T.innerWidth(), j())
2359            }
2360
2361            function j() {
2362                T.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function() {
2363                    nb -= a(this).outerWidth()
2364                }), mb.width(nb + "px"), db = 0
2365            }
2366
2367            function k() {
2368                if (Z && Y) {
2369                    var b = mb.outerHeight(),
2370                        c = fb.outerWidth();
2371                    hb -= b, a(lb).find(">.jspCap:visible,>.jspArrow").each(function() {
2372                        nb += a(this).outerWidth()
2373                    }), nb -= c, S -= c, R -= b, mb.parent().append(a('<div class="jspCorner" />').css("width", b + "px")), h(), j()
2374                }
2375                Z && Q.width(T.outerWidth() - tb + "px"), V = Q.outerHeight(), X = V / S, Z && (ob = Math.ceil(1 / W * nb), ob > P.horizontalDragMaxWidth ? ob = P.horizontalDragMaxWidth : ob < P.horizontalDragMinWidth && (ob = P.horizontalDragMinWidth), bb.width(ob + "px"), cb = nb - ob, u(db)), Y && (ib = Math.ceil(1 / X * hb), ib > P.verticalDragMaxHeight ? ib = P.verticalDragMaxHeight : ib < P.verticalDragMinHeight && (ib = P.verticalDragMinHeight), $.height(ib + "px"), _ = hb - ib, s(ab))
2376            }
2377
2378            function l(a, b, c, d) {
2379                var e, f = "before",
2380                    g = "after";
2381                "os" == b && (b = /Mac/.test(navigator.platform) ? "after" : "split"), b == f ? g = b : b == g && (f = b, e = c, c = d, d = e), a[f](c)[g](d)
2382            }
2383
2384            function m(a, b, c) {
2385                return function() {
2386                    return n(a, b, this, c), this.blur(), !1
2387                }
2388            }
2389
2390            function n(b, c, d, e) {
2391                d = a(d).addClass("jspActive");
2392                var f, g, h = !0,
2393                    i = function() {
2394                        0 !== b && vb.scrollByX(b * P.arrowButtonSpeed), 0 !== c && vb.scrollByY(c * P.arrowButtonSpeed), g = setTimeout(i, h ? P.initialDelay : P.arrowRepeatFreq), h = !1
2395                    };
2396                i(), f = e ? "mouseout.jsp" : "mouseup.jsp", e = e || a("html"), e.bind(f, function() {
2397                    d.removeClass("jspActive"), g && clearTimeout(g), g = null, e.unbind(f)
2398                })
2399            }
2400
2401            function o() {
2402                p(), Y && fb.bind("mousedown.jsp", function(b) {
2403                    if (b.originalTarget === c || b.originalTarget == b.currentTarget) {
2404                        var d, e = a(this),
2405                            f = e.offset(),
2406                            g = b.pageY - f.top - ab,
2407                            h = !0,
2408                            i = function() {
2409                                var a = e.offset(),
2410                                    c = b.pageY - a.top - ib / 2,
2411                                    f = S * P.scrollPagePercent,
2412                                    k = _ * f / (V - S);
2413                                if (0 > g) ab - k > c ? vb.scrollByY(-f) : r(c);
2414                                else {
2415                                    if (!(g > 0)) return j(), void 0;
2416                                    c > ab + k ? vb.scrollByY(f) : r(c)
2417                                }
2418                                d = setTimeout(i, h ? P.initialDelay : P.trackClickRepeatFreq), h = !1
2419                            },
2420                            j = function() {
2421                                d && clearTimeout(d), d = null, a(document).unbind("mouseup.jsp", j)
2422                            };
2423                        return i(), a(document).bind("mouseup.jsp", j), !1
2424                    }
2425                }), Z && mb.bind("mousedown.jsp", function(b) {
2426                    if (b.originalTarget === c || b.originalTarget == b.currentTarget) {
2427                        var d, e = a(this),
2428                            f = e.offset(),
2429                            g = b.pageX - f.left - db,
2430                            h = !0,
2431                            i = function() {
2432                                var a = e.offset(),
2433                                    c = b.pageX - a.left - ob / 2,
2434                                    f = R * P.scrollPagePercent,
2435                                    k = cb * f / (U - R);
2436                                if (0 > g) db - k > c ? vb.scrollByX(-f) : t(c);
2437                                else {
2438                                    if (!(g > 0)) return j(), void 0;
2439                                    c > db + k ? vb.scrollByX(f) : t(c)
2440                                }
2441                                d = setTimeout(i, h ? P.initialDelay : P.trackClickRepeatFreq), h = !1
2442                            },
2443                            j = function() {
2444                                d && clearTimeout(d), d = null, a(document).unbind("mouseup.jsp", j)
2445                            };
2446                        return i(), a(document).bind("mouseup.jsp", j), !1
2447                    }
2448                })
2449            }
2450
2451            function p() {
2452                mb && mb.unbind("mousedown.jsp"), fb && fb.unbind("mousedown.jsp")
2453            }
2454
2455            function q() {
2456                a("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp"), $ && $.removeClass("jspActive"), bb && bb.removeClass("jspActive")
2457            }
2458
2459            function r(a, b) {
2460                Y && (0 > a ? a = 0 : a > _ && (a = _), b === c && (b = P.animateScroll), b ? vb.animate($, "top", a, s) : ($.css("top", a), s(a)))
2461            }
2462
2463            function s(a) {
2464                a === c && (a = $.position().top), T.scrollTop(0), ab = a;
2465                var b = 0 === ab,
2466                    e = ab == _,
2467                    f = a / _,
2468                    g = -f * (V - S);
2469                (wb != b || yb != e) && (wb = b, yb = e, d.trigger("jsp-arrow-change", [wb, yb, xb, zb])), v(b, e), Q.css("top", g), d.trigger("jsp-scroll-y", [-g, b, e]).trigger("scroll")
2470            }
2471
2472            function t(a, b) {
2473                Z && (0 > a ? a = 0 : a > cb && (a = cb), b === c && (b = P.animateScroll), b ? vb.animate(bb, "left", a, u) : (bb.css("left", a), u(a)))
2474            }
2475
2476            function u(a) {
2477                a === c && (a = bb.position().left), T.scrollTop(0), db = a;
2478                var b = 0 === db,
2479                    e = db == cb,
2480                    f = a / cb,
2481                    g = -f * (U - R);
2482                (xb != b || zb != e) && (xb = b, zb = e, d.trigger("jsp-arrow-change", [wb, yb, xb, zb])), w(b, e), Q.css("left", g), d.trigger("jsp-scroll-x", [-g, b, e]).trigger("scroll")
2483            }
2484
2485            function v(a, b) {
2486                P.showArrows && (jb[a ? "addClass" : "removeClass"]("jspDisabled"), kb[b ? "addClass" : "removeClass"]("jspDisabled"))
2487            }
2488
2489            function w(a, b) {
2490                P.showArrows && (pb[a ? "addClass" : "removeClass"]("jspDisabled"), qb[b ? "addClass" : "removeClass"]("jspDisabled"))
2491            }
2492
2493            function x(a, b) {
2494                var c = a / (V - S);
2495                r(c * _, b)
2496            }
2497
2498            function y(a, b) {
2499                var c = a / (U - R);
2500                t(c * cb, b)
2501            }
2502
2503            function z(b, c, d) {
2504                var e, f, g, h, i, j, k, l, m, n = 0,
2505                    o = 0;
2506                try {
2507                    e = a(b)
2508                } catch (p) {
2509                    return
2510                }
2511                for (f = e.outerHeight(), g = e.outerWidth(), T.scrollTop(0), T.scrollLeft(0); !e.is(".jspPane");)
2512                    if (n += e.position().top, o += e.position().left, e = e.offsetParent(), /^body|html$/i.test(e[0].nodeName)) return;
2513                h = B(), j = h + S, h > n || c ? l = n - P.horizontalGutter : n + f > j && (l = n - S + f + P.horizontalGutter), isNaN(l) || x(l, d), i = A(), k = i + R, i > o || c ? m = o - P.horizontalGutter : o + g > k && (m = o - R + g + P.horizontalGutter), isNaN(m) || y(m, d)
2514            }
2515
2516            function A() {
2517                return -Q.position().left
2518            }
2519
2520            function B() {
2521                return -Q.position().top
2522            }
2523
2524            function C() {
2525                var a = V - S;
2526                return a > 20 && a - B() < 10
2527            }
2528
2529            function D() {
2530                var a = U - R;
2531                return a > 20 && a - A() < 10
2532            }
2533
2534            function E() {
2535                T.unbind(Bb).bind(Bb, function(a, b, c, d) {
2536                    var e = db,
2537                        f = ab,
2538                        g = a.deltaFactor || P.mouseWheelSpeed;
2539                    return vb.scrollBy(c * g, -d * g, !1), e == db && f == ab
2540                })
2541            }
2542
2543            function F() {
2544                T.unbind(Bb)
2545            }
2546
2547            function G() {
2548                return !1
2549            }
2550
2551            function H() {
2552                Q.find(":input,a").unbind("focus.jsp").bind("focus.jsp", function(a) {
2553                    z(a.target, !1)
2554                })
2555            }
2556
2557            function I() {
2558                Q.find(":input,a").unbind("focus.jsp")
2559            }
2560
2561            function J() {
2562                function b() {
2563                    var a = db,
2564                        b = ab;
2565                    switch (c) {
2566                        case 40:
2567                            vb.scrollByY(P.keyboardSpeed, !1);
2568                            break;
2569                        case 38:
2570                            vb.scrollByY(-P.keyboardSpeed, !1);
2571                            break;
2572                        case 34:
2573                        case 32:
2574                            vb.scrollByY(S * P.scrollPagePercent, !1);
2575                            break;
2576                        case 33:
2577                            vb.scrollByY(-S * P.scrollPagePercent, !1);
2578                            break;
2579                        case 39:
2580                            vb.scrollByX(P.keyboardSpeed, !1);
2581                            break;
2582                        case 37:
2583                            vb.scrollByX(-P.keyboardSpeed, !1)
2584                    }
2585                    return e = a != db || b != ab
2586                }
2587                var c, e, f = [];
2588                Z && f.push(lb[0]), Y && f.push(eb[0]), Q.focus(function() {
2589                    d.focus()
2590                }
2590), d.attr("tabindex", 0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp", function(d) {
2591                    if (d.target === this || f.length && a(d.target).closest(f).length) {
2592                        var g = db,
2593                            h = ab;
2594                        switch (d.keyCode) {
2595                            case 40:
2596                            case 38:
2597                            case 34:
2598                            case 32:
2599                            case 33:
2600                            case 39:
2601                            case 37:
2602                                c = d.keyCode, b();
2603                                break;
2604                            case 35:
2605                                x(V - S), c = null;
2606                                break;
2607                            case 36:
2608                                x(0), c = null
2609                        }
2610                        return e = d.keyCode == c && g != db || h != ab, !e
2611                    }
2612                }).bind("keypress.jsp", function(a) {
2613                    return a.keyCode == c && b(), !e
2614                }), P.hideFocus ? (d.css("outline", "none"), "hideFocus" in T[0] && d.attr("hideFocus", !0)) : (d.css("outline", ""), "hideFocus" in T[0] && d.attr("hideFocus", !1))
2615            }
2616
2617            function K() {
2618                d.attr("tabindex", "-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")
2619            }
2620
2621            function L() {
2622                if (location.hash && location.hash.length > 1) {
2623                    var b, c, d = escape(location.hash.substr(1));
2624                    try {
2625                        b = a("#" + d + ', a[name="' + d + '"]')
2626                    } catch (e) {
2627                        return
2628                    }
2629                    b.length && Q.find(d) && (0 === T.scrollTop() ? c = setInterval(function() {
2630                        T.scrollTop() > 0 && (z(b, !0), a(document).scrollTop(T.position().top), clearInterval(c))
2631                    }, 50) : (z(b, !0), a(document).scrollTop(T.position().top)))
2632                }
2633            }
2634
2635            function M() {
2636                a(document.body).data("jspHijack") || (a(document.body).data("jspHijack", !0), a(document.body).delegate("a[href*=#]", "click", function(c) {
2637                    var d, e, f, g, h, i, j = this.href.substr(0, this.href.indexOf("#")),
2638                        k = location.href;
2639                    if (-1 !== location.href.indexOf("#") && (k = location.href.substr(0, location.href.indexOf("#"))), j === k) {
2640                        d = escape(this.href.substr(this.href.indexOf("#") + 1));
2641                        try {
2642                            e = a("#" + d + ', a[name="' + d + '"]')
2643                        } catch (l) {
2644                            return
2645                        }
2646                        e.length && (f = e.closest(".jspScrollable"), g = f.data("jsp"), g.scrollToElement(e, !0), f[0].scrollIntoView && (h = a(b).scrollTop(), i = e.offset().top, (h > i || i > h + a(b).height()) && f[0].scrollIntoView()), c.preventDefault())
2647                    }
2648                }))
2649            }
2650
2651            function N() {
2652                var a, b, c, d, e, f = !1;
2653                T.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp", function(g) {
2654                    var h = g.originalEvent.touches[0];
2655                    a = A(), b = B(), c = h.pageX, d = h.pageY, e = !1, f = !0
2656                }).bind("touchmove.jsp", function(g) {
2657                    if (f) {
2658                        var h = g.originalEvent.touches[0],
2659                            i = db,
2660                            j = ab;
2661                        return vb.scrollTo(a + c - h.pageX, b + d - h.pageY), e = e || Math.abs(c - h.pageX) > 5 || Math.abs(d - h.pageY) > 5, i == db && j == ab
2662                    }
2663                }).bind("touchend.jsp", function() {
2664                    f = !1
2665                }).bind("click.jsp-touchclick", function() {
2666                    return e ? (e = !1, !1) : void 0
2667                })
2668            }
2669
2670            function O() {
2671                var a = B(),
2672                    b = A();
2673                d.removeClass("jspScrollable").unbind(".jsp"), d.replaceWith(Ab.append(Q.children())), Ab.scrollTop(a), Ab.scrollLeft(b), rb && clearInterval(rb)
2674            }
2675            var P, Q, R, S, T, U, V, W, X, Y, Z, $, _, ab, bb, cb, db, eb, fb, gb, hb, ib, jb, kb, lb, mb, nb, ob, pb, qb, rb, sb, tb, ub, vb = this,
2676                wb = !0,
2677                xb = !0,
2678                yb = !1,
2679                zb = !1,
2680                Ab = d.clone(!1, !1).empty(),
2681                Bb = a.fn.mwheelIntent ? "mwheelIntent.jsp" : "mousewheel.jsp";
2682            "border-box" === d.css("box-sizing") ? (sb = 0, tb = 0) : (sb = d.css("paddingTop") + " " + d.
2682css("paddingRight") + " " + d.css("paddingBottom") + " " + d.css("paddingLeft"), tb = (parseInt(d.css("paddingLeft"), 10) || 0) + (parseInt(d.css("paddingRight"), 10) || 0)), a.extend(vb, {
2683                reinitialise: function(b) {
2684                    b = a.extend({}, P, b), f(b)
2685                },
2686                scrollToElement: function(a, b, c) {
2687                    z(a, b, c)
2688                },
2689                scrollTo: function(a, b, c) {
2690                    y(a, c), x(b, c)
2691                },
2692                scrollToX: function(a, b) {
2693                    y(a, b)
2694                },
2695                scrollToY: function(a, b) {
2696                    x(a, b)
2697                },
2698                scrollToPercentX: function(a, b) {
2699                    y(a * (U - R), b)
2700                },
2701                scrollToPercentY: function(a, b) {
2702                    x(a * (V - S), b)
2703                },
2704                scrollBy: function(a, b, c) {
2705                    vb.scrollByX(a, c), vb.scrollByY(b, c)
2706                },
2707                scrollByX: function(a, b) {
2708                    var c = A() + Math[0 > a ? "floor" : "ceil"](a),
2709                        d = c / (U - R);
2710                    t(d * cb, b)
2711                },
2712                scrollByY: function(a, b) {
2713                    var c = B() + Math[0 > a ? "floor" : "ceil"](a),
2714                        d = c / (V - S);
2715                    r(d * _, b)
2716                },
2717                positionDragX: function(a, b) {
2718                    t(a, b)
2719                },
2720                positionDragY: function(a, b) {
2721                    r(a, b)
2722                },
2723                animate: function(a, b, c, d) {
2724                    var e = {};
2725                    e[b] = c, a.animate(e, {
2726                        duration: P.animateDuration,
2727                        easing: P.animateEase,
2728                        queue: !1,
2729                        step: d
2730                    })
2731                },
2732                getContentPositionX: function() {
2733                    return A()
2734                },
2735                getContentPositionY: function() {
2736                    return B()
2737                },
2738                getContentWidth: function() {
2739                    return U
2740                },
2741                getContentHeight: function() {
2742                    return V
2743                },
2744                getPercentScrolledX: function() {
2745                    return A() / (U - R)
2746                },
2747                getPercentScrolledY: function() {
2748                    return B() / (V - S)
2749                },
2750                getIsScrollableH: function() {
2751                    return Z
2752                },
2753                getIsScrollableV: function() {
2754                    return Y
2755                },
2756                getContentPane: function() {
2757                    return Q
2758                },
2759                scrollToBottom: function(a) {
2760                    r(_, a)
2761                },
2762                hijackInternalLinks: a.noop,
2763                destroy: function() {
2764                    O()
2765                }
2766            }), f(e)
2767        }
2768        return d = a.extend({}, a.fn.jScrollPane.defaults, d), a.each(["arrowButtonSpeed", "trackClickSpeed", "keyboardSpeed"], function() {
2769            d[this] = d[this] || d.speed
2770        }), this.each(function() {
2771            var b = a(this),
2772                c = b.data("jsp");
2773            c ? c.reinitialise(d) : (a("script", b).filter('[type="text/javascript"],:not([type])').remove(), c = new e(b, d), b.data("jsp", c))
2774        })
2775    }, a.fn.jScrollPane.defaults = {
2776        showArrows: !1,
2777        maintainPosition: !0,
2778        stickToBottom: !1,
2779        stickToRight: !1,
2780        clickOnTrack: !0,
2781        autoReinitialise: !1,
2782        autoReinitialiseDelay: 500,
2783        verticalDragMinHeight: 0,
2784        verticalDragMaxHeight: 99999,
2785        horizontalDragMinWidth: 0,
2786        horizontalDragMaxWidth: 99999,
2787        contentWidth: c,
2788        animateScroll: !1,
2789        animateDuration: 300,
2790        animateEase: "linear",
2791        hijackInternalLinks: !1,
2792        verticalGutter: 4,
2793        horizontalGutter: 4,
2794        mouseWheelSpeed: 3,
2795        arrowButtonSpeed: 0,
2796        arrowRepeatFreq: 50,
2797        arrowScrollOnHover: !1,
2798        trackClickSpeed: 0,
2799        trackClickRepeatFreq: 70,
2800        verticalArrowPositions: "split",
2801        horizontalArrowPositions: "split",
2802        enableKeyboardNavigation: !0,
2803        hideFocus: !1,
2804        keyboardSpeed: 0,
2805        initialDelay: 300,
2806        speed: 30,
2807        scrollPagePercent: .8
2808    }
2809}(jQuery, this);
2810
2811jQuery(document).ready(function($) {
2812
2813    $('.gm-style-iw').parent().parent().addClass('wpgmp_infowindow_css');
2814    $("div.scroll-pane").jScrollPane();
2815
2816    $(".accordion").accordion({
2817        speed: "slow"
2818    });
2819
2820
2821    $('span a').on('click', function(e) {
2822        var elem = $('div.wpgmp_categories');
2823        if ($(this).hasClass('wpgmp_grid')) {
2824            elem.fadeOut(500, function() {
2825                elem.removeClass('wpgmp_listing_list').addClass('wpgmp_listing_grid');
2826                $('.wpgmp_locations').equalHeightGrid();
2827                elem.fadeIn(500);
2828            });
2829        } else if ($(this).hasClass('wpgmp_list')) {
2830            elem.fadeOut(500, function() {
2831                elem.removeClass('wpgmp_listing_grid').addClass('wpgmp_listing_list');
2832                $('.wpgmp_locations').equalHeightGrid();
2833                elem.fadeIn(500);
2834            });
2835        }
2836    });
2837
2838});
2839
2840/*  jQuery.print, version 1.0.3
2841 *  (c) Sathvik Ponangi, Doers' Guild
2842 * Licence: CC-By (http://creativecommons.org/licenses/by/3.0/)
2843 *--------------------------------------------------------------------------*/
2844
2845(function($) {
2846    "use strict";
2847    // A nice closure for our definitions
2848
2849    function getjQueryObject(string) {
2850        // Make string a vaild jQuery thing
2851        var jqObj = $("");
2852        try {
2853            jqObj = $(string).clone();
2854        } catch (e) {
2855            jqObj = $("<span />").html(string);
2856        }
2857        return jqObj;
2858    }
2859
2860    function isNode(o) {
2861        /* http://stackoverflow.com/a/384380/937891 */
2862        return !!(typeof Node === "object" ? o instanceof Node : o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string");
2863    }
2864
2865
2866    $.print = $.fn.print = function() {
2867        // Print a given set of elements
2868
2869        var options, $this, self = this;
2870
2871        // console.log("Printing", this, arguments);
2872
2873        if (self instanceof $) {
2874            // Get the node if it is a jQuery object
2875            self = self.get(0);
2876        }
2877
2878        if (isNode(self)) {
2879            // If `this` is a HTML element, i.e. for
2880            // $(selector).print()
2881            $this = $(self);
2882            if (arguments.length > 0) {
2883                options = arguments[0];
2884            }
2885        } else {
2886            if (arguments.length > 0) {
2887                // $.print(selector,options)
2888                $this = $(arguments[0]);
2889                if (isNode($this[0])) {
2890                    if (arguments.length > 1) {
2891                        options = arguments[1];
2892                    }
2893                } else {
2894                    // $.print(options)
2895                    options = arguments[0];
2896                    $this = $("html");
2897                }
2898            } else {
2899                // $.print()
2900                $this = $("html");
2901            }
2902        }
2903
2904        // Default options
2905        var defaults = {
2906            globalStyles: true,
2907            mediaPrint: false,
2908            stylesheet: null,
2909            noPrintSelector: ".no-print",
2910            iframe: true,
2911            append: null,
2912            prepend: null
2913        };
2914        // Merge with user-options
2915        options = $.extend({}, defaults, (options || {}));
2916
2917        var $styles = $("");
2918        if (options.globalStyles) {
2919            // Apply the stlyes from the current sheet to the printed page
2920            $styles = $("style, link, meta, title");
2921        } else if (options.mediaPrint) {
2922            // Apply the media-print stylesheet
2923            $styles = $("link[media=print]");
2924        }
2925        if (options.stylesheet) {
2926            // Add a custom stylesheet if given
2927            $styles = $.merge($styles, $('<link rel="stylesheet" href="' + options.stylesheet + '">'));
2928        }
2929
2930        // Create a copy of the element to print
2931        var copy = $this.clone();
2932        // Wrap it in a span to get the HTML markup string
2933        copy = $("<span/>").append(copy);
2934        // Remove unwanted elements
2935        copy.find(options.noPrintSelector).remove();
2936        // Add in the styles
2937        copy.append($styles.clone());
2938        // Appedned content
2939        copy.append(getjQueryObject(options.append));
2940        // Prepended content
2941        copy.prepend(getjQueryObject(options.prepend));
2942        // Get the HTML markup string
2943        var content = copy.html();
2944        // Destroy the copy
2945        copy.remove();
2946
2947        var w, wdoc;
2948        if (options.iframe) {
2949            // Use an iframe for printing
2950            try {
2951                var $iframe = $(options.iframe + "");
2952                var iframeCount = $iframe.length;
2953                if (iframeCount === 0) {
2954                    // Create a new iFrame if none is given
2955                    $iframe = $('<iframe height="0" width="0" border="0" wmode="Opaque"/>').prependTo('body').css({
2956                        "position": "absolute",
2957                        "top": -999,
2958                        "left": -999
2959                    });
2960                }
2961                w = $iframe.get(0);
2962                w = w.contentWindow || w.contentDocument || w;
2963                wdoc = w.document || w.contentDocument || w;
2964                wdoc.open();
2965                wdoc.write(content);
2966                wdoc.close();
2967                setTimeout(function() {
2968                    // Fix for IE : Allow it to render the iframe
2969                    w.focus();
2970                    w.print();
2971                    setTimeout(function() {
2972                        // Fix for IE
2973                        if (iframeCount === 0) {
2974                            // Destroy the iframe if created here
2975                            $iframe.remove();
2976                        }
2977                    }, 100);
2978                }, 250);
2979            } catch (e) {
2980                // Use the pop-up method if iframe fails for some reason
2981                console.error("Failed to print from iframe", e.stack, e.message);
2982                w = window.open();
2983                w.document.write(content);
2984                w.document.close();
2985                w.focus();
2986                w.print();
2987                w.close();
2988            }
2989        } else {
2990            // Use a new window for printing
2991            w = window.open();
2992            w.document.write(content);
2993            w.document.close();
2994            w.focus();
2995            w.print();
2996            w.close();
2997        }
2998        return this;
2999    };
3000
3001})(jQuery);
3002
3003(function($) {
3004
3005    /**
3006     * Set all elements within the collection to have the same height.
3007     */
3008    $.fn.equalHeight = function() {
3009        var heights = [];
3010        $.each(this, function(i, element) {
3011            $element = $(element);
3012            var element_height;
3013            // Should we include the elements padding in it's height?
3014            var includePadding = ($element.css('box-sizing') == 'border-box') || ($element.css('-moz-box-sizing') == 'border-box');
3015            if (includePadding) {
3016                element_height = $element.innerHeight();
3017            } else {
3018                element_height = $element.height();
3019            }
3020            heights.push(element_height);
3021        });
3022        this.css('height', Math.max.apply(window, heights) + 'px');
3023        return this;
3024    };
3025
3026    /**
3027     * Create a grid of equal height elements.
3028     */
3029    $.fn.equalHeightGrid = function(columns) {
3030        var $tiles = this;
3031        $tiles.css('height', 'auto');
3032        for (var i = 0; i < $tiles.length; i++) {
3033            if (i % columns === 0) {
3034                var row = $($tiles[i]);
3035                for (var n = 1; n < columns; n++) {
3036                    row = row.add($tiles[i + n]);
3037                }
3038                row.equalHeight();
3039            }
3040        }
3041        return this;
3042    };
3043
3044    /**
3045     * Detect how many columns there are in a given layout.
3046     */
3047    $.fn.detectGridColumns = function() {
3048        var offset = 0,
3049            cols = 0;
3050        this.each(function(i, elem) {
3051            var elem_offset = $(elem).offset().top;
3052            if (offset === 0 || elem_offset == offset) {
3053                cols++;
3054                offset = elem_offset;
3055            } else {
3056                return false;
3057            }
3058        });
3059        return cols;
3060    };
3061
3062    /**
3063     * Ensure equal heights now, on ready, load and resize.
3064     */
3065    $.fn.responsiveEqualHeightGrid = function() {
3066        var _this = this;
3067
3068        function syncHeights() {
3069            var cols = _this.detectGridColumns();
3070            _this.equalHeightGrid(cols);
3071        }
3072        $(window).bind('resize load', syncHeights);
3073        syncHeights();
3074        return this;
3075    };
3076
3077})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.