/* PicLens Lite JavaScript: version 1.0
 * Copyright (c) 2008 Cooliris, Inc.
 * All Rights Reserved.
 *
 * The JavaScript portion of PicLens Lite is licensed under BSD.
 * For details, see http://lite.piclens.com/bsdlicense
 * This launcher includes and interacts with SWFObject (MIT), BrowserDetect (BSD Compatible), and Lytebox (CC Attribution 3.0).
 *
 * There are two versions of this JS:
 * http://lite.piclens.com/current/piclens.js		   contains the full file with comments	(~43KB)
 * http://lite.piclens.com/current/piclens_optimized.js contains a light version for deployment (~29KB)
 */
var PicLensLite = {
	// The PUBLIC API

	// PicLens Lite can be deployed in one of two ways:
	// 1) include http://lite.piclens.com/current/piclens.js in the <head> of your webpage
	// 2) download the PicLensLite.zip and deploy it on your own website (unzip it anywhere, and include the JS file in the <head> of your page)
	//
	// For example: the directory layout looks like:
	//	 lite.piclens.com/current/ contains the SWF, JS, and image files
	//					 /lytebox/ contains basic slideshow support for browsers w/o Flash
	//
	// Pointing to the JS will automatically configure PicLens Lite relative to that URL...
	// Alternatively, you can customize the URLs with a public method (see setLiteURLs)

	// 1) Call PicLensLite.start() to launch the default feed (specified in the head)
	// 2) Call PicLensLite.start({feedUrl:'http://myWebsite.com/myFeed.rss', ...}) to launch a specific feed
	//	Option 2 supports the following named arguments:
	//		feedUrl  : String  // is the URL to the specific Media RSS feed you want to launch
	//		feedData : String  // is the Media RSS feed itself (do not use feedUrl if you want to programmatically generate & pass in the feed text)
	//		guid	 : String  // starts from the item in the feed that is tagged w/ this unique id
	//		maxScale : Number  // normally, images fill the stage; 0 -> never scale up; any other positive number S --> scale up to S times the original size of the photo (but never bigger than the stage)
	// To enable smoothing for images. a crossdomain.xml file is required at the root of your image server.
	// Lite detects this crossdomain.xml and applies smoothing automatically.
	start : function(namedArgs) {
		this.determineBrowserParameters();
		clearTimeout(this.REMOVE_TIMER_ID);

		// handle named arguments
		if (namedArgs) {
			this.ARGS = namedArgs;
		}
		this.START_ITEM_GUID = null;
		if (typeof namedArgs != "undefined") {
			//////////////////////////////////////////////////////////////////////
			// custom arguments are passed through as FlashVars
			if (namedArgs.guid) {
				this.START_ITEM_GUID = namedArgs.guid;
			}

			//////////////////////////////////////////////////////////////////////
			// if feedUrl is specified, it launches immediately
			if (namedArgs.feedUrl) {
				this.THE_FEED_URL = namedArgs.feedUrl;
				if (this.checkForPluginAndLaunchIfPossible(namedArgs.feedUrl)) {
					return;
				}
				if (namedArgs.loadFeedInFlash) {
					// read up on flash crossdomain if you choose this option (Flash can only load XML feeds from servers hosting a crossdomain.xml)
					this.LOAD_FEED_IN_FLASH = true;
					// pass the URL to Flash, and load the contents via a GET request
					this.showFlashUI();
				} else {
					// load the contents of the URL via AJAX, and launch the Flash UI afterward....
					this.loadViaXHR(namedArgs.feedUrl);
				}
			}
			// Option 2: pass in the feed XML directly through Javascript
			// use either feedUrl OR feedData, but not both!
			if (namedArgs.feedData) {
				this.showFlashUI(namedArgs.feedData);
			}
			// Option 3: pass the feed URL as a FlashVar and have Flash load it (less preferable than Option 1)

		} else {
			// find the feed from the header, since none was specified
			// build list of XML feeds
			var feeds = this.indexFeeds();
			if (feeds.length != 0) { // view the first feed, if available
				var feed = feeds[0];
				this.loadViaXHR(feed.url);
			}
		}
	},
	// check if the Flash Slideshow is currently running
	isRunning : function () {
		return this.LITE_IS_RUNNING;
	},
	// OPTIONAL: customize the location of resources by calling this BEFORE PicLensLite.start(...)
	// Normally, you do not need to call this, as we locate the PicLensLite files relative to the JS file
	// To use this function, pass in an object with the following named arguments:
	// args = {
	//   lite	  : other paths can be determined from this (make sure it ends in a slash)
	//	 swf	 : the URL of the SWF file					  1
	//	 button  : image allowing users to download piclens   1
	//   lbox	  : where to find lytebox					  1
	//	 lboxcss : the CSS file							      2
	//	 lboxjs  : the JS file								  2
	// }
	//
	// 1: Can be determined from args.lite
	// 2: Can be determined from args.lbox or args.lite
	setLiteURLs : function(args) {
		if (args.swf) {
			this.LITE_URL = args.swf;
		} else if (args.lite) {
			this.LITE_URL = args.lite + "PicLensLite.swf";
		} // if both lite & swf aren't set, it won't work

		if (args.button) {
			this.BUTTON_URL = args.button;
		} else if (args.lite) {
			this.BUTTON_URL = args.lite + "NoFlash.jpg";
		}

		var lboxUrl = "";
		if (args.lbox) {
			lboxUrl = args.lbox;
		} else if (args.lite) {
			lboxUrl = args.lite + "../lytebox/";
		}

		if (args.lboxcss) {
			this.LBOX_CSS_URL = args.lboxcss;
		} else if (lboxUrl != "") {
			this.LBOX_CSS_URL = lboxUrl + "lytebox.css";
		}

		if (args.lboxjs) {
			this.LBOX_JS_URL = args.lboxjs;
		} else if (lboxUrl != "") {
			this.LBOX_JS_URL = lboxUrl + "lytebox.js";
		}

		this.URLS_DETERMINED = true;
	},


	//////////////////////////////////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
	// The PRIVATE API is below
	// DO NOT USE these functions or variables directly, as they WILL change in future releases
	// Please email us to request changes to the public API if necessary
	ARGS			 : {},
	DEBUG_NOCLIENT   : false,	   // if true, we will NEVER launch the PicLens Client (for testing Lite)
	DEBUG_NOFLASH	 : false,	   // if true, we will assume the user does not have Flash (for testing Lite)
	MARGIN_W		 : 60,		  // horizontal padding
	MARGIN_H		 : 20,		  // vertical padding
	LITE_BG_DIV	     : null,		// the grey/black background overlay
	LITE_FG_DIV	     : null,		// the foreground div that contains the flash component
	URLS_DETERMINED  : false,	   // have we determined all the necessary URLs yet?
	LITE_URL		 : null,		// the location of PicLensLite.SWF
	BUTTON_URL	     : null,		// image to display if the user doesn't have flash
	LBOX_CSS_URL	 : null,		// where to find lytebox css/js files
	LBOX_JS_URL	     : null,
	LBOX_COUNT	     : 0,			// try to start lytebox, but if it doesn't exist after a few tries, give up...
	OS_WIN		     : false,	   // sadly, sometimes we have to do something different depending on our Browser/OS/Configuration
	OS_MAC		     : false,
	BROWSER_FFX	     : false,
	BROWSER_SAF	     : false,
	BROWSER_IE	     : false,
	BROWSER_IE6	     : false,
	THE_FEED		 : "",		  // the feed text
	THE_FEED_URL	 : "",		  // the feed url
	LOAD_FEED_IN_FLASH : false,	 // whether to ask flash to load the feed
	LITE_IS_RUNNING  : false,
	piclensIsRunning_: false,	   // maintain compatibility with Our Wordpress Plugin for a few iterations... :)
	FLASH_ID_1	     : "pllflash1", // outer
	FLASH_ID_2	     : "pllflash2", // inner
	FLASH_VER		 : null,		// which version of Flash are we running?
	FLASH_URL		 : "http://www.adobe.com/go/getflashplayer",
	PL_URL		     : "http://download.piclens.com/partner/",   // downloads PL immediately
	LEARN_PL_URL	 : "http://affiliate.piclens.com/partner/",  // landing page to read about / download PL
	START_ITEM_GUID  : null,		// start from this item, if not null
	REMOVE_TIMER_ID  : 0,		   // the timer for removing the children...
	RESIZE_TIMER_IE6 : null,		// every second, it auto resizes the UI
	RESIZE_HANDLER_EXISTS : false,  // for safari, it adds a handler to detect user resize events
	FONT			 : "font-family: Lucida Grande, Myriad Pro, Verdana, Helvetica, Arial, sans-serif;",

	addKeyHandlers : function() {
		var self = this;
		document.onkeydown = function(e) {
			var keycode;
			if (e == null) { // ie
			  keycode = window.event.keyCode;
			} else { // mozilla
			  keycode = e.which;
			}
			self.handleKeyPress(keycode);
			return false;
		}
	},
	addMouseHandlers : function() {
		if (window.addEventListener) { // for Firefox
			window.addEventListener("DOMMouseScroll", this.handleMouseWheel, false);
		}
		if (document.attachEvent) { // for IE/Opera
			document.attachEvent("onmousewheel", this.handleMouseWheel);
		}
		window.onmousewheel = document.onmousewheel = this.handleMouseWheel; // for other browsers
	},
	// call this at the last possible moment (especially for Win/Firefox)
	appendElementsToDocument : function() {
		document.body.appendChild(this.LITE_BG_DIV);
		document.body.appendChild(this.LITE_FG_DIV);
	},
	autoResize : function() { // for the IE6 auto resize
		if (!this.isRunning()) {
			// unregister the timer
			clearInterval(this.RESIZE_TIMER_IE6);
			return;
		}

		var pageSize = this.getPageSize();

		// resize the BG and FG divs
		if (this.LITE_BG_DIV) {
			this.LITE_BG_DIV.style.height = pageSize.h + 'px';
			this.LITE_BG_DIV.style.width = pageSize.w + 'px';
		}
		if (this.LITE_FG_DIV) {
			var w = (pageSize.w - this.MARGIN_W * 2);
			var h = (pageSize.h - this.MARGIN_H * 2);

			var fg = this.LITE_FG_DIV;
			fg.style.left = fg.style.right = this.MARGIN_W + 'px';
			fg.style.top = fg.style.bottom = this.MARGIN_H + 'px';
			fg.style.width = w + 'px';
			fg.style.height = h + 'px';

			var flashObj = this.getFlash();
			if (flashObj) {
				flashObj.width = w;
				flashObj.height = h;
			}
		}
	},
	checkForPluginAndLaunchIfPossible : function(url) {
		// check if we have the correct version of piclens, if so... pass it onto the client itself, and do not use LITE
		if (this.hasPicLensClient()) {
			window.piclens.launch(url,'','');
			return true; // launched!
		}
		return false;
	},
	createBackgroundOverlay : function() {
		// create a background div that covers the whole page
		var bg = document.createElement('div');
		this.LITE_BG_DIV = bg;
		var self = this;
		bg.id = "lite_bg_div";
		bg.style.position = 'fixed';

		var style = bg.style;

		// sticks to the sides when the window resizes
		style.width = "100%";
		style.height = "100%";

		if (this.BROWSER_IE6) {
			style.position = 'absolute';
			var pageSize = this.getPageSize();
			style.height = pageSize.h + 'px';
			style.width = pageSize.w + 'px';
		}

		style.left = '0px';
		style.right = '0px';
		style.top = '0px';
		style.bottom = '0px';
		style.backgroundColor = '#000';
		style.opacity = '0.5';
		style.filter = 'alpha(opacity=50)'; // IE7
		if (this.BROWSER_FFX && this.OS_MAC) {
			style.opacity = '1';
		}
		style.zIndex = 1000;
		bg.onclick = function() {
			self.exitPicLensLite();
		};
	},
	createForegroundFlashComponent : function() { // configure the box
		var fg = document.createElement('div');
		this.LITE_FG_DIV = fg;
		fg.id = "lite_fg_div";

		var style = fg.style;
		style.backgroundColor = '#000';
		style.position = 'fixed';
		style.left = style.right = this.MARGIN_W + 'px';
		style.top = style.bottom = this.MARGIN_H + 'px';
		style.border = '2px solid #555';
		style.zIndex = 1001;	   // above the bg

		if (this.BROWSER_IE6) {
			style.position = 'absolute';
			var pageSize = this.getPageSize();
			style.width = (pageSize.w - this.MARGIN_W * 2) + 'px';
			style.height = (pageSize.h - this.MARGIN_H * 2) + 'px';
		}
	},
	// this just removes the HTML elements
	// we call this from Flash (thus, we need to allow the function to return before removing the children)
	closeFlashUI : function() {
		var doc = document;

		// remove the keyboard & mouse handlers...
		doc.onkeydown = "";
		window.onmousewheel = doc.onmousewheel = "";
		if (window.removeEventListener) {
			window.removeEventListener("DOMMouseScroll", this.handleMouseWheel, false);
		}
		if (doc.detachEvent) { // IE/Opera
			doc.detachEvent("onmousewheel", this.handleMouseWheel);
		}

		// should we just hide the div?
		this.LITE_BG_DIV.style.display = 'none';
		this.LITE_FG_DIV.style.display = 'none';

		this.REMOVE_TIMER_ID = setTimeout("PicLensLite.removeChildren()", 150); // 0.15 seconds
	},
	// helps us handle cross-browser quirks...
	determineBrowserParameters : function() {
		// BrowserDetect {.OS, .browser, .version}
		// e.g., "Mac Firefox 2" and "Windows Explorer 7"
		this.OS_MAC = (BrowserDetect.OS == "Mac");
		this.OS_WIN = (BrowserDetect.OS == "Windows");
		this.BROWSER_FFX = (BrowserDetect.browser == "Firefox");
		this.BROWSER_SAF = (BrowserDetect.browser == "Safari");
		this.BROWSER_IE = (BrowserDetect.browser == "Explorer");
		this.BROWSER_IE6 = (this.BROWSER_IE && BrowserDetect.version == "6");

		// what version of Flash is the browser running?
		this.FLASH_VER = swfobject.getFlashPlayerVersion();
	},
	// we should tell Flash we are exiting when this is called...
	// this should only be called when the user clicks outside of the flash component
	// all other exits are handled through Flash
	exitPicLensLite : function() {
		// if it's not running already, we just remove the DIVs
		this.setRunningFlag(false);
		var fl = this.getFlash();
		if (fl != null && fl.fl_exitPicLensLite) { // binding exists
			// tell flash that we are quitting
			fl.fl_exitPicLensLite();
		} else {
			// if flash isn't defined, we just do the closeFlashUI
			this.closeFlashUI();
		}
	},
	// a website should include the absolute URL of the piclens.js in its header
	// This function looks for the script tag and extracts the ROOT_URL
	// <script type="text/javascript" src="ROOT_URL/piclens.js"></script>
	// we assume the SWF and JPEG/PNG/GIF files are relative to this ROOT_URL...
	findScriptLocation : function() {
		// if the webmaster has already called setLiteURLs, we do not need to do this automatically
		if (this.URLS_DETERMINED) { return; }

		var scriptTags = document.getElementsByTagName("script");
		for (var i = 0; i != scriptTags.length; ++i) {
			var script = scriptTags[i];
			var type = script.getAttribute("type");
			if (type == "text/javascript") {
				var testLocation = script.getAttribute("src");
				if (testLocation == null) {
					continue;
				}
				var index = testLocation.indexOf("piclens.js");
				if (index != -1) {
					this.setLiteURLs({lite:testLocation.substring(0,index)});
					return;
				} else {
					index = testLocation.indexOf("piclens_optimized.js");
					if (index != -1) {
						this.setLiteURLs({lite:testLocation.substring(0,index)});
						return;
					}
				}
			}
		}
	},
	getCurrentURL : function() {
		return location.href;
	},
	getFeedURL : function() { // called by Flash to locate the feed when necessary
		return encodeURIComponent(this.THE_FEED_URL);
	},
	// returns an object describing the page size of the browser window
	getPageSize : function() {
		var xScroll, yScroll, windowWidth, windowHeight;
		var doc = document;
		var body = doc.body;
		if (window.innerHeight && window.scrollMaxY) {
			xScroll = doc.scrollWidth;
			yScroll = (this.isFrame ? parent.innerHeight : self.innerHeight) + (this.isFrame ? parent.scrollMaxY : self.scrollMaxY);
		} else if (body.scrollHeight > body.offsetHeight){
			xScroll = body.scrollWidth;
			yScroll = body.scrollHeight;
		} else {
			var html = doc.getElementsByTagName("html").item(0);
			xScroll = html.offsetWidth;
			yScroll = html.offsetHeight;
			xScroll = (xScroll < body.offsetWidth) ? body.offsetWidth : xScroll;
			yScroll = (yScroll < body.offsetHeight) ? body.offsetHeight : yScroll;
		}
		var docElement = doc.documentElement;
		if (self.innerHeight) {
			windowWidth = (this.isFrame) ? parent.innerWidth : self.innerWidth;
			windowHeight = (this.isFrame) ? parent.innerHeight : self.innerHeight;
		} else if (docElement && docElement.clientHeight) {
			windowWidth = docElement.clientWidth;
			windowHeight = docElement.clientHeight;
		} else if (body) {
			var html = doc.getElementsByTagName("html").item(0);
			windowWidth = html.clientWidth;
			windowHeight = html.clientHeight;
			windowWidth = (windowWidth == 0) ? body.clientWidth : windowWidth;
			windowHeight = (windowHeight == 0) ? body.clientHeight : windowHeight;
		}
		var pageHeight = (yScroll < windowHeight) ? windowHeight : yScroll;
		var pageWidth = (xScroll < windowWidth) ? windowWidth : xScroll;
		return {pw:pageWidth, ph:pageHeight, w:windowWidth, h:windowHeight}; // pw and ph are the larger pair. use w and h.
	},
	getElementsFromXMLFeed : function() {
		var xmlDoc;
		if (window.ActiveXObject) { // IE
		  	xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		  	xmlDoc.async=false;
		  	xmlDoc.loadXML(PicLensLite.THE_FEED);
		} else { // code for Mozilla, Firefox, Opera, etc.
			var parser = new DOMParser();
			xmlDoc = parser.parseFromString(PicLensLite.THE_FEED, "text/xml");
		}
		var elements = xmlDoc.getElementsByTagName('*');
		return elements;
	},
	getBasicSlideShowHTML : function() {
		// make sure the lytebox JS is included
		var head = document.getElementsByTagName('head').item(0);

		// add the script tag
		var script  = document.createElement('script');
		script.src  = this.LBOX_JS_URL;
		script.type = 'text/javascript';
		head.appendChild(script);

		// add the lytebox CSS too
		var link = document.createElement('link');
		link.rel = "stylesheet";
		link.href = this.LBOX_CSS_URL;
		link.type = "text/css";
		link.media = "screen";
		head.appendChild(link);

		// find all image URLs from the feed.
		var xmlElements = this.getElementsFromXMLFeed();

		var firstImage = true;
		var firstImageURL;
		var i;
		var otherURLsHidden = "";
		for (i = 0; i < xmlElements.length; i++) {
			if (xmlElements[i].nodeName == "media:content") { // what about the namespace?
				var strURL = xmlElements[i].getAttribute("url");
				if (strURL.indexOf(".flv") == -1) {		   // only for images... avoid FLV files
					var imgURL = xmlElements[i].getAttribute("url");
					if (firstImage) {
						firstImageURL = imgURL;
						firstImage = false;
					} else {
						otherURLsHidden += '<a href="' + xmlElements[i].getAttribute("url") + '" rel="lytebox[lite]"></a> ';
					}
				}
			}
		}

		var basicSlideShow = "<div id='lightbox_images' align='center' style='display: none; padding-top:10px; color:#FFFFFF; font-size:.8em; " +this.FONT+ " color:#999999;'>";
		basicSlideShow +=  '( Alternatively, <a href="'+ firstImageURL +'" rel="lytebox[lite]" style="color:#656588">click here</a> for a basic slideshow. )';
		basicSlideShow += otherURLsHidden;
		basicSlideShow += "</div><br/>"

		return basicSlideShow;
	},
	generateAlternativeContent : function() {
		var altContentHTML = '<div id="altContent" style="text-align:center; margin: 0 0 0 0; padding: 0 0 0 0; background-color: #252525; min-width:860px;">';
		altContentHTML += '<div align="center" style="width: 100%; padding-top:60px; '+this.FONT+'">';

		var v = this.FLASH_VER;
		var flashMessage;
		if (v.major > 0) { // has some version of Flash
			flashMessage = "update your Flash Player from version "+ v.major + '.' + v.minor + '.' + v.release + " to version 9.0.28 or newer";
		} else {
			flashMessage = "install the most recent Flash Player";
		}

		var basicSlideShow = "";
		if (this.THE_FEED) {   // do this only if we've loaded the feed in AJAX
			basicSlideShow = this.getBasicSlideShowHTML();
		}

		var downloadPL = this.PL_URL;
		var learnPL = this.LEARN_PL_URL;
		var pid = this.ARGS.pid;
		if (pid) {
			downloadPL += pid + "/";
			learnPL += pid + "/";
		}

		altContentHTML +=
			"<div style='padding:10px;'>" +
				"<span style='padding-left:25px; color:#C6C6C6; font-size:1.5em; font-weight: bold; " +this.FONT+ "'>You're just a few clicks away from going full screen!</span><br/>" +
				"<span style='padding-left:25px; padding-bottom: 15px; color:#C6C6C6; font-size:.9em; " +this.FONT+ "'>You must get the PicLens browser plugin, or "+flashMessage+".</span>" +
			"</div>" +
			'<img src="'+this.BUTTON_URL+'" alt="" border="0" usemap="#Map">' +
			'<map name="Map" id="Map">' +
				'<area shape="rect" coords="31,34,316,293" href="' + downloadPL +'" alt="" />' +
				'<area shape="rect" coords="593,209,825,301" href="' + this.FLASH_URL +'" alt="" />' +
				'<area shape="rect" coords="328,136,448,158" href="' + learnPL +'" alt="" />' +
			'</map>';

		altContentHTML += '</div>';
		altContentHTML += basicSlideShow;
		altContentHTML += '<div align="center" style="color:#666666; font-size:11px; '+this.FONT+'">&copy; 2008 Cooliris, Inc. All trademarks are property of their respective holders.<br/><br/><br/></div>';
		altContentHTML += '</div>';
		return altContentHTML;
	},
	generateFlashVars : function() {
		var flashVars = '';
		if (this.START_ITEM_GUID != null) {
			flashVars += "&startItemGUID=" + this.START_ITEM_GUID;
		}
		if (this.LOAD_FEED_IN_FLASH) {
			flashVars += "&feedURL=" + this.getFeedURL(); // may need crossdomain.xml to allow loading of feed
		}
		if (this.ARGS.pid) {
			flashVars += "&pid=" + this.ARGS.pid;
		}
		if (this.ARGS.maxScale) {
			flashVars += "&maxScale=" + this.ARGS.maxScale;
		}
		if (flashVars != '') {
			// flashVars will start with &. We remove it here.
			flashVars = flashVars.substring(1);
		}
		return flashVars;
	},
	// does the right thing for each browser
	// returns the Flash object, so we can communicate with it over the ExternalInterface
	getFlash : function() {
		// we should determine which one to pass back depending on Browser/OS configuration
		if (this.BROWSER_SAF || this.BROWSER_IE) {
			return document.getElementById(this.FLASH_ID_1); // outer <object>
		} else {
			return document.getElementById(this.FLASH_ID_2); // inner <object>
		}
	},
	getWindowSize : function() { // inner size
		var docElement = document.documentElement;
		var docBody = document.body;
		var w = 0, h = 0;
		if (typeof(window.innerWidth) == 'number') {
			// not IE
			w = window.innerWidth;
			h = window.innerHeight;
		} else if (docElement && (docElement.clientWidth || docElement.clientHeight)) {
			// IE 6+ in 'standards compliant mode'
			w = docElement.clientWidth;
			h = docElement.clientHeight;
		} else if (docBody && (docBody.clientWidth || docBody.clientHeight)) {
			// IE 4 compatible
			w = docBody.clientWidth;
			h = docBody.clientHeight;
		}
		return {w:w, h:h}
	},
	// The SWF calls this to get the Feed...
	getFeedFromJS : function() {
		return this.THE_FEED;
	},
	handleKeyPress : function(code) {
		if (!this.isRunning()) { return; }
		var fl = this.getFlash();
		if (fl != null && fl.fl_keyPressed) {
			fl.fl_keyPressed(code); // forward to Flash
		} else {
			if (code == 27){ // ESC to close
				this.closeFlashUI();
			}
		}
	},
	handleMouseWheel : function(e) {
		// e.wheelDelta
		// Safari/Windows (MouseWheel Up is +120; Down is -120)
		var delta = 0;
		if (!e) {
			e = window.event;
		}
		if (e.wheelDelta) { // IE/Opera
			delta = e.wheelDelta/120;
			if (window.opera) {
				delta = -delta;
			}
		} else if (e.detail) { // Firefox/Moz
			// on mac, don't divide by 3...
			if (Math.abs(e.detail) < 3) {
				delta = -e.detail;
			} else {
				delta = -e.detail/3;
			}
		}
		if (delta) {
			// don't send abs values < 1; otherwise, you can only scroll next
			PicLensLite.sendMouseScrollToFlash(delta);
		}
		if (e.preventDefault) {
			e.preventDefault();
		}
		e.returnValue = false;
		return false;
	},
	// check whether PicLens is available
	hasPicLensClient : function(url) {
		// if we are debugging, do not bother checking
		if (this.DEBUG_NOCLIENT) {
			return false;
		}

		// check if the bridge has already been defined
		var clientExists = false;
		if (window.piclens) {
			clientExists = true;
		} else {
			// if not, try to define it here...
			var context = null;
			if (typeof PicLensContext != 'undefined') { // Firefox ONLY
				context = new PicLensContext();
			} else {									// IE ONLY
				try {
					context = new ActiveXObject("PicLens.Context");
				} catch (e) {
					context = null;
				}
			}

		   window.piclens = context;
			if (window.piclens) {
				clientExists = true;
			}
		}
		if (clientExists) {
			// check the version number
			var version;
			try { version = window.piclens.version; } catch (e) { return false; }

			var parts = version.split('.'); // minimum version is: 1 . 6 . 0 . 824
			if (parts[0] > 1) {			 // a version 2.X product
				return true;
			} else if (parts[0] == 1) {	 // a 1.X product
				if (parts[1] > 6) {		 // a version 1.7.X product
					return true;
				} else if (parts[1] == 6) { // a 1.6 product
					if (parts[2] > 0) {	 // a version 1.6.1.X product
						return true;
					} else if (parts[2] == 0) {
						if (parts[3] >= 824) { // 1.6.0.824 or newer...
							return true;
						}
					}
				}
			}

			// e.g., a 0.X product
			return false;
		} else {
			return false;
		}
	},
	showLyteboxLink : function() {
		myLytebox.updateLyteboxItems();
		myLytebox.doAnimations = false;
		var lboxImages = document.getElementById('lightbox_images')
		if (lboxImages != null) {
			lboxImages.style.display = "block";
		}
	},
	startLytebox : function() { // allows us to include lytebox, unmodified
		if (typeof myLytebox != "undefined") {
			this.showLyteboxLink();
		} else {
			if (typeof initLytebox != "undefined") {
				initLytebox();
				this.showLyteboxLink();
			} else {
				if (this.LBOX_COUNT >= 4) {
					return; // give up after 600 ms
				}
				setTimeout("PicLensLite.startLytebox()", 150); // try again in 150 ms
				this.LBOX_COUNT++;
			}
		}
	},
	injectFlashPlayer : function() {
		var fg = this.LITE_FG_DIV;

		// determine the width and height of the flash component
		var flashW = '100%';
		var flashH = '100%';
		var flashWInner = '100%';
		var flashHInner = '100%';
		if (this.BROWSER_IE6) {
			flashWInner = '0';
			flashHInner = '0';
		}

		var flashVars = this.generateFlashVars();
		var altContentHTML = this.generateAlternativeContent(); // non-flash content

		if (this.meetsRequirements()) {
			fg.innerHTML =
				'<object id="'+ this.FLASH_ID_1 +'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+flashW+'" height="'+flashH+'">' + // SAF & IE
					'<param name="movie" value="' + this.LITE_URL + '" />' +
					'<param name="quality" value="high"/> ' +
					'<param name="bgcolor" value="#000000"/> ' +
					'<param name="allowScriptAccess" value="always"/> ' +
					'<param name="FlashVars" value="' + flashVars + '"/> ' +
					'<param name="allowFullScreen" value="true"/> ' +
					'<param name="wmode" value="window"/> ' +
					'<param name="scale" value="noscale"/> ' +
						'<object type="application/x-shockwave-flash" data="' + this.LITE_URL + '" width="'+flashWInner+'" height="'+flashHInner+'" ' + // NOT IE
							'quality="high" ' +
							'bgcolor="#000000" id="'+ this.FLASH_ID_2 + '" ' +
							'quality="high" ' +
							'FlashVars="' + flashVars + '" ' +
							'allowFullScreen="true" ' +
							'scale="noscale" ' +
							'wmode="window" ' +
							'allowScriptAccess="always">' +
							'<div>'+
								altContentHTML +
							'</div>'+
						'</object>'+ // NOT IE
				'</object>';
		} else {
			fg.innerHTML = altContentHTML;
			fg.style.minWidth = "860px";
			fg.style.minHeight = "550px";
			fg.style.backgroundColor = '#252525';
		}

		if (this.BROWSER_SAF) {
			this.resizeUI(); // fixes layout
		}
	},
	// find the RSS feeds on this page, and return an array
	indexFeeds : function() {
		var linkTags = document.getElementsByTagName("link");
		var feeds = [];
		for (var i = 0; i != linkTags.length; ++i) {
			var link = linkTags[i], type = link.getAttribute("type");
			if (type == "application/rss+xml" || type == "text/xml") {
				feeds.push({ title: link.getAttribute("title"), url: link.getAttribute("href") });
			}
		}
		return feeds;
	},
	// once we get the response text, we launch flash
	loadViaXHR : function(url) {
		var self = this;
		var request = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP.3.0");
		request.open("GET", url, true);
		request.onreadystatechange = function() {
			if (request.readyState == 4 && (request.status == 200 || request.status == 0)) { // 0 -> File System Testing
				if (request.responseText) {
					// at this point, we have the text
					self.showFlashUI(request.responseText);
				}
			}
		};
		request.send("");
	},
	meetsRequirements : function() {
		if (this.DEBUG_NOFLASH) {
			return false;
		}
		// if IE7, and Flash Detect returns ver 0, we show the Flash anyways
		var ie7FlashDetectionWorkaround = (this.FLASH_VER.major == 0) && this.BROWSER_IE;
		return swfobject.hasFlashPlayerVersion("9.0.28") || ie7FlashDetectionWorkaround;
	},
	removeChildren : function() {
		// remove the bg & fg divs (after a timeout)
		document.body.removeChild(this.LITE_BG_DIV);
		document.body.removeChild(this.LITE_FG_DIV);
	},
	resizeUI : function() { // resize event handler (for Safari)
		if (this.LITE_FG_DIV) {
			var pageSize = this.getPageSize();
			var w = (pageSize.w - this.MARGIN_W * 2);
			var h = (pageSize.h - this.MARGIN_H * 2);

			var fg = this.LITE_FG_DIV;
			fg.style.left = fg.style.right = this.MARGIN_W + 'px';
			fg.style.top = fg.style.bottom = this.MARGIN_H + 'px';
			fg.style.width = w + 'px';
			fg.style.height = h + 'px';

			var flashObj = this.getFlash();
			if (flashObj) {
				flashObj.style.width = w;
				flashObj.style.height = h;
				flashObj.width = w;
				flashObj.height = h;
			}
		}
	},
	setRunningFlag : function (flag) {
		this.LITE_IS_RUNNING = flag;
		this.piclensIsRunning_ = flag;
	},
	setResizeHandler : function() { // for safari
		if (!this.RESIZE_HANDLER_EXISTS && this.BROWSER_SAF) {
			var self = this;
			window.addEventListener('resize', function() { self.resizeUI(); }, false);
			this.RESIZE_HANDLER_EXISTS = true;
		}
	},
	setResizeTimer : function() {
		// only do it for IE6...
		if (this.BROWSER_IE6) {
			this.RESIZE_TIMER_IE6 = setInterval("PicLensLite.autoResize()", 1000);
		}
	},
	showFlashUI : function(feedText) {
		this.THE_FEED = feedText; // may be "", if we are loading it in Flash
		this.findScriptLocation();
		this.createBackgroundOverlay();
		this.createForegroundFlashComponent();
		if (this.BROWSER_IE) {
			this.appendElementsToDocument();
		}
		this.injectFlashPlayer();
		if (!this.BROWSER_IE) {
			// Win Firefox needs this to be last
			// Other Browsers are also OK with this
			this.appendElementsToDocument();
		}
		this.addKeyHandlers();
		this.addMouseHandlers();
		this.setRunningFlag(true);
		this.setResizeTimer();
		this.setResizeHandler();
		this.startLytebox();
	},
	sendMouseScrollToFlash : function(delta) {
		if (!this.isRunning()) { return; }
		var fl = this.getFlash();
		if (fl != null && fl.fl_mouseMoved) {
			fl.fl_mouseMoved(delta);
		}
	}
	// do not end the last function with a comma; it messes up IE7
}



