# Source: wp-google-maps.combined.js

    // js/v8/core.js
    /**
     * @module WPGMZA
     * @summary This is the core Javascript module. Some code exists in ../core.js, the functionality there will slowly be handed over to this module.
     */
    (function($) {
    	var core = {
    		maps: [],
    		events: null,
    		settings: null,

    		loadingHTML: '<div class="wpgmza-preloader"><div class="wpgmza-loader">...</div></div>',

    		/**
    		 * @function guid
    		 * @summary Utility function returns a GUID
    		 * @static
    		 * @return {string} The GUID
    		 */
    		guid: function() { // Public Domain/MIT
    		  var d = new Date().getTime();
    			if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
    				d += performance.now(); //use high-precision timer if available
    			}
    			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    				var r = (d + Math.random() * 16) % 16 | 0;
    				d = Math.floor(d / 16);
    				return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    			});
    		},

    		/**
    		 * @function hexOpacityToRGBA
    		 * @summary Takes a hex string and opacity value and converts it to Openlayers RGBA format
    		 * @param {string} colour The hex color string
    		 * @param {number} opacity The opacity from 0.0 - 1.0
    		 * @static
    		 * @return {array} RGBA where color components are 0 - 255 and opacity is 0.0 - 1.0
    		 */
    		hexOpacityToRGBA: function(colour, opacity)
    		{
    			hex = parseInt(colour.replace(/^#/, ""), 16);
    			return [
    				(hex & 0xFF0000) >> 16,
    				(hex & 0xFF00) >> 8,
    				hex & 0xFF,
    				parseFloat(opacity)
    			];
    		},

    		latLngRegexp: /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/,

    		/**
    		 * @function isLatLngString
    		 * @summary Utility function returns true is string is a latitude and longitude
    		 * @param str {string} The string to attempt to parse as coordinates
    		 * @static
    		 * @return {array} the matched latitude and longitude or null if no match
    		 */
    		isLatLngString: function(str)
    		{
    			if(typeof str != "string")
    				return null;

    			// Remove outer brackets
    			if(str.match(/^\(.+\)$/))
    				str = str.replace(/^\(|\)$/, "");

    			var m = str.match(WPGMZA.latLngRegexp);

    			if(!m)
    				return null;

    			return {
    				lat: parseFloat(m[1]),
    				lng: parseFloat(m[3])
    			};
    		},

    		/**
    		 * @function stringToLatLng
    		 * @summary Utility function returns a latLng literal given a valid latLng string
    		 * @param str {string} The string to attempt to parse as coordinates
    		 * @static
    		 * @return {object} LatLng literal
    		 */
    		stringToLatLng: function(str)
    		{
    			var result = WPGMZA.isLatLngString(str);

    			if(!result)
    				throw new Error("Not a valid latLng");

    			return result;
    		},

    		/**
    		 * @function getImageDimensions
    		 * @summary Utility function to get the dimensions of an image, caches results for best performance
    		 * @param src {string} Image source URL
    		 * @param callback {function} Callback to recieve image dimensions
    		 * @static
    		 * @return {void}
    		 */
    		imageDimensionsCache: {},
    		getImageDimensions: function(src, callback)
    		{
    			if(WPGMZA.imageDimensionsCache[src])
    			{
    				callback(WPGMZA.imageDimensionsCache[src]);
    				return;
    			}

    			var img = document.createElement("img");
    			img.onload = function(event) {
    				var result = {
    					width: image.width,
    					height: image.height
    				};
    				WPGMZA.imageDimensionsCache[src] = result;
    				callback(result);
    			};
    			img.src = src;
    		},

    		/**
    		 * @function isDeveloperMode
    		 * @summary Returns true if developer mode is set
    		 * @static
    		 * @return {boolean} True if developer mode is on
    		 */
    		isDeveloperMode: function()
    		{
    			return this.developer_mode || (window.Cookies && window.Cookies.get("wpgmza-developer-mode"));
    		},

    		/**
    		 * @function isProVersion
    		 * @summary Returns true if the Pro add-on is active
    		 * @static
    		 * @return {boolean} True if the Pro add-on is active
    		 */
    		isProVersion: function()
    		{
    			return (this._isProVersion == "1");
    		},

    		/**
    		 * @function openMediaDialog
    		 * @summary Opens the WP media dialog and returns the result to a callback
    		 * @param {function} callback Callback to recieve the attachment ID as the first parameter and URL as the second
    		 * @static
    		 * @return {void}
    		 */
    		openMediaDialog: function(callback) {
    			// Media upload
    			var file_frame;

    			// If the media frame already exists, reopen it.
    			if ( file_frame ) {
    				// Set the post ID to what we want
    				file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
    				// Open frame
    				file_frame.open();
    				return;
    			}

    			// Create the media frame.
    			file_frame = wp.media.frames.file_frame = wp.media({
    				title: 'Select a image to upload',
    				button: {
    					text: 'Use this image',
    				},
    				multiple: false	// Set to true to allow multiple files to be selected
    			});

    			// When an image is selected, run a callback.
    			file_frame.on( 'select', function() {
    				// We set multiple to false so only get one image from the uploader
    				attachment = file_frame.state().get('selection').first().toJSON();

    				callback(attachment.id, attachment.url);
    			});

    			// Finally, open the modal
    			file_frame.open();
    		},

    		/**
    		 * @function getCurrentPosition
    		 * @summary This function will get the users position, it first attempts to get
    		 * high accuracy position (mobile with GPS sensors etc.), if that fails
    		 * (desktops will time out) then it tries again without high accuracy
    		 * enabled
    		 * @static
    		 * @return {object} The users position as a LatLng literal
    		 */
    		getCurrentPosition: function(callback)
    		{
    			if(!navigator.geolocation)
    			{
    				console.warn("No geolocation available on this device");
    				return;
    			}

    			var options = {
    				enableHighAccuracy: true
    			};

    			navigator.geolocation.getCurrentPosition(function(position) {
    				callback(position);
    			},
    			function(error) {

    				options.enableHighAccuracy = false;

    				navigator.geolocation.getCurrentPosition(function(position) {
    					callback(position);
    				},
    				function(error) {
    					console.warn(error.code, error.message);
    				},
    				options);

    			},
    			options);
    		},

    		/**
    		 * @function runCatchableTask
    		 * @summary Runs a catchable task and displays a friendly error if the function throws an error
    		 * @param {function} callback The function to run
    		 * @param {HTMLElement} friendlyErrorContainer The container element to hold the error
    		 * @static
    		 * @return {void}
    		 */
    		runCatchableTask: function(callback, friendlyErrorContainer) {

    			if(WPGMZA.isDeveloperMode())
    				callback();
    			else
    				try{
    					callback();
    				}catch(e) {
    					var friendlyError = new WPGMZA.FriendlyError(e);
    					$(friendlyErrorContainer).html("");
    					$(friendlyErrorContainer).append(friendlyError.element);
    					$(friendlyErrorContainer).show();
    				}
    		},

    		/**
    		 * @function assertInstanceOf
    		 * @summary
    		 * This function is for checking inheritence has been setup correctly.
    		 * For objects that have engine and Pro specific classes, it will automatically
    		 * add the engine and pro prefix to the supplied string and if such an object
    		 * exists it will test against that name rather than the un-prefix argument
    		 * supplied.
    		 *
    		 * For example, if we are running the Pro addon with Google maps as the engine,
    		 * if you supply Marker as the instance name the function will check to see
    		 * if instance is an instance of GoogleProMarker
    		 * @param {object} instance The object to check
    		 * @param {string} instanceName The class name as a string which this object should be an instance of
    		 * @static
    		 * @return {void}
    		 */
    		assertInstanceOf: function(instance, instanceName) {
    			var engine, fullInstanceName, assert;
    			var pro = WPGMZA.isProVersion() ? "Pro" : "";

    			switch(WPGMZA.settings.engine)
    			{
    				case "google-maps":
    					engine = "Google";
    					break;

    				default:
    					engine = "OL";
    					break;
    			}

    			if(WPGMZA[engine + pro + instanceName])
    				fullInstanceName = engine + pro + instanceName;
    			else if(WPGMZA[pro + instanceName])
    				fullInstanceName = pro + instanceName;
    			else if(WPGMZA[engine + instanceName])
    				fullInstanceName = engine + instanceName;
    			else
    				fullInstanceName = instanceName;

    			assert = instance instanceof WPGMZA[fullInstanceName];

    			if(!assert)
    				throw new Error("Object must be an instance of " + fullInstanceName + " (did you call a constructor directly, rather than createInstance?)");
    		},

    		/**
    		 * @function getMapByID
    		 * @param {mixed} id The ID of the map to retrieve
    		 * @static
    		 * @return {object} The map object, or null if no such map exists
    		 */
    		getMapByID: function(id) {
    			for(var i = 0; i < WPGMZA.maps.length; i++) {
    				if(WPGMZA.maps[i].id == id)
    					return WPGMZA.maps[i];
    			}

    			return null;
    		},

    		/**
    		 * @function isGoogleAutocompleteSupported
    		 * @summary Shorthand function to determine if the Places Autocomplete is available
    		 * @static
    		 * @return {boolean}
    		 */
    		isGoogleAutocompleteSupported: function() {
    			return typeof google === 'object' && typeof google.maps === 'object' && typeof google.maps.places === 'object' && typeof google.maps.places.Autocomplete === 'function';
    		}
    	};

    	if(window.WPGMZA)
    		window.WPGMZA = $.extend(window.WPGMZA, core);
    	else
    		window.WPGMZA = core;

    	for(var key in WPGMZA_localized_data)
    	{
    		var value = WPGMZA_localized_data[key];
    		WPGMZA[key] = value;
    	}

    	/*for(var key in WPGMZA_localized_data)
    		WPGMZA[key] = WPGMZA_localized_data[key];

    	$(document).ready(function(event) {
    		// Datatables to throw errors
    		if($.fn.dataTable)
    			$.fn.dataTable.ext.errMode = 'throw';

    		// Combined script warning
    		if($("script[src*='wp-google-maps.combined.js'], script[src*='wp-google-maps-pro.combined.js']").length)
    			console.warn("Minified script is out of date, using combined script instead.");

    		// Check for multiple jQuery versions
    		var elements = $("script").filter(function() {
    			return this.src.match(/(^|\/)jquery\.(min\.)?js(\?|$)/i);
    		});

    		if(elements.length > 1)
    			console.warn("Multiple jQuery versions detected: ", elements);

    		// Disable map edit page preloader in developer more
    		if(WPGMZA.isDeveloperMode())
    			$("#wpgmza-map-edit-page form.wpgmza").show();

    		// Shortcode boxes
    		$(".wpgmza_copy_shortcode").on("click", function() {
    			var temp = $("<input>");
    			var temp2 = $('<div id="wpgmza_tmp" style="display: none;" width:100%; text-align:center;"/>');
    			$(document.body).append(temp);
    			temp.val($(this).val()).select();
    			document.execCommand("copy");
    			temp.remove();
    			$(this).after(temp2);
    			$(temp2).html(
    				$("[data-shortcode-copy-string]").attr("data-shortcode-copy-string")
    			);
    			$(temp2).fadeIn();
    			setTimeout(function() {
    				$(temp2).fadeOut();
    			}, 1000);
    			setTimeout(function() {
    				$(temp2).remove();
    			}, 1500);
    		});

    		// Fancy switches
    		// $("form.wpgmza .cmn-toggle").each(function(index, el) {
    		//
    		// 	$(el).wrap("<div class='switch'/>");
    		// 	$(el).after("<label for=""/>")
    		//
    		// });

    		$("form.wpgmza").on("click", ".switch label", function(event) {
    			var input = $(this).prev(".cmn-toggle");

    			if(input.prop("disabled"))
    				return;

    			var val = !input.prop("checked");

    			input.prop("checked", val);

    			if(val)
    				input.attr("checked", "checked");
    			else
    				input.removeAttr("checked");

    			input.trigger("change");
    		});

    		// Geolocation warnings
    		if(window.location.protocol != 'https:')
    		{
    			var warning = '<span class="notice notice-warning">' + WPGMZA.localized_strings.unsecure_geolocation + "</span>";

    			$(".wpgmza-geolocation-setting").after(
    				$(warning)
    			);
    		}

    		// Switch off thanks for feedback message
    		document.cookie = "wpgmza_feedback_thanks=false; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
    	});*/
    })(jQuery);

    // js/v8/distance.js
    /**
     * @namespace WPGMZA
     * @module Distance
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.Distance = {

    		MILES:					true,
    		KILOMETERS:				false,

    		MILES_PER_KILOMETER:	0.621371,
    		KILOMETERS_PER_MILE:	1.60934,

    		// TODO: Implement WPGMZA.settings.distance_units

    		/**
    		 * Converts a UI distance (eg from a form control) to meters,
    		 * accounting for the global units setting
    		 */
    		uiToMeters: function(uiDistance)
    		{
    			return parseFloat(uiDistance) / (WPGMZA.settings.distance_units == WPGMZA.Distance.MILES ? WPGMZA.Distance.MILES_PER_KILOMETER : 1) * 1000;
    		},

    		/**
    		 * Converts a UI distance (eg from a form control) to kilometers,
    		 * accounting for the global units setting
    		 */
    		uiToKilometers: function(uiDistance)
    		{
    			return WPGMZA.Distance.uiToMeters(uiDistance) * 0.001;
    		},

    		/**
    		 * Converts a UI distance (eg from a form control) to miles,
    		 * accounting for the global units setting
    		 */
    		uiToMiles: function(uiDistance)
    		{
    			return WPGMZA.Distance.uiToKilometers(uiDistance) * WPGMZA.Distance.MILES_PER_KILOMETER;
    		},

    		kilometersToUI: function(km)
    		{
    			if(WPGMZA.settings.distance_units == WPGMZA.Distance.MILES)
    				return km * WPGMZA.Distance.MILES_PER_KILOMETER;
    			return km;
    		}

    	};

    })(jQuery);

    // js/v8/event-dispatcher.js
    /**
     * @namespace WPGMZA
     * @module EventDispatcher
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.EventDispatcher = function()
    	{
    		WPGMZA.assertInstanceOf(this, "EventDispatcher");

    		this._listenersByType = [];
    	}

    	WPGMZA.EventDispatcher.prototype.addEventListener = function(type, listener, thisObject, useCapture)
    	{
    		var arr;

    		var types = type.split(/\s+/);
    		if(types.length > 1)
    		{
    			for(var i = 0; i < types.length; i++)
    				this.addEventListener(types[i], listener, thisObject, useCapture);

    			return;
    		}

    		if(!(listener instanceof Function))
    			throw new Error("Listener must be a function");

    		if(!(arr = this._listenersByType[type]))
    			arr = this._listenersByType[type] = [];

    		var obj = {
    			listener: listener,
    			thisObject: (thisObject ? thisObject : this),
    			useCapture: (useCapture ? true : false)
    			};

    		arr.push(obj);
    	}

    	WPGMZA.EventDispatcher.prototype.on = WPGMZA.EventDispatcher.prototype.addEventListener;

    	WPGMZA.EventDispatcher.prototype.removeEventListener = function(type, listener, thisObject, useCapture)
    	{
    		var arr, index, obj;

    		if(!(arr = this._listenersByType[type]))
    			return;

    		if(!thisObject)
    			thisObject = this;

    		useCapture = (useCapture ? true : false);

    		for(var i = 0; i < arr.length; i++)
    		{
    			obj = arr[i];

    			if(obj.listener == listener && obj.thisObject == thisObject && obj.useCapture == useCapture)
    			{
    				arr.splice(i, 1);
    				return;
    			}
    		}
    	}

    	WPGMZA.EventDispatcher.prototype.off = WPGMZA.EventDispatcher.prototype.removeEventListener;

    	WPGMZA.EventDispatcher.prototype.hasEventListener = function(type)
    	{
    		return (_listenersByType[type] ? true : false);
    	}

    	WPGMZA.EventDispatcher.prototype.dispatchEvent = function(event)
    	{
    		if(!(event instanceof WPGMZA.Event))
    		{
    			if(typeof event == "string")
    				event = new WPGMZA.Event(event);
    			else
    			{
    				var src = event;
    				event = new WPGMZA.Event();
    				for(var name in src)
    					event[name] = src[name];
    			}
    		}

    		event.target = this;

    		var path = [];
    		for(var obj = this.parent; obj != null; obj = obj.parent)
    			path.unshift(obj);

    		event.phase = WPGMZA.Event.CAPTURING_PHASE;
    		for(var i = 0; i < path.length && !event._cancelled; i++)
    			path[i]._triggerListeners(event);

    		if(event._cancelled)
    			return;

    		event.phase = WPGMZA.Event.AT_TARGET;
    		this._triggerListeners(event);

    		event.phase = WPGMZA.Event.BUBBLING_PHASE;
    		for(i = path.length - 1; i >= 0 && !event._cancelled; i--)
    			path[i]._triggerListeners(event);
    	}

    	WPGMZA.EventDispatcher.prototype.trigger = WPGMZA.EventDispatcher.prototype.dispatchEvent;

    	WPGMZA.EventDispatcher.prototype._triggerListeners = function(event)
    	{
    		var arr, obj;

    		if(!(arr = this._listenersByType[event.type]))
    			return;

    		for(var i = 0; i < arr.length; i++)
    		{
    			obj = arr[i];

    			if(event.phase == WPGMZA.Event.CAPTURING_PHASE && !obj.useCapture)
    				continue;

    			obj.listener.call(arr[i].thisObject, event);
    		}
    	}

    	WPGMZA.events = new WPGMZA.EventDispatcher();

    })(jQuery);

    // js/v8/event.js
    /**
     * @namespace WPGMZA
     * @module Event
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.Event = function(options)
    	{
    		if(typeof options == "string")
    			this.type = options;

    		this.bubbles		= true;
    		this.cancelable		= true;
    		this.phase			= WPGMZA.Event.PHASE_CAPTURE;
    		this.target			= null;

    		this._cancelled = false;

    		if(typeof options == "object")
    			for(var name in options)
    				this[name] = options[name];
    	}

    	WPGMZA.Event.CAPTURING_PHASE		= 0;
    	WPGMZA.Event.AT_TARGET				= 1;
    	WPGMZA.Event.BUBBLING_PHASE			= 2;

    	WPGMZA.Event.prototype.stopPropagation = function()
    	{
    		this._cancelled = true;
    	}

    })(jQuery);

    // js/v8/friendly-error.js
    /**
     * @namespace WPGMZA
     * @module FriendlyError
     * @requires WPGMZA
     */
    (function($) {

    	/*var template = '\
    		<div class="notice notice-error"> \
    			<p> \
    			' + WPGMZA.localized_strings.friendly_error + ' \
    			</p> \
    			<pre style="white-space: pre-line;"></pre> \
    		<div> \
    		';

    	WPGMZA.FriendlyError = function(nativeError)
    	{
    		if(!WPGMZA.is_admin)
    		{
    			this.element = $(WPGMZA.preloaderHTML);
    			$(this.element).removeClass("animated");
    			return;
    		}

    		$("#wpgmza-map-edit-page>.wpgmza-preloader").remove();

    		this.element = $(template);
    		this.element.find("pre").html(nativeError.message + "\r\n" + nativeError.stack + "\r\n\r\n on " + window.location.href);
    	}*/

    })(jQuery);

    // js/v8/geocoder.js
    /**
     * @namespace WPGMZA
     * @module Geocoder
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.Geocoder = function()
    	{
    		WPGMZA.assertInstanceOf(this, "Geocoder");
    	}

    	WPGMZA.Geocoder.SUCCESS			= "success";
    	WPGMZA.Geocoder.ZERO_RESULTS	= "zero-results";
    	WPGMZA.Geocoder.FAIL			= "fail";

    	WPGMZA.Geocoder.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				return WPGMZA.GoogleGeocoder;
    				break;

    			default:
    				return WPGMZA.OLGeocoder;
    				break;
    		}
    	}

    	WPGMZA.Geocoder.createInstance = function()
    	{
    		var constructor = WPGMZA.Geocoder.getConstructor();
    		return new constructor();
    	}

    	WPGMZA.Geocoder.prototype.getLatLngFromAddress = function(options, callback)
    	{
    		if(WPGMZA.isLatLngString(options.address))
    		{
    			var parts = options.address.split(/,\s*/);
    			var latLng = {
    				lat: parseFloat(parts[0]),
    				lng: parseFloat(parts[1])
    			}
    			callback(latLng);
    		}
    	}

    	WPGMZA.Geocoder.prototype.geocode = function(options, callback)
    	{
    		return this.getLatLngFromAddress(options, callback);
    	}

    })(jQuery);

    // js/v8/info-window.js
    /**
     * @namespace WPGMZA
     * @module InfoWindow
     * @requires WPGMZA.EventDispatcher
     */
    (function($) {

    	WPGMZA.InfoWindow = function(mapObject)
    	{
    		var self = this;

    		WPGMZA.EventDispatcher.call(this);

    		WPGMZA.assertInstanceOf(this, "InfoWindow");

    		if(!mapObject)
    			return;

    		this.mapObject = mapObject;

    		if(mapObject.map)
    		{
    			// This has to be slightly delayed so the map initialization won't overwrite the infowindow element
    			setTimeout(function() {
    				self.onMapObjectAdded(event);
    			}, 100);
    		}
    		else
    			mapObject.addEventListener("added", function(event) {
    				self.onMapObjectAdded(event);
    			});
    	}

    	WPGMZA.InfoWindow.prototype = Object.create(WPGMZA.EventDispatcher.prototype);
    	WPGMZA.InfoWindow.prototype.constructor = WPGMZA.InfoWindow;

    	WPGMZA.InfoWindow.OPEN_BY_CLICK = 1;
    	WPGMZA.InfoWindow.OPEN_BY_HOVER = 2;

    	WPGMZA.InfoWindow.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				if(WPGMZA.isProVersion())
    					return WPGMZA.GoogleProInfoWindow;
    				return WPGMZA.GoogleInfoWindow;
    				break;

    			default:
    				if(WPGMZA.isProVersion())
    					return WPGMZA.OLProInfoWindow;
    				return WPGMZA.OLInfoWindow;
    				break;
    		}
    	}

    	WPGMZA.InfoWindow.createInstance = function(mapObject)
    	{
    		var constructor = this.getConstructor();
    		return new constructor(mapObject);
    	}

    	/**
    	 * Gets the content for the info window and passes it to the specified callback - this allows for delayed loading (eg AJAX) as well as instant content
    	 * @return void
    	 */
    	WPGMZA.InfoWindow.prototype.getContent = function(callback)
    	{
    		var html = "";

    		if(this.mapObject instanceof WPGMZA.Marker)
    			html = this.mapObject.address;

    		callback(html);
    	}

    	/**
    	 * Opens the info window
    	 * @return boolean FALSE if the info window should not & will not open, TRUE if it will
    	 */
    	WPGMZA.InfoWindow.prototype.open = function(map, mapObject)
    	{
    		var self = this;

    		this.mapObject = mapObject;

    		if(WPGMZA.settings.disable_infowindows)
    			return false;

    		return true;
    	}

    	WPGMZA.InfoWindow.prototype.close = function()
    	{

    	}

    	/**
    	 * Event listener for when the map object is added. This will cause the info window to open if the map object has infoopen set
    	 * @return void
    	 */
    	WPGMZA.InfoWindow.prototype.onMapObjectAdded = function()
    	{
    		if(this.mapObject.settings.infoopen == 1)
    			this.open();
    	}

    })(jQuery);

    // js/v8/latlng.js
    /**
     * @namespace WPGMZA
     * @module LatLng
     * @requires WPGMZA
     */
    (function($) {

    	/**
    	 * Constructor
    	 * @param mixed A latLng literal, or latitude
    	 * @param mixed The latitude, where arg is a longitude
    	 */
    	WPGMZA.LatLng = function(arg, lng)
    	{
    		this._lat = 0;
    		this._lng = 0;

    		if(arguments.length == 0)
    			return;

    		if(arguments.length == 1)
    		{
    			if(typeof arg != "object" || !("lat" in arg && "lng" in arg))
    				throw new Error("Argument must be a LatLng literal");

    			this.lat = arg.lat;
    			this.lng = arg.lng;
    		}
    		else
    		{
    			this.lat = arg;
    			this.lng = lng;
    		}
    	}

    	WPGMZA.LatLng.isValid = function(obj)
    	{
    		if(typeof obj != "object")
    			return false;

    		if(!("lat" in obj && "lng" in obj))
    			return false;

    		return true;
    	}

    	Object.defineProperty(WPGMZA.LatLng.prototype, "lat", {
    		get: function() {
    			return this._lat;
    		},
    		set: function(val) {
    			if(!$.isNumeric(val))
    				throw new Error("Latitude must be numeric");
    			this._lat = parseFloat( val );
    		}
    	});

    	Object.defineProperty(WPGMZA.LatLng.prototype, "lng", {
    		get: function() {
    			return this._lng;
    		},
    		set: function(val) {
    			if(!$.isNumeric(val))
    				throw new Error("Longitude must be numeric");
    			this._lng = parseFloat( val );
    		}
    	});

    	WPGMZA.LatLng.prototype.toString = function()
    	{
    		return this._lat + ", " + this._lng;
    	}

    	WPGMZA.LatLng.prototype.toGoogleLatLng = function()
    	{
    		return new google.maps.LatLng({
    			lat: this.lat,
    			lng: this.lng
    		});
    	}

    	/**
    	 * @function moveByDistance
    	 * @summary Moves this latLng by the specified kilometers along the given heading
    	 * @return void
    	 * With many thanks to Hu Kenneth - https://gis.stackexchange.com/questions/234473/get-a-lonlat-point-by-distance-or-between-2-lonlat-points
    	 */
    	WPGMZA.LatLng.prototype.moveByDistance = function(kilometers, heading)
    	{
    		var radius 		= 6371;

    		var delta 		= parseFloat(kilometers) / radius;
    		var theta 		= parseFloat(heading) / 180 * Math.PI;

    		var phi1 		= this.lat / 180 * Math.PI;
    		var lambda1 	= this.lng / 180 * Math.PI;

    		var sinPhi1 	= Math.sin(phi1), cosPhi1 = Math.cos(phi1);
    		var sinDelta	= Math.sin(delta), cosDelta = Math.cos(delta);
    		var sinTheta	= Math.sin(theta), cosTheta = Math.cos(theta);

    		var sinPhi2		= sinPhi1 * cosDelta + cosPhi1 * sinDelta * cosTheta;
    		var phi2		= Math.asin(sinPhi2);
    		var y			= sinTheta * sinDelta * cosPhi1;
    		var x			= cosDelta - sinPhi1 * sinPhi2;
    		var lambda2		= lambda1 + Math.atan2(y, x);

    		this.lat		= phi2 * 180 / Math.PI;
    		this.lng		= lambda2 * 180 / Math.PI;
    	}

    })(jQuery);

    // js/v8/latlngbounds.js
    /**
     * @namespace WPGMZA
     * @module LatLngBounds
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.LatLngBounds = function(southWest, northEast)
    	{

    	}

    	WPGMZA.LatLngBounds.prototype.isInInitialState = function()
    	{
    		return (this.north == undefined && this.south == undefined && this.west == undefined && this.east == undefined);
    	}

    	WPGMZA.LatLngBounds.prototype.extend = function(latLng)
    	{
    		if(this.isInInitialState())
    		{
    			this.north = this.south = this.west = this.east = new WPGMZA.LatLng(latLng);
    			return;
    		}

    		if(!(latLng instanceof WPGMZA.LatLng))
    			latLng = new WPGMZA.LatLng(latLng);

    		if(latLng.lat < this.north)
    			this.north = latLng.lat;

    		if(latLng.lat > this.south)
    			this.south = latLng.lat;

    		if(latLng.lng < this.west)
    			this.west = latLng.lng;

    		if(latLng.lng > this.east)
    			this.east = latLng.lng;
    	}

    })(jQuery);

    // js/v8/map-object.js
    /**
     * @namespace WPGMZA
     * @module MapObject
     * @requires WPGMZA.EventDispatcher
     */
    (function($) {

    	WPGMZA.MapObject = function(row)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "MapObject");

    		WPGMZA.EventDispatcher.call(this);

    		this.id = -1;
    		this.guid = WPGMZA.guid();
    		this.modified = true;
    		this.settings = {};

    		if(row)
    		{
    			for(var name in row)
    			{
    				if(name == "settings")
    				{
    					if(row["settings"] == null)
    						this["settings"] = {};
    					else switch(typeof row["settings"]) {
    						case "string":
    							this["settings"] = JSON.parse(row[name]);
    							break;
    						case "object":
    							this["settings"] = row[name];
    							break;
    						default:
    							throw new Error("Don't know how to interpret settings")
    							break;
    					}

    					for(var name in this.settings)
    					{
    						var value = this.settings[name];
    						if(String(value).match(/^-?\d+$/))
    							this.settings[name] = parseInt(value);
    					}
    				}
    				else
    					this[name] = row[name];
    			}
    		}
    	}

    	WPGMZA.MapObject.prototype = Object.create(WPGMZA.EventDispatcher.prototype);
    	WPGMZA.MapObject.prototype.constructor = WPGMZA.MapObject;

    	WPGMZA.MapObject.prototype.parseGeometry = function(string)
    	{
    		var stripped, pairs, coords, results = [];
    		stripped = string.replace(/[^ ,\d\.\-+e]/g, "");
    		pairs = stripped.split(",");

    		for(var i = 0; i < pairs.length; i++)
    		{
    			coords = pairs[i].split(" ");
    			results.push({
    				lat: parseFloat(coords[1]),
    				lng: parseFloat(coords[0])
    			});
    		}

    		return results;
    	}

    	WPGMZA.MapObject.prototype.toJSON = function()
    	{
    		return {
    			id: this.id,
    			guid: this.guid,
    			settings: this.settings
    		};
    	}

    })(jQuery);

    // js/v8/circle.js
    /**
     * @namespace WPGMZA
     * @module Circle
     * @requires WPGMZA.MapObject
     */
    (function($) {

    	var Parent = WPGMZA.MapObject;

    	/**
    	 * @class Circle
    	 * @summary Represents a generic circle. <b>Please do not instantiate this object directly, use createInstance</b>
    	 * @return {WPGMZA.Circle}
    	 */
    	WPGMZA.Circle = function(options, engineCircle)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "Circle");

    		this.center = new WPGMZA.LatLng();
    		this.radius = 100;

    		Parent.apply(this, arguments);
    	}

    	WPGMZA.Circle.prototype = Object.create(Parent.prototype);
    	WPGMZA.Circle.prototype.constructor = WPGMZA.Circle;

    	/**
    	 * @function createInstance
    	 * @summary Creates an instance of a circle, <b>please always use this function rather than calling the constructor directly</b>
    	 * @param {object} options Options for the object (optional)
    	 */
    	WPGMZA.Circle.createInstance = function(options)
    	{
    		var constructor;

    		if(WPGMZA.settings.engine == "google-maps")
    			constructor = WPGMZA.GoogleCircle;
    		else
    			constructor = WPGMZA.OLCircle;

    		return new constructor(options);
    	}

    	/**
    	 * @function getCenter
    	 * @returns {WPGMZA.LatLng}
    	 */
    	WPGMZA.Circle.prototype.getCenter = function()
    	{
    		return this.center.clone();
    	}

    	/**
    	 * @function setCenter
    	 * @param {object|WPGMZA.LatLng} latLng either a literal or as a WPGMZA.LatLng
    	 * @returns {void}
    	 */
    	WPGMZA.Circle.prototype.setCenter = function(latLng)
    	{
    		this.center.lat = latLng.lat;
    		this.center.lng = latLng.lng;
    	}

    	/**
    	 * @function getRadius
    	 * @summary Returns the circles radius in kilometers
    	 * @returns {WPGMZA.LatLng}
    	 */
    	WPGMZA.Circle.prototype.getRadius = function()
    	{
    		return this.radius;
    	}

    	/**
    	 * @function setRadius
    	 * @param {number} The radius
    	 * @returns {void}
    	 */
    	WPGMZA.Circle.prototype.setRadius = function(radius)
    	{
    		this.radius = radius;
    	}

    	/**
    	 * @function getMap
    	 * @summary Returns the map that this circle is being displayed on
    	 * @return {WPGMZA.Map}
    	 */
    	WPGMZA.Circle.prototype.getMap = function()
    	{
    		return this.map;
    	}

    	/**
    	 * @function setMap
    	 * @param {WPGMZA.Map} The target map
    	 * @summary Puts this circle on a map
    	 * @return {void}
    	 */
    	WPGMZA.Circle.prototype.setMap = function(map)
    	{
    		if(this.map)
    			this.map.removeCircle(this);

    		if(map)
    			map.addCircle(this);

    	}

    })(jQuery);

    // js/v8/map-settings.js
    /**
     * @namespace WPGMZA
     * @module MapSettings
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.MapSettings = function(element)
    	{
    		var str = element.getAttribute("data-settings");
    		var json = JSON.parse(str);

    		//var id = $(element).attr("data-map-id");
    		//var json = JSON.parse(window["wpgmza_map_settings_" + id]);

    		WPGMZA.assertInstanceOf(this, "MapSettings");

    		for(var key in json)
    		{
    			var value = json[key];

    			if(String(value).match(/^-?\d+$/))
    				value = parseInt(value);

    			this[key] = value;
    		}
    	}

    	WPGMZA.MapSettings.prototype.toOLViewOptions = function()
    	{
    		var options = {
    			center: ol.proj.fromLonLat([-119.4179, 36.7783]),
    			zoom: 4
    		};

    		function empty(name)
    		{
    			if(typeof self[name] == "object")
    				return false;

    			return !self[name] || !self[name].length;
    		}

    		// Start location
    		if(typeof this.start_location == "string")
    		{
    			var coords = this.start_location.replace(/^\(|\)$/g, "").split(",");
    			if(WPGMZA.isLatLngString(this.start_location))
    				options.center = ol.proj.fromLonLat([
    					parseFloat(coords[1]),
    					parseFloat(coords[0])
    				]);
    			else
    				console.warn("Invalid start location");
    		}

    		if(this.center)
    		{
    			options.center = ol.proj.fromLonLat([
    				parseFloat(this.center.lng),
    				parseFloat(this.center.lat)
    			]);
    		}

    		// Start zoom
    		if(this.zoom)
    			options.zoom = parseInt(this.zoom);

    		if(this.start_zoom)
    			options.zoom = parseInt(this.start_zoom);

    		// Zoom limits
    		// TODO: This matches the Google code, so some of these could be potentially put on a parent class
    		if(!empty("min_zoom"))
    			options.minZoom = parseInt(this.min_zoom);
    		if(!empty("max_zoom"))
    			options.maxZoom = parseInt(this.max_zoom);

    		return options;
    	}

    	WPGMZA.MapSettings.prototype.toGoogleMapsOptions = function()
    	{
    		var self = this;
    		var latLngCoords = (this.start_location && this.start_location.length ? this.start_location.split(",") : [36.7783, -119.4179]);

    		function empty(name)
    		{
    			if(typeof self[name] == "object")
    				return false;

    			return !self[name] || !self[name].length;
    		}

    		function formatCoord(coord)
    		{
    			if($.isNumeric(coord))
    				return coord;
    			return parseFloat( String(coord).replace(/[\(\)\s]/, "") );
    		}

    		var latLng = new google.maps.LatLng(
    			formatCoord(latLngCoords[0]),
    			formatCoord(latLngCoords[1])
    		);

    		var zoom = (this.start_zoom ? parseInt(this.start_zoom) : 4);

    		if(!this.start_zoom && this.zoom)
    			zoom = parseInt( this.zoom );

    		var options = {
    			zoom:			zoom,
    			center:			latLng
    		};

    		if(!empty("center"))
    			options.center = new google.maps.LatLng({
    				lat: parseFloat(this.center.lat),
    				lng: parseFloat(this.center.lng)
    			});

    		if(!empty("min_zoom"))
    			options.minZoom = parseInt(this.min_zoom);
    		if(!empty("max_zoom"))
    			options.maxZoom = parseInt(this.max_zoom);

    		// These settings are all inverted because the checkbox being set means "disabled"
    		options.zoomControl 			= !(this.map_zoom == true);
    		options.panControl 				= !(this.map_pan == true);
    		options.mapTypeControl			= !(this.disable_map_type_controls == true);
    		options.streetViewControl		= !(this.map_streetview == true);
    		options.fullscreenControl		= !(this.map_full_screen_control == true);

    		options.draggable				= !(this.map_draggable == true);
    		options.disableDoubleClickZoom	= !(this.map_clickzoom == true);
    		options.scrollwheel				= !(this.map_scroll == true);

    		if(this.force_greedy_gestures)
    			options.gestureHandling = "greedy";

    		switch(parseInt(this.map_type))
    		{
    			case 2:
    				options.mapTypeId = google.maps.MapTypeId.SATELLITE;
    				break;

    			case 3:
    				options.mapTypeId = google.maps.MapTypeId.HYBRID;
    				break;

    			case 4:
    				options.mapTypeId = google.maps.MapTypeId.TERRAIN;
    				break;

    			default:
    				options.mapTypeId = google.maps.MapTypeId.ROADMAP;
    				break;
    		}

    		if(this.theme_data && this.theme_data.length > 0)
    		{
    			try{
    				options.styles = JSON.parse(this.theme_data);
    			}catch(e) {
    				alert("Your theme data is not valid JSON and has been ignored");
    			}
    		}

    		return options;
    	}
    })(jQuery);

    // js/v8/map.js
    /**
     * @namespace WPGMZA
     * @module Map
     * @requires WPGMZA.EventDispatcher
     */
    (function($) {

    	/**
    	 * Constructor
    	 * @param element to contain map
    	 */
    	WPGMZA.Map = function(element, options)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "Map");

    		WPGMZA.EventDispatcher.call(this);

    		if(!(element instanceof HTMLElement))
    			throw new Error("Argument must be a HTMLElement");

    		this.id = element.getAttribute("data-map-id");
    		if(!/\d+/.test(this.id))
    			throw new Error("Map ID must be an integer");

    		WPGMZA.maps.push(this);
    		this.element = element;
    		this.element.wpgmzaMap = this;

    		this.engineElement = element;

    		this.markers = [];
    		this.polygons = [];
    		this.polylines = [];
    		this.circles = [];

    		this.loadSettings();
    	}

    	WPGMZA.Map.prototype = Object.create(WPGMZA.EventDispatcher.prototype);
    	WPGMZA.Map.prototype.constructor = WPGMZA.Map;

    	WPGMZA.Map.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				if(WPGMZA.isProVersion())
    					return WPGMZA.GoogleProMap;

    				return WPGMZA.GoogleMap;
    				break;

    			default:
    				if(WPGMZA.isProVersion())
    					return WPGMZA.OLProMap;

    				return WPGMZA.OLMap;
    				break;
    		}
    	}

    	WPGMZA.Map.createInstance = function(element, options)
    	{
    		var constructor = WPGMZA.Map.getConstructor();
    		return new constructor(element, options);
    	}

    	/**
    	 * Loads the maps settings and sets some defaults
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.loadSettings = function()
    	{
    		var settings = new WPGMZA.MapSettings(this.element);
    		this.settings = $.extend({}, WPGMZA.settings, settings);
    	}

    	/**
    	 * Sets options in bulk on map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.setOptions = function(options)
    	{
    		for(var name in options)
    			this.settings[name] = options[name];
    	}

    	/**
    	 * Gets the distance between two latLngs in kilometers
    	 * NB: Static function
    	 * @return number
    	 */
    	var earthRadiusMeters = 6371;
    	var piTimes360 = Math.PI / 360;

    	function deg2rad(deg) {
    	  return deg * (Math.PI/180)
    	};

    	/**
    	 * This gets the distance in kilometers between two latitude / longitude points
    	 * TODO: Move this to the distance class, or the LatLng class
    	 * @return void
    	 */
    	WPGMZA.Map.getGeographicDistance = function(lat1, lon1, lat2, lon2)
    	{
    		var dLat = deg2rad(lat2-lat1);
    		var dLon = deg2rad(lon2-lon1);

    		var a =
    			Math.sin(dLat/2) * Math.sin(dLat/2) +
    			Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
    			Math.sin(dLon/2) * Math.sin(dLon/2);

    		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    		var d = earthRadiusMeters * c; // Distance in km

    		return d;
    	}

    	WPGMZA.Map.prototype.setCenter = function(latLng)
    	{
    		if(!("lat" in latLng && "lng" in latLng))
    			throw new Error("Argument is not an object with lat and lng");
    	}

    	/**
    	 * Sets the dimensions of the map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.setDimensions = function(width, height)
    	{
    		$(this.element).css({
    			width: width
    		});

    		$(this.engineElement).css({
    			width: "100%",
    			height: height
    		});
    	}

    	/**
    	 * Adds the specified marker to this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.addMarker = function(marker)
    	{
    		if(!(marker instanceof WPGMZA.Marker))
    			throw new Error("Argument must be an instance of WPGMZA.Marker");

    		marker.map = this;
    		marker.parent = this;

    		this.markers.push(marker);
    		this.dispatchEvent({type: "markeradded", marker: marker});
    		marker.dispatchEvent({type: "added"});
    	}

    	/**
    	 * Removes the specified marker from this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.removeMarker = function(marker)
    	{
    		if(!(marker instanceof WPGMZA.Marker))
    			throw new Error("Argument must be an instance of WPGMZA.Marker");

    		if(marker.map !== this)
    			throw new Error("Wrong map error");

    		marker.map = null;
    		marker.parent = null;

    		this.markers.splice(this.markers.indexOf(marker), 1);
    		this.dispatchEvent({type: "markerremoved", marker: marker});
    		marker.dispatchEvent({type: "removed"});
    	}

    	WPGMZA.Map.prototype.getMarkerByID = function(id)
    	{
    		for(var i = 0; i < this.markers.length; i++)
    		{
    			if(this.markers[i].id == id)
    				return this.markers[i];
    		}

    		return null;
    	}

    	WPGMZA.Map.prototype.removeMarkerByID = function(id)
    	{
    		var marker = this.getMarkerByID(id);

    		if(!marker)
    			return;

    		this.removeMarker(marker);
    	}

    	/**
    	 * Adds the specified polygon to this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.addPolygon = function(polygon)
    	{
    		if(!(polygon instanceof WPGMZA.Polygon))
    			throw new Error("Argument must be an instance of WPGMZA.Polygon");

    		polygon.map = this;

    		this.polygons.push(polygon);
    		this.dispatchEvent({type: "polygonadded", polygon: polygon});
    	}

    	/**
    	 * Removes the specified polygon from this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.deletePolygon = function(polygon)
    	{
    		if(!(polygon instanceof WPGMZA.Polygon))
    			throw new Error("Argument must be an instance of WPGMZA.Polygon");

    		if(polygon.map !== this)
    			throw new Error("Wrong map error");

    		polygon.map = null;

    		this.polygons.splice(this.polygons.indexOf(polygon), 1);
    		this.dispatchEvent({type: "polygonremoved", polygon: polygon});
    	}

    	WPGMZA.Map.prototype.getPolygonByID = function(id)
    	{
    		for(var i = 0; i < this.polygons.length; i++)
    		{
    			if(this.polygons[i].id == id)
    				return this.polygons[i];
    		}

    		return null;
    	}

    	WPGMZA.Map.prototype.deletePolygonByID = function(id)
    	{
    		var polygon = this.getPolygonByID(id);

    		if(!polygon)
    			return;

    		this.deletePolygon(polygon);
    	}

    	/**
    	 * Gets a polyline by ID
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.getPolylineByID = function(id)
    	{
    		for(var i = 0; i < this.polylines.length; i++)
    		{
    			if(this.polylines[i].id == id)
    				return this.polylines[i];
    		}

    		return null;
    	}

    	/**
    	 * Adds the specified polyline to this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.addPolyline = function(polyline)
    	{
    		if(!(polyline instanceof WPGMZA.Polyline))
    			throw new Error("Argument must be an instance of WPGMZA.Polyline");

    		polyline.map = this;

    		this.polylines.push(polyline);
    		this.dispatchEvent({type: "polylineadded", polyline: polyline});
    	}

    	/**
    	 * Removes the specified polyline from this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.deletePolyline = function(polyline)
    	{
    		if(!(polyline instanceof WPGMZA.Polyline))
    			throw new Error("Argument must be an instance of WPGMZA.Polyline");

    		if(polyline.map !== this)
    			throw new Error("Wrong map error");

    		polyline.map = null;

    		this.polylines.splice(this.polylines.indexOf(polyline), 1);
    		this.dispatchEvent({type: "polylineremoved", polyline: polyline});
    	}

    	WPGMZA.Map.prototype.getPolylineByID = function(id)
    	{
    		for(var i = 0; i < this.polylines.length; i++)
    		{
    			if(this.polylines[i].id == id)
    				return this.polylines[i];
    		}

    		return null;
    	}

    	WPGMZA.Map.prototype.deletePolylineByID = function(id)
    	{
    		var polyline = this.getPolylineByID(id);

    		if(!polyline)
    			return;

    		this.deletePolyline(polyline);
    	}

    	/**
    	 * Adds the specified circle to this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.addCircle = function(circle)
    	{
    		if(!(circle instanceof WPGMZA.Circle))
    			throw new Error("Argument must be an instance of WPGMZA.Circle");

    		circle.map = this;

    		this.circles.push(circle);
    		this.dispatchEvent({type: "circleadded", circle: circle});
    	}

    	/**
    	 * Removes the specified circle from this map
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.removeCircle = function(circle)
    	{
    		if(!(circle instanceof WPGMZA.Circle))
    			throw new Error("Argument must be an instance of WPGMZA.Circle");

    		if(circle.map !== this)
    			throw new Error("Wrong map error");

    		circle.map = null;

    		this.circles.splice(this.circles.indexOf(circle), 1);
    		this.dispatchEvent({type: "circleremoved", circle: circle});
    	}

    	WPGMZA.Map.prototype.getCircleByID = function(id)
    	{
    		for(var i = 0; i < this.circles.length; i++)
    		{
    			if(this.circles[i].id == id)
    				return this.circles[i];
    		}

    		return null;
    	}

    	WPGMZA.Map.prototype.deleteCircleByID = function(id)
    	{
    		var circle = this.getCircleByID(id);

    		if(!circle)
    			return;

    		this.deleteCircle(circle);
    	}

    	/**
    	 * Nudges the map viewport by the given pixel coordinates
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.nudge = function(x, y)
    	{
    		var pixels = this.latLngToPixels(this.getCenter());

    		pixels.x += parseFloat(x);
    		pixels.y += parseFloat(y);

    		if(isNaN(pixels.x) || isNaN(pixels.y))
    			throw new Error("Invalid coordinates supplied");

    		var latLng = this.pixelsToLatLng(pixels);

    		this.setCenter(latLng);
    	}

    	/**
    	 * Triggered when the window resizes
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.onWindowResize = function(event)
    	{

    	}

    	/**
    	 * Listener for when the engine map div is resized
    	 * @return void
    	 */
    	WPGMZA.Map.prototype.onElementResized = function(event)
    	{

    	}

    	WPGMZA.Map.prototype.onBoundsChanged = function(event)
    	{
    		// Native events
    		this.trigger("boundschanged");
    		$(this.element).trigger("boundschanged.wpgmza");

    		// Google / legacy compatibility events
    		this.trigger("bounds_changed");
    		$(this.element).trigger("bounds_changed");
    	}

    	WPGMZA.Map.prototype.onIdle = function(event)
    	{
    		$(this.element).trigger("idle");
    		$(this.element).trigger("idle.wpgmza");
    	}

    	/*$(document).ready(function() {
    		function createMaps()
    		{
    			// TODO: Test that this works for maps off screen (which borks google)
    			$(".wpgmza-map").each(function(index, el) {
    				if(!el.wpgmzaMap)
    				{
    					WPGMZA.runCatchableTask(function() {
    						WPGMZA.Map.createInstance(el);
    					}, el);
    				}
    			});
    		}

    		createMaps();

    		// Call again each second to load AJAX maps
    		setInterval(createMaps, 1000);
    	});*/
    })(jQuery);

    // js/v8/maps-engine-dialog.js
    /**
     * @namespace WPGMZA
     * @module MapsEngineDialog
     * @requires WPGMZA
     */
    (function($) {

    	WPGMZA.MapsEngineDialog = function(element)
    	{
    		var self = this;

    		this.element = element;

    		$(element).show();
    		$(element).remodal().open();

    		$("[data-maps-engine]").on("click", function(event) {

    			self.onButtonClicked(event);

    		});
    	}

    	WPGMZA.MapsEngineDialog.prototype.onButtonClicked = function(event)
    	{
    		$(event.target).prop("disabled", true);

    		$.ajax(WPGMZA.ajaxurl, {
    			method: "POST",
    			data: {
    				action: "wpgmza_maps_engine_dialog_set_engine",
    				engine: $(event.target).attr("data-maps-engine")
    			},
    			success: function(response, status, xhr) {
    				window.location.reload();
    			}
    		});
    	}

    	$(window).on("load", function(event) {

    		var element = $("#wpgmza-maps-engine-dialog");

    		if(!element.length)
    			return;

    		if(WPGMZA.settings.wpgmza_maps_engine_dialog_done)
    			return;

    		WPGMZA.mapsEngineDialog = new WPGMZA.MapsEngineDialog(element);

    	});

    })(jQuery);

    // js/v8/marker.js
    /**
     * @namespace WPGMZA
     * @module Marker
     * @requires WPGMZA
     */
    (function($) {
    	/**
    	 * Constructor
    	 * @param json to load (optional)
    	 */
    	WPGMZA.Marker = function(row)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "Marker");

    		this.lat = "36.778261";
    		this.lng = "-119.4179323999";
    		this.address = "California";
    		this.title = null;
    		this.description = "";
    		this.link = "";
    		this.icon = "";
    		this.approved = 1;
    		this.pic = null;

    		WPGMZA.MapObject.apply(this, arguments);

    		if(row && row.heatmap)
    			return; // Don't listen for these events on heatmap markers.

    		this.on("init", function(event) {
    			if(row.position)
    				this.setPosition(row.position);

    			if(row.map)
    				row.map.addMarker(this);
    		});

    		this.addEventListener("added", function(event) {
    			self.onAdded(event);
    		});
    	}

    	WPGMZA.Marker.prototype = Object.create(WPGMZA.MapObject.prototype);
    	WPGMZA.Marker.prototype.constructor = WPGMZA.Marker;

    	/**
    	 * Gets the constructor. You can use this instead of hard coding the parent class when inheriting,
    	 * which is helpful for making subclasses that work with Basic only, Pro, Google, OL or a
    	 * combination of the four.
    	 * @return function
    	 */
    	WPGMZA.Marker.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				if(WPGMZA.isProVersion())
    					return WPGMZA.GoogleProMarker;
    				return WPGMZA.GoogleMarker;
    				break;

    			default:
    				if(WPGMZA.isProVersion())
    					return WPGMZA.OLProMarker;
    				return WPGMZA.OLMarker;
    				break;
    		}
    	}

    	WPGMZA.Marker.createInstance = function(row)
    	{
    		var constructor = WPGMZA.Marker.getConstructor();
    		return new constructor(row);
    	}

    	WPGMZA.Marker.ANIMATION_NONE			= "0";
    	WPGMZA.Marker.ANIMATION_BOUNCE			= "1";
    	WPGMZA.Marker.ANIMATION_DROP			= "2";

    	WPGMZA.Marker.prototype.onAdded = function(event)
    	{
    		var self = this;

    		this.infoWindow = WPGMZA.InfoWindow.createInstance(this);

    		this.addEventListener("click", function(event) {
    			self.onClick(event);
    		});

    		this.addEventListener("mouseover", function(event) {
    			self.onMouseOver(event);
    		});

    		this.addEventListener("select", function(event) {
    			self.onSelect(event);
    		});

    		if(this.map.settings.marker == this.id)
    			self.trigger("select");
    	}

    	/**
    	 * This function will hide the last info the user interacted with
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.hidePreviousInteractedInfoWindow = function()
    	{
    		if(!this.map.lastInteractedMarker)
    			return;

    		this.map.lastInteractedMarker.infoWindow.close();
    	}

    	WPGMZA.Marker.prototype.openInfoWindow = function()
    	{
    		this.hidePreviousInteractedInfoWindow();

    		this.infoWindow.open(this.map, this);
    		this.map.lastInteractedMarker = this;
    	}

    	WPGMZA.Marker.prototype.onClick = function(event)
    	{

    	}

    	WPGMZA.Marker.prototype.onSelect = function(event)
    	{
    		this.openInfoWindow();
    	}

    	WPGMZA.Marker.prototype.onMouseOver = function(event)
    	{
    		if(this.map.settings.info_window_open_by == WPGMZA.InfoWindow.OPEN_BY_HOVER)
    			this.openInfoWindow();
    	}

    	WPGMZA.Marker.prototype.getIcon = function()
    	{
    		return WPGMZA.settings.default_marker_icon;
    	}

    	/**
    	 * Gets the position of the marker
    	 * @return object
    	 */
    	WPGMZA.Marker.prototype.getPosition = function()
    	{
    		return {
    			lat: parseFloat(this.lat),
    			lng: parseFloat(this.lng)
    		};
    	}

    	/**
    	 * Sets the position of the marker
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.setPosition = function(latLng)
    	{
    		if(latLng instanceof WPGMZA.LatLng)
    		{
    			this.lat = latLng.lat;
    			this.lng = latLng.lng;
    		}
    		else
    		{
    			this.lat = parseFloat(latLng.lat);
    			this.lng = parseFloat(latLng.lng);
    		}
    	}

    	/**
    	 * Set the marker animation
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.getAnimation = function(animation)
    	{
    		return this.settings.animation;
    	}

    	/**
    	 * Set the marker animation
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.setAnimation = function(animation)
    	{
    		this.settings.animation = animation;
    	}

    	/**
    	 * Get the marker visibility
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.getVisible = function(visible)
    	{

    	}

    	/**
    	 * Set the marker visibility. This is used by the store locator etc. and is not a setting
    	 * @return void
    	 */
    	WPGMZA.Marker.prototype.setVisible = function(visible)
    	{
    		if(!visible && this.infoWindow)
    			this.infoWindow.close();
    	}

    	WPGMZA.Marker.prototype.setMap = function(map)
    	{
    		if(!map)
    		{
    			if(this.map)
    				this.map.removeMarker(this);

    			return;
    		}

    		map.addMarker(this);
    	}

    	WPGMZA.Marker.prototype.getDraggable = function()
    	{

    	}

    	WPGMZA.Marker.prototype.setDraggable = function(draggable)
    	{

    	}

    	WPGMZA.Marker.prototype.panIntoView = function()
    	{
    		if(!this.map)
    			throw new Error("Marker hasn't been added to a map");

    		this.map.setCenter(this.getPosition());
    	}

    	/**
    	 * Returns the marker as a JSON object
    	 * @return object
    	 */
    	WPGMZA.Marker.prototype.toJSON = function()
    	{
    		var result = WPGMZA.MapObject.prototype.toJSON.call(this);
    		var position = this.getPosition();

    		$.extend(result, {
    			lat: position.lat,
    			lng: position.lng,
    			address: this.address,
    			title: this.title,
    			description: this.description,
    			link: this.link,
    			icon: this.icon,
    			pic: this.pic,
    			approved: this.approved
    		});

    		return result;
    	}

    })(jQuery);

    // js/v8/modern-store-locator-circle.js
    /**
     * @namespace WPGMZA
     * @module ModernStoreLocatorCircle
     * @requires WPGMZA
     */
    (function($) {

    	/**
    	 * This module is the modern store locator circle
    	 * @constructor
    	 */
    	WPGMZA.ModernStoreLocatorCircle = function(map_id, settings) {
    		var self = this;
    		var map;

    		if(WPGMZA.isProVersion())
    			map = this.map = MYMAP[map_id].map;
    		else
    			map = this.map = MYMAP.map;

    		this.map_id = map_id;
    		this.mapElement = map.element;
    		this.mapSize = {
    			width:  $(this.mapElement).width(),
    			height: $(this.mapElement).height()
    		};

    		this.initCanvasLayer();

    		this.settings = {
    			center: new WPGMZA.LatLng(0, 0),
    			radius: 1,
    			color: "#63AFF2",

    			shadowColor: "white",
    			shadowBlur: 4,

    			centerRingRadius: 10,
    			centerRingLineWidth: 3,

    			numInnerRings: 9,
    			innerRingLineWidth: 1,
    			innerRingFade: true,

    			numOuterRings: 7,

    			ringLineWidth: 1,

    			mainRingLineWidth: 2,

    			numSpokes: 6,
    			spokesStartAngle: Math.PI / 2,

    			numRadiusLabels: 6,
    			radiusLabelsStartAngle: Math.PI / 2,
    			radiusLabelFont: "13px sans-serif",

    			visible: false
    		};

    		if(settings)
    			this.setOptions(settings);
    	};

    	WPGMZA.ModernStoreLocatorCircle.createInstance = function(map, settings) {

    		if(WPGMZA.settings.engine == "google-maps")
    			return new WPGMZA.GoogleModernStoreLocatorCircle(map, settings);
    		else
    			return new WPGMZA.OLModernStoreLocatorCircle(map, settings);

    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.initCanvasLayer = function() {

    	}

    	WPGMZA.ModernStoreLocatorCircle.prototype.onResize = function(event) {
    		this.draw();
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.onUpdate = function(event) {
    		this.draw();
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.setOptions = function(options) {
    		for(var name in options)
    		{
    			var functionName = "set" + name.substr(0, 1).toUpperCase() + name.substr(1);

    			if(typeof this[functionName] == "function")
    				this[functionName](options[name]);
    			else
    				this.settings[name] = options[name];
    		}
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.getResolutionScale = function() {
    		return window.devicePixelRatio || 1;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.getCenter = function() {
    		return this.getPosition();
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.setCenter = function(value) {
    		this.setPosition(value);
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.getPosition = function() {
    		return this.settings.center;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.setPosition = function(position) {
    		this.settings.center = position;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.getRadius = function() {
    		return this.settings.radius;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.setRadius = function(radius) {

    		if(isNaN(radius))
    			throw new Error("Invalid radius");

    		this.settings.radius = radius;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.getVisible = function(visible) {
    		return this.settings.visible;
    	};

    	WPGMZA.ModernStoreLocatorCircle.prototype.setVisible = function(visible) {
    		this.settings.visible = visible;
    	};

    	/**
    	 * This function transforms a km radius into canvas space
    	 * @return number
    	 */
    	WPGMZA.ModernStoreLocatorCircle.prototype.getTransformedRadius = function(km)
    	{
    		throw new Error("Abstract function called");
    	}

    	WPGMZA.ModernStoreLocatorCircle.prototype.getContext = function(type)
    	{
    		throw new Error("Abstract function called");
    	}

    	WPGMZA.ModernStoreLocatorCircle.prototype.getCanvasDimensions = function()
    	{
    		throw new Error("Abstract function called");
    	}

    	WPGMZA.ModernStoreLocatorCircle.prototype.draw = function() {

    		var settings = this.settings;
    		var canvasDimensions = this.getCanvasDimensions();

            var canvasWidth = canvasDimensions.width;
            var canvasHeight = canvasDimensions.height;

    		var map = this.map;
    		var resolutionScale = this.getResolutionScale();

    		context = this.getContext("2d");
            context.clearRect(0, 0, canvasWidth, canvasHeight);

    		if(!settings.visible)
    			return;

    		context.shadowColor = settings.shadowColor;
    		context.shadowBlur = settings.shadowBlur;

    		// NB: 2018/02/13 - Left this here in case it needs to be calibrated more accurately
    		/*if(!this.testCircle)
    		{
    			this.testCircle = new google.maps.Circle({
    				strokeColor: "#ff0000",
    				strokeOpacity: 0.5,
    				strokeWeight: 3,
    				map: this.map,
    				center: this.settings.center
    			});
    		}

    		this.testCircle.setCenter(settings.center);
    		this.testCircle.setRadius(settings.radius * 1000);*/

            // Reset transform
            context.setTransform(1, 0, 0, 1, 0, 0);

            var scale = Math.pow(2, map.getZoom()) * resolutionScale;
            context.scale(scale, scale);

    		// Translate by world origin
    		var offset = this.getWorldOriginOffset();
    		context.translate(offset.x, offset.y);

            // Get center and project to pixel space
    		var center = new WPGMZA.LatLng(this.settings.center);
    		var worldPoint = this.getCenterPixels();

    		var rgba = WPGMZA.hexToRgba(settings.color);
    		var ringSpacing = this.getTransformedRadius(settings.radius) / (settings.numInnerRings + 1);

    		// TODO: Implement gradients for color and opacity

    		// Inside circle (fixed?)
            context.strokeStyle = settings.color;
    		context.lineWidth = (1 / scale) * settings.centerRingLineWidth;

    		context.beginPath();
    		context.arc(
    			worldPoint.x,
    			worldPoint.y,
    			this.getTransformedRadius(settings.centerRingRadius) / scale, 0, 2 * Math.PI
    		);
    		context.stroke();
    		context.closePath();

    		// Spokes
    		var radius = this.getTransformedRadius(settings.radius) + (ringSpacing * settings.numOuterRings) + 1;
    		var grad = context.createRadialGradient(0, 0, 0, 0, 0, radius);
    		var rgba = WPGMZA.hexToRgba(settings.color);
    		var start = WPGMZA.rgbaToString(rgba), end;
    		var spokeAngle;

    		rgba.a = 0;
    		end = WPGMZA.rgbaToString(rgba);

    		grad.addColorStop(0, start);
    		grad.addColorStop(1, end);

    		context.save();

    		context.translate(worldPoint.x, worldPoint.y);
    		context.strokeStyle = grad;
    		context.lineWidth = 2 / scale;

    		for(var i = 0; i < settings.numSpokes; i++)
    		{
    			spokeAngle = settings.spokesStartAngle + (Math.PI * 2) * (i / settings.numSpokes);

    			x = Math.cos(spokeAngle) * radius;
    			y = Math.sin(spokeAngle) * radius;

    			context.setLineDash([2 / scale, 15 / scale]);

    			context.beginPath();
    			context.moveTo(0, 0);
    			context.lineTo(x, y);
    			context.stroke();
    		}

    		context.setLineDash([]);

    		context.restore();

    		// Inner ringlets
    		context.lineWidth = (1 / scale) * settings.innerRingLineWidth;

    		for(var i = 1; i <= settings.numInnerRings; i++)
    		{
    			var radius = i * ringSpacing;

    			if(settings.innerRingFade)
    				rgba.a = 1 - (i - 1) / settings.numInnerRings;

    			context.strokeStyle = WPGMZA.rgbaToString(rgba);

    			context.beginPath();
    			context.arc(worldPoint.x, worldPoint.y, radius, 0, 2 * Math.PI);
    			context.stroke();
    			context.closePath();
    		}

    		// Main circle
    		context.strokeStyle = settings.color;
    		context.lineWidth = (1 / scale) * settings.centerRingLineWidth;

    		context.beginPath();
    		context.arc(worldPoint.x, worldPoint.y, this.getTransformedRadius(settings.radius), 0, 2 * Math.PI);
    		context.stroke();
    		context.closePath();

    		// Outer ringlets
    		var radius = radius + ringSpacing;
    		for(var i = 0; i < settings.numOuterRings; i++)
    		{
    			if(settings.innerRingFade)
    				rgba.a = 1 - i / settings.numOuterRings;

    			context.strokeStyle = WPGMZA.rgbaToString(rgba);

    			context.beginPath();
    			context.arc(worldPoint.x, worldPoint.y, radius, 0, 2 * Math.PI);
    			context.stroke();
    			context.closePath();

    			radius += ringSpacing;
    		}

    		// Text
    		if(settings.numRadiusLabels > 0)
    		{
    			var m;
    			var radius = this.getTransformedRadius(settings.radius);
    			var clipRadius = (12 * 1.1) / scale;
    			var x, y;

    			if(m = settings.radiusLabelFont.match(/(\d+)px/))
    				clipRadius = (parseInt(m[1]) / 2 * 1.1) / scale;

    			context.font = settings.radiusLabelFont;
    			context.textAlign = "center";
    			context.textBaseline = "middle";
    			context.fillStyle = settings.color;

    			context.save();

    			context.translate(worldPoint.x, worldPoint.y)

    			for(var i = 0; i < settings.numRadiusLabels; i++)
    			{
    				var spokeAngle = settings.radiusLabelsStartAngle + (Math.PI * 2) * (i / settings.numRadiusLabels);
    				var textAngle = spokeAngle + Math.PI / 2;
    				var text = settings.radiusString;
    				var width;

    				if(Math.sin(spokeAngle) > 0)
    					textAngle -= Math.PI;

    				x = Math.cos(spokeAngle) * radius;
    				y = Math.sin(spokeAngle) * radius;

    				context.save();

    				context.translate(x, y);

    				context.rotate(textAngle);
    				context.scale(1 / scale, 1 / scale);

    				width = context.measureText(text).width;
    				height = width / 2;
    				context.clearRect(-width, -height, 2 * width, 2 * height);

    				context.fillText(settings.radiusString, 0, 0);

    				context.restore();
    			}

    			context.restore();
    		}
    	}

    })(jQuery);

    // js/v8/modern-store-locator.js
    /**
     * @namespace WPGMZA
     * @module ModernStoreLocator
     * @requires WPGMZA
     */
    (function($) {

    	/**
    	 * The new modern look store locator. It takes the elements
    	 * from the default look and moves them into the map, wrapping
    	 * in a new element so we can apply new styles.
    	 * @return Object
    	 */
    	WPGMZA.ModernStoreLocator = function(map_id)
    	{
    		var self = this;
    		var original;

    		WPGMZA.assertInstanceOf(this, "ModernStoreLocator");

    		if(WPGMZA.isProVersion())
    			 original = $(".wpgmza_sl_search_button[mid='" + map_id + "']").closest(".wpgmza_sl_main_div");
    		else
    			original = $(".wpgmza_sl_search_button").closest(".wpgmza_sl_main_div");

    		if(!original.length)
    			return;

    		// Build / re-arrange elements
    		this.element = $("<div class='wpgmza-modern-store-locator'><div class='wpgmza-inner wpgmza-modern-hover-opaque'/></div>")[0];

    		var inner = $(this.element).find(".wpgmza-inner");

    		var titleSearch = $(original).find("[id='nameInput_" + map_id + "']");
    		if(titleSearch.length)
    		{
    			var placeholder = wpgmaps_localize[map_id].other_settings.store_locator_name_string;
    			if(placeholder && placeholder.length)
    				titleSearch.attr("placeholder", placeholder);
    			inner.append(titleSearch);
    		}

    		var addressInput;
    		if(WPGMZA.isProVersion())
    			addressInput = $(original).find(".addressInput");
    		else
    			addressInput = $(original).find("#addressInput");

    		if(wpgmaps_localize[map_id].other_settings.store_locator_query_string && wpgmaps_localize[map_id].other_settings.store_locator_query_string.length)
    			addressInput.attr("placeholder", wpgmaps_localize[map_id].other_settings.store_locator_query_string);

    		inner.append(addressInput);

    		inner.append($(original).find("select.wpgmza_sl_radius_select"));
    		// inner.append($(original).find(".wpgmza_filter_select_" + map_id));

    		// Buttons
    		this.searchButton = $(original).find( ".wpgmza_sl_search_button" );
    		inner.append(this.searchButton);

    		this.resetButton = $(original).find( ".wpgmza_sl_reset_button_div" );
    		inner.append(this.resetButton);

    		this.resetButton.hide();

    		if(WPGMZA.isProVersion())
    		{
    			this.searchButton.on("click", function(event) {
    				if($("addressInput_" + map_id).val() == 0)
    					return;

    				self.searchButton.hide();
    				self.resetButton.show();
    			});
    			this.resetButton.on("click", function(event) {
    				self.resetButton.hide();
    				self.searchButton.show();
    			});
    		}

    		// Distance type
    		inner.append($("#wpgmza_distance_type_" + map_id));

    		// Categories
    		var container = $(original).find(".wpgmza_cat_checkbox_holder");
    		var ul = $(container).children("ul");
    		var items = $(container).find("li");
    		var numCategories = 0;

    		//$(items).find("ul").remove();
    		//$(ul).append(items);

    		var icons = [];

    		items.each(function(index, el) {
    			var id = $(el).attr("class").match(/\d+/);

    			for(var category_id in wpgmza_category_data) {

    				if(id == category_id) {
    					var src = wpgmza_category_data[category_id].image;
    					var icon = $('<div class="wpgmza-chip-icon"/>');

    					icon.css({
    						"background-image": "url('" + src + "')",
    						"width": $("#wpgmza_cat_checkbox_" + category_id + " + label").height() + "px"
    					});
    					icons.push(icon);

                        if(src != null && src != ""){
    					   //$(el).find("label").prepend(icon);
                           $("#wpgmza_cat_checkbox_" + category_id + " + label").prepend(icon);
                        }

    					numCategories++;

    					break;
    				}

    			}
    		});

            $(this.element).append(container);

    		if(numCategories) {
    			this.optionsButton = $('<span class="wpgmza_store_locator_options_button"><i class="fas fa-list"></i></span>');
    			$(this.searchButton).before(this.optionsButton);
    		}

    		setInterval(function() {

    			icons.forEach(function(icon) {
    				var height = $(icon).height();
    				$(icon).css({"width": height + "px"});
    				$(icon).closest("label").css({"padding-left": height + 8 + "px"});
    			});

    			$(container).css("width", $(self.element).find(".wpgmza-inner").outerWidth() + "px");

    		}, 1000);

    		$(this.element).find(".wpgmza_store_locator_options_button").on("click", function(event) {

    			if(container.hasClass("wpgmza-open"))
    				container.removeClass("wpgmza-open");
    			else
    				container.addClass("wpgmza-open");

    		});

    		// Remove original element
    		$(original).remove();

    		// Event listeners
    		$(this.element).find("input, select").on("focus", function() {
    			$(inner).addClass("active");
    		});

    		$(this.element).find("input, select").on("blur", function() {
    			$(inner).removeClass("active");
    		});
    	}

    	WPGMZA.ModernStoreLocator.createInstance = function(map_id)
    	{
    		if(WPGMZA.settings.engine == "google-maps")
    			return new WPGMZA.GoogleModernStoreLocator(map_id);
    		else
    			return new WPGMZA.OLModernStoreLocator(map_id);
    	}

    })(jQuery);

    // js/v8/polygon.js
    /**
     * @namespace WPGMZA
     * @module Polygon
     * @requires WPGMZA.MapObject
     */
    (function($) {
    	WPGMZA.Polygon = function(row, enginePolygon)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "Polygon");

    		this.paths = null;
    		this.title = null;
    		this.name = null;
    		this.link = null;

    		WPGMZA.MapObject.apply(this, arguments);
    	}

    	WPGMZA.Polygon.prototype = Object.create(WPGMZA.MapObject.prototype);
    	WPGMZA.Polygon.prototype.constructor = WPGMZA.Polygon;

    	WPGMZA.Polygon.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				if(WPGMZA.isProVersion())
    					return WPGMZA.GoogleProPolygon;
    				return WPGMZA.GooglePolygon;
    				break;

    			default:
    				if(WPGMZA.isProVersion())
    					return WPGMZA.OLProPolygon;
    				return WPGMZA.OLPolygon;
    				break;
    		}
    	}

    	WPGMZA.Polygon.createInstance = function(row, engineObject)
    	{
    		var constructor = WPGMZA.Polygon.getConstructor();
    		return new constructor(row, engineObject);
    	}

    	WPGMZA.Polygon.prototype.toJSON = function()
    	{
    		var result = WPGMZA.MapObject.prototype.toJSON.call(this);

    		$.extend(result, {
    			name:		this.name,
    			title:		this.title,
    			link:		this.link,
    		});

    		return result;
    	}

    })(jQuery);

    // js/v8/polyline.js
    /**
     * @namespace WPGMZA
     * @module Polyline
     * @requires WPGMZA.MapObject
     */
    (function($) {
    	WPGMZA.Polyline = function(row, googlePolyline)
    	{
    		var self = this;

    		WPGMZA.assertInstanceOf(this, "Polyline");

    		this.title = null;

    		WPGMZA.MapObject.apply(this, arguments);
    	}

    	WPGMZA.Polyline.prototype = Object.create(WPGMZA.MapObject.prototype);
    	WPGMZA.Polyline.prototype.constructor = WPGMZA.Polyline;

    	WPGMZA.Polyline.getConstructor = function()
    	{
    		switch(WPGMZA.settings.engine)
    		{
    			case "google-maps":
    				return WPGMZA.GooglePolyline;
    				break;

    			default:
    				return WPGMZA.OLPolyline;
    				break;
    		}
    	}

    	WPGMZA.Polyline.createInstance = function(row, engineObject)
    	{
    		var constructor = WPGMZA.Polyline.getConstructor();
    		return new constructor(row, engineObject);
    	}

    	WPGMZA.Polyline.prototype.getPoints = function()
    	{
    		return this.toJSON().points;
    	}

    	WPGMZA.Polyline.prototype.toJSON = function()
    	{
    		var result = WPGMZA.MapObject.prototype.toJSON.call(this);

    		result.title = this.title;

    		return result;
    	}

    })(jQuery);

    // js/v8/google-maps/google-circle.js
    /**
     * @namespace WPGMZA
     * @module GoogleCircle
     * @requires WPGMZA.Circle
     */
    (function($) {

    	WPGMZA.GoogleCircle = function(options, googleCircle)
    	{
    		var self = this;

    		WPGMZA.Circle.call(this, options, googleCircle);

    		if(googleCircle)
    		{
    			this.googleCircle = googleCircle;
    		}
    		else
    		{
    			this.googleCircle = new google.maps.Circle();
    			this.googleCircle.wpgmzaCircle = this;
    		}

    		google.maps.event.addListener(this.googleCircle, "click", function() {
    			self.dispatchEvent({type: "click"});
    		});

    		if(options)
    		{
    			var googleOptions = {};

    			googleOptions = $.extend({}, options);
    			delete googleOptions.map;
    			delete googleOptions.center;

    			if(options.center)
    				googleOptions.center = new google.maps.LatLng({
    					lat: options.center.lat,
    					lng: options.center.lng
    				});

    			this.googleCircle.setOptions(googleOptions);

    			if(options.map)
    				options.map.addCircle(this);
    		}
    	}

    	WPGMZA.GoogleCircle.prototype = Object.create(WPGMZA.Circle.prototype);
    	WPGMZA.GoogleCircle.prototype.constructor = WPGMZA.GoogleCircle;

    })(jQuery);

    // js/v8/google-maps/google-geocoder.js
    /**
     * @namespace WPGMZA
     * @module GoogleGeocoder
     * @requires WPGMZA.Geocoder
     */
    (function($) {

    	WPGMZA.GoogleGeocoder = function()
    	{

    	}

    	WPGMZA.GoogleGeocoder.prototype = Object.create(WPGMZA.Geocoder.prototype);
    	WPGMZA.GoogleGeocoder.prototype.constructor = WPGMZA.GoogleGeocoder;

    	WPGMZA.GoogleGeocoder.prototype.getLatLngFromAddress = function(options, callback)
    	{
    		if(!options || !options.address)
    			throw new Error("No address specified");

    		if(WPGMZA.isLatLngString(options.address))
    			return WPGMZA.Geocoder.prototype.getLatLngFromAddress.call(this, options, callback);

    		if(options.country)
    			options.componentRestrictions = {
    				country: options.country
    			};

    		var geocoder = new google.maps.Geocoder();
    		geocoder.geocode(options, function(results, status) {
    			if(status == google.maps.GeocoderStatus.OK)
    			{
    				var location = results[0].geometry.location;
    				latLng = {
    					lat: location.lat(),
    					lng: location.lng()
    				};

    				var results = [
    					{
    						geometry: {
    							location: latLng
    						},
    						latLng: latLng
    					}
    				];

    				callback(results, WPGMZA.Geocoder.SUCCESS);
    			}
    			else
    			{
    				var nativeStatus = WPGMZA.Geocoder.FAIL;

    				if(status == google.maps.GeocoderStatus.ZERO_RESULTS)
    					nativeStatus = WPGMZA.Geocoder.ZERO_RESULTS;

    				callback(null, nativeStatus);
    			}
    		});
    	}

    })(jQuery);

    // js/v8/google-maps/google-info-window.js
    /**
     * @namespace WPGMZA
     * @module GoogleInfoWindow
     * @requires WPGMZA.InfoWindow
     * @pro-requires WPGMZA.ProInfoWindow
     */
    (function($) {

    	var Parent;

    	WPGMZA.GoogleInfoWindow = function(mapObject)
    	{
    		Parent.call(this, mapObject);

    		this.setMapObject(mapObject);
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProInfoWindow;
    	else
    		Parent = WPGMZA.InfoWindow;

    	WPGMZA.GoogleInfoWindow.prototype = Object.create(Parent.prototype);
    	WPGMZA.GoogleInfoWindow.prototype.constructor = WPGMZA.GoogleInfoWindow;

    	WPGMZA.GoogleInfoWindow.prototype.setMapObject = function(mapObject)
    	{
    		if(mapObject instanceof WPGMZA.Marker)
    			this.googleObject = mapObject.googleMarker;
    		else if(mapObject instanceof WPGMZA.Polygon)
    			this.googleObject = mapObject.googlePolygon;
    		else if(mapObject instanceof WPGMZA.Polyline)
    			this.googleObject = mapObject.googlePolyline;
    	}

    	WPGMZA.GoogleInfoWindow.prototype.createGoogleInfoWindow = function()
    	{
    		if(this.googleInfoWindow)
    			return;

    		this.googleInfoWindow = new google.maps.InfoWindow();
    	}

    	/**
    	 * Opens the info window
    	 * @return boolean FALSE if the info window should not & will not open, TRUE if it will
    	 */
    	WPGMZA.GoogleInfoWindow.prototype.open = function(map, mapObject)
    	{
    		var self = this;

    		if(!Parent.prototype.open.call(this, map, mapObject))
    			return false;

    		this.createGoogleInfoWindow();
    		this.setMapObject(mapObject);

    		this.googleInfoWindow.open(
    			this.mapObject.map.googleMap,
    			this.googleObject
    		);

    		if(this.content)
    			this.googleInfoWindow.setContent(this.content);

    		//this.

    		/*this.getContent(function(html) {

    			// Wrap HTML with unique ID
    			var guid = WPGMZA.guid();
    			var html = "<div id='" + guid + "'>" + html + "</div>";
    			var div, intervalID;

    			self.googleInfoWindow.setContent(html);
    			self.googleInfoWindow.open(
    				self.mapObject.map.googleMap,
    				self.googleObject
    			);

    			intervalID = setInterval(function(event) {

    				div = $("#" + guid);

    				if(div.find(".gm-style-iw").length)
    				{
    					div[0].wpgmzaMapObject = self.mapObject;

    					self.dispatchEvent("infowindowopen");
    					div.trigger("infowindowopen");
    					clearInterval(intervalID);
    				}

    			}, 50);

    		});*/

    		return true;
    	}

    	WPGMZA.GoogleInfoWindow.prototype.close = function()
    	{
    		if(!this.googleInfoWindow)
    			return;

    		WPGMZA.InfoWindow.prototype.close.call(this);

    		this.googleInfoWindow.close();
    	}

    	WPGMZA.GoogleInfoWindow.prototype.setContent = function(html)
    	{
    		this.content = html;

    		this.createGoogleInfoWindow();

    		this.googleInfoWindow.setContent(html);
    	}

    })(jQuery);

    // js/v8/google-maps/google-map.js
    /**
     * @namespace WPGMZA
     * @module GoogleMap
     * @requires WPGMZA.Map
     * @pro-requires WPGMZA.ProMap
     */
    (function($) {
    	var Parent;

    	/**
    	 * Constructor
    	 * @param element to contain the map
    	 */
    	WPGMZA.GoogleMap = function(element, options)
    	{
    		var self = this;

    		if(!window.google)
    			throw new Error("Google API not loaded - " + wpgmza_api_not_enqueued_reason);

    		Parent.call(this, element, options);

    		this.loadGoogleMap();

    		if(options)
    			this.setOptions(options);

    		google.maps.event.addListener(this.googleMap, "click", function(event) {
    			self.dispatchEvent("click");
    		});

    		google.maps.event.addListener(this.googleMap, "rightclick", function(event) {
    			var wpgmzaEvent = new WPGMZA.Event("rightclick");
    			wpgmzaEvent.latLng = {
    				lat: event.latLng.lat(),
    				lng: event.latLng.lng()
    			};
    			self.dispatchEvent(wpgmzaEvent);
    		});

    		google.maps.event.addListener(this.googleMap, "dragend", function(event) {
    			self.dispatchEvent("dragend");
    		});

    		google.maps.event.addListener(this.googleMap, "zoom_changed", function(event) {
    			self.dispatchEvent("zoom_changed");
    			self.dispatchEvent("zoomchanged");
    		});

    		// Idle event
    		google.maps.event.addListener(this.googleMap, "idle", function(event) {
    			self.onIdle(event);
    		});

    		// Dispatch event
    		if(!WPGMZA.isProVersion())
    		{
    			this.dispatchEvent("created");
    			WPGMZA.events.dispatchEvent({type: "mapcreated", map: this});
    		}
    	}

    	// If we're running the Pro version, inherit from ProMap, otherwise, inherit from Map
    	if(WPGMZA.isProVersion())
    	{
    		Parent = WPGMZA.ProMap;
    		WPGMZA.GoogleMap.prototype = Object.create(WPGMZA.ProMap.prototype);
    	}
    	else
    	{
    		Parent = WPGMZA.Map;
    		WPGMZA.GoogleMap.prototype = Object.create(WPGMZA.Map.prototype);
    	}
    	WPGMZA.GoogleMap.prototype.constructor = WPGMZA.GoogleMap;

    	/**
    	 * Creates the Google Maps map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.loadGoogleMap = function()
    	{
    		var self = this;
    		var options = this.settings.toGoogleMapsOptions();

    		this.googleMap = new google.maps.Map(this.engineElement, options);
    		google.maps.event.addListener(this.googleMap, "bounds_changed", function() {
    			self.onBoundsChanged();
    		});

    		if(this.settings.bicycle)
    			this.enableBicycleLayer(true);
    		if(this.settings.traffic)
    			this.enableTrafficLayer(true);
    		if(this.settings.transport)
    			this.enablePublicTransportLayer(true);
    		this.showPointsOfInterest(this.settings.show_points_of_interest);

    		// Move the loading wheel into the map element (it has to live outside in the HTML file because it'll be overwritten by Google otherwise)
    		$(this.engineElement).append($(this.element).find(".wpgmza-loader"));
    	}

    	WPGMZA.GoogleMap.prototype.setOptions = function(options)
    	{
    		Parent.prototype.setOptions.call(this, options);

    		this.googleMap.setOptions(this.settings.toGoogleMapsOptions());

    		var clone = $.extend({}, options);
    		if(clone.center instanceof WPGMZA.LatLng || typeof clone.center == "object")
    			clone.center = {
    				lat: parseFloat(clone.center.lat),
    				lng: parseFloat(clone.center.lng)
    			};

    		this.googleMap.setOptions(clone);
    	}

    	/**
    	 * Adds the specified marker to this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.addMarker = function(marker)
    	{
    		marker.googleMarker.setMap(this.googleMap);

    		Parent.prototype.addMarker.call(this, marker);
    	}

    	/**
    	 * Removes the specified marker from this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.removeMarker = function(marker)
    	{
    		marker.googleMarker.setMap(null);

    		Parent.prototype.removeMarker.call(this, marker);
    	}

    	/**
    	 * Adds the specified polygon to this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.addPolygon = function(polygon)
    	{
    		polygon.googlePolygon.setMap(this.googleMap);

    		Parent.prototype.addPolygon.call(this, polygon);
    	}

    	/**
    	 * Removes the specified polygon from this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.removePolygon = function(polygon)
    	{
    		polygon.googlePolygon.setMap(null);

    		Parent.prototype.removePolygon.call(this, polygon);
    	}

    	/**
    	 * Adds the specified polyline to this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.addPolyline = function(polyline)
    	{
    		polyline.googlePolyline.setMap(this.googleMap);

    		Parent.prototype.addPolyline.call(this, polyline);
    	}

    	/**
    	 * Removes the specified polygon from this map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.removePolyline = function(polyline)
    	{
    		polyline.googlePolyline.setMap(null);

    		Parent.prototype.removePolyline.call(this, polyline);
    	}

    	WPGMZA.GoogleMap.prototype.addCircle = function(circle)
    	{
    		circle.googleCircle.setMap(this.googleMap);

    		Parent.prototype.addCircle.call(this, circle);
    	}

    	WPGMZA.GoogleMap.prototype.removeCircle = function(circle)
    	{
    		circle.googleCircle.setMap(null);

    		Parent.prototype.removeCircle.call(this, circle);
    	}

    	/**
    	 * Delegate for google maps getCenter
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.getCenter = function()
    	{
    		var latLng = this.googleMap.getCenter();

    		return {
    			lat: latLng.lat(),
    			lng: latLng.lng()
    		};
    	}

    	/**
    	 * Delegate for google maps setCenter
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.setCenter = function(latLng)
    	{
    		WPGMZA.Map.prototype.setCenter.call(this, latLng);

    		if(latLng instanceof WPGMZA.LatLng)
    			this.googleMap.setCenter({
    				lat: latLng.lat,
    				lng: latLng.lng
    			});
    		else
    			this.googleMap.setCenter(latLng);
    	}

    	/**
    	 * Delegate for google maps setPan
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.panTo = function(latLng)
    	{
    		if(latLng instanceof WPGMZA.LatLng)
    			this.googleMap.panTo({
    				lat: latLng.lat,
    				lng: latLng.lng
    			});
    		else
    			this.googleMap.panTo(latLng);
    	}

    	/**
    	 * Delegate for google maps getCenter
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.getZoom = function()
    	{
    		return this.googleMap.getZoom();
    	}

    	/**
    	 * Delegate for google maps getZoom
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.setZoom = function(value)
    	{
    		return this.googleMap.setZoom(value);
    	}

    	/**
    	 * Gets the bounds
    	 * @return object
    	 */
    	WPGMZA.GoogleMap.prototype.getBounds = function()
    	{
    		var bounds = this.googleMap.getBounds();
    		var northEast = bounds.getNorthEast();
    		var southWest = bounds.getSouthWest();

    		return {
    			topLeft: {
    				lat: northEast.lat(),
    				lng: southWest.lng()
    			},
    			bottomRight: {
    				lat: southWest.lat(),
    				lng: northEast.lng()
    			}
    		};
    	}

    	/**
    	 * Fit to given boundaries
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.fitBounds = function(southWest, northEast)
    	{
    		if(southWest instanceof WPGMZA.LatLng)
    			southWest = {lat: southWest.lat, lng: southWest.lng};
    		if(northEast instanceof WPGMZA.LatLng)
    			northEast = {lat: northEast.lat, lng: northEast.lng};

    		this.googleMap.fitBounds(southWest, northEast);
    	}

    	/**
    	 * Fit the map boundaries to visible markers
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.fitBoundsToVisibleMarkers = function()
    	{
    		var bounds = new google.maps.LatLngBounds();
    		for(var i = 0; i < this.markers.length; i++)
    		{
    			if(markers[i].getVisible())
    				bounds.extend(markers[i].getPosition());
    		}
    		this.googleMap.fitBounds(bounds);
    	}

    	/**
    	 * Enables / disables the bicycle layer
    	 * @param enable boolean, enable or not
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.enableBicycleLayer = function(enable)
    	{
    		if(!this.bicycleLayer)
    			this.bicycleLayer = new google.maps.BicyclingLayer();

    		this.bicycleLayer.setMap(
    			enable ? this.googleMap : null
    		);
    	}

    	/**
    	 * Enables / disables the bicycle layer
    	 * @param enable boolean, enable or not
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.enableTrafficLayer = function(enable)
    	{
    		if(!this.trafficLayer)
    			this.trafficLayer = new google.maps.TrafficLayer();

    		this.trafficLayer.setMap(
    			enable ? this.googleMap : null
    		);
    	}

    	/**
    	 * Enables / disables the bicycle layer
    	 * @param enable boolean, enable or not
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.enablePublicTransportLayer = function(enable)
    	{
    		if(!this.publicTransportLayer)
    			this.publicTransportLayer = new google.maps.TransitLayer();

    		this.publicTransportLayer.setMap(
    			enable ? this.googleMap : null
    		);
    	}

    	/**
    	 * Shows / hides points of interest
    	 * @param show boolean, enable or not
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.showPointsOfInterest = function(show)
    	{
    		// TODO: This will bug the front end because there is textarea with theme data
    		var text = $("textarea[name='theme_data']").val();

    		if(!text)
    			return;

    		var styles = JSON.parse(text);

    		styles.push({
    			featureType: "poi",
    			stylers: [
    				{
    					visibility: (show ? "on" : "off")
    				}
    			]
    		});

    		this.googleMap.setOptions({styles: styles});
    	}

    	/**
    	 * Gets the min zoom of the map
    	 * @return int
    	 */
    	WPGMZA.GoogleMap.prototype.getMinZoom = function()
    	{
    		return parseInt(this.settings.min_zoom);
    	}

    	/**
    	 * Sets the min zoom of the map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.setMinZoom = function(value)
    	{
    		this.googleMap.setOptions({
    			minZoom: value,
    			maxZoom: this.getMaxZoom()
    		});
    	}

    	/**
    	 * Gets the min zoom of the map
    	 * @return int
    	 */
    	WPGMZA.GoogleMap.prototype.getMaxZoom = function()
    	{
    		return parseInt(this.settings.max_zoom);
    	}

    	/**
    	 * Sets the min zoom of the map
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.setMaxZoom = function(value)
    	{
    		this.googleMap.setOptions({
    			minZoom: this.getMinZoom(),
    			maxZoom: value
    		});
    	}

    	WPGMZA.GoogleMap.prototype.latLngToPixels = function(latLng)
    	{
    		var map = this.googleMap;
    		var nativeLatLng = new google.maps.LatLng({
    			lat: parseFloat(latLng.lat),
    			lng: parseFloat(latLng.lng)
    		});
    		var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
    		var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
    		var scale = Math.pow(2, map.getZoom());
    		var worldPoint = map.getProjection().fromLatLngToPoint(nativeLatLng);
    		return {
    			x: (worldPoint.x - bottomLeft.x) * scale,
    			y: (worldPoint.y - topRight.y) * scale
    		};
    	}

    	WPGMZA.GoogleMap.prototype.pixelsToLatLng = function(x, y)
    	{
    		if(y == undefined)
    		{
    			if("x" in x && "y" in x)
    			{
    				y = x.y;
    				x = x.x;
    			}
    			else
    				console.warn("Y coordinate undefined in pixelsToLatLng (did you mean to pass 2 arguments?)");
    		}

    		var map = this.googleMap;
    		var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
    		var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
    		var scale = Math.pow(2, map.getZoom());
    		var worldPoint = new google.maps.Point(x / scale + bottomLeft.x, y / scale + topRight.y);
    		var latLng = map.getProjection().fromPointToLatLng(worldPoint);
    		return {
    			lat: latLng.lat(),
    			lng: latLng.lng()
    		};
    	}

    	/**
    	 * Handle the map element resizing
    	 * @return void
    	 */
    	WPGMZA.GoogleMap.prototype.onElementResized = function(event)
    	{
    		if(!this.googleMap)
    			return;
    		google.maps.event.trigger(this.googleMap, "resize");
    	}

    })(jQuery);

    // js/v8/google-maps/google-marker.js
    /**
     * @namespace WPGMZA
     * @module GoogleMarker
     * @requires WPGMZA.Marker
     * @pro-requires WPGMZA.ProMarker
     */
    (function($) {

    	var Parent;

    	WPGMZA.GoogleMarker = function(row)
    	{
    		var self = this;

    		Parent.call(this, row);

    		this.googleMarker = new google.maps.Marker(/*this.settings*/);
    		this.googleMarker.wpgmzaMarker = this;

    		this.googleMarker.setPosition(new google.maps.LatLng({
    			lat: parseFloat(this.lat),
    			lng: parseFloat(this.lng)
    		}));

    		this.googleMarker.setLabel(this.settings.label);

    		if(this.animation)
    			this.googleMarker.setAnimation(this.animation);

    		google.maps.event.addListener(this.googleMarker, "click", function() {
    			self.dispatchEvent("click");
    			self.dispatchEvent("select");
    		});

    		google.maps.event.addListener(this.googleMarker, "mouseover", function() {
    			self.dispatchEvent("mouseover");
    		});

    		google.maps.event.addListener(this.googleMarker, "dragend", function() {
    			var googleMarkerPosition = self.googleMarker.getPosition();

    			self.setPosition({
    				lat: googleMarkerPosition.lat(),
    				lng: googleMarkerPosition.lng()
    			});

    			self.dispatchEvent("dragend");
    		});

    		this.trigger("init");
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProMarker;
    	else
    		Parent = WPGMZA.Marker;
    	WPGMZA.GoogleMarker.prototype = Object.create(Parent.prototype);
    	WPGMZA.GoogleMarker.prototype.constructor = WPGMZA.GoogleMarker;

    	WPGMZA.GoogleMarker.prototype.setLabel = function(label)
    	{
    		if(!label)
    		{
    			this.googleMarker.setLabel(null);
    			return;
    		}

    		this.googleMarker.setLabel({
    			text: label
    		});

    		if(!this.googleMarker.getIcon())
    			this.googleMarker.setIcon(WPGMZA.settings.default_marker_icon);
    	}

    	/**
    	 * Sets the position of the marker
    	 * @return void
    	 */
    	WPGMZA.GoogleMarker.prototype.setPosition = function(latLng)
    	{
    		Parent.prototype.setPosition.call(this, latLng);
    		this.googleMarker.setPosition({
    			lat: this.lat,
    			lng: this.lng
    		});
    	}

    	/**
    	 * Sets the position offset of a marker
    	 * @return void
    	 */
    	WPGMZA.GoogleMarker.prototype.setOffset = function(x, y)
    	{
    		var self = this;
    		var icon = this.googleMarker.getIcon();
    		var img = new Image();
    		var params;

    		if(typeof icon == "string")
    			params = {
    				url: icon
    			};
    		else
    			params = icon;

    		img.onload = function()
    		{
    			var defaultAnchor = {
    				x: img.width / 2,
    				y: img.height
    			};

    			params.anchor = new google.maps.Point(defaultAnchor.x - x, defaultAnchor.y - y);

    			self.googleMarker.setIcon(params);
    		}

    		img.src = params.url;
    	}

    	/**
    	 * Set the marker animation
    	 * @return void
    	 */
    	WPGMZA.GoogleMarker.prototype.setAnimation = function(animation)
    	{
    		Parent.prototype.setAnimation.call(this, animation);
    		this.googleMarker.setAnimation(animation);
    	}

    	/**
    	 * Sets the visibility of the marker
    	 * @return void
    	 */
    	WPGMZA.GoogleMarker.prototype.setVisible = function(visible)
    	{
    		Parent.prototype.setVisible.call(this, visible);

    		this.googleMarker.setVisible(visible);
    	}

    	WPGMZA.GoogleMarker.prototype.setDraggable = function(draggable)
    	{
    		this.googleMarker.setDraggable(draggable);
    	}

    })(jQuery);

    // js/v8/google-maps/google-modern-store-locator-circle.js
    /**
     * @namespace WPGMZA
     * @module GoogleModernStoreLocatorCircle
     * @requires WPGMZA.ModernStoreLocatorCircle
     */
    (function($) {

    	WPGMZA.GoogleModernStoreLocatorCircle = function(map, settings)
    	{
    		var self = this;

    		WPGMZA.ModernStoreLocatorCircle.call(this, map, settings);

    		this.intervalID = setInterval(function() {

    			var mapSize = {
    				width: $(self.mapElement).width(),
    				height: $(self.mapElement).height()
    			};

    			if(mapSize.width == self.mapSize.width && mapSize.height == self.mapSize.height)
    				return;

    			self.canvasLayer.resize_();
    			self.canvasLayer.draw();

    			self.mapSize = mapSize;

    		}, 1000);

    		$(document).bind('webkitfullscreenchange mozfullscreenchange fullscreenchange', function() {

    			self.canvasLayer.resize_();
    			self.canvasLayer.draw();

    		});
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype = Object.create(WPGMZA.ModernStoreLocatorCircle.prototype);
    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.constructor = WPGMZA.GoogleModernStoreLocatorCircle;

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.initCanvasLayer = function()
    	{
    		var self = this;

    		if(this.canvasLayer)
    		{
    			this.canvasLayer.setMap(null);
    			this.canvasLayer.setAnimate(false);
    		}

    		this.canvasLayer = new CanvasLayer({
    			map: this.map.googleMap,
    			resizeHandler: function(event) {
    				self.onResize(event);
    			},
    			updateHandler: function(event) {
    				self.onUpdate(event);
    			},
    			animate: true,
    			resolutionScale: this.getResolutionScale()
            });
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.setOptions = function(options)
    	{
    		WPGMZA.ModernStoreLocatorCircle.prototype.setOptions.call(this, options);

    		this.canvasLayer.scheduleUpdate();
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.setPosition = function(position)
    	{
    		WPGMZA.ModernStoreLocatorCircle.prototype.setPosition.call(this, position);

    		this.canvasLayer.scheduleUpdate();
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.setRadius = function(radius)
    	{
    		WPGMZA.ModernStoreLocatorCircle.prototype.setRadius.call(this, radius);

    		this.canvasLayer.scheduleUpdate();
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getTransformedRadius = function(km)
    	{
    		var multiplierAtEquator = 0.006395;
    		var spherical = google.maps.geometry.spherical;

    		var center = this.settings.center;
    		var equator = new WPGMZA.LatLng({
    			lat: 0.0,
    			lng: 0.0
    		});
    		var latitude = new WPGMZA.LatLng({
    			lat: center.lat,
    			lng: 0.0
    		});

    		var offsetAtEquator = spherical.computeOffset(equator.toGoogleLatLng(), km * 1000, 90);
    		var offsetAtLatitude = spherical.computeOffset(latitude.toGoogleLatLng(), km * 1000, 90);

    		var factor = offsetAtLatitude.lng() / offsetAtEquator.lng();
    		var result = km * multiplierAtEquator * factor;

    		if(isNaN(result))
    			throw new Error("here");

    		return result;
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getCanvasDimensions = function()
    	{
    		return {
    			width: this.canvasLayer.canvas.width,
    			height: this.canvasLayer.canvas.height
    		};
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getWorldOriginOffset = function()
    	{
    		var projection = this.map.googleMap.getProjection();
    		var position = projection.fromLatLngToPoint(this.canvasLayer.getTopLeft());

    		return {
    			x: -position.x,
    			y: -position.y
    		};
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getCenterPixels = function()
    	{
    		var center = new WPGMZA.LatLng(this.settings.center);
    		var projection = this.map.googleMap.getProjection();
    		return projection.fromLatLngToPoint(center.toGoogleLatLng());
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getContext = function(type)
    	{
    		return this.canvasLayer.canvas.getContext("2d");
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.getScale = function()
    	{
    		return Math.pow(2, this.map.getZoom()) * this.getResolutionScale();
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.setVisible = function(visible)
    	{
    		WPGMZA.ModernStoreLocatorCircle.prototype.setVisible.call(this, visible);

    		this.canvasLayer.scheduleUpdate();
    	}

    	WPGMZA.GoogleModernStoreLocatorCircle.prototype.destroy = function()
    	{
    		this.canvasLayer.setMap(null);
    		this.canvasLayer = null;

    		clearInterval(this.intervalID);
    	}

    })(jQuery);

    // js/v8/google-maps/google-modern-store-locator.js
    /**
     * @namespace WPGMZA
     * @module GoogleModernStoreLocator
     * @requires WPGMZA.ModernStoreLocator
     */
    (function($) {

    	WPGMZA.GoogleModernStoreLocator = function(map_id)
    	{
    		WPGMZA.ModernStoreLocator.call(this, map_id);

    		var googleMap;

    		if(WPGMZA.isProVersion())
    			googleMap = MYMAP[map_id].map.googleMap;
    		else
    			googleMap = MYMAP.map.googleMap;

    		googleMap.controls[google.maps.ControlPosition.TOP_CENTER].push(this.element);
    	}

    	WPGMZA.GoogleModernStoreLocator.prototype = Object.create(WPGMZA.ModernStoreLocator.prototype);
    	WPGMZA.GoogleModernStoreLocator.prototype.constructor = WPGMZA.GoogleModernStoreLocator;

    })(jQuery);

    // js/v8/google-maps/google-polygon.js
    /**
     * @namespace WPGMZA
     * @module GooglePolygon
     * @requires WPGMZA.Polygon
     * @pro-requires WPGMZA.ProPolygon
     */
    (function($) {

    	var Parent;

    	WPGMZA.GooglePolygon = function(row, googlePolygon)
    	{
    		var self = this;

    		Parent.call(this, row, googlePolygon);

    		if(googlePolygon)
    		{
    			this.googlePolygon = googlePolygon;
    		}
    		else
    		{
    			this.googlePolygon = new google.maps.Polygon(this.settings);

    			if(row && row.points)
    			{
    				var paths = this.parseGeometry(row.points);
    				this.googlePolygon.setOptions({paths: paths});
    			}
    		}

    		this.googlePolygon.wpgmzaPolygon = this;

    		google.maps.event.addListener(this.googlePolygon, "click", function() {
    			self.dispatchEvent({type: "click"});
    		});
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProPolygon;
    	else
    		Parent = WPGMZA.Polygon;

    	WPGMZA.GooglePolygon.prototype = Object.create(Parent.prototype);
    	WPGMZA.GooglePolygon.prototype.constructor = WPGMZA.GooglePolygon;

    	/**
    	 * Returns true if the polygon is editable
    	 * @return void
    	 */
    	WPGMZA.GooglePolygon.prototype.getEditable = function()
    	{
    		return this.googlePolygon.getOptions().editable;
    	}

    	/**
    	 * Sets the editable state of the polygon
    	 * @return void
    	 */
    	WPGMZA.GooglePolygon.prototype.setEditable = function(value)
    	{
    		this.googlePolygon.setOptions({editable: value});
    	}

    	/**
    	 * Returns the polygon represented by a JSON object
    	 * @return object
    	 */
    	WPGMZA.GooglePolygon.prototype.toJSON = function()
    	{
    		var result = WPGMZA.Polygon.prototype.toJSON.call(this);

    		result.points = [];

    		// TODO: Support holes using multiple paths
    		var path = this.googlePolygon.getPath();
    		for(var i = 0; i < path.getLength(); i++)
    		{
    			var latLng = path.getAt(i);
    			result.points.push({
    				lat: latLng.lat(),
    				lng: latLng.lng()
    			});
    		}

    		return result;
    	}

    })(jQuery);

    // js/v8/google-maps/google-polyline.js
    /**
     * @namespace WPGMZA
     * @module GooglePolyline
     * @requires WPGMZA.Polyline
     */
    (function($) {

    	WPGMZA.GooglePolyline = function(row, googlePolyline)
    	{
    		var self = this;

    		WPGMZA.Polyline.call(this, row, googlePolyline);

    		if(googlePolyline)
    		{
    			this.googlePolyline = googlePolyline;
    		}
    		else
    		{
    			this.googlePolyline = new google.maps.Polyline(this.settings);
    			this.googlePolyline.wpgmzaPolyline = this;

    			if(row && row.points)
    			{
    				var path = this.parseGeometry(row.points);
    				this.setPoints(path);
    			}
    		}

    		google.maps.event.addListener(this.googlePolyline, "click", function() {
    			self.dispatchEvent({type: "click"});
    		});
    	}

    	WPGMZA.GooglePolyline.prototype = Object.create(WPGMZA.Polyline.prototype);
    	WPGMZA.GooglePolyline.prototype.constructor = WPGMZA.GooglePolyline;

    	WPGMZA.GooglePolyline.prototype.setEditable = function(value)
    	{
    		this.googlePolyline.setOptions({editable: value});
    	}

    	WPGMZA.GooglePolyline.prototype.setPoints = function(points)
    	{
    		this.googlePolyline.setOptions({path: points});
    	}

    	WPGMZA.GooglePolyline.prototype.toJSON = function()
    	{
    		var result = WPGMZA.Polyline.prototype.toJSON.call(this);

    		result.points = [];

    		var path = this.googlePolyline.getPath();
    		for(var i = 0; i < path.getLength(); i++)
    		{
    			var latLng = path.getAt(i);
    			result.points.push({
    				lat: latLng.lat(),
    				lng: latLng.lng()
    			});
    		}

    		return result;
    	}

    })(jQuery);

    // js/v8/google-maps/google-vertex-context-menu.js
    /**
     * @namespace WPGMZA
     * @module GoogleVertexContextMenu
     * @requires wpgmza_api_call
     */
    (function($) {

    	if(WPGMZA.settings.engine != "google-maps")
    		return;

    	WPGMZA.GoogleVertexContextMenu = function(mapEditPage)
    	{
    		var self = this;

    		this.mapEditPage = mapEditPage;

    		this.element = document.createElement("div");
    		this.element.className = "wpgmza-vertex-context-menu";
    		this.element.innerHTML = "Delete";

    		google.maps.event.addDomListener(this.element, "click", function(event) {
    			self.removeVertex();
    			event.preventDefault();
    			event.stopPropagation();
    			return false;
    		});
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype = new google.maps.OverlayView();

    	WPGMZA.GoogleVertexContextMenu.prototype.onAdd = function()
    	{
    		var self = this;
    		var map = this.getMap();

    		this.getPanes().floatPane.appendChild(this.element);
    		this.divListener = google.maps.event.addDomListener(map.getDiv(), "mousedown", function(e) {
    			if(e.target != self.element)
    				self.close();
    		}, true);
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype.onRemove = function()
    	{
    		google.maps.event.removeListener(this.divListener);
    		this.element.parentNode.removeChild(this.element);

    		this.set("position");
    		this.set("path");
    		this.set("vertex");
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype.open = function(map, path, vertex)
    	{
    		this.set('position', path.getAt(vertex));
    		this.set('path', path);
    		this.set('vertex', vertex);
    		this.setMap(map);
    		this.draw();
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype.close = function()
    	{
    		this.setMap(null);
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype.draw = function()
    	{
    		var position = this.get('position');
    		var projection = this.getProjection();

    		if (!position || !projection)
    		  return;

    		var point = projection.fromLatLngToDivPixel(position);
    		this.element.style.top = point.y + 'px';
    		this.element.style.left = point.x + 'px';
    	}

    	WPGMZA.GoogleVertexContextMenu.prototype.removeVertex = function()
    	{
    		var path = this.get('path');
    		var vertex = this.get('vertex');

    		if (!path || vertex == undefined) {
    		  this.close();
    		  return;
    		}

    		path.removeAt(vertex);
    		this.close();
    	}

    })(jQuery);

    // js/v8/open-layers/ol-circle.js
    /**
     * @namespace WPGMZA
     * @module OLCircle
     * @requires WPGMZA.Circle
     */
    (function($) {

    	var Parent = WPGMZA.Circle;

    	WPGMZA.OLCircle = function(options, olFeature)
    	{
    		var self = this;

    		this.center = {lat: 0, lng: 0};
    		this.radius = 0;

    		Parent.call(this, options, olFeature);

    		if(!this.settings.fillColor)
    		{
    			this.settings.fillColor = "#ff0000";
    			this.settings.fillOpacity = 0.6;
    		}

    		this.olStyle = new ol.style.Style(this.getStyleFromSettings());

    		// IMPORTANT: Please note that due to what appears to be a bug in OpenLayers, the following code MUST be exected specifically in this order, or the circle won't appear
    		var vectorLayer3857 = new ol.layer.Vector({
    			source: new ol.source.Vector(),
    			style: this.olStyle
    		});

    		if(olFeature)
    		{
    			this.olFeature = olFeature;
    		}
    		else
    		{
    			var wgs84Sphere = new ol.Sphere(6378137);
    			var radius = this.radius;
    			var x, y;

    			x = this.center.lng;
    			y = this.center.lat;

    			var circle4326 = ol.geom.Polygon.circular(wgs84Sphere, [x, y], radius, 64);
    			var circle3857 = circle4326.clone().transform('EPSG:4326', 'EPSG:3857');

    			vectorLayer3857.getSource().addFeature(new ol.Feature(circle3857));
    		}

    		this.layer = vectorLayer3857;

    		options.map.olMap.addLayer(vectorLayer3857);
    	}

    	WPGMZA.OLCircle.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLCircle.prototype.constructor = WPGMZA.OLCircle;

    	WPGMZA.OLCircle.prototype.getStyleFromSettings = function()
    	{
    		var params = {};

    		if(this.settings.strokeOpacity)
    			params.stroke = new ol.style.Stroke({
    				color: WPGMZA.hexOpacityToRGBA(this.settings.strokeColor, this.settings.strokeOpacity)
    			});

    		if(this.settings.fillOpacity)
    			params.fill = new ol.style.Fill({
    				color: WPGMZA.hexOpacityToRGBA(this.settings.fillColor, this.settings.fillOpacity)
    			});

    		return params;
    	}

    	WPGMZA.OLCircle.prototype.updateStyleFromSettings = function()
    	{
    		// Re-create the style - working on it directly doesn't cause a re-render
    		var params = this.getStyleFromSettings();
    		this.olStyle = new ol.style.Style(params);
    		this.layer.setStyle(this.olStyle);
    	}

    })(jQuery);

    // js/v8/open-layers/ol-geocoder.js
    /**
     * @namespace WPGMZA
     * @module OLGeocoder
     * @requires WPGMZA.Geocoder
     */
    (function($) {

    	/**
    	 * @class OLGeocoder
    	 * @extends Geocoder
    	 * @summary OpenLayers geocoder - uses Nominatim by default
    	 */
    	WPGMZA.OLGeocoder = function()
    	{

    	}

    	WPGMZA.OLGeocoder.prototype = Object.create(WPGMZA.Geocoder.prototype);
    	WPGMZA.OLGeocoder.prototype.constructor = WPGMZA.OLGeocoder;

    	/**
    	 * @function getResponseFromCache
    	 * @access protected
    	 * @summary Tries to retrieve cached coordinates from server cache
    	 * @param {string} address The street address to geocode
    	 * @param {function} callback Where to send the results, as an array
    	 * @return {void}
    	 */
    	WPGMZA.OLGeocoder.prototype.getResponseFromCache = function(address, callback)
    	{
    		$.ajax(WPGMZA.ajaxurl, {
    			data: {
    				action: "wpgmza_query_nominatim_cache",
    				query: address
    			},
    			success: function(response, xhr, status) {
    				callback(response);
    			}
    		});
    	}

    	/**
    	 * @function getResponseFromNominatim
    	 * @access protected
    	 * @summary Queries Nominatim on the specified address
    	 * @param {object} options An object containing the options for geocoding, address is a mandatory field
    	 * @param {function} callback The function to send the results to, as an array
    	 */
    	WPGMZA.OLGeocoder.prototype.getResponseFromNominatim = function(options, callback)
    	{
    		var data = {
    			q: options.address,
    			format: "json"
    		};

    		if(options.country)
    			data.countrycodes = options.country;

    		$.ajax("https://nominatim.openstreetmap.org/search/", {
    			data: data,
    			success: function(response, xhr, status) {
    				callback(response);
    			},
    			error: function(response, xhr, status) {
    				callback(null, WPGMZA.Geocoder.FAIL)
    			}
    		});
    	}

    	/**
    	 * @function cacheResponse
    	 * @access protected
    	 * @summary Caches a response on the server, usually after it's been returned from Nominatim
    	 * @param {string} address The street address
    	 * @param {object|array} response The response to cache
    	 * @returns {void}
    	 */
    	WPGMZA.OLGeocoder.prototype.cacheResponse = function(address, response)
    	{
    		$.ajax(WPGMZA.ajaxurl, {
    			data: {
    				action: "wpgmza_store_nominatim_cache",
    				query: address,
    				response: JSON.stringify(response)
    			},
    			method: "POST"
    		});
    	}

    	/**
    	 * @function getLatLngFromAddress
    	 * @access public
    	 * @summary Attempts to geocode an address, firstly by checking the cache for previous
    	 * results, if this fails the Nominatim server will be queried, cached and sent to the
    	 * specified callback
    	 * @param {object} options An object containing the options for geocoding, address is a mandatory field
    	 * @param {function} callback The function to send the results to, as an array
    	 * @returns {void}
    	 */
    	WPGMZA.OLGeocoder.prototype.getLatLngFromAddress = function(options, callback)
    	{
    		var self = this;
    		var address = options.address;

    		var latLng;
    		if(latLng = WPGMZA.isLatLngString(address))
    			return WPGMZA.Geocoder.prototype.getLatLngFromAddress.call(this, options, callback);

    		function finish(response, status)
    		{
    			for(var i = 0; i < response.length; i++)
    			{
    				response[i].geometry = {
    					location: new WPGMZA.LatLng({
    						lat: parseFloat(response[i].lat),
    						lng: parseFloat(response[i].lon)
    					})
    				};

    				response[i].lat = parseFloat(response[i].lat);
    				response[i].lng = parseFloat(response[i].lon);
    			}

    			callback(response, status);
    		}

    		this.getResponseFromCache(address, function(response) {
    			if(response.length)
    			{
    				finish(response, WPGMZA.Geocoder.SUCCESS);
    				return;
    			}

    			self.getResponseFromNominatim(options, function(response, status) {
    				if(status == WPGMZA.Geocoder.FAIL)
    				{
    					callback(null, WPGMZA.Geocoder.FAIL);
    					return;
    				}

    				if(response.length == 0)
    				{
    					callback(response, WPGMZA.Geocoder.ZERO_RESULTS);
    					return;
    				}

    				finish(response, WPGMZA.Geocoder.SUCCESS);

    				self.cacheResponse(address, response);
    			});
    		});
    	}

    })(jQuery);

    // js/v8/open-layers/ol-info-window.js
    /**
     * @namespace WPGMZA
     * @module OLInfoWindow
     * @requires WPGMZA.InfoWindow
     * @pro-requires WPGMZA.ProInfoWindow
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLInfoWindow = function(mapObject)
    	{
    		var self = this;

    		Parent.call(this, mapObject);

    		this.element = $("<div class='ol-info-window-container ol-info-window-plain'></div>")[0];

    		$(this.element).on("click", ".ol-info-window-close", function(event) {
    			self.close();
    		});
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProInfoWindow;
    	else
    		Parent = WPGMZA.InfoWindow;

    	WPGMZA.OLInfoWindow.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLInfoWindow.prototype.constructor = WPGMZA.OLInfoWindow;

    	/**
    	 * Opens the info window
    	 * TODO: This should take a mapObject, not an event
    	 * @return boolean FALSE if the info window should not & will not open, TRUE if it will
    	 */
    	WPGMZA.OLInfoWindow.prototype.open = function(map, mapObject)
    	{
    		var self = this;
    		var latLng = mapObject.getPosition();

    		if(!WPGMZA.InfoWindow.prototype.open.call(this, map, mapObject))
    			return false;

    		if(this.overlay)
    			this.mapObject.map.olMap.removeOverlay(this.overlay);

    		this.overlay = new ol.Overlay({
    			element: this.element
    		});

    		this.overlay.setPosition(ol.proj.fromLonLat([
    			latLng.lng,
    			latLng.lat
    		]));
    		self.mapObject.map.olMap.addOverlay(this.overlay);

    		$(this.element).show();

    		this.dispatchEvent("infowindowopen");
    		$(this.element).trigger("infowindowopen.wpgmza");
    	}

    	WPGMZA.OLInfoWindow.prototype.close = function(event)
    	{
    		// TODO: Why? This shouldn't have to be here. Removing the overlay should hide the element (it doesn't)
    		$(this.element).hide();

    		if(!this.overlay)
    			return;

    		WPGMZA.InfoWindow.prototype.close.call(this);

    		this.mapObject.map.olMap.removeOverlay(this.overlay);
    		this.overlay = null;
    	}

    	WPGMZA.OLInfoWindow.prototype.setContent = function(html)
    	{
    		$(this.element).html("<i class='fa fa-times ol-info-window-close' aria-hidden='true'></i>" + html);
    	}

    })(jQuery);

    // js/v8/open-layers/ol-map.js
    /**
     * @namespace WPGMZA
     * @module OLMap
     * @requires WPGMZA.Map
     * @pro-requires WPGMZA.ProMap
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLMap = function(element, options)
    	{
    		var self = this;

    		Parent.call(this, element);

    		this.setOptions(options);

    		var viewOptions = this.settings.toOLViewOptions();

    		$(this.element).html("");

    		this.olMap = new ol.Map({
    			target: $(element)[0],
    			layers: [
    				new ol.layer.Tile({
    					source: new ol.source.OSM()
    				})
    			],
    			view: new ol.View(viewOptions)
    		});

    		// TODO: Re-implement using correct setting names
    		// Interactions
    		this.olMap.getInteractions().forEach(function(interaction) {

    			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
    			if(interaction instanceof ol.interaction.DragPan)
    				interaction.setActive( (this.settings.map_draggable ? false : true) );
    			else if(interaction instanceof ol.interaction.DoubleClickZoom)
    				interaction.setActive( (this.settings.map_clickzoom ? false : true) );
    			else if(interaction instanceof ol.interaction.MouseWheelZoom)
    				interaction.setActive( (this.settings.map_scroll ? false : true) );

    		}, this);

    		// Controls
    		this.olMap.getControls().forEach(function(control) {

    			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
    			if(control instanceof ol.control.Zoom && this.settings.map_zoom)
    				this.olMap.removeControl(control);

    		}, this);

    		if(!this.settings.map_full_screen_control)
    			this.olMap.addControl(new ol.control.FullScreen());

    		// Marker layer
    		this.markerLayer = new ol.layer.Vector({
    			source: new ol.source.Vector({
    				features: []
    			})
    		});
    		this.olMap.addLayer(this.markerLayer);

    		// Listen for end of pan so we can wrap longitude if needs be
    		this.olMap.on("moveend", function(event) {
    			self.wrapLongitude();
    			self.dispatchEvent("dragend");
    			self.onIdle();
    		});

    		// Listen for zoom
    		this.olMap.getView().on("change:resolution", function(event) {
    			self.dispatchEvent("zoom_changed");
    			self.dispatchEvent("zoomchanged");
    			self.onIdle();

    			$(self.element).trigger("zoomchanged.wpgmza");
    		});

    		// Listen for bounds changing
    		this.olMap.getView().on("change", function() {
    			// Wrap longitude
    			self.onBoundsChanged();
    		});
    		self.onBoundsChanged();

    		// Store locator center
    		var marker;
    		if(this.storeLocator && (marker = this.storeLocator.centerPointMarker))
    		{
    			this.olMap.addOverlay(marker.overlay);
    			marker.setVisible(false);
    		}

    		// Cycling layer
    		console.log(this.settings);

    		// Right click listener
    		$(this.element).on("click contextmenu", function(event) {

    			var isRight;
    			event = event || window.event;

    			if("which" in event)
    				isRight = event.which == 3;
    			else if("button" in event)
    				isRight = event.button == 2;

    			if(!isRight)
    				return;

    			return self.onRightClick(event);
    		});

    		// Dispatch event
    		if(!WPGMZA.isProVersion())
    		{
    			this.dispatchEvent("created");
    			WPGMZA.events.dispatchEvent({type: "mapcreated", map: this});
    		}
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProMap;
    	else
    		Parent = WPGMZA.Map;

    	WPGMZA.OLMap.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLMap.prototype.constructor = WPGMZA.OLMap;

    	WPGMZA.OLMap.prototype.wrapLongitude = function()
    	{
    		var center = this.getCenter();

    		if(center.lng >= -180 && center.lng <= 180)
    			return;

    		center.lng = center.lng - 360 * Math.floor(center.lng / 360);

    		if(center.lng > 180)
    			center.lng -= 360;

    		this.setCenter(center);
    	}

    	WPGMZA.OLMap.prototype.getCenter = function()
    	{
    		var lonLat = ol.proj.toLonLat(
    			this.olMap.getView().getCenter()
    		);
    		return {
    			lat: lonLat[1],
    			lng: lonLat[0]
    		};
    	}

    	WPGMZA.OLMap.prototype.setCenter = function(latLng)
    	{
    		var view = this.olMap.getView();

    		WPGMZA.Map.prototype.setCenter.call(this, latLng);

    		view.setCenter(ol.proj.fromLonLat([
    			latLng.lng,
    			latLng.lat
    		]));

    		this.wrapLongitude();

    		this.onBoundsChanged();
    	}

    	WPGMZA.OLMap.prototype.getBounds = function()
    	{
    		var bounds = this.olMap.getView().calculateExtent(this.olMap.getSize());

    		var topLeft = ol.proj.toLonLat([bounds[0], bounds[1]]);
    		var bottomRight = ol.proj.toLonLat([bounds[2], bounds[3]]);

    		return {
    			topLeft: {
    				lat: topLeft[1],
    				lng: topLeft[0]
    			},
    			bottomRight: {
    				lat: bottomRight[1],
    				lng: bottomRight[0]
    			}
    		};
    	}

    	/**
    	 * Fit to given boundaries
    	 * @return void
    	 */
    	WPGMZA.OLMap.prototype.fitBounds = function(southWest, northEast)
    	{
    		this.olMap.getView().fitExtent(
    			[southWest.lng, southWest.lat, northEast.lng, northEast.lat],
    			this.olMap.getSize()
    		);
    	}

    	WPGMZA.OLMap.prototype.panTo = function(latLng)
    	{
    		var view = this.olMap.getView();
    		view.animate({
    			center: ol.proj.fromLonLat([
    				parseFloat(latLng.lng),
    				parseFloat(latLng.lat),
    			]),
    			duration: 500
    		});
    	}

    	WPGMZA.OLMap.prototype.getZoom = function()
    	{
    		return Math.round( this.olMap.getView().getZoom() ) + 1;
    	}

    	WPGMZA.OLMap.prototype.setZoom = function(value)
    	{
    		this.olMap.getView().setZoom(value);
    	}

    	WPGMZA.OLMap.prototype.getMinZoom = function()
    	{
    		return this.olMap.getView().getMinZoom();
    	}

    	WPGMZA.OLMap.prototype.setMinZoom = function(value)
    	{
    		this.olMap.getView().setMinZoom(value);
    	}

    	WPGMZA.OLMap.prototype.getMaxZoom = function()
    	{
    		return this.olMap.getView().getMaxZoom();
    	}

    	WPGMZA.OLMap.prototype.setMaxZoom = function(value)
    	{
    		this.olMap.getView().setMaxZoom(value);
    	}

    	WPGMZA.OLMap.prototype.setOptions = function(options)
    	{
    		Parent.prototype.setOptions.call(this, options);

    		if(!this.olMap)
    			return;

    		this.olMap.getView().setProperties( this.settings.toOLViewOptions() );
    	}

    	/**
    	 * TODO: Consider moving all these functions to their respective classes, same on google map (DO IT!!! It's very misleading having them here)
    	 */
    	WPGMZA.OLMap.prototype.addMarker = function(marker)
    	{
    		this.olMap.addOverlay(marker.overlay);

    		Parent.prototype.addMarker.call(this, marker);
    	}

    	WPGMZA.OLMap.prototype.removeMarker = function(marker)
    	{
    		this.olMap.removeOverlay(marker.overlay);

    		Parent.prototype.removeMarker.call(this, marker);
    	}

    	WPGMZA.OLMap.prototype.addPolygon = function(polygon)
    	{
    		this.olMap.addLayer(polygon.layer);

    		Parent.prototype.addPolygon.call(this, polygon);
    	}

    	WPGMZA.OLMap.prototype.removePolygon = function(polygon)
    	{
    		this.olMap.removeLayer(polygon.layer);

    		Parent.prototype.removePolygon.call(this, polygon);
    	}

    	WPGMZA.OLMap.prototype.addPolyline = function(polyline)
    	{
    		this.olMap.addLayer(polyline.layer);

    		Parent.prototype.addPolyline.call(this, polyline);
    	}

    	WPGMZA.OLMap.prototype.removePolyline = function(polyline)
    	{
    		this.olMap.removeLayer(polyline.layer);

    		Parent.prototype.removePolyline.call(this, polyline);
    	}

    	WPGMZA.OLMap.prototype.addCircle = function(circle)
    	{
    		this.olMap.addLayer(circle.layer);

    		Parent.prototype.addCircle.call(this, circle);
    	}

    	WPGMZA.OLMap.prototype.removeCircle = function(circle)
    	{
    		this.olMap.removeLayer(circle.layer);

    		Parent.prototype.removeCircle.call(this, circle);
    	}

    	WPGMZA.OLMap.prototype.pixelsToLatLng = function(x, y)
    	{
    		if(y == undefined)
    		{
    			if("x" in x && "y" in x)
    			{
    				y = x.y;
    				x = x.x;
    			}
    			else
    				console.warn("Y coordinate undefined in pixelsToLatLng (did you mean to pass 2 arguments?)");
    		}

    		var coord = this.olMap.getCoordinateFromPixel([x, y]);

    		if(!coord)
    			return {
    				x: null,
    				y: null
    			};

    		var lonLat = ol.proj.toLonLat(coord);
    		return {
    			lat: lonLat[1],
    			lng: lonLat[0]
    		};
    	}

    	WPGMZA.OLMap.prototype.latLngToPixels = function(latLng)
    	{
    		var coord = ol.proj.fromLonLat([latLng.lng, latLng.lat]);
    		var pixel = this.olMap.getPixelFromCoordinate(coord);

    		if(!pixel)
    			return {
    				x: null,
    				y: null
    			};

    		return {
    			x: pixel[0],
    			y: pixel[1]
    		};
    	}

    	WPGMZA.OLMap.prototype.enableBicycleLayer = function(value)
    	{
    		if(value)
    		{
    			if(!this.bicycleLayer)
    				this.bicycleLayer = new ol.layer.Tile({
    					source: new ol.source.OSM({
    						url: "http://{a-c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"
    					})
    				});

    			this.olMap.addLayer(this.bicycleLayer);
    		}
    		else
    		{
    			if(!this.bicycleLayer)
    				return;

    			this.olMap.removeLayer(this.bicycleLayer);
    		}
    	}

    	WPGMZA.OLMap.prototype.onElementResized = function(event)
    	{
    		this.olMap.updateSize();
    	}

    	WPGMZA.OLMap.prototype.onRightClick = function(event)
    	{
    		if($(event.target).closest(".ol-marker, .wpgmza_modern_infowindow, .wpgmza-modern-store-locator").length)
    			return true;

    		var parentOffset = $(this.element).offset();
    		var relX = event.pageX - parentOffset.left;
    		var relY = event.pageY - parentOffset.top;
    		var latLng = this.pixelsToLatLng(relX, relY);

    		this.trigger({type: "rightclick", latLng: latLng});
    		$(this.element).trigger("rightclick.wpgmza");

    		event.preventDefault();
    		return false;
    	}

    })(jQuery);

    // js/v8/open-layers/ol-marker.js
    /**
     * @namespace WPGMZA
     * @module OLMarker
     * @requires WPGMZA.Marker
     * @pro-requires WPGMZA.ProMarker
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLMarker = function(row)
    	{
    		var self = this;

    		Parent.call(this, row);

    		var origin = ol.proj.fromLonLat([
    			parseFloat(this.lng),
    			parseFloat(this.lat)
    		]);

    		this.element = $("<div class='ol-marker'><img src='" + WPGMZA.settings.default_marker_icon + "'/></div>")[0];

    		$(this.element).on("click", function(event) {
    			self.dispatchEvent("click");
    			self.dispatchEvent("select");
    		});

    		$(this.element).on("mouseover", function(event) {
    			self.dispatchEvent("mouseover");
    		});

    		this.overlay = new ol.Overlay({
    			element: this.element
    		});
    		this.overlay.setPosition(origin);

    		if(this.animation)
    			this.setAnimation(this.animation);

    		this.setLabel(this.settings.label);

    		if(row.draggable)
    			this.setDraggable(true);

    		this.trigger("init");
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProMarker;
    	else
    		Parent = WPGMZA.Marker;
    	WPGMZA.OLMarker.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLMarker.prototype.constructor = WPGMZA.OLMarker;

    	WPGMZA.OLMarker.prototype.addLabel = function()
    	{
    		this.setLabel(this.getLabelText());
    	}

    	WPGMZA.OLMarker.prototype.setLabel = function(label)
    	{
    		if(!label)
    		{
    			if(this.label)
    				$(this.element).find(".ol-marker-label").remove();

    			return;
    		}

    		if(!this.label)
    		{
    			this.label = $("<div class='ol-marker-label'/>");
    			$(this.element).append(this.label);
    		}

    		this.label.html(label);
    	}

    	WPGMZA.OLMarker.prototype.setVisible = function(visible)
    	{
    		Parent.prototype.setVisible(visible);

    		this.overlay.getElement().style.display = (visible ? "block" : "none");
    	}

    	WPGMZA.OLMarker.prototype.setPosition = function(latLng)
    	{
    		Parent.prototype.setPosition.call(this, latLng);

    		var origin = ol.proj.fromLonLat([
    			parseFloat(this.lng),
    			parseFloat(this.lat)
    		]);

    		this.overlay.setPosition(origin);
    	}

    	WPGMZA.OLMarker.prototype.setOffset = function(x, y)
    	{
    		this.element.style.position = "relative";
    		this.element.style.left = x + "px";
    		this.element.style.top = y + "px";
    	}

    	WPGMZA.OLMarker.prototype.setAnimation = function(anim)
    	{
    		Parent.prototype.setAnimation.call(this, anim);

    		switch(anim)
    		{
    			case WPGMZA.Marker.ANIMATION_NONE:
    				$(this.element).removeAttr("data-anim");
    				break;

    			case WPGMZA.Marker.ANIMATION_BOUNCE:
    				$(this.element).attr("data-anim", "bounce");
    				break;

    			case WPGMZA.Marker.ANIMATION_DROP:
    				$(this.element).attr("data-anim", "drop");
    				break;
    		}
    	}

    	WPGMZA.OLMarker.prototype.setDraggable = function(draggable)
    	{
    		var self = this;

    		if(draggable)
    		{
    			var options = {
    				disabled: false
    			};

    			if(!this.jQueryDraggableInitialized)
    			{
    				options.stop = function(event) {
    					self.onDragEnd(event);
    				}
    			}

    			$(this.element).draggable(options);
    		}
    		else
    			$(this.element).draggable({disabled: true});
    	}

    	WPGMZA.OLMarker.prototype.onDragEnd = function(event)
    	{
    		var offset = {
    			top:	parseFloat( $(this.element).css("top").match(/-?\d+/)[0] ),
    			left:	parseFloat( $(this.element).css("left").match(/-?\d+/)[0] )
    		};

    		$(this.element).css({
    			top: 	"0px",
    			left: 	"0px"
    		});

    		console.log(offset);

    		var currentLatLng 		= this.getPosition();
    		var pixelsBeforeDrag 	= this.map.latLngToPixels(currentLatLng);
    		var pixelsAfterDrag		= {
    			x: pixelsBeforeDrag.x + offset.left,
    			y: pixelsBeforeDrag.y + offset.top
    		};
    		var latLngAfterDrag		= this.map.pixelsToLatLng(pixelsAfterDrag);

    		this.setPosition(latLngAfterDrag);

    		this.trigger({type: "dragend", latLng: latLngAfterDrag})
    		$(this.element).trigger("dragend.wpgmza");
    	}

    })(jQuery);

    // js/v8/open-layers/ol-modern-store-locator-circle.js
    /**
     * @namespace WPGMZA
     * @module OLModernStoreLocatorCircle
     * @requires WPGMZA.ModernStoreLocatorCircle
     */
    (function($) {

    	WPGMZA.OLModernStoreLocatorCircle = function(map, settings)
    	{
    		WPGMZA.ModernStoreLocatorCircle.call(this, map, settings);
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype = Object.create(WPGMZA.ModernStoreLocatorCircle.prototype);
    	WPGMZA.OLModernStoreLocatorCircle.prototype.constructor = WPGMZA.OLModernStoreLocatorCircle;

    	WPGMZA.OLModernStoreLocatorCircle.prototype.initCanvasLayer = function()
    	{
    		var self = this;
    		var mapElement = $(this.map.element);
    		var olViewportElement = mapElement.children(".ol-viewport");

    		this.canvas = document.createElement("canvas");
    		this.canvas.className = "wpgmza-ol-canvas-overlay";
    		mapElement.append(this.canvas);

    		this.renderFunction = function(event) {

    			if(self.canvas.width != olViewportElement.width() || self.canvas.height != olViewportElement.height())
    			{
    				self.canvas.width = olViewportElement.width();
    				self.canvas.height = olViewportElement.height();

    				$(this.canvas).css({
    					width: olViewportElement.width() + "px",
    					height: olViewportElement.height() + "px"
    				});
    			}

    			self.draw();
    		};

    		this.map.olMap.on("postrender", this.renderFunction);
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getContext = function(type)
    	{
    		return this.canvas.getContext(type);
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getCanvasDimensions = function()
    	{
    		return {
    			width: this.canvas.width,
    			height: this.canvas.height
    		};
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getCenterPixels = function()
    	{
    		var center = this.map.latLngToPixels(this.settings.center);

    		return center;
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getWorldOriginOffset = function()
    	{
    		return {
    			x: 0,
    			y: 0
    		};
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getTransformedRadius = function(km)
    	{
    		var center = new WPGMZA.LatLng(this.settings.center);
    		var outer = new WPGMZA.LatLng(center);

    		outer.moveByDistance(km, 90);

    		var centerPixels = this.map.latLngToPixels(center);
    		var outerPixels = this.map.latLngToPixels(outer);

    		return Math.abs(outerPixels.x - centerPixels.x);

    		if(!window.testMarker){
    			window.testMarker = WPGMZA.Marker.createInstance({
    				position: outer
    			});
    			WPGMZA.maps[0].addMarker(window.testMarker);
    		}

    		return 100;
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.getScale = function()
    	{
    		return 1;
    	}

    	WPGMZA.OLModernStoreLocatorCircle.prototype.destroy = function()
    	{
    		$(this.canvas).remove();

    		this.map.olMap.un("postrender", this.renderFunction);
    		this.map = null;
    		this.canvas = null;
    	}

    })(jQuery);

    // js/v8/open-layers/ol-modern-store-locator.js
    /**
     * @namespace WPGMZA
     * @module OLModernStoreLocator
     * @requires WPGMZA.ModernStoreLocator
     */
    (function($) {

    	WPGMZA.OLModernStoreLocator = function(map_id)
    	{
    		var element;

    		WPGMZA.ModernStoreLocator.call(this, map_id);

    		if(WPGMZA.isProVersion())
    			element = $(".wpgmza_map[data-map-id='" + map_id + "']");
    		else
    			element = $("#wpgmza_map");

    		element.append(this.element);
    	}

    	WPGMZA.OLModernStoreLocator.prototype = Object.create(WPGMZA.ModernStoreLocator);
    	WPGMZA.OLModernStoreLocator.prototype.constructor = WPGMZA.OLModernStoreLocator;

    })(jQuery);

    // js/v8/open-layers/ol-polygon.js
    /**
     * @namespace WPGMZA
     * @module OLPolygon
     * @requires WPGMZA.Polygon
     * @pro-requires WPGMZA.ProPolygon
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLPolygon = function(row, olFeature)
    	{
    		var self = this;

    		Parent.call(this, row, olFeature);

    		this.olStyle = new ol.style.Style();

    		if(olFeature)
    		{
    			this.olFeature = olFeature;
    		}
    		else
    		{
    			var coordinates = [[]];

    			if(row && row.points)
    			{
    				var paths = this.parseGeometry(row.points);

    				for(var i = 0; i < paths.length; i++)
    					coordinates[0].push(ol.proj.fromLonLat([
    						parseFloat(paths[i].lng),
    						parseFloat(paths[i].lat)
    					]));

    				this.olStyle = new ol.style.Style(this.getStyleFromSettings());
    			}

    			this.olFeature = new ol.Feature({
    				geometry: new ol.geom.Polygon(coordinates)
    			});
    		}

    		this.layer = new ol.layer.Vector({
    			source: new ol.source.Vector({
    				features: [this.olFeature]
    			}),
    			style: this.olStyle
    		});

    		this.layer.getSource().getFeatures()[0].setProperties({
    			wpgmzaPolygon: this
    		});
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProPolygon;
    	else
    		Parent = WPGMZA.Polygon;

    	WPGMZA.OLPolygon.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLPolygon.prototype.constructor = WPGMZA.OLPolygon;

    	WPGMZA.OLPolygon.prototype.getStyleFromSettings = function()
    	{
    		var params = {};

    		if(this.settings.strokeOpacity)
    			params.stroke = new ol.style.Stroke({
    				color: WPGMZA.hexOpacityToRGBA(this.settings.strokeColor, this.settings.strokeOpacity)
    			});

    		if(this.settings.fillOpacity)
    			params.fill = new ol.style.Fill({
    				color: WPGMZA.hexOpacityToRGBA(this.settings.fillColor, this.settings.fillOpacity)
    			});

    		return params;
    	}

    	WPGMZA.OLPolygon.prototype.updateStyleFromSettings = function()
    	{
    		// Re-create the style - working on it directly doesn't cause a re-render
    		var params = this.getStyleFromSettings();
    		this.olStyle = new ol.style.Style(params);
    		this.layer.setStyle(this.olStyle);
    	}

    	WPGMZA.OLPolygon.prototype.setEditable = function(editable)
    	{

    	}

    	WPGMZA.OLPolygon.prototype.toJSON = function()
    	{
    		var result = Parent.prototype.toJSON.call(this);
    		var coordinates = this.olFeature.getGeometry().getCoordinates()[0];

    		result.points = [];

    		for(var i = 0; i < coordinates.length; i++)
    		{
    			var lonLat = ol.proj.toLonLat(coordinates[i]);
    			var latLng = {
    				lat: lonLat[1],
    				lng: lonLat[0]
    			};
    			result.points.push(latLng);
    		}

    		return result;
    	}

    })(jQuery);

    // js/v8/open-layers/ol-polyline.js
    /**
     * @namespace WPGMZA
     * @module OLPolyline
     * @requires WPGMZA.Polyline
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLPolyline = function(row, olFeature)
    	{
    		var self = this;

    		WPGMZA.Polyline.call(this, row);

    		this.olStyle = new ol.style.Style();

    		if(olFeature)
    		{
    			this.olFeature = olFeature;
    		}
    		else
    		{
    			var coordinates = [];

    			if(row && row.points)
    			{
    				var path = this.parseGeometry(row.points);

    				for(var i = 0; i < path.length; i++)
    					coordinates.push(ol.proj.fromLonLat([
    						parseFloat(path[i].lng),
    						parseFloat(path[i].lat)
    					]));
    			}

    			var params = this.getStyleFromSettings();
    			this.olStyle = new ol.style.Style(params);

    			this.olFeature = new ol.Feature({
    				geometry: new ol.geom.LineString(coordinates)
    			});
    		}

    		this.layer = new ol.layer.Vector({
    			source: new ol.source.Vector({
    				features: [this.olFeature]
    			}),
    			style: this.olStyle
    		});

    		this.layer.getSource().getFeatures()[0].setProperties({
    			wpgmzaPolyling: this
    		});
    	}

    	Parent = WPGMZA.Polyline;

    	WPGMZA.OLPolyline.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLPolyline.prototype.constructor = WPGMZA.OLPolyline;

    	WPGMZA.OLPolyline.prototype.getStyleFromSettings = function()
    	{
    		var params = {};

    		if(this.settings.strokeOpacity)
    			params.stroke = new ol.style.Stroke({
    				color: WPGMZA.hexOpacityToRGBA(this.settings.strokeColor, this.settings.strokeOpacity),
    				width: parseInt(this.settings.strokeWeight)
    			});

    		return params;
    	}

    	WPGMZA.OLPolyline.prototype.updateStyleFromSettings = function()
    	{
    		// Re-create the style - working on it directly doesn't cause a re-render
    		var params = this.getStyleFromSettings();
    		this.olStyle = new ol.style.Style(params);
    		this.layer.setStyle(this.olStyle);
    	}

    	WPGMZA.OLPolyline.prototype.setEditable = function(editable)
    	{

    	}

    	WPGMZA.OLPolyline.prototype.setPoints = function(points)
    	{
    		if(this.olFeature)
    			this.layer.getSource().removeFeature(this.olFeature);

    		var coordinates = [];

    		for(var i = 0; i < points.length; i++)
    			coordinates.push(ol.proj.fromLonLat([
    				parseFloat(points[i].lng),
    				parseFloat(points[i].lat)
    			]));

    		this.olFeature = new ol.Feature({
    			geometry: new ol.geom.LineString(coordinates)
    		});

    		this.layer.getSource().addFeature(this.olFeature);
    	}

    	WPGMZA.OLPolyline.prototype.toJSON = function()
    	{
    		var result = Parent.prototype.toJSON.call(this);
    		var coordinates = this.olFeature.getGeometry().getCoordinates();

    		result.points = [];

    		for(var i = 0; i < coordinates.length; i++)
    		{
    			var lonLat = ol.proj.toLonLat(coordinates[i]);
    			var latLng = {
    				lat: lonLat[1],
    				lng: lonLat[0]
    			};
    			result.points.push(latLng);
    		}

    		return result;
    	}

    })(jQuery);