text: /**
   * History.js Core
   * @author Benjamin Arthur Lupton <contact@balupton.com>
   * @copyright 2010-2011 Benjamin Arthur Lupton <contact@balupton.com>
   * @license New BSD License <http://creativecommons.org/licenses/BSD/>
   */
  
  (function(window,undefined){
  	"use strict";
  
  	// --------------------------------------------------------------------------
  	// Initialise
  
  	// Localise Globals
  	var
  		console = window.console||undefined, // Prevent a JSLint complain
  		document = window.document, // Make sure we are using the correct document
  		navigator = window.navigator, // Make sure we are using the correct navigator
  		amplify = window.amplify||false, // Amplify.js
  		setTimeout = window.setTimeout,
  		clearTimeout = window.clearTimeout,
  		setInterval = window.setInterval,
  		JSON = window.JSON,
  		History = window.History = window.History||{}, // Public History Object
  		history = window.history; // Old History Object
  
  	// MooTools Compatibility
  	JSON.stringify = JSON.stringify||JSON.encode;
  	JSON.parse = JSON.parse||JSON.decode;
  
  	// Check Existence
  	if ( typeof History.init !== 'undefined' ) {
  		throw new Error('History.js Core has already been loaded...');
  	}
  
  	// Initialise History
  	History.init = function(){
  		// Check Load Status of Adapter
  		if ( typeof History.Adapter === 'undefined' ) {
  			return false;
  		}
  
  		// Check Load Status of Core
  		if ( typeof History.initCore !== 'undefined' ) {
  			History.initCore();
  		}
  
  		// Check Load Status of HTML4 Support
  		if ( typeof History.initHtml4 !== 'undefined' ) {
  			History.initHtml4();
  		}
  
  		// Return true
  		return true;
  	};
  
  	// --------------------------------------------------------------------------
  	// Initialise Core
  
  	// Initialise Core
  	History.initCore = function(){
  		// Initialise
  		if ( typeof History.initCore.initialized !== 'undefined' ) {
  			// Already Loaded
  			return false;
  		}
  		else {
  			History.initCore.initialized = true;
  		}
  
  		// ----------------------------------------------------------------------
  		// Options
  
  		/**
  		 * History.options
  		 * Configurable options
  		 */
  		History.options = History.options||{};
  
  		/**
  		 * History.options.hashChangeInterval
  		 * How long should the interval be before hashchange checks
  		 */
  		History.options.hashChangeInterval = History.options.hashChangeInterval || 100;
  
  		/**
  		 * History.options.safariPollInterval
  		 * How long should the interval be before safari poll checks
  		 */
  		History.options.safariPollInterval = History.options.safariPollInterval || 500;
  
  		/**
  		 * History.options.doubleCheckInterval
  		 * How long should the interval be before we perform a double check
  		 */
  		History.options.doubleCheckInterval = History.options.doubleCheckInterval || 500;
  
  		/**
  		 * History.options.storeInterval
  		 * How long should we wait between store calls
  		 */
  		History.options.storeInterval = History.options.storeInterval || 1000;
  
  		/**
  		 * History.options.busyDelay
  		 * How long should we wait between busy events
  		 */
  		History.options.busyDelay = History.options.busyDelay || 250;
  
  		/**
  		 * History.options.debug
  		 * If true will enable debug messages to be logged
  		 */
  		History.options.debug = History.options.debug || false;
  
  		/**
  		 * History.options.initialTitle
  		 * What is the title of the initial state
  		 */
  		History.options.initialTitle = History.options.initialTitle || document.title;
  
  
  		// ----------------------------------------------------------------------
  		// Debug
  
  		/**
  		 * History.debug(message,...)
  		 * Logs the passed arguments if debug enabled
  		 */
  		History.debug = function(){
  			if ( (History.options.debug||false) ) {
  				History.log.apply(History,arguments);
  			}
  		};
  
  		/**
  		 * History.log(message,...)
  		 * Logs the passed arguments
  		 */
  		History.log = function(){
  			// Prepare
  			var
  				consoleExists = !(typeof console === 'undefined' || typeof console.log === 'undefined' || typeof console.log.apply === 'undefined'),
  				textarea = document.getElementById('log'),
  				message,
  				i,n
  				;
  
  			// Write to Console
  			if ( consoleExists ) {
  				var args = Array.prototype.slice.call(arguments);
  				message = args.shift();
  				if ( typeof console.debug !== 'undefined' ) {
  					console.debug.apply(console,[message,args]);
  				}
  				else {
  					console.log.apply(console,[message,args]);
  				}
  			}
  			else {
  				message = ("\n"+arguments[0]+"\n");
  			}
  
  			// Write to log
  			for ( i=1,n=arguments.length; i<n; ++i ) {
  				var arg = arguments[i];
  				if ( typeof arg === 'object' && typeof JSON !== 'undefined' ) {
  					try {
  						arg = JSON.stringify(arg);
  					}
  					catch ( Exception ) {
  						// Recursive Object
  					}
  				}
  				message += "\n"+arg+"\n";
  			}
  
  			// Textarea
  			if ( textarea ) {
  				textarea.value += message+"\n-----\n";
  				textarea.scrollTop = textarea.scrollHeight - textarea.clientHeight;
  			}
  			// No Textarea, No Console
  			else if ( !consoleExists ) {
  				alert(message);
  			}
  
  			// Return true
  			return true;
  		};
  
  		// ----------------------------------------------------------------------
  		// Emulated Status
  
  		/**
  		 * History.getInternetExplorerMajorVersion()
  		 * Get's the major version of Internet Explorer
  		 * @return {integer}
  		 * @license Public Domain
  		 * @author Benjamin Arthur Lupton <contact@balupton.com>
  		 * @author James Padolsey <https://gist.github.com/527683>
  		 */
  		History.getInternetExplorerMajorVersion = function(){
  			var result = History.getInternetExplorerMajorVersion.cached =
  					(typeof History.getInternetExplorerMajorVersion.cached !== 'undefined')
  				?	History.getInternetExplorerMajorVersion.cached
  				:	(function(){
  						var v = 3,
  								div = document.createElement('div'),
  								all = div.getElementsByTagName('i');
  						while ( (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->') && all[0] ) {}
  						return (v > 4) ? v : false;
  					})()
  				;
  			return result;
  		};
  
  		/**
  		 * History.isInternetExplorer()
  		 * Are we using Internet Explorer?
  		 * @return {boolean}
  		 * @license Public Domain
  		 * @author Benjamin Arthur Lupton <contact@balupton.com>
  		 */
  		History.isInternetExplorer = function(){
  			var result =
  				History.isInternetExplorer.cached =
  				(typeof History.isInternetExplorer.cached !== 'undefined')
  					?	History.isInternetExplorer.cached
  					:	Boolean(History.getInternetExplorerMajorVersion())
  				;
  			return result;
  		};
  
  		/**
  		 * History.emulated
  		 * Which features require emulating?
  		 */
  		History.emulated = {
  			pushState: !Boolean(
  				window.history && window.history.pushState && window.history.replaceState
  				&& !(
  					(/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i).test(navigator.userAgent) /* disable for versions of iOS before version 4.3 (8F190) */
  					|| (/AppleWebKit\/5([0-2]|3[0-2])/i).test(navigator.userAgent) /* disable for the mercury iOS browser, or at least older versions of the webkit engine */
  				)
  			),
  			hashChange: Boolean(
  				!(('onhashchange' in window) || ('onhashchange' in document))
  				||
  				(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8)
  			)
  		};
  
  		/**
  		 * History.enabled
  		 * Is History enabled?
  		 */
  		History.enabled = !History.emulated.pushState;
  
  		/**
  		 * History.bugs
  		 * Which bugs are present
  		 */
  		History.bugs = {
  			/**
  			 * Safari 5 and Safari iOS 4 fail to return to the correct state once a hash is replaced by a `replaceState` call
  			 * https://bugs.webkit.org/show_bug.cgi?id=56249
  			 */
  			setHash: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
  
  			/**
  			 * Safari 5 and Safari iOS 4 sometimes fail to apply the state change under busy conditions
  			 * https://bugs.webkit.org/show_bug.cgi?id=42940
  			 */
  			safariPoll: Boolean(!History.emulated.pushState && navigator.vendor === 'Apple Computer, Inc.' && /AppleWebKit\/5([0-2]|3[0-3])/.test(navigator.userAgent)),
  
  			/**
  			 * MSIE 6 and 7 sometimes do not apply a hash even it was told to (requiring a second call to the apply function)
  			 */
  			ieDoubleCheck: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 8),
  
  			/**
  			 * MSIE 6 requires the entire hash to be encoded for the hashes to trigger the onHashChange event
  			 */
  			hashEscape: Boolean(History.isInternetExplorer() && History.getInternetExplorerMajorVersion() < 7)
  		};
  
  		/**
  		 * History.isEmptyObject(obj)
  		 * Checks to see if the Object is Empty
  		 * @param {Object} obj
  		 * @return {boolean}
  		 */
  		History.isEmptyObject = function(obj) {
  			for ( var name in obj ) {
  				return false;
  			}
  			return true;
  		};
  
  		/**
  		 * History.cloneObject(obj)
  		 * Clones a object
  		 * @param {Object} obj
  		 * @return {Object}
  		 */
  		History.cloneObject = function(obj) {
  			var hash,newObj;
  			if ( obj ) {
  				hash = JSON.stringify(obj);
  				newObj = JSON.parse(hash);
  			}
  			else {
  				newObj = {};
  			}
  			return newObj;
  		};
  
  		// ----------------------------------------------------------------------
  		// URL Helpers
  
  		/**
  		 * History.getRootUrl()
  		 * Turns "http://mysite.com/dir/page.html?asd" into "http://mysite.com"
  		 * @return {String} rootUrl
  		 */
  		History.getRootUrl = function(){
  			// Create
  			var rootUrl = document.location.protocol+'//'+(document.location.hostname||document.location.host);
  			if ( document.location.port||false ) {
  				rootUrl += ':'+document.location.port;
  			}
  			rootUrl += '/';
  
  			// Return
  			return rootUrl;
  		};
  
  		/**
  		 * History.getBaseHref()
  		 * Fetches the `href` attribute of the `<base href="...">` element if it exists
  		 * @return {String} baseHref
  		 */
  		History.getBaseHref = function(){
  			// Create
  			var
  				baseElements = document.getElementsByTagName('base'),
  				baseElement = null,
  				baseHref = '';
  
  			// Test for Base Element
  			if ( baseElements.length === 1 ) {
  				// Prepare for Base Element
  				baseElement = baseElements[0];
  				baseHref = baseElement.href.replace(/[^\/]+$/,'');
  			}
  
  			// Adjust trailing slash
  			baseHref = baseHref.replace(/\/+$/,'');
  			if ( baseHref ) baseHref += '/';
  
  			// Return
  			return baseHref;
  		};
  
  		/**
  		 * History.getBaseUrl()
  		 * Fetches the baseHref or basePageUrl or rootUrl (whichever one exists first)
  		 * @return {String} baseUrl
  		 */
  		History.getBaseUrl = function(){
  			// Create
  			var baseUrl = History.getBaseHref()||History.getBasePageUrl()||History.getRootUrl();
  
  			// Return
  			return baseUrl;
  		};
  
  		/**
  		 * History.getPageUrl()
  		 * Fetches the URL of the current page
  		 * @return {String} pageUrl
  		 */
  		History.getPageUrl = function(){
  			// Fetch
  			var
  				State = History.getState(false,false),
  				stateUrl = (State||{}).url||document.location.href;
  
  			// Create
  			var pageUrl = stateUrl.replace(/\/+$/,'').replace(/[^\/]+$/,function(part,index,string){
  				return (/\./).test(part) ? part : part+'/';
  			});
  
  			// Return
  			return pageUrl;
  		};
  
  		/**
  		 * History.getBasePageUrl()
  		 * Fetches the Url of the directory of the current page
  		 * @return {String} basePageUrl
  		 */
  		History.getBasePageUrl = function(){
  			// Create
  			var basePageUrl = document.location.href.replace(/[#\?].*/,'').replace(/[^\/]+$/,function(part,index,string){
  				return (/[^\/]$/).test(part) ? '' : part;
  			}).replace(/\/+$/,'')+'/';
  
  			// Return
  			return basePageUrl;
  		};
  
  		/**
  		 * History.getFullUrl(url)
  		 * Ensures that we have an absolute URL and not a relative URL
  		 * @param {string} url
  		 * @param {Boolean} allowBaseHref
  		 * @return {string} fullUrl
  		 */
  		History.getFullUrl = function(url,allowBaseHref){
  			// Prepare
  			var fullUrl = url, firstChar = url.substring(0,1);
  			allowBaseHref = (typeof allowBaseHref === 'undefined') ? true : allowBaseHref;
  
  			// Check
  			if ( /[a-z]+\:\/\//.test(url) ) {
  				// Full URL
  			}
  			else if ( firstChar === '/' ) {
  				// Root URL
  				fullUrl = History.getRootUrl()+url.replace(/^\/+/,'');
  			}
  			else if ( firstChar === '#' ) {
  				// Anchor URL
  				fullUrl = History.getPageUrl().replace(/#.*/,'')+url;
  			}
  			else if ( firstChar === '?' ) {
  				// Query URL
  				fullUrl = History.getPageUrl().replace(/[\?#].*/,'')+url;
  			}
  			else {
  				// Relative URL
  				if ( allowBaseHref ) {
  					fullUrl = History.getBaseUrl()+url.replace(/^(\.\/)+/,'');
  				} else {
  					fullUrl = History.getBasePageUrl()+url.replace(/^(\.\/)+/,'');
  				}
  				// We have an if condition above as we do not want hashes
  				// which are relative to the baseHref in our URLs
  				// as if the baseHref changes, then all our bookmarks
  				// would now point to different locations
  				// whereas the basePageUrl will always stay the same
  			}
  
  			// Return
  			return fullUrl.replace(/\#$/,'');
  		};
  
  		/**
  		 * History.getShortUrl(url)
  		 * Ensures that we have a relative URL and not a absolute URL
  		 * @param {string} url
  		 * @return {string} url
  		 */
  		History.getShortUrl = function(url){
  			// Prepare
  			var shortUrl = url, baseUrl = History.getBaseUrl(), rootUrl = History.getRootUrl();
  
  			// Trim baseUrl
  			if ( History.emulated.pushState ) {
  				// We are in a if statement as when pushState is not emulated
  				// The actual url these short urls are relative to can change
  				// So within the same session, we the url may end up somewhere different
  				shortUrl = shortUrl.replace(baseUrl,'');
  			}
  
  			// Trim rootUrl
  			shortUrl = shortUrl.replace(rootUrl,'/');
  
  			// Ensure we can still detect it as a state
  			if ( History.isTraditionalAnchor(shortUrl) ) {
  				shortUrl = './'+shortUrl;
  			}
  
  			// Clean It
  			shortUrl = shortUrl.replace(/^(\.\/)+/g,'./').replace(/\#$/,'');
  
  			// Return
  			return shortUrl;
  		};
  
  		// ----------------------------------------------------------------------
  		// State Storage
  
  		/**
  		 * History.store
  		 * The store for all session specific data
  		 */
  		History.store = amplify ? (amplify.store('History.store')||{}) : {};
  		History.store.idToState = History.store.idToState||{};
  		History.store.urlToId = History.store.urlToId||{};
  		History.store.stateToId = History.store.stateToId||{};
  
  		/**
  		 * History.idToState
  		 * 1-1: State ID to State Object
  		 */
  		History.idToState = History.idToState||{};
  
  		/**
  		 * History.stateToId
  		 * 1-1: State String to State ID
  		 */
  		History.stateToId = History.stateToId||{};
  
  		/**
  		 * History.urlToId
  		 * 1-1: State URL to State ID
  		 */
  		History.urlToId = History.urlToId||{};
  
  		/**
  		 * History.storedStates
  		 * Store the states in an array
  		 */
  		History.storedStates = History.storedStates||[];
  
  		/**
  		 * History.savedStates
  		 * Saved the states in an array
  		 */
  		History.savedStates = History.savedStates||[];
  
  		/**
  		 * History.getState()
  		 * Get an object containing the data, title and url of the current state
  		 * @param {Boolean} friendly
  		 * @param {Boolean} create
  		 * @return {Object} State
  		 */
  		History.getState = function(friendly,create){
  			// Prepare
  			if ( typeof friendly === 'undefined' ) { friendly = true; }
  			if ( typeof create === 'undefined' ) { create = true; }
  
  			// Fetch
  			var State = History.getLastSavedState();
  
  			// Create
  			if ( !State && create ) {
  				State = History.createStateObject();
  			}
  
  			// Adjust
  			if ( friendly ) {
  				State = History.cloneObject(State);
  				State.url = State.cleanUrl||State.url;
  			}
  
  			// Return
  			return State;
  		};
  
  		/**
  		 * History.getIdByState(State)
  		 * Gets a ID for a State
  		 * @param {State} newState
  		 * @return {String} id
  		 */
  		History.getIdByState = function(newState){
  
  			// Fetch ID
  			var id = History.extractId(newState.url);
  			if ( !id ) {
  				// Find ID via State String
  				var str = History.getStateString(newState);
  				if ( typeof History.stateToId[str] !== 'undefined' ) {
  					id = History.stateToId[str];
  				}
  				else if ( typeof History.store.stateToId[str] !== 'undefined' ) {
  					id = History.store.stateToId[str];
  				}
  				else {
  					// Generate a new ID
  					while ( true ) {
  						id = String(Math.floor(Math.random()*1000));
  						if ( typeof History.idToState[id] === 'undefined' && typeof History.store.idToState[id] === 'undefined' ) {
  							break;
  						}
  					}
  
  					// Apply the new State to the ID
  					History.stateToId[str] = id;
  					History.idToState[id] = newState;
  				}
  			}
  
  			// Return ID
  			return id;
  		};
  
  		/**
  		 * History.normalizeState(State)
  		 * Expands a State Object
  		 * @param {object} State
  		 * @return {object}
  		 */
  		History.normalizeState = function(oldState){
  			// Prepare
  			if ( !oldState || (typeof oldState !== 'object') ) {
  				oldState = {};
  			}
  
  			// Check
  			if ( typeof oldState.normalized !== 'undefined' ) {
  				return oldState;
  			}
  
  			// Adjust
  			if ( !oldState.data || (typeof oldState.data !== 'object') ) {
  				oldState.data = {};
  			}
  
  			// ----------------------------------------------------------------------
  
  			// Create
  			var newState = {};
  			newState.normalized = true;
  			newState.title = oldState.title||'';
  			newState.url = History.getFullUrl(History.unescapeString(oldState.url||document.location.href));
  			newState.hash = History.getShortUrl(newState.url);
  			newState.data = History.cloneObject(oldState.data);
  
  			// Fetch ID
  			newState.id = History.getIdByState(newState);
  
  			// ----------------------------------------------------------------------
  
  			// Clean the URL
  			newState.cleanUrl = newState.url.replace(/\??\&_suid.*/,'');
  			newState.url = newState.cleanUrl;
  
  			// Check to see if we have more than just a url
  			var dataNotEmpty = !History.isEmptyObject(newState.data);
  
  			// Apply
  			if ( newState.title || dataNotEmpty ) {
  				// Add ID to Hash
  				newState.hash = History.getShortUrl(newState.url).replace(/\??\&_suid.*/,'');
  				if ( !/\?/.test(newState.hash) ) {
  					newState.hash += '?';
  				}
  				newState.hash += '&_suid='+newState.id;
  			}
  
  			// Create the Hashed URL
  			newState.hashedUrl = History.getFullUrl(newState.hash);
  
  			// ----------------------------------------------------------------------
  
  			// Update the URL if we have a duplicate
  			if ( (History.emulated.pushState || History.bugs.safariPoll) && History.hasUrlDuplicate(newState) ) {
  				newState.url = newState.hashedUrl;
  			}
  
  			// ----------------------------------------------------------------------
  
  			// Return
  			return newState;
  		};
  
  		/**
  		 * History.createStateObject(data,title,url)
  		 * Creates a object based on the data, title and url state params
  		 * @param {object} data
  		 * @param {string} title
  		 * @param {string} url
  		 * @return {object}
  		 */
  		History.createStateObject = function(data,title,url){
  			// Hashify
  			var State = {
  				'data': data,
  				'title': title,
  				'url': url
  			};
  
  			// Expand the State
  			State = History.normalizeState(State);
  
  			// Return object
  			return State;
  		};
  
  		/**
  		 * History.getStateById(id)
  		 * Get a state by it's UID
  		 * @param {String} id
  		 */
  		History.getStateById = function(id){
  			// Prepare
  			id = String(id);
  
  			// Retrieve
  			var State = History.idToState[id] || History.store.idToState[id] || undefined;
  
  			// Return State
  			return State;
  		};
  
  		/**
  		 * Get a State's String
  		 * @param {State} passedState
  		 */
  		History.getStateString = function(passedState){
  			// Prepare
  			var State = History.normalizeState(passedState);
  
  			// Clean
  			var cleanedState = {
  				data: State.data,
  				title: passedState.title,
  				url: passedState.url
  			};
  
  			// Fetch
  			var str = JSON.stringify(cleanedState);
  
  			// Return
  			return str;
  		};
  
  		/**
  		 * Get a State's ID
  		 * @param {State} passedState
  		 * @return {String} id
  		 */
  		History.getStateId = function(passedState){
  			// Prepare
  			var State = History.normalizeState(passedState);
  
  			// Fetch
  			var id = State.id;
  
  			// Return
  			return id;
  		};
  
  		/**
  		 * History.getHashByState(State)
  		 * Creates a Hash for the State Object
  		 * @param {State} passedState
  		 * @return {String} hash
  		 */
  		History.getHashByState = function(passedState){
  			// Prepare
  			var hash, State = History.normalizeState(passedState);
  
  			// Fetch
  			hash = State.hash;
  
  			// Return
  			return hash;
  		};
  
  		/**
  		 * History.extractId(url_or_hash)
  		 * Get a State ID by it's URL or Hash
  		 * @param {string} url_or_hash
  		 * @return {string} id
  		 */
  		History.extractId = function ( url_or_hash ) {
  			// Prepare
  			var id;
  
  			// Extract
  			var parts,url;
  			parts = /(.*)\&_suid=([0-9]+)$/.exec(url_or_hash);
  			url = parts ? (parts[1]||url_or_hash) : url_or_hash;
  			id = parts ? String(parts[2]||'') : '';
  
  			// Return
  			return id||false;
  		};
  
  		/**
  		 * History.isTraditionalAnchor
  		 * Checks to see if the url is a traditional anchor or not
  		 * @param {String} url_or_hash
  		 * @return {Boolean}
  		 */
  		History.isTraditionalAnchor = function(url_or_hash){
  			// Check
  			var isTraditional = !(/[\/\?\.]/.test(url_or_hash));
  
  			// Return
  			return isTraditional;
  		};
  
  		/**
  		 * History.extractState
  		 * Get a State by it's URL or Hash
  		 * @param {String} url_or_hash
  		 * @return {State|null}
  		 */
  		History.extractState = function(url_or_hash,create){
  			// Prepare
  			var State = null;
  			create = create||false;
  
  			// Fetch SUID
  			var id = History.extractId(url_or_hash);
  			if ( id ) {
  				State = History.getStateById(id);
  			}
  
  			// Fetch SUID returned no State
  			if ( !State ) {
  				// Fetch URL
  				var url = History.getFullUrl(url_or_hash);
  
  				// Check URL
  				id = History.getIdByUrl(url)||false;
  				if ( id ) {
  					State = History.getStateById(id);
  				}
  
  				// Create State
  				if ( !State && create && !History.isTraditionalAnchor(url_or_hash) ) {
  					State = History.createStateObject(null,null,url);
  				}
  			}
  
  			// Return
  			return State;
  		};
  
  		/**
  		 * History.getIdByUrl()
  		 * Get a State ID by a State URL
  		 */
  		History.getIdByUrl = function(url){
  			// Fetch
  			var id = History.urlToId[url] || History.store.urlToId[url] || undefined;
  
  			// Return
  			return id;
  		};
  
  		/**
  		 * History.getLastSavedState()
  		 * Get an object containing the data, title and url of the current state
  		 * @return {Object} State
  		 */
  		History.getLastSavedState = function(){
  			return History.savedStates[History.savedStates.length-1]||undefined;
  		};
  
  		/**
  		 * History.getLastStoredState()
  		 * Get an object containing the data, title and url of the current state
  		 * @return {Object} State
  		 */
  		History.getLastStoredState = function(){
  			return History.storedStates[History.storedStates.length-1]||undefined;
  		};
  
  		/**
  		 * History.hasUrlDuplicate
  		 * Checks if a Url will have a url conflict
  		 * @param {Object} newState
  		 * @return {Boolean} hasDuplicate
  		 */
  		History.hasUrlDuplicate = function(newState) {
  			// Prepare
  			var hasDuplicate = false;
  
  			// Fetch
  			var oldState = History.extractState(newState.url);
  
  			// Check
  			hasDuplicate = oldState && oldState.id !== newState.id;
  
  			// Return
  			return hasDuplicate;
  		};
  
  		/**
  		 * History.storeState
  		 * Store a State
  		 * @param {Object} newState
  		 * @return {Object} newState
  		 */
  		History.storeState = function(newState){
  			// Store the State
  			History.urlToId[newState.url] = newState.id;
  
  			// Push the State
  			History.storedStates.push(History.cloneObject(newState));
  
  			// Return newState
  			return newState;
  		};
  
  		/**
  		 * History.isLastSavedState(newState)
  		 * Tests to see if the state is the last state
  		 * @param {Object} newState
  		 * @return {boolean} isLast
  		 */
  		History.isLastSavedState = function(newState){
  			// Prepare
  			var isLast = false;
  
  			// Check
  			if ( History.savedStates.length ) {
  				var
  					newId = newState.id,
  					oldState = History.getLastSavedState(),
  					oldId = oldState.id;
  
  				// Check
  				isLast = (newId === oldId);
  			}
  
  			// Return
  			return isLast;
  		};
  
  		/**
  		 * History.saveState
  		 * Push a State
  		 * @param {Object} newState
  		 * @return {boolean} changed
  		 */
  		History.saveState = function(newState){
  			// Check Hash
  			if ( History.isLastSavedState(newState) ) {
  				return false;
  			}
  
  			// Push the State
  			History.savedStates.push(History.cloneObject(newState));
  
  			// Return true
  			return true;
  		};
  
  		/**
  		 * History.getStateByIndex()
  		 * Gets a state by the index
  		 * @param {integer} index
  		 * @return {Object}
  		 */
  		History.getStateByIndex = function(index){
  			// Prepare
  			var State = null;
  
  			// Handle
  			if ( typeof index === 'undefined' ) {
  				// Get the last inserted
  				State = History.savedStates[History.savedStates.length-1];
  			}
  			else if ( index < 0 ) {
  				// Get from the end
  				State = History.savedStates[History.savedStates.length+index];
  			}
  			else {
  				// Get from the beginning
  				State = History.savedStates[index];
  			}
  
  			// Return State
  			return State;
  		};
  
  		// ----------------------------------------------------------------------
  		// Hash Helpers
  
  		/**
  		 * History.getHash()
  		 * Gets the current document hash
  		 * @return {string}
  		 */
  		History.getHash = function(){
  			var hash = History.unescapeHash(document.location.hash);
  			return hash;
  		};
  
  		/**
  		 * History.unescapeString()
  		 * Unescape a string
  		 * @param {String} str
  		 * @return {string}
  		 */
  		History.unescapeString = function(str){
  			// Prepare
  			var result = str;
  
  			// Unescape hash
  			var tmp;
  			while ( true ) {
  				tmp = window.unescape(result);
  				if ( tmp === result ) {
  					break;
  				}
  				result = tmp;
  			}
  
  			// Return result
  			return result;
  		};
  
  		/**
  		 * History.unescapeHash()
  		 * normalize and Unescape a Hash
  		 * @param {String} hash
  		 * @return {string}
  		 */
  		History.unescapeHash = function(hash){
  			// Prepare
  			var result = History.normalizeHash(hash);
  
  			// Unescape hash
  			result = History.unescapeString(result);
  
  			// Return result
  			return result;
  		};
  
  		/**
  		 * History.normalizeHash()
  		 * normalize a hash across browsers
  		 * @return {string}
  		 */
  		History.normalizeHash = function(hash){
  			var result = hash.replace(/[^#]*#/,'').replace(/#.*/, '');
  
  			// Return result
  			return result;
  		};
  
  		/**
  		 * History.setHash(hash)
  		 * Sets the document hash
  		 * @param {string} hash
  		 * @return {History}
  		 */
  		History.setHash = function(hash,queue){
  			// Handle Queueing
  			if ( queue !== false && History.busy() ) {
  				// Wait + Push to Queue
  				//History.debug('History.setHash: we must wait', arguments);
  				History.pushQueue({
  					scope: History,
  					callback: History.setHash,
  					args: arguments,
  					queue: queue
  				});
  				return false;
  			}
  
  			// Log
  			//History.debug('History.setHash: called',hash);
  
  			// Prepare
  			var adjustedHash = History.escapeHash(hash);
  
  			// Make Busy + Continue
  			History.busy(true);
  
  			// Check if hash is a state
  			var State = History.extractState(hash,true);
  			if ( State && !History.emulated.pushState ) {
  				// Hash is a state so skip the setHash
  				//History.debug('History.setHash: Hash is a state so skipping the hash set with a direct pushState call',arguments);
  
  				// PushState
  				History.pushState(State.data,State.title,State.url,false);
  			}
  			else if ( document.location.hash !== adjustedHash ) {
  				// Hash is a proper hash, so apply it
  
  				// Handle browser bugs
  				if ( History.bugs.setHash ) {
  					// Fix Safari Bug https://bugs.webkit.org/show_bug.cgi?id=56249
  
  					// Fetch the base page
  					var pageUrl = History.getPageUrl();
  
  					// Safari hash apply
  					History.pushState(null,null,pageUrl+'#'+adjustedHash,false);
  				}
  				else {
  					// Normal hash apply
  					document.location.hash = adjustedHash;
  				}
  			}
  
  			// Chain
  			return History;
  		};
  
  		/**
  		 * History.escape()
  		 * normalize and Escape a Hash
  		 * @return {string}
  		 */
  		History.escapeHash = function(hash){
  			var result = History.normalizeHash(hash);
  
  			// Escape hash
  			result = window.escape(result);
  
  			// IE6 Escape Bug
  			if ( !History.bugs.hashEscape ) {
  				// Restore common parts
  				result = result
  					.replace(/\%21/g,'!')
  					.replace(/\%26/g,'&')
  					.replace(/\%3D/g,'=')
  					.replace(/\%3F/g,'?');
  			}
  
  			// Return result
  			return result;
  		};
  
  		/**
  		 * History.getHashByUrl(url)
  		 * Extracts the Hash from a URL
  		 * @param {string} url
  		 * @return {string} url
  		 */
  		History.getHashByUrl = function(url){
  			// Extract the hash
  			var hash = String(url)
  				.replace(/([^#]*)#?([^#]*)#?(.*)/, '$2')
  				;
  
  			// Unescape hash
  			hash = History.unescapeHash(hash);
  
  			// Return hash
  			return hash;
  		};
  
  		/**
  		 * History.setTitle(title)
  		 * Applies the title to the document
  		 * @param {State} newState
  		 * @return {Boolean}
  		 */
  		History.setTitle = function(newState){
  			// Prepare
  			var title = newState.title;
  
  			// Initial
  			if ( !title ) {
  				var firstState = History.getStateByIndex(0);
  				if ( firstState && firstState.url === newState.url ) {
  					title = firstState.title||History.options.initialTitle;
  				}
  			}
  
  			// Apply
  			try {
  				document.getElementsByTagName('title')[0].innerHTML = title.replace('<','&lt;').replace('>','&gt;').replace(' & ',' &amp; ');
  			}
  			catch ( Exception ) { }
  			document.title = title;
  
  			// Chain
  			return History;
  		};
  
  		// ----------------------------------------------------------------------
  		// Queueing
  
  		/**
  		 * History.queues
  		 * The list of queues to use
  		 * First In, First Out
  		 */
  		History.queues = [];
  
  		/**
  		 * History.busy(value)
  		 * @param {boolean} value [optional]
  		 * @return {boolean} busy
  		 */
  		History.busy = function(value){
  			// Apply
  			if ( typeof value !== 'undefined' ) {
  				//History.debug('History.busy: changing ['+(History.busy.flag||false)+'] to ['+(value||false)+']', History.queues.length);
  				History.busy.flag = value;
  			}
  			// Default
  			else if ( typeof History.busy.flag === 'undefined' ) {
  				History.busy.flag = false;
  			}
  
  			// Queue
  			if ( !History.busy.flag ) {
  				// Execute the next item in the queue
  				clearTimeout(History.busy.timeout);
  				var fireNext = function(){
  					if ( History.busy.flag ) return;
  					for ( var i=History.queues.length-1; i >= 0; --i ) {
  						var queue = History.queues[i];
  						if ( queue.length === 0 ) continue;
  						var item = queue.shift();
  						History.fireQueueItem(item);
  						History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
  					}
  				};
  				History.busy.timeout = setTimeout(fireNext,History.options.busyDelay);
  			}
  
  			// Return
  			return History.busy.flag;
  		};
  
  		/**
  		 * History.fireQueueItem(item)
  		 * Fire a Queue Item
  		 * @param {Object} item
  		 * @return {Mixed} result
  		 */
  		History.fireQueueItem = function(item){
  			return item.callback.apply(item.scope||History,item.args||[]);
  		};
  
  		/**
  		 * History.pushQueue(callback,args)
  		 * Add an item to the queue
  		 * @param {Object} item [scope,callback,args,queue]
  		 */
  		History.pushQueue = function(item){
  			// Prepare the queue
  			History.queues[item.queue||0] = History.queues[item.queue||0]||[];
  
  			// Add to the queue
  			History.queues[item.queue||0].push(item);
  
  			// Chain
  			return History;
  		};
  
  		/**
  		 * History.queue (item,queue), (func,queue), (func), (item)
  		 * Either firs the item now if not busy, or adds it to the queue
  		 */
  		History.queue = function(item,queue){
  			// Prepare
  			if ( typeof item === 'function' ) {
  				item = {
  					callback: item
  				};
  			}
  			if ( typeof queue !== 'undefined' ) {
  				item.queue = queue;
  			}
  
  			// Handle
  			if ( History.busy() ) {
  				History.pushQueue(item);
  			} else {
  				History.fireQueueItem(item);
  			}
  
  			// Chain
  			return History;
  		};
  
  		/**
  		 * History.clearQueue()
  		 * Clears the Queue
  		 */
  		History.clearQueue = function(){
  			History.busy.flag = false;
  			History.queues = [];
  			return History;
  		};
  
  
  		// ----------------------------------------------------------------------
  		// IE Bug Fix
  
  		/**
  		 * History.stateChanged
  		 * States whether or not the state has changed since the last double check was initialised
  		 */
  		History.stateChanged = false;
  
  		/**
  		 * History.doubleChecker
  		 * Contains the timeout used for the double checks
  		 */
  		History.doubleChecker = false;
  
  		/**
  		 * History.doubleCheckComplete()
  		 * Complete a double check
  		 * @return {History}
  		 */
  		History.doubleCheckComplete = function(){
  			// Update
  			History.stateChanged = true;
  
  			// Clear
  			History.doubleCheckClear();
  
  			// Chain
  			return History;
  		};
  
  		/**
  		 * History.doubleCheckClear()
  		 * Clear a double check
  		 * @return {History}
  		 */
  		History.doubleCheckClear = function(){
  			// Clear
  			if ( History.doubleChecker ) {
  				clearTimeout(History.doubleChecker);
  				History.doubleChecker = false;
  			}
  
  			// Chain
  			return History;
  		};
  
  		/**
  		 * History.doubleCheck()
  		 * Create a double check
  		 * @return {History}
  		 */
  		History.doubleCheck = function(tryAgain){
  			// Reset
  			History.stateChanged = false;
  			History.doubleCheckClear();
  
  			// Fix IE6,IE7 bug where calling history.back or history.forward does not actually change the hash (whereas doing it manually does)
  			// Fix Safari 5 bug where sometimes the state does not change: https://bugs.webkit.org/show_bug.cgi?id=42940
  			if ( History.bugs.ieDoubleCheck ) {
  				// Apply Check
  				History.doubleChecker = setTimeout(
  					function(){
  						History.doubleCheckClear();
  						if ( !History.stateChanged ) {
  							//History.debug('History.doubleCheck: State has not yet changed, trying again', arguments);
  							// Re-Attempt
  							tryAgain();
  						}
  						return true;
  					},
  					History.options.doubleCheckInterval
  				);
  			}
  
  			// Chain
  			return History;
  		};
  
  		// ----------------------------------------------------------------------
  		// Safari Bug Fix
  
  		/**
  		 * History.safariStatePoll()
  		 * Poll the current state
  		 * @return {History}
  		 */
  		History.safariStatePoll = function(){
  			// Poll the URL
  
  			// Get the Last State which has the new URL
  			var
  				urlState = History.extractState(document.location.href),
  				newState;
  
  			// Check for a difference
  			if ( !History.isLastSavedState(urlState) ) {
  				newState = urlState;
  			}
  			else {
  				return;
  			}
  
  			// Check if we have a state with that url
  			// If not create it
  			if ( !newState ) {
  				//History.debug('History.safariStatePoll: new');
  				newState = History.createStateObject();
  			}
  
  			// Apply the New State
  			//History.debug('History.safariStatePoll: trigger');
  			History.Adapter.trigger(window,'popstate');
  
  			// Chain
  			return History;
  		};
  
  		// ----------------------------------------------------------------------
  		// State Aliases
  
  		/**
  		 * History.back(queue)
  		 * Send the browser history back one item
  		 * @param {Integer} queue [optional]
  		 */
  		History.back = function(queue){
  			//History.debug('History.back: called', arguments);
  
  			// Handle Queueing
  			if ( queue !== false && History.busy() ) {
  				// Wait + Push to Queue
  				//History.debug('History.back: we must wait', arguments);
  				History.pushQueue({
  					scope: History,
  					callback: History.back,
  					args: arguments,
  					queue: queue
  				});
  				return false;
  			}
  
  			// Make Busy + Continue
  			History.busy(true);
  
  			// Fix certain browser bugs that prevent the state from changing
  			History.doubleCheck(function(){
  				History.back(false);
  			});
  
  			// Go back
  			history.go(-1);
  
  			// End back closure
  			return true;
  		};
  
  		/**
  		 * History.forward(queue)
  		 * Send the browser history forward one item
  		 * @param {Integer} queue [optional]
  		 */
  		History.forward = function(queue){
  			//History.debug('History.forward: called', arguments);
  
  			// Handle Queueing
  			if ( queue !== false && History.busy() ) {
  				// Wait + Push to Queue
  				//History.debug('History.forward: we must wait', arguments);
  				History.pushQueue({
  					scope: History,
  					callback: History.forward,
  					args: arguments,
  					queue: queue
  				});
  				return false;
  			}
  
  			// Make Busy + Continue
  			History.busy(true);
  
  			// Fix certain browser bugs that prevent the state from changing
  			History.doubleCheck(function(){
  				History.forward(false);
  			});
  
  			// Go forward
  			history.go(1);
  
  			// End forward closure
  			return true;
  		};
  
  		/**
  		 * History.go(index,queue)
  		 * Send the browser history back or forward index times
  		 * @param {Integer} queue [optional]
  		 */
  		History.go = function(index,queue){
  			//History.debug('History.go: called', arguments);
  
  			// Prepare
  			var i;
  
  			// Handle
  			if ( index > 0 ) {
  				// Forward
  				for ( i=1; i<=index; ++i ) {
  					History.forward(queue);
  				}
  			}
  			else if ( index < 0 ) {
  				// Backward
  				for ( i=-1; i>=index; --i ) {
  					History.back(queue);
  				}
  			}
  			else {
  				throw new Error('History.go: History.go requires a positive or negative integer passed.');
  			}
  
  			// Chain
  			return History;
  		};
  
  
  		// ----------------------------------------------------------------------
  		// Initialise
  
  		/**
  		 * Create the initial State
  		 */
  		History.saveState(History.storeState(History.extractState(document.location.href,true)));
  
  		/**
  		 * Bind for Saving Store
  		 */
  		if ( amplify ) {
  			History.onUnload = function(){
  				// Prepare
  				var
  					currentStore = amplify.store('History.store')||{},
  					item;
  
  				// Ensure
  				currentStore.idToState = currentStore.idToState || {};
  				currentStore.urlToId = currentStore.urlToId || {};
  				currentStore.stateToId = currentStore.stateToId || {};
  
  				// Sync
  				for ( item in History.idToState ) {
  					if ( !History.idToState.hasOwnProperty(item) ) {
  						continue;
  					}
  					currentStore.idToState[item] = History.idToState[item];
  				}
  				for ( item in History.urlToId ) {
  					if ( !History.urlToId.hasOwnProperty(item) ) {
  						continue;
  					}
  					currentStore.urlToId[item] = History.urlToId[item];
  				}
  				for ( item in History.stateToId ) {
  					if ( !History.stateToId.hasOwnProperty(item) ) {
  						continue;
  					}
  					currentStore.stateToId[item] = History.stateToId[item];
  				}
  
  				// Update
  				History.store = currentStore;
  
  				// Store
  				amplify.store('History.store',currentStore);
  			};
  			// For Internet Explorer
  			setInterval(History.onUnload,History.options.storeInterval);
  			// For Other Browsers
  			History.Adapter.bind(window,'beforeunload',History.onUnload);
  			History.Adapter.bind(window,'unload',History.onUnload);
  			// Both are enabled for consistency
  		}
  
  
  		// ----------------------------------------------------------------------
  		// HTML5 State Support
  
  		if ( History.emulated.pushState ) {
  			/*
  			 * Provide Skeleton for HTML4 Browsers
  			 */
  
  			// Prepare
  			var emptyFunction = function(){};
  			History.pushState = History.pushState||emptyFunction;
  			History.replaceState = History.replaceState||emptyFunction;
  		}
  		else {
  			/*
  			 * Use native HTML5 History API Implementation
  			 */
  
  			/**
  			 * History.onPopState(event,extra)
  			 * Refresh the Current State
  			 */
  			History.onPopState = function(event){
  				// Reset the double check
  				History.doubleCheckComplete();
  
  				// Check for a Hash, and handle apporiatly
  				var currentHash	= History.getHash();
  				if ( currentHash ) {
  					// Expand Hash
  					var currentState = History.extractState(currentHash||document.location.href,true);
  					if ( currentState ) {
  						// We were able to parse it, it must be a State!
  						// Let's forward to replaceState
  						//History.debug('History.onPopState: state anchor', currentHash, currentState);
  						History.replaceState(currentState.data, currentState.title, currentState.url, false);
  					}
  					else {
  						// Traditional Anchor
  						//History.debug('History.onPopState: traditional anchor', currentHash);
  						History.Adapter.trigger(window,'anchorchange');
  						History.busy(false);
  					}
  
  					// We don't care for hashes
  					History.expectedStateId = false;
  					return false;
  				}
  
  				// Prepare
  				var newState = false;
  
  				// Prepare
  				event = event||{};
  				if ( typeof event.state === 'undefined' ) {
  					// jQuery
  					if ( typeof event.originalEvent !== 'undefined' && typeof event.originalEvent.state !== 'undefined' ) {
  						event.state = event.originalEvent.state||false;
  					}
  					// MooTools
  					else if ( typeof event.event !== 'undefined' && typeof event.event.state !== 'undefined' ) {
  						event.state = event.event.state||false;
  					}
  				}
  
  				// Ensure
  				event.state = (event.state||false);
  
  				// Fetch State
  				if ( event.state ) {
  					// Vanilla: Back/forward button was used
  					newState = History.getStateById(event.state);
  				}
  				else if ( History.expectedStateId ) {
  					// Vanilla: A new state was pushed, and popstate was called manually
  					newState = History.getStateById(History.expectedStateId);
  				}
  				else {
  					// Initial State
  					newState = History.extractState(document.location.href);
  				}
  
  				// The State did not exist in our store
  				if ( !newState ) {
  					// Regenerate the State
  					newState = History.createStateObject(null,null,document.location.href);
  				}
  
  				// Clean
  				History.expectedStateId = false;
  
  				// Check if we are the same state
  				if ( History.isLastSavedState(newState) ) {
  					// There has been no change (just the page's hash has finally propagated)
  					//History.debug('History.onPopState: no change', newState, History.savedStates);
  					History.busy(false);
  					return false;
  				}
  
  				// Store the State
  				History.storeState(newState);
  				History.saveState(newState);
  
  				// Force update of the title
  				History.setTitle(newState);
  
  				// Fire Our Event
  				History.Adapter.trigger(window,'statechange');
  				History.busy(false);
  
  				// Return true
  				return true;
  			};
  			History.Adapter.bind(window,'popstate',History.onPopState);
  
  			/**
  			 * History.pushState(data,title,url)
  			 * Add a new State to the history object, become it, and trigger onpopstate
  			 * We have to trigger for HTML4 compatibility
  			 * @param {object} data
  			 * @param {string} title
  			 * @param {string} url
  			 * @return {true}
  			 */
  			History.pushState = function(data,title,url,queue){
  				//History.debug('History.pushState: called', arguments);
  
  				// Check the State
  				if ( History.getHashByUrl(url) && History.emulated.pushState ) {
  					throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
  				}
  
  				// Handle Queueing
  				if ( queue !== false && History.busy() ) {
  					// Wait + Push to Queue
  					//History.debug('History.pushState: we must wait', arguments);
  					History.pushQueue({
  						scope: History,
  						callback: History.pushState,
  						args: arguments,
  						queue: queue
  					});
  					return false;
  				}
  
  				// Make Busy + Continue
  				History.busy(true);
  
  				// Create the newState
  				var newState = History.createStateObject(data,title,url);
  
  				// Check it
  				if ( History.isLastSavedState(newState) ) {
  					// Won't be a change
  					History.busy(false);
  				}
  				else {
  					// Store the newState
  					History.storeState(newState);
  					History.expectedStateId = newState.id;
  
  					// Push the newState
  					history.pushState(newState.id,newState.title,newState.url);
  
  					// Fire HTML5 Event
  					History.Adapter.trigger(window,'popstate');
  				}
  
  				// End pushState closure
  				return true;
  			};
  
  			/**
  			 * History.replaceState(data,title,url)
  			 * Replace the State and trigger onpopstate
  			 * We have to trigger for HTML4 compatibility
  			 * @param {object} data
  			 * @param {string} title
  			 * @param {string} url
  			 * @return {true}
  			 */
  			History.replaceState = function(data,title,url,queue){
  				//History.debug('History.replaceState: called', arguments);
  
  				// Check the State
  				if ( History.getHashByUrl(url) && History.emulated.pushState ) {
  					throw new Error('History.js does not support states with fragement-identifiers (hashes/anchors).');
  				}
  
  				// Handle Queueing
  				if ( queue !== false && History.busy() ) {
  					// Wait + Push to Queue
  					//History.debug('History.replaceState: we must wait', arguments);
  					History.pushQueue({
  						scope: History,
  						callback: History.replaceState,
  						args: arguments,
  						queue: queue
  					});
  					return false;
  				}
  
  				// Make Busy + Continue
  				History.busy(true);
  
  				// Create the newState
  				var newState = History.createStateObject(data,title,url);
  
  				// Check it
  				if ( History.isLastSavedState(newState) ) {
  					// Won't be a change
  					History.busy(false);
  				}
  				else {
  					// Store the newState
  					History.storeState(newState);
  					History.expectedStateId = newState.id;
  
  					// Push the newState
  					history.replaceState(newState.id,newState.title,newState.url);
  
  					// Fire HTML5 Event
  					History.Adapter.trigger(window,'popstate');
  				}
  
  				// End replaceState closure
  				return true;
  			};
  
  			// Be aware, the following is only for native pushState implementations
  			// If you are wanting to include something for all browsers
  			// Then include it above this if block
  
  			/**
  			 * Setup Safari Fix
  			 */
  			if ( History.bugs.safariPoll ) {
  				setInterval(History.safariStatePoll, History.options.safariPollInterval);
  			}
  
  			/**
  			 * Ensure Cross Browser Compatibility
  			 */
  			if ( navigator.vendor === 'Apple Computer, Inc.' || (navigator.appCodeName||'') === 'Mozilla' ) {
  				/**
  				 * Fix Safari HashChange Issue
  				 */
  
  				// Setup Alias
  				History.Adapter.bind(window,'hashchange',function(){
  					History.Adapter.trigger(window,'popstate');
  				});
  
  				// Initialise Alias
  				if ( History.getHash() ) {
  					History.Adapter.onDomLoad(function(){
  						History.Adapter.trigger(window,'hashchange');
  					});
  				}
  			}
  
  		} // !History.emulated.pushState
  
  	}; // History.initCore
  
  	// Try and Initialise History
  	History.init();
  
  })(window);
  