text: /**
   * @namespace WPGMZA
   * @module LatLng
   * @requires WPGMZA
   */
  jQuery(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)
  		{
  			// TODO: Support latlng string
  			
  			if(typeof arg == "string")
  			{
  				var m;
  				
  				if(!(m = arg.match(WPGMZA.LatLng.REGEXP)))
  					throw new Error("Invalid LatLng string");
  				
  				arg = {
  					lat: m[1],
  					lng: m[3]
  				};
  			}
  			
  			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.REGEXP = /^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/;
  	
  	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.fromGoogleLatLng = function(googleLatLng)
  	{
  		return new WPGMZA.LatLng(
  			googleLatLng.lat(),
  			googleLatLng.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;
  	}
  	
  });