text: /*
   * L.Util contains various utility functions used throughout Leaflet code.
   */
  
  L.Util = {
  	extend: function (dest) { // (Object[, Object, ...]) ->
  		var sources = Array.prototype.slice.call(arguments, 1),
  		    i, j, len, src;
  
  		for (j = 0, len = sources.length; j < len; j++) {
  			src = sources[j] || {};
  			for (i in src) {
  				if (src.hasOwnProperty(i)) {
  					dest[i] = src[i];
  				}
  			}
  		}
  		return dest;
  	},
  
  	bind: function (fn, obj) { // (Function, Object) -> Function
  		var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;
  		return function () {
  			return fn.apply(obj, args || arguments);
  		};
  	},
  
  	stamp: (function () {
  		var lastId = 0, key = '_leaflet_id';
  		return function (/*Object*/ obj) {
  			obj[key] = obj[key] || ++lastId;
  			return obj[key];
  		};
  	}()),
  
  	limitExecByInterval: function (fn, time, context) {
  		var lock, execOnUnlock;
  
  		return function wrapperFn() {
  			var args = arguments;
  
  			if (lock) {
  				execOnUnlock = true;
  				return;
  			}
  
  			lock = true;
  
  			setTimeout(function () {
  				lock = false;
  
  				if (execOnUnlock) {
  					wrapperFn.apply(context, args);
  					execOnUnlock = false;
  				}
  			}, time);
  
  			fn.apply(context, args);
  		};
  	},
  
  	falseFn: function () {
  		return false;
  	},
  
  	formatNum: function (num, digits) {
  		var pow = Math.pow(10, digits || 5);
  		return Math.round(num * pow) / pow;
  	},
  
  	splitWords: function (str) {
  		return str.replace(/^\s+|\s+$/g, '').split(/\s+/);
  	},
  
  	setOptions: function (obj, options) {
  		obj.options = L.extend({}, obj.options, options);
  		return obj.options;
  	},
  
  	getParamString: function (obj, existingUrl) {
  		var params = [];
  		for (var i in obj) {
  			if (obj.hasOwnProperty(i)) {
  				params.push(encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]));
  			}
  		}
  		return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
  	},
  
  	template: function (str, data) {
  		return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
  			var value = data[key];
  			if (!data.hasOwnProperty(key)) {
  				throw new Error('No value provided for variable ' + str);
  			}
  			return value;
  		});
  	},
  
  	isArray: function (obj) {
  		return (Object.prototype.toString.call(obj) === '[object Array]');
  	},
  
  	emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
  };
  
  (function () {
  
  	// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  
  	function getPrefixed(name) {
  		var i, fn,
  		    prefixes = ['webkit', 'moz', 'o', 'ms'];
  
  		for (i = 0; i < prefixes.length && !fn; i++) {
  			fn = window[prefixes[i] + name];
  		}
  
  		return fn;
  	}
  
  	var lastTime = 0;
  
  	function timeoutDefer(fn) {
  		var time = +new Date(),
  		    timeToCall = Math.max(0, 16 - (time - lastTime));
  
  		lastTime = time + timeToCall;
  		return window.setTimeout(fn, timeToCall);
  	}
  
  	var requestFn = window.requestAnimationFrame ||
  	        getPrefixed('RequestAnimationFrame') || timeoutDefer;
  
  	var cancelFn = window.cancelAnimationFrame ||
  	        getPrefixed('CancelAnimationFrame') ||
  	        getPrefixed('CancelRequestAnimationFrame') ||
  	        function (id) { window.clearTimeout(id); };
  
  
  	L.Util.requestAnimFrame = function (fn, context, immediate, element) {
  		fn = L.bind(fn, context);
  
  		if (immediate && requestFn === timeoutDefer) {
  			fn();
  		} else {
  			return requestFn.call(window, fn, element);
  		}
  	};
  
  	L.Util.cancelAnimFrame = function (id) {
  		if (id) {
  			cancelFn.call(window, id);
  		}
  	};
  
  }());
  
  // shortcuts for most used utility functions
  L.extend = L.Util.extend;
  L.bind = L.Util.bind;
  L.stamp = L.Util.stamp;
  L.setOptions = L.Util.setOptions;
  