/*	SWFObject v2.0 rc1 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	Released under the MIT License: http://www.opensource.org/licenses/mit-license.php */
var swfobject=function(){var _1=[];var _2=[];var _3=null;var _4=null;var _5=false;var _6=false;var ua=function(){var _8=typeof document.getElementById!="undefined"&&typeof document.getElementsByTagName!="undefined"&&typeof document.createElement!="undefined"&&typeof document.appendChild!="undefined"&&typeof document.replaceChild!="undefined"&&typeof document.removeChild!="undefined"&&typeof document.cloneNode!="undefined";var _9=[0,0,0];var d=null;if(typeof navigator.plugins!="undefined"&&typeof navigator.plugins["Shockwave Flash"]=="object"){d=navigator.plugins["Shockwave Flash"].description;if(d){d=d.replace(/^.*\s+(\S+\s+\S+$)/,"$1");_9[0]=parseInt(d.replace(/^(.*)\..*$/,"$1"),10);_9[1]=parseInt(d.replace(/^.*\.(.*)\s.*$/,"$1"),10);_9[2]=/r/.test(d)?parseInt(d.replace(/^.*r(.*)$/,"$1"),10):0;}}else{if(typeof window.ActiveXObject!="undefined"){var a=null;var _c=false;try{a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");_9=[6,0,21];a.AllowScriptAccess="always";}catch(e){if(_9[0]==6){_c=true;}}if(!_c){try{a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(e){}}}if(!_c&&typeof a=="object"){try{d=a.GetVariable("$version");if(d){d=d.split(" ")[1].split(",");_9=[parseInt(d[0],10),parseInt(d[1],10),parseInt(d[2],10)];}}catch(e){}}}}var u=navigator.userAgent.toLowerCase();var p=navigator.platform.toLowerCase();var _f=/webkit/.test(u);var _10=_f?parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):0;var ie=false;var win=p?/win/.test(p):/win/.test(u);var mac=p?/mac/.test(p):/mac/.test(u);/*@cc_on ie=true;@if(@_win32)win=true;@elif(@_mac)mac=true;@end@*/return {w3cdom:_8,playerVersion:_9,webkit:_f,webkitVersion:_10,ie:ie,win:win,mac:mac};}();var _14=function(){if(!ua.w3cdom){return;}addDomLoadEvent(main);if(ua.ie&&ua.win){try{document.write("<script id=__ie_ondomload defer=true src=//:></script>");var s=document.getElementById("__ie_ondomload");if(s){s.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);callDomLoadFunctions();}};}}catch(e){}}if(ua.webkit&&typeof document.readyState!="undefined"){_3=setInterval(function(){if(/loaded|complete/.test(document.readyState)){callDomLoadFunctions();}},10);}if(typeof document.addEventListener!="undefined"){document.addEventListener("DOMContentLoaded",callDomLoadFunctions,null);}addLoadEvent(callDomLoadFunctions);}();function callDomLoadFunctions(){if(_5){return;}if(ua.ie&&ua.win){var s=document.createElement("span");try{var t=document.getElementsByTagName("body")[0].appendChild(s);t.parentNode.removeChild(t);}catch(e){return;}}_5=true;if(_3){clearInterval(_3);_3=null;}var dl=_1.length;for(var i=0;i<dl;i++){_1[i]();}}function addDomLoadEvent(fn){if(_5){fn();}else{_1[_1.length]=fn;}}function addLoadEvent(fn){if(typeof window.addEventListener!="undefined"){window.addEventListener("load",fn,false);}else{if(typeof document.addEventListener!="undefined"){document.addEventListener("load",fn,false);}else{if(typeof window.attachEvent!="undefined"){window.attachEvent("onload",fn);}else{if(typeof window.onload=="function"){var _1c=window.onload;window.onload=function(){_1c();fn();};}else{window.onload=fn;}}}}}function main(){var rl=_2.length;for(var i=0;i<rl;i++){var id=_2[i].id;if(ua.playerVersion[0]>0){var obj=document.getElementById(id);if(obj){if(hasPlayerVersion(_2[i].swfVersion)){if(ua.webkit&&ua.webkitVersion<312){fixParams(obj);}}else{if(_2[i].expressInstall&&!_6&&hasPlayerVersion([6,0,65])&&(ua.win||ua.mac)){showExpressInstall(_2[i]);}else{displayAltContent(obj);}}}}createCSS("#"+id,"visibility:visible");}}function fixParams(obj){var _22=obj.getElementsByTagName("object")[0];if(_22){var e=document.createElement("embed");var a=_22.attributes;if(a){var al=a.length;for(var i=0;i<al;i++){if(a[i].nodeName.toLowerCase()=="data"){e.setAttribute("src",a[i].nodeValue);}else{e.setAttribute(a[i].nodeName,a[i].nodeValue);}}}var c=_22.childNodes;if(c){var cl=c.length;for(var j=0;j<cl;j++){if(c[j].nodeType==1&&c[j].nodeName.toLowerCase()=="param"){e.setAttribute(c[j].getAttribute("name"),c[j].getAttribute("value"));}}}obj.parentNode.replaceChild(e,obj);}}function fixObjectLeaks(){if(ua.ie&&ua.win&&hasPlayerVersion([8,0,0])){window.attachEvent("onunload",function(){var o=document.getElementsByTagName("object");if(o){var ol=o.length;for(var i=0;i<ol;i++){o[i].style.display="none";for(var x in o[i]){if(typeof o[i][x]=="function"){o[i][x]=function(){};}}}}});}}function showExpressInstall(_2e){_6=true;var obj=document.getElementById(_2e.id);if(obj){if(_2e.altContentId){var ac=document.getElementById(_2e.altContentId);if(ac){_4=ac;}}else{_4=abstractAltContent(obj);}var w=_2e.width?_2e.width:(obj.getAttribute("width")?obj.getAttribute("width"):0);if(parseInt(w,10)<310){w="310";}var h=_2e.height?_2e.height:(obj.getAttribute("height")?obj.getAttribute("height"):0);if(parseInt(h,10)<137){h="137";}var pt=ua.ie&&ua.win?"ActiveX":"PlugIn";document.title=document.title.slice(0,47)+" - Flash Player Installation";var dt=document.title;var fv="MMredirectURL="+window.location+"&MMplayerType="+pt+"&MMdoctitle="+dt;var el=obj;if(ua.ie&&ua.win&&obj.readyState!=4){el=document.createElement("div");obj.parentNode.insertBefore(el,obj);obj.style.display="none";window.attachEvent("onload",function(){obj.parentNode.removeChild(obj);});}createSWF({data:_2e.expressInstall,id:"SWFObjectExprInst",width:w,height:h},{flashvars:fv},el);}}function displayAltContent(obj){if(ua.ie&&ua.win&&obj.readyState!=4){var el=document.createElement("div");obj.parentNode.insertBefore(el,obj);el.parentNode.replaceChild(abstractAltContent(obj),el);obj.style.display="none";window.attachEvent("onload",function(){obj.parentNode.removeChild(obj);});}else{obj.parentNode.replaceChild(abstractAltContent(obj),obj);}}function abstractAltContent(obj){var ac=document.createElement("div");if(ua.win&&ua.ie){ac.innerHTML=obj.innerHTML;}else{var _3b=obj.getElementsByTagName("object")[0];if(_3b){var c=_3b.childNodes;if(c){var cl=c.length;for(var i=0;i<cl;i++){if(!(c[i].nodeType==1&&c[i].nodeName.toLowerCase()=="param")&&!(c[i].nodeType==8)){ac.appendChild(c[i].cloneNode(true));}}}}}return ac;}function createSWF(_3f,_40,el){if(ua.ie&&ua.win){var att="";for(var i in _3f){if(typeof _3f[i]=="string"){if(i=="data"){_40.movie=_3f[i];}else{if(i.toLowerCase()=="styleclass"){att+=" class=\""+_3f[i]+"\"";}else{if(i!="classid"){att+=" "+i+"=\""+_3f[i]+"\"";}}}}}var par="";for(var j in _40){if(typeof _40[j]=="string"){par+="<param name=\""+j+"\" value=\""+_40[j]+"\" />";}}el.outerHTML="<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\""+att+">"+par+"</object>";fixObjectLeaks();}else{if(ua.webkit&&ua.webkitVersion<312){var e=document.createElement("embed");e.setAttribute("type","application/x-shockwave-flash");for(var k in _3f){if(typeof _3f[k]=="string"){if(k=="data"){e.setAttribute("src",_3f[k]);}else{if(k.toLowerCase()=="styleclass"){e.setAttribute("class",_3f[k]);}else{if(k!="classid"){e.setAttribute(k,_3f[k]);}}}}}for(var l in _40){if(typeof _40[l]=="string"){if(l!="movie"){e.setAttribute(l,_40[l]);}}}el.parentNode.replaceChild(e,el);}else{var o=document.createElement("object");o.setAttribute("type","application/x-shockwave-flash");for(var m in _3f){if(typeof _3f[m]=="string"){if(m.toLowerCase()=="styleclass"){o.setAttribute("class",_3f[m]);}else{if(m!="classid"){o.setAttribute(m,_3f[m]);}}}}for(var n in _40){if(typeof _40[n]=="string"&&n!="movie"){createObjParam(o,n,_40[n]);}}el.parentNode.replaceChild(o,el);}}}function createObjParam(el,_4d,_4e){var p=document.createElement("param");p.setAttribute("name",_4d);p.setAttribute("value",_4e);el.appendChild(p);}function hasPlayerVersion(rv){return (ua.playerVersion[0]>rv[0]||(ua.playerVersion[0]==rv[0]&&ua.playerVersion[1]>rv[1])||(ua.playerVersion[0]==rv[0]&&ua.playerVersion[1]==rv[1]&&ua.playerVersion[2]>=rv[2]))?true:false;}function createCSS(sel,_52){if(ua.ie&&ua.mac){return;}var h=document.getElementsByTagName("head")[0];var s=document.createElement("style");s.setAttribute("type","text/css");s.setAttribute("media","screen");if(!(ua.ie&&ua.win)&&typeof document.createTextNode!="undefined"){s.appendChild(document.createTextNode(sel+" {"+_52+"}"));}h.appendChild(s);if(ua.ie&&ua.win&&typeof document.styleSheets!="undefined"&&document.styleSheets.length>0){var ls=document.styleSheets[document.styleSheets.length-1];if(typeof ls.addRule=="object"){ls.addRule(sel,_52);}}}return {registerObject:function(_56,_57,_58){if(!ua.w3cdom||!_56||!_57){return;}var _59={};_59.id=_56;var v=_57.split(".");_59.swfVersion=[parseInt(v[0],10),parseInt(v[1],10),parseInt(v[2],10)];_59.expressInstall=_58?_58:false;_2[_2.length]=_59;createCSS("#"+_56,"visibility:hidden");},getObjectById:function(_5b){var r=null;if(ua.w3cdom&&_5){var o=document.getElementById(_5b);if(o){var n=o.getElementsByTagName("object")[0];if(!n||(n&&typeof o.SetVariable!="undefined")){r=o;}else{if(typeof n.SetVariable!="undefined"){r=n;}}}}return r;},embedSWF:function(_5f,_60,_61,_62,_63,_64,_65,_66,_67){if(!ua.w3cdom||!_5f||!_60||!_61||!_62||!_63){return;}if(hasPlayerVersion(_63.split("."))){createCSS("#"+_60,"visibility:hidden");var att=(typeof _67=="object")?_67:{};att.data=_5f;att.width=_61;att.height=_62;var par=(typeof _66=="object")?_66:{};if(typeof _65=="object"){for(var i in _65){if(typeof _65[i]=="string"){if(typeof par.flashvars!="undefined"){par.flashvars+="&"+i+"="+_65[i];}else{par.flashvars=i+"="+_65[i];}}}}addDomLoadEvent(function(){createSWF(att,par,document.getElementById(_60));createCSS("#"+_60,"visibility:visible");});}else{if(_64&&!_6&&hasPlayerVersion([6,0,65])&&(ua.win||ua.mac)){createCSS("#"+_60,"visibility:hidden");addDomLoadEvent(function(){var _6b={};_6b.id=_6b.altContentId=_60;_6b.width=_61;_6b.height=_62;_6b.expressInstall=_64;showExpressInstall(_6b);createCSS("#"+_60,"visibility:visible");});}}},getFlashPlayerVersion:function(){return {major:ua.playerVersion[0],minor:ua.playerVersion[1],release:ua.playerVersion[2]};},hasFlashPlayerVersion:function(_6c){return hasPlayerVersion(_6c.split("."));},createSWF:function(_6d,_6e,el){if(ua.w3cdom&&_5){createSWF(_6d,_6e,el);}},createCSS:function(sel,_71){if(ua.w3cdom){createCSS(sel,_71);}},addDomLoadEvent:addDomLoadEvent,addLoadEvent:addLoadEvent,getQueryParamValue:function(_72){var q=document.location.search||document.location.hash;if(_72==null){return q;}if(q){var _74=q.substring(1).split("&");for(var i=0;i<_74.length;i++){if(_74[i].substring(0,_74[i].indexOf("="))==_72){return _74[i].substring((_74[i].indexOf("=")+1));}}}return "";},expressInstallCallback:function(){if(_6&&_4){var obj=document.getElementById("SWFObjectExprInst");if(obj){obj.parentNode.replaceChild(_4,obj);_4=null;_6=false;}}}};}();

/* BrowserDetect: http://www.quirksmode.org/js/detect.html */
var BrowserDetect={
	init:function() { this.browser = this.searchString(this.dataBrowser) || "Unknown Browser"; this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown Version"; this.OS = this.searchString(this.dataOS) || "Unknown OS"; },
	searchString:function(data) { for (var i=0;i<data.length;i++)	{ var dataString = data[i].string; var dataProp = data[i].prop; this.versionSearchString = data[i].versionSearch || data[i].identity; if (dataString) { if (dataString.indexOf(data[i].subString) != -1) {return data[i].identity;} } else if (dataProp) { return data[i].identity; } } },
	searchVersion:function(dataString) { var index = dataString.indexOf(this.versionSearchString); if (index == -1) {return;} return parseFloat(dataString.substring(index+this.versionSearchString.length+1)); },
	dataBrowser:[
		{ string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
		{ string: navigator.vendor, subString: "Apple", identity: "Safari" },
		{ prop: window.opera, identity: "Opera" },
		{ string: navigator.vendor, subString: "iCab", identity: "iCab" },
		{ string: navigator.vendor, subString: "KDE", identity: "Konqueror" },
		{ string: navigator.userAgent, subString: "Firefox", identity: "Firefox" },
		{ string: navigator.vendor, subString: "Camino", identity: "Camino" },
		{ string: navigator.userAgent, subString: "Netscape", identity: "Netscape" }, // newer Netscapes (6+)
		{ string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
		{ string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
		{ string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" } // older Netscapes (4-)
	],
	dataOS:[{ string: navigator.platform, subString: "Win", identity: "Windows" }, { string: navigator.platform, subString: "Mac", identity: "Mac" }, { string: navigator.platform, subString: "Linux", identity: "Linux" } ]
}

BrowserDetect.init();
