/*
 * Build No: 17443 
 */
/*
 * jQuery Cycle Plugin (with Transition Definitions)
 * Examples and documentation at: http://jquery.malsup.com/cycle/
 * Copyright (c) 2007-2010 M. Alsup
 * Version: 2.88 (08-JUN-2010)
 * Dual licensed under the MIT and GPL licenses.
 * http://jquery.malsup.com/license.html
 * Requires: jQuery v1.2.6 or later
 */
(function($){var ver="2.88";if($.support==undefined){$.support={opacity:!($.browser.msie)};}function debug(s){if($.fn.cycle.debug){log(s);}}function log(){if(window.console&&window.console.log){window.console.log("[cycle] "+Array.prototype.join.call(arguments," "));}}$.fn.cycle=function(options,arg2){var o={s:this.selector,c:this.context};if(this.length===0&&options!="stop"){if(!$.isReady&&o.s){log("DOM not ready, queuing slideshow");$(function(){$(o.s,o.c).cycle(options,arg2);});return this;}log("terminating; zero elements found by selector"+($.isReady?"":" (DOM not ready)"));return this;}return this.each(function(){var opts=handleArguments(this,options,arg2);if(opts===false){return;}opts.updateActivePagerLink=opts.updateActivePagerLink||$.fn.cycle.updateActivePagerLink;if(this.cycleTimeout){clearTimeout(this.cycleTimeout);}this.cycleTimeout=this.cyclePause=0;var $cont=$(this);var $slides=opts.slideExpr?$(opts.slideExpr,this):$cont.children();var els=$slides.get();if(els.length<2){log("terminating; too few slides: "+els.length);return;}var opts2=buildOptions($cont,$slides,els,opts,o);if(opts2===false){return;}var startTime=opts2.continuous?10:getTimeout(els[opts2.currSlide],els[opts2.nextSlide],opts2,!opts2.rev);if(startTime){startTime+=(opts2.delay||0);if(startTime<10){startTime=10;}debug("first timeout: "+startTime);this.cycleTimeout=setTimeout(function(){go(els,opts2,0,(!opts2.rev&&!opts.backwards));},startTime);}});};function handleArguments(cont,options,arg2){if(cont.cycleStop==undefined){cont.cycleStop=0;}if(options===undefined||options===null){options={};}if(options.constructor==String){switch(options){case"destroy":case"stop":var opts=$(cont).data("cycle.opts");if(!opts){return false;}cont.cycleStop++;if(cont.cycleTimeout){clearTimeout(cont.cycleTimeout);}cont.cycleTimeout=0;$(cont).removeData("cycle.opts");if(options=="destroy"){destroy(opts);}return false;case"toggle":cont.cyclePause=(cont.cyclePause===1)?0:1;checkInstantResume(cont.cyclePause,arg2,cont);return false;case"pause":cont.cyclePause=1;return false;case"resume":cont.cyclePause=0;checkInstantResume(false,arg2,cont);return false;case"prev":case"next":var opts=$(cont).data("cycle.opts");if(!opts){log('options not found, "prev/next" ignored');return false;}$.fn.cycle[options](opts);return false;default:options={fx:options};}return options;}else{if(options.constructor==Number){var num=options;options=$(cont).data("cycle.opts");if(!options){log("options not found, can not advance slide");return false;}if(num<0||num>=options.elements.length){log("invalid slide index: "+num);return false;}options.nextSlide=num;if(cont.cycleTimeout){clearTimeout(cont.cycleTimeout);cont.cycleTimeout=0;}if(typeof arg2=="string"){options.oneTimeFx=arg2;}go(options.elements,options,1,num>=options.currSlide);return false;}}return options;function checkInstantResume(isPaused,arg2,cont){if(!isPaused&&arg2===true){var options=$(cont).data("cycle.opts");if(!options){log("options not found, can not resume");return false;}if(cont.cycleTimeout){clearTimeout(cont.cycleTimeout);cont.cycleTimeout=0;}go(options.elements,options,1,(!opts.rev&&!opts.backwards));}}}function removeFilter(el,opts){if(!$.support.opacity&&opts.cleartype&&el.style.filter){try{el.style.removeAttribute("filter");}catch(smother){}}}function destroy(opts){if(opts.next){$(opts.next).unbind(opts.prevNextEvent);}if(opts.prev){$(opts.prev).unbind(opts.prevNextEvent);}if(opts.pager||opts.pagerAnchorBuilder){$.each(opts.pagerAnchors||[],function(){this.unbind().remove();});}opts.pagerAnchors=null;if(opts.destroy){opts.destroy(opts);}}function buildOptions($cont,$slides,els,options,o){var opts=$.extend({},$.fn.cycle.defaults,options||{},$.metadata?$cont.metadata():$.meta?$cont.data():{});if(opts.autostop){opts.countdown=opts.autostopCount||els.length;}var cont=$cont[0];$cont.data("cycle.opts",opts);opts.$cont=$cont;opts.stopCount=cont.cycleStop;opts.elements=els;opts.before=opts.before?[opts.before]:[];opts.after=opts.after?[opts.after]:[];opts.after.unshift(function(){opts.busy=0;});if(!$.support.opacity&&opts.cleartype){opts.after.push(function(){removeFilter(this,opts);});}if(opts.continuous){opts.after.push(function(){go(els,opts,0,(!opts.rev&&!opts.backwards));});}saveOriginalOpts(opts);if(!$.support.opacity&&opts.cleartype&&!opts.cleartypeNoBg){clearTypeFix($slides);}if($cont.css("position")=="static"){$cont.css("position","relative");}if(opts.width){$cont.width(opts.width);}if(opts.height&&opts.height!="auto"){$cont.height(opts.height);}if(opts.startingSlide){opts.startingSlide=parseInt(opts.startingSlide);}else{if(opts.backwards){opts.startingSlide=els.length-1;}}if(opts.random){opts.randomMap=[];for(var i=0;i<els.length;i++){opts.randomMap.push(i);}opts.randomMap.sort(function(a,b){return Math.random()-0.5;});opts.randomIndex=1;opts.startingSlide=opts.randomMap[1];}else{if(opts.startingSlide>=els.length){opts.startingSlide=0;}}opts.currSlide=opts.startingSlide||0;var first=opts.startingSlide;$slides.css({position:"absolute",top:0,left:0}).hide().each(function(i){var z;if(opts.backwards){z=first?i<=first?els.length+(i-first):first-i:els.length-i;}else{z=first?i>=first?els.length-(i-first):first-i:els.length-i;}$(this).css("z-index",z);});$(els[first]).css("opacity",1).show();removeFilter(els[first],opts);if(opts.fit&&opts.width){$slides.width(opts.width);}if(opts.fit&&opts.height&&opts.height!="auto"){$slides.height(opts.height);}var reshape=opts.containerResize&&!$cont.innerHeight();if(reshape){var maxw=0,maxh=0;for(var j=0;j<els.length;j++){var $e=$(els[j]),e=$e[0],w=$e.outerWidth(),h=$e.outerHeight();if(!w){w=e.offsetWidth||e.width||$e.attr("width");}if(!h){h=e.offsetHeight||e.height||$e.attr("height");}maxw=w>maxw?w:maxw;maxh=h>maxh?h:maxh;}if(maxw>0&&maxh>0){$cont.css({width:maxw+"px",height:maxh+"px"});}}if(opts.pause){$cont.hover(function(){this.cyclePause++;},function(){this.cyclePause--;});}if(supportMultiTransitions(opts)===false){return false;}var requeue=false;options.requeueAttempts=options.requeueAttempts||0;$slides.each(function(){var $el=$(this);this.cycleH=(opts.fit&&opts.height)?opts.height:($el.height()||this.offsetHeight||this.height||$el.attr("height")||0);this.cycleW=(opts.fit&&opts.width)?opts.width:($el.width()||this.offsetWidth||this.width||$el.attr("width")||0);if($el.is("img")){var loadingIE=($.browser.msie&&this.cycleW==28&&this.cycleH==30&&!this.complete);var loadingFF=($.browser.mozilla&&this.cycleW==34&&this.cycleH==19&&!this.complete);var loadingOp=($.browser.opera&&((this.cycleW==42&&this.cycleH==19)||(this.cycleW==37&&this.cycleH==17))&&!this.complete);var loadingOther=(this.cycleH==0&&this.cycleW==0&&!this.complete);if(loadingIE||loadingFF||loadingOp||loadingOther){if(o.s&&opts.requeueOnImageNotLoaded&&++options.requeueAttempts<100){log(options.requeueAttempts," - img slide not loaded, requeuing slideshow: ",this.src,this.cycleW,this.cycleH);setTimeout(function(){$(o.s,o.c).cycle(options);},opts.requeueTimeout);requeue=true;return false;}else{log("could not determine size of image: "+this.src,this.cycleW,this.cycleH);}}}return true;});if(requeue){return false;}opts.cssBefore=opts.cssBefore||{};opts.animIn=opts.animIn||{};opts.animOut=opts.animOut||{};$slides.not(":eq("+first+")").css(opts.cssBefore);if(opts.cssFirst){$($slides[first]).css(opts.cssFirst);}if(opts.timeout){opts.timeout=parseInt(opts.timeout);if(opts.speed.constructor==String){opts.speed=$.fx.speeds[opts.speed]||parseInt(opts.speed);}if(!opts.sync){opts.speed=opts.speed/2;}var buffer=opts.fx=="shuffle"?500:250;while((opts.timeout-opts.speed)<buffer){opts.timeout+=opts.speed;}}if(opts.easing){opts.easeIn=opts.easeOut=opts.easing;}if(!opts.speedIn){opts.speedIn=opts.speed;}if(!opts.speedOut){opts.speedOut=opts.speed;}opts.slideCount=els.length;opts.currSlide=opts.lastSlide=first;if(opts.random){if(++opts.randomIndex==els.length){opts.randomIndex=0;}opts.nextSlide=opts.randomMap[opts.randomIndex];}else{if(opts.backwards){opts.nextSlide=opts.startingSlide==0?(els.length-1):opts.startingSlide-1;}else{opts.nextSlide=opts.startingSlide>=(els.length-1)?0:opts.startingSlide+1;}}if(!opts.multiFx){var init=$.fn.cycle.transitions[opts.fx];if($.isFunction(init)){init($cont,$slides,opts);}else{if(opts.fx!="custom"&&!opts.multiFx){log("unknown transition: "+opts.fx,"; slideshow terminating");return false;}}}var e0=$slides[first];if(opts.before.length){opts.before[0].apply(e0,[e0,e0,opts,true]);}if(opts.after.length>1){opts.after[1].apply(e0,[e0,e0,opts,true]);}if(opts.next){$(opts.next).bind(opts.prevNextEvent,function(){return advance(opts,opts.rev?-1:1);});}if(opts.prev){$(opts.prev).bind(opts.prevNextEvent,function(){return advance(opts,opts.rev?1:-1);});}if(opts.pager||opts.pagerAnchorBuilder){buildPager(els,opts);}exposeAddSlide(opts,els);return opts;}function saveOriginalOpts(opts){opts.original={before:[],after:[]};opts.original.cssBefore=$.extend({},opts.cssBefore);opts.original.cssAfter=$.extend({},opts.cssAfter);opts.original.animIn=$.extend({},opts.animIn);opts.original.animOut=$.extend({},opts.animOut);$.each(opts.before,function(){opts.original.before.push(this);});$.each(opts.after,function(){opts.original.after.push(this);});}function supportMultiTransitions(opts){var i,tx,txs=$.fn.cycle.transitions;if(opts.fx.indexOf(",")>0){opts.multiFx=true;opts.fxs=opts.fx.replace(/\s*/g,"").split(",");for(i=0;i<opts.fxs.length;i++){var fx=opts.fxs[i];tx=txs[fx];if(!tx||!txs.hasOwnProperty(fx)||!$.isFunction(tx)){log("discarding unknown transition: ",fx);opts.fxs.splice(i,1);i--;}}if(!opts.fxs.length){log("No valid transitions named; slideshow terminating.");return false;}}else{if(opts.fx=="all"){opts.multiFx=true;opts.fxs=[];for(p in txs){tx=txs[p];if(txs.hasOwnProperty(p)&&$.isFunction(tx)){opts.fxs.push(p);}}}}if(opts.multiFx&&opts.randomizeEffects){var r1=Math.floor(Math.random()*20)+30;for(i=0;i<r1;i++){var r2=Math.floor(Math.random()*opts.fxs.length);opts.fxs.push(opts.fxs.splice(r2,1)[0]);}debug("randomized fx sequence: ",opts.fxs);}return true;}function exposeAddSlide(opts,els){opts.addSlide=function(newSlide,prepend){var $s=$(newSlide),s=$s[0];if(!opts.autostopCount){opts.countdown++;}els[prepend?"unshift":"push"](s);if(opts.els){opts.els[prepend?"unshift":"push"](s);}opts.slideCount=els.length;$s.css("position","absolute");$s[prepend?"prependTo":"appendTo"](opts.$cont);if(prepend){opts.currSlide++;opts.nextSlide++;}if(!$.support.opacity&&opts.cleartype&&!opts.cleartypeNoBg){clearTypeFix($s);}if(opts.fit&&opts.width){$s.width(opts.width);}if(opts.fit&&opts.height&&opts.height!="auto"){$slides.height(opts.height);}s.cycleH=(opts.fit&&opts.height)?opts.height:$s.height();s.cycleW=(opts.fit&&opts.width)?opts.width:$s.width();$s.css(opts.cssBefore);if(opts.pager||opts.pagerAnchorBuilder){$.fn.cycle.createPagerAnchor(els.length-1,s,$(opts.pager),els,opts);}if($.isFunction(opts.onAddSlide)){opts.onAddSlide($s);}else{$s.hide();}};}$.fn.cycle.resetState=function(opts,fx){fx=fx||opts.fx;opts.before=[];opts.after=[];opts.cssBefore=$.extend({},opts.original.cssBefore);opts.cssAfter=$.extend({},opts.original.cssAfter);opts.animIn=$.extend({},opts.original.animIn);opts.animOut=$.extend({},opts.original.animOut);opts.fxFn=null;$.each(opts.original.before,function(){opts.before.push(this);});$.each(opts.original.after,function(){opts.after.push(this);});var init=$.fn.cycle.transitions[fx];if($.isFunction(init)){init(opts.$cont,$(opts.elements),opts);}};function go(els,opts,manual,fwd){if(manual&&opts.busy&&opts.manualTrump){debug("manualTrump in go(), stopping active transition");$(els).stop(true,true);opts.busy=false;}if(opts.busy){debug("transition active, ignoring new tx request");return;}var p=opts.$cont[0],curr=els[opts.currSlide],next=els[opts.nextSlide];if(p.cycleStop!=opts.stopCount||p.cycleTimeout===0&&!manual){return;}if(!manual&&!p.cyclePause&&!opts.bounce&&((opts.autostop&&(--opts.countdown<=0))||(opts.nowrap&&!opts.random&&opts.nextSlide<opts.currSlide))){if(opts.end){opts.end(opts);}return;}var changed=false;if((manual||!p.cyclePause)&&(opts.nextSlide!=opts.currSlide)){changed=true;var fx=opts.fx;curr.cycleH=curr.cycleH||$(curr).height();curr.cycleW=curr.cycleW||$(curr).width();next.cycleH=next.cycleH||$(next).height();next.cycleW=next.cycleW||$(next).width();if(opts.multiFx){if(opts.lastFx==undefined||++opts.lastFx>=opts.fxs.length){opts.lastFx=0;}fx=opts.fxs[opts.lastFx];opts.currFx=fx;}if(opts.oneTimeFx){fx=opts.oneTimeFx;opts.oneTimeFx=null;}$.fn.cycle.resetState(opts,fx);if(opts.before.length){$.each(opts.before,function(i,o){if(p.cycleStop!=opts.stopCount){return;}o.apply(next,[curr,next,opts,fwd]);});}var after=function(){$.each(opts.after,function(i,o){if(p.cycleStop!=opts.stopCount){return;}o.apply(next,[curr,next,opts,fwd]);});};debug("tx firing; currSlide: "+opts.currSlide+"; nextSlide: "+opts.nextSlide);opts.busy=1;if(opts.fxFn){opts.fxFn(curr,next,opts,after,fwd,manual&&opts.fastOnEvent);}else{if($.isFunction($.fn.cycle[opts.fx])){$.fn.cycle[opts.fx](curr,next,opts,after,fwd,manual&&opts.fastOnEvent);}else{$.fn.cycle.custom(curr,next,opts,after,fwd,manual&&opts.fastOnEvent);}}}if(changed||opts.nextSlide==opts.currSlide){opts.lastSlide=opts.currSlide;if(opts.random){opts.currSlide=opts.nextSlide;if(++opts.randomIndex==els.length){opts.randomIndex=0;}opts.nextSlide=opts.randomMap[opts.randomIndex];if(opts.nextSlide==opts.currSlide){opts.nextSlide=(opts.currSlide==opts.slideCount-1)?0:opts.currSlide+1;}}else{if(opts.backwards){var roll=(opts.nextSlide-1)<0;if(roll&&opts.bounce){opts.backwards=!opts.backwards;opts.nextSlide=1;opts.currSlide=0;}else{opts.nextSlide=roll?(els.length-1):opts.nextSlide-1;opts.currSlide=roll?0:opts.nextSlide+1;}}else{var roll=(opts.nextSlide+1)==els.length;if(roll&&opts.bounce){opts.backwards=!opts.backwards;opts.nextSlide=els.length-2;opts.currSlide=els.length-1;}else{opts.nextSlide=roll?0:opts.nextSlide+1;opts.currSlide=roll?els.length-1:opts.nextSlide-1;}}}}if(changed&&opts.pager){opts.updateActivePagerLink(opts.pager,opts.currSlide,opts.activePagerClass);}var ms=0;if(opts.timeout&&!opts.continuous){ms=getTimeout(els[opts.currSlide],els[opts.nextSlide],opts,fwd);}else{if(opts.continuous&&p.cyclePause){ms=10;}}if(ms>0){p.cycleTimeout=setTimeout(function(){go(els,opts,0,(!opts.rev&&!opts.backwards));},ms);}}$.fn.cycle.updateActivePagerLink=function(pager,currSlide,clsName){$(pager).each(function(){$(this).children().removeClass(clsName).eq(currSlide).addClass(clsName);});};function getTimeout(curr,next,opts,fwd){if(opts.timeoutFn){var t=opts.timeoutFn.call(curr,curr,next,opts,fwd);while((t-opts.speed)<250){t+=opts.speed;}debug("calculated timeout: "+t+"; speed: "+opts.speed);if(t!==false){return t;}}return opts.timeout;}$.fn.cycle.next=function(opts){advance(opts,opts.rev?-1:1);};$.fn.cycle.prev=function(opts){advance(opts,opts.rev?1:-1);};function advance(opts,val){var els=opts.elements;var p=opts.$cont[0],timeout=p.cycleTimeout;if(timeout){clearTimeout(timeout);p.cycleTimeout=0;}if(opts.random&&val<0){opts.randomIndex--;if(--opts.randomIndex==-2){opts.randomIndex=els.length-2;}else{if(opts.randomIndex==-1){opts.randomIndex=els.length-1;}}opts.nextSlide=opts.randomMap[opts.randomIndex];}else{if(opts.random){opts.nextSlide=opts.randomMap[opts.randomIndex];}else{opts.nextSlide=opts.currSlide+val;if(opts.nextSlide<0){if(opts.nowrap){return false;}opts.nextSlide=els.length-1;}else{if(opts.nextSlide>=els.length){if(opts.nowrap){return false;}opts.nextSlide=0;}}}}var cb=opts.onPrevNextEvent||opts.prevNextClick;if($.isFunction(cb)){cb(val>0,opts.nextSlide,els[opts.nextSlide]);}go(els,opts,1,val>=0);return false;}function buildPager(els,opts){var $p=$(opts.pager);$.each(els,function(i,o){$.fn.cycle.createPagerAnchor(i,o,$p,els,opts);});opts.updateActivePagerLink(opts.pager,opts.startingSlide,opts.activePagerClass);}$.fn.cycle.createPagerAnchor=function(i,el,$p,els,opts){var a;if($.isFunction(opts.pagerAnchorBuilder)){a=opts.pagerAnchorBuilder(i,el);debug("pagerAnchorBuilder("+i+", el) returned: "+a);}else{a='<a href="#">'+(i+1)+"</a>";}if(!a){return;}var $a=$(a);if($a.parents("body").length===0){var arr=[];if($p.length>1){$p.each(function(){var $clone=$a.clone(true);$(this).append($clone);arr.push($clone[0]);});$a=$(arr);}else{$a.appendTo($p);}}opts.pagerAnchors=opts.pagerAnchors||[];opts.pagerAnchors.push($a);$a.bind(opts.pagerEvent,function(e){e.preventDefault();opts.nextSlide=i;var p=opts.$cont[0],timeout=p.cycleTimeout;if(timeout){clearTimeout(timeout);p.cycleTimeout=0;}var cb=opts.onPagerEvent||opts.pagerClick;if($.isFunction(cb)){cb(opts.nextSlide,els[opts.nextSlide]);}go(els,opts,1,opts.currSlide<i);});if(!/^click/.test(opts.pagerEvent)&&!opts.allowPagerClickBubble){$a.bind("click.cycle",function(){return false;});}if(opts.pauseOnPagerHover){$a.hover(function(){opts.$cont[0].cyclePause++;},function(){opts.$cont[0].cyclePause--;});}};$.fn.cycle.hopsFromLast=function(opts,fwd){var hops,l=opts.lastSlide,c=opts.currSlide;if(fwd){hops=c>l?c-l:opts.slideCount-l;}else{hops=c<l?l-c:l+opts.slideCount-c;}return hops;};function clearTypeFix($slides){debug("applying clearType background-color hack");function hex(s){s=parseInt(s).toString(16);return s.length<2?"0"+s:s;}function getBg(e){for(;e&&e.nodeName.toLowerCase()!="html";e=e.parentNode){var v=$.css(e,"background-color");if(v.indexOf("rgb")>=0){var rgb=v.match(/\d+/g);return"#"+hex(rgb[0])+hex(rgb[1])+hex(rgb[2]);}if(v&&v!="transparent"){return v;}}return"#ffffff";}$slides.each(function(){$(this).css("background-color",getBg(this));});}$.fn.cycle.commonReset=function(curr,next,opts,w,h,rev){$(opts.elements).not(curr).hide();opts.cssBefore.opacity=1;opts.cssBefore.display="block";if(w!==false&&next.cycleW>0){opts.cssBefore.width=next.cycleW;}if(h!==false&&next.cycleH>0){opts.cssBefore.height=next.cycleH;}opts.cssAfter=opts.cssAfter||{};opts.cssAfter.display="none";$(curr).css("zIndex",opts.slideCount+(rev===true?1:0));$(next).css("zIndex",opts.slideCount+(rev===true?0:1));};$.fn.cycle.custom=function(curr,next,opts,cb,fwd,speedOverride){var $l=$(curr),$n=$(next);var speedIn=opts.speedIn,speedOut=opts.speedOut,easeIn=opts.easeIn,easeOut=opts.easeOut;$n.css(opts.cssBefore);if(speedOverride){if(typeof speedOverride=="number"){speedIn=speedOut=speedOverride;}else{speedIn=speedOut=1;}easeIn=easeOut=null;}var fn=function(){$n.animate(opts.animIn,speedIn,easeIn,cb);};$l.animate(opts.animOut,speedOut,easeOut,function(){if(opts.cssAfter){$l.css(opts.cssAfter);}if(!opts.sync){fn();}});if(opts.sync){fn();}};$.fn.cycle.transitions={fade:function($cont,$slides,opts){$slides.not(":eq("+opts.currSlide+")").css("opacity",0);opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts);opts.cssBefore.opacity=0;});opts.animIn={opacity:1};opts.animOut={opacity:0};opts.cssBefore={top:0,left:0};}};$.fn.cycle.ver=function(){return ver;};$.fn.cycle.defaults={fx:"fade",timeout:4000,timeoutFn:null,continuous:0,speed:1000,speedIn:null,speedOut:null,next:null,prev:null,onPrevNextEvent:null,prevNextEvent:"click.cycle",pager:null,onPagerEvent:null,pagerEvent:"click.cycle",allowPagerClickBubble:false,pagerAnchorBuilder:null,before:null,after:null,end:null,easing:null,easeIn:null,easeOut:null,shuffle:null,animIn:null,animOut:null,cssBefore:null,cssAfter:null,fxFn:null,height:"auto",startingSlide:0,sync:1,random:0,fit:0,containerResize:1,pause:0,pauseOnPagerHover:0,autostop:0,autostopCount:0,delay:0,slideExpr:null,cleartype:!$.support.opacity,cleartypeNoBg:false,nowrap:0,fastOnEvent:0,randomizeEffects:1,rev:0,manualTrump:true,requeueOnImageNotLoaded:true,requeueTimeout:250,activePagerClass:"activeSlide",updateActivePagerLink:null,backwards:false};})(jQuery);
/*
 * jQuery Cycle Plugin Transition Definitions
 * This script is a plugin for the jQuery Cycle Plugin
 * Examples and documentation at: http://malsup.com/jquery/cycle/
 * Copyright (c) 2007-2010 M. Alsup
 * Version:	 2.72
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 */
(function($){$.fn.cycle.transitions.none=function($cont,$slides,opts){opts.fxFn=function(curr,next,opts,after){$(next).show();$(curr).hide();after();};};$.fn.cycle.transitions.scrollUp=function($cont,$slides,opts){$cont.css("overflow","hidden");opts.before.push($.fn.cycle.commonReset);var h=$cont.height();opts.cssBefore={top:h,left:0};opts.cssFirst={top:0};opts.animIn={top:0};opts.animOut={top:-h};};$.fn.cycle.transitions.scrollDown=function($cont,$slides,opts){$cont.css("overflow","hidden");opts.before.push($.fn.cycle.commonReset);var h=$cont.height();opts.cssFirst={top:0};opts.cssBefore={top:-h,left:0};opts.animIn={top:0};opts.animOut={top:h};};$.fn.cycle.transitions.scrollLeft=function($cont,$slides,opts){$cont.css("overflow","hidden");opts.before.push($.fn.cycle.commonReset);var w=$cont.width();opts.cssFirst={left:0};opts.cssBefore={left:w,top:0};opts.animIn={left:0};opts.animOut={left:0-w};};$.fn.cycle.transitions.scrollRight=function($cont,$slides,opts){$cont.css("overflow","hidden");opts.before.push($.fn.cycle.commonReset);var w=$cont.width();opts.cssFirst={left:0};opts.cssBefore={left:-w,top:0};opts.animIn={left:0};opts.animOut={left:w};};$.fn.cycle.transitions.scrollHorz=function($cont,$slides,opts){$cont.css("overflow","hidden").width();opts.before.push(function(curr,next,opts,fwd){$.fn.cycle.commonReset(curr,next,opts);opts.cssBefore.left=fwd?(next.cycleW-1):(1-next.cycleW);opts.animOut.left=fwd?-curr.cycleW:curr.cycleW;});opts.cssFirst={left:0};opts.cssBefore={top:0};opts.animIn={left:0};opts.animOut={top:0};};$.fn.cycle.transitions.scrollVert=function($cont,$slides,opts){$cont.css("overflow","hidden");opts.before.push(function(curr,next,opts,fwd){$.fn.cycle.commonReset(curr,next,opts);opts.cssBefore.top=fwd?(1-next.cycleH):(next.cycleH-1);opts.animOut.top=fwd?curr.cycleH:-curr.cycleH;});opts.cssFirst={top:0};opts.cssBefore={left:0};opts.animIn={top:0};opts.animOut={left:0};};$.fn.cycle.transitions.slideX=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$(opts.elements).not(curr).hide();$.fn.cycle.commonReset(curr,next,opts,false,true);opts.animIn.width=next.cycleW;});opts.cssBefore={left:0,top:0,width:0};opts.animIn={width:"show"};opts.animOut={width:0};};$.fn.cycle.transitions.slideY=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$(opts.elements).not(curr).hide();$.fn.cycle.commonReset(curr,next,opts,true,false);opts.animIn.height=next.cycleH;});opts.cssBefore={left:0,top:0,height:0};opts.animIn={height:"show"};opts.animOut={height:0};};$.fn.cycle.transitions.shuffle=function($cont,$slides,opts){var i,w=$cont.css("overflow","visible").width();$slides.css({left:0,top:0});opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,true,true);});if(!opts.speedAdjusted){opts.speed=opts.speed/2;opts.speedAdjusted=true;}opts.random=0;opts.shuffle=opts.shuffle||{left:-w,top:15};opts.els=[];for(i=0;i<$slides.length;i++){opts.els.push($slides[i]);}for(i=0;i<opts.currSlide;i++){opts.els.push(opts.els.shift());}opts.fxFn=function(curr,next,opts,cb,fwd){var $el=fwd?$(curr):$(next);$(next).css(opts.cssBefore);var count=opts.slideCount;$el.animate(opts.shuffle,opts.speedIn,opts.easeIn,function(){var hops=$.fn.cycle.hopsFromLast(opts,fwd);for(var k=0;k<hops;k++){fwd?opts.els.push(opts.els.shift()):opts.els.unshift(opts.els.pop());}if(fwd){for(var i=0,len=opts.els.length;i<len;i++){$(opts.els[i]).css("z-index",len-i+count);}}else{var z=$(curr).css("z-index");$el.css("z-index",parseInt(z)+1+count);}$el.animate({left:0,top:0},opts.speedOut,opts.easeOut,function(){$(fwd?this:curr).hide();if(cb){cb();}});});};opts.cssBefore={display:"block",opacity:1,top:0,left:0};};$.fn.cycle.transitions.turnUp=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,false);opts.cssBefore.top=next.cycleH;opts.animIn.height=next.cycleH;});opts.cssFirst={top:0};opts.cssBefore={left:0,height:0};opts.animIn={top:0};opts.animOut={height:0};};$.fn.cycle.transitions.turnDown=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,false);opts.animIn.height=next.cycleH;opts.animOut.top=curr.cycleH;});opts.cssFirst={top:0};opts.cssBefore={left:0,top:0,height:0};opts.animOut={height:0};};$.fn.cycle.transitions.turnLeft=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,true);opts.cssBefore.left=next.cycleW;opts.animIn.width=next.cycleW;});opts.cssBefore={top:0,width:0};opts.animIn={left:0};opts.animOut={width:0};};$.fn.cycle.transitions.turnRight=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,true);opts.animIn.width=next.cycleW;opts.animOut.left=curr.cycleW;});opts.cssBefore={top:0,left:0,width:0};opts.animIn={left:0};opts.animOut={width:0};};$.fn.cycle.transitions.zoom=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,false,true);opts.cssBefore.top=next.cycleH/2;opts.cssBefore.left=next.cycleW/2;opts.animIn={top:0,left:0,width:next.cycleW,height:next.cycleH};opts.animOut={width:0,height:0,top:curr.cycleH/2,left:curr.cycleW/2};});opts.cssFirst={top:0,left:0};opts.cssBefore={width:0,height:0};};$.fn.cycle.transitions.fadeZoom=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,false);opts.cssBefore.left=next.cycleW/2;opts.cssBefore.top=next.cycleH/2;opts.animIn={top:0,left:0,width:next.cycleW,height:next.cycleH};});opts.cssBefore={width:0,height:0};opts.animOut={opacity:0};};$.fn.cycle.transitions.blindX=function($cont,$slides,opts){var w=$cont.css("overflow","hidden").width();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts);opts.animIn.width=next.cycleW;opts.animOut.left=curr.cycleW;});opts.cssBefore={left:w,top:0};opts.animIn={left:0};opts.animOut={left:w};};$.fn.cycle.transitions.blindY=function($cont,$slides,opts){var h=$cont.css("overflow","hidden").height();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts);opts.animIn.height=next.cycleH;opts.animOut.top=curr.cycleH;});opts.cssBefore={top:h,left:0};opts.animIn={top:0};opts.animOut={top:h};};$.fn.cycle.transitions.blindZ=function($cont,$slides,opts){var h=$cont.css("overflow","hidden").height();var w=$cont.width();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts);opts.animIn.height=next.cycleH;opts.animOut.top=curr.cycleH;});opts.cssBefore={top:h,left:w};opts.animIn={top:0,left:0};opts.animOut={top:h,left:w};};$.fn.cycle.transitions.growX=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,true);opts.cssBefore.left=this.cycleW/2;opts.animIn={left:0,width:this.cycleW};opts.animOut={left:0};});opts.cssBefore={width:0,top:0};};$.fn.cycle.transitions.growY=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,false);opts.cssBefore.top=this.cycleH/2;opts.animIn={top:0,height:this.cycleH};opts.animOut={top:0};});opts.cssBefore={height:0,left:0};};$.fn.cycle.transitions.curtainX=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,false,true,true);opts.cssBefore.left=next.cycleW/2;opts.animIn={left:0,width:this.cycleW};opts.animOut={left:curr.cycleW/2,width:0};});opts.cssBefore={top:0,width:0};};$.fn.cycle.transitions.curtainY=function($cont,$slides,opts){opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,false,true);opts.cssBefore.top=next.cycleH/2;opts.animIn={top:0,height:next.cycleH};opts.animOut={top:curr.cycleH/2,height:0};});opts.cssBefore={left:0,height:0};};$.fn.cycle.transitions.cover=function($cont,$slides,opts){var d=opts.direction||"left";var w=$cont.css("overflow","hidden").width();var h=$cont.height();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts);if(d=="right"){opts.cssBefore.left=-w;}else{if(d=="up"){opts.cssBefore.top=h;}else{if(d=="down"){opts.cssBefore.top=-h;}else{opts.cssBefore.left=w;}}}});opts.animIn={left:0,top:0};opts.animOut={opacity:1};opts.cssBefore={top:0,left:0};};$.fn.cycle.transitions.uncover=function($cont,$slides,opts){var d=opts.direction||"left";var w=$cont.css("overflow","hidden").width();var h=$cont.height();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,true,true);if(d=="right"){opts.animOut.left=w;}else{if(d=="up"){opts.animOut.top=-h;}else{if(d=="down"){opts.animOut.top=h;}else{opts.animOut.left=-w;}}}});opts.animIn={left:0,top:0};opts.animOut={opacity:1};opts.cssBefore={top:0,left:0};};$.fn.cycle.transitions.toss=function($cont,$slides,opts){var w=$cont.css("overflow","visible").width();var h=$cont.height();opts.before.push(function(curr,next,opts){$.fn.cycle.commonReset(curr,next,opts,true,true,true);if(!opts.animOut.left&&!opts.animOut.top){opts.animOut={left:w*2,top:-h/2,opacity:0};}else{opts.animOut.opacity=0;}});opts.cssBefore={left:0,top:0};opts.animIn={left:0};};$.fn.cycle.transitions.wipe=function($cont,$slides,opts){var w=$cont.css("overflow","hidden").width();var h=$cont.height();opts.cssBefore=opts.cssBefore||{};var clip;if(opts.clip){if(/l2r/.test(opts.clip)){clip="rect(0px 0px "+h+"px 0px)";}else{if(/r2l/.test(opts.clip)){clip="rect(0px "+w+"px "+h+"px "+w+"px)";}else{if(/t2b/.test(opts.clip)){clip="rect(0px "+w+"px 0px 0px)";}else{if(/b2t/.test(opts.clip)){clip="rect("+h+"px "+w+"px "+h+"px 0px)";}else{if(/zoom/.test(opts.clip)){var top=parseInt(h/2);var left=parseInt(w/2);clip="rect("+top+"px "+left+"px "+top+"px "+left+"px)";}}}}}}opts.cssBefore.clip=opts.cssBefore.clip||clip||"rect(0px 0px 0px 0px)";var d=opts.cssBefore.clip.match(/(\d+)/g);var t=parseInt(d[0]),r=parseInt(d[1]),b=parseInt(d[2]),l=parseInt(d[3]);opts.before.push(function(curr,next,opts){if(curr==next){return;}var $curr=$(curr),$next=$(next);$.fn.cycle.commonReset(curr,next,opts,true,true,false);opts.cssAfter.display="block";var step=1,count=parseInt((opts.speedIn/13))-1;(function f(){var tt=t?t-parseInt(step*(t/count)):0;var ll=l?l-parseInt(step*(l/count)):0;var bb=b<h?b+parseInt(step*((h-b)/count||1)):h;var rr=r<w?r+parseInt(step*((w-r)/count||1)):w;$next.css({clip:"rect("+tt+"px "+rr+"px "+bb+"px "+ll+"px)"});(step++<=count)?setTimeout(f,13):$curr.css("display","none");})();});opts.cssBefore={display:"block",opacity:1,top:0,left:0};opts.animIn={left:0};opts.animOut={left:0};};})(jQuery);

Date.prototype.setISO8601 = function(dString) {
		var regexp = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)(:)?(\d\d)(\.\d+)?(Z|([+-])(\d\d)(:)?(\d\d))/;
		if (dString.toString().match(new RegExp(regexp))) {
			var d = dString.match(new RegExp(regexp));
			var offset = 0;
			this.setUTCDate(1);
			this.setUTCFullYear(parseInt(d[1], 10));
			this.setUTCMonth(parseInt(d[3], 10) - 1);
			this.setUTCDate(parseInt(d[5], 10));
			this.setUTCHours(parseInt(d[7], 10));
			this.setUTCMinutes(parseInt(d[9], 10));
			this.setUTCSeconds(parseInt(d[11], 10));
			if (d[12])
				this.setUTCMilliseconds(parseFloat(d[12]) * 1000);
			else
				this.setUTCMilliseconds(0);
			if (d[13] != 'Z') {
				offset = (d[15] * 60) + parseInt(d[17], 10);
				offset *= ((d[14] == '-') ? -1 : 1);
				this.setTime(this.getTime() - offset * 60 * 1000);
			}
		} else {
			this.setTime(Date.parse(dString));
		}
		return this;
	};

 
/**
 * Observant Visualisation Javascript API
 *
 * @author Robert Tooker
 * @author Prashant Raju
 */

/*
 * obsviz is the 'namespace' for the Observant Visualisation Javascript API
 */
var obsviz = (function() {
    /**
     * BASE_URL
     * The base URL for JSONP calls
     */
    var BASE_URL = 'http://obsrv.it/ringo';

    /**
     * EXPORT_URL
     * The URL to post data against
     */
    var EXPORT_URL = 'http://obsrv.it/jsapi/exporter';

    /**
     * DEBUG
     * Outputs debugging information to console if running firebug
     */
    var DEBUG = 'true';

    /**
     * DEBUG_LEVEL
     * The debugging level (1-5) where 1 = ALL LOGGING
     *                                 2 = FINE GRAINED
     *                                 3 = DEFAULT
     *                                 4 = ERROR INFORMATION ONLY
     *                                 5 = FATAL ERRORS ONLY
     */
    var DEBUG_LEVEL = '3';

    /**
     * SYSPLANS
     * "Associative Array" of system plan objects, where the index is the plan ID
     */
    var SYSPLANS = {};

    /**
     * SYSINSTANCES
     * "Associative Array" of system instance objects, where the index is the plan ID
     */
    var SYSINSTANCES = {};

    /**
     * SYSDATA
     * "Associative Array" of system data, where the index is the data URL
     */
    var SYSDATA = {};

    /**
     * GALLERIES
     * "Associative Array" of galleries, where the index is the container div
     */
    var GALLERIES = {};
    
    /**
     * THEME
     *  - Base : always use 
     *  - Light
     *  - Dark
     */
    var newBASE = { chartOptions: {
    	chart: {
			margin: [80, 30, 60, 70],
	        style: {
	        	fontFamily: '10px "Helvetica Neue", Helvetica, Verdana, Arial, sans-serif'
	        }
	    },
	    colors: ["#ff5110", "#7cc26e", "#5f9cd2", "#f7a661", "#9d68aa", "#cb705b", "#d580b3", "#737373"],
	    legend: {enabled: false},
	    credits: {enabled: true},
	    tooltip: {
			backgroundColor: {
				linearGradient: [0, 0, 0, 50],
				stops: [
					[0, 'rgba(96, 96, 96, .8)'],
					[1, 'rgba(16, 16, 16, .8)']
				]
			},
			borderWidth: 0,
			style: {
				color: '#FFF'
			}
		},
	    xAxis: {
	    	lineWidth: 0.5,
	    	tickColor: '#777',
	    	lineColor: '#777',
	        type: 'datetime',
	        dateTimeLabelFormats: {
                second: '%H:%M:%S',
                minute: '%H:%M',
                hour: '%l:%M%P',
                day: '%e %b',
                week: '%e %b',
                month: '%b %y',
                year: '%Y'
            },
            labels: {
            	style: { 
					color: '#999'
				}
            }
	    },
	    plotOptions: {
         line: {
            lineWidth: 2,
            states: {
               hover: {
                  lineWidth: 3
               }
            },
            marker: {
               enabled: false,
               states: {
                  hover: {
                     enabled: true,
                     symbol: 'circle',
                     radius: 8,
                     lineWidth: 1
                  }
               }   
            }
         },
         column: {
         	borderWidth: 0,
         	borderColor: "#ff5110"
         },
         series: {
         	shadow: false,
         	animation: false
         }
        }
    }};
    var THEME = {
    	base: {
    		chartOptions: {
    			chart: {
    				plotBackgroundColor: null,
					plotShadow: false,
					plotBorderWidth: 0,
					margin: [80, 30, 60, 70],
					backgroundColor: {
						linearGradient: [0, 0, 0, 100],
						stops: [
							[0, 'rgb(255, 255, 255)'],
							[1, 'rgb(238, 238, 238)']
						]
					}
    			},
				colors: ["#ff5110", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee", 
		"#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
				title: {
					style: { 
						font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif',
						margin: '10px 0 0 15px',
						textAlign: 'left'
					}
				},
				subtitle: {
					style: { 
						font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif',
						margin: '5px 0 0 15px',
						textAlign: 'left'
					}
				},
				xAxis: {
					lineColor: '#777',
					tickColor: '#777',
					labels: {
						style: {
							color: '#777'
						}
					},
					title: {
						style: {
							font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
						}				
					}
				},
				yAxis: {
					alternateGridColor: null,
					minorTickInterval: null,
					lineWidth: 1,
					lineColor: '#777',
					tickWidth: 1,
					tickColor: '#777',
					labels: {
						style: {
							color: '#777'
						}
					},
					title: {
						style: {
							font: 'normal 11px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
						}
					}
				},
				legend: {
					enabled: false,
					itemStyle: {
						color: '#CCC'
					},
					itemHoverStyle: {
						color: '#FFF'
					},
					itemHiddenStyle: {
						color: '#333'
					}
				},
				credits: {
					style: {
						right: '10px',
						bottom: '10px'
					}
				},
				labels: {
					style: {
						color: '#CCC'
					}
				},
				tooltip: {
					backgroundColor: {
						linearGradient: [0, 0, 0, 50],
						stops: [
							[0, 'rgba(96, 96, 96, .8)'],
							[1, 'rgba(16, 16, 16, .8)']
						]
					},
					borderWidth: 0,
					style: {
						color: '#FFF'
					}
				},
				plotOptions: {
					line: {
						lineWidth: 1,
						marker: {
							lineWidth: 0,
							lineColor: '#ff5110',
							radius: 0,
							states: {
				               hover: {
				                  enabled: true,
				                  radius: 4,
				                  lineWidth: 3
				               }
				            }
						}
					},
					column: {
						lineWidth: 4,
						borderWidth: 0
					},
					area: {
			         lineWidth: 2,
			         marker: {
			            enabled: false,
			            states: {
			               hover: {
			                  enabled: true,
			                  radius: 4
			               }
			            }
			         },
			         series: {
				         shadow: false,
				         animation: false,
				         states: {
				            hover: {
				               lineWidth: 3                  
				            }
				         }
			         }
			       }
				}
    		}
    	},
    	light: {
    		chartOptions: {
	    		chart: {
					backgroundColor: {
						linearGradient: [0, 0, 0, 100],
						stops: [
							[0, 'rgb(255, 255, 255)'],
							[1, 'rgb(238, 238, 238)']
						]
					},
					borderWidth: 0.1,
					borderColor: '#999',
					borderRadius: 10
				},
				title: {
					style: { 
						color: '#000'
					}
				},
				subtitle: {
					style: { 
						color: '#666'
					}
				},
				xAxis: {
					title: {
						style: {
							color: '#000'
						}				
					}
				},
				yAxis: {
					gridLineColor: 'rgba(0, 0, 0, .1)',
					title: {
						style: {
							color: '#000'
						}
					}
				},
				plotOptions: {
					area: {
			         fillColor: {
			            linearGradient: [0, 0, 0, 200],
			            stops: [
			               [0, 'rgba(255,81,16,1)'],
			               [1, 'rgba(255,255,255,0)']
			            ]
			         }
			      }
				}
	        }
    	},
    	dark: {
    		chartOptions: {
    			chart: {
	                backgroundColor: {
						linearGradient: [0, 0, 0, 100],
						stops: [
							[0, 'rgb(46, 51, 56)'],
							[1, 'rgb(18, 21, 24)']
						]
					},
					borderWidth: 0,
					borderRadius: 5
	            },
	            title: {
					style: { 
						color: '#FFF'					
					}
				},
				subtitle: {
					style: { 
						color: '#999'
					}
				},
				xAxis: {
					title: {
						style: {
							color: '#fff'
						}				
					}
				},
				yAxis: {
					gridLineColor: 'rgba(255, 255, 255, .1)',
					title: {
						style: {
							color: '#fff'
						}				
					}
				},
				plotOptions: {
					area: {
			         fillColor: {
			            linearGradient: [0, 0, 0, 300],
			            stops: [
			               [0, 'rgba(255,81,16,1)'],
			               [1, 'rgba(0,0,0,0)']
			            ]
			         }
			      }
				}
			}
    	}
    };
    
    /**
     * Creates the photo after the system plan has been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param system the observant system
     */
    function photoCallBack(container, options, sysplan) {
        // set default options and merge in user options
        var baseOptions = {
            defaultSize: false
        };
        var empty = {};
        var mergedOptions = {};
        if (options.photoOptions !== undefined) {
            mergedOptions = jQuery.extend(true, empty, baseOptions, options.photoOptions);
        } else {
            mergedOptions = jQuery.extend(true, empty, baseOptions);
        }

        // if a visualisation has been defined then search for it
        var activeEntity = null;
        if(options.vizId){
            jQuery.each(sysplan.entities, function(i,entity){
                // check if the vizId has been set perform normal loop
                if(options.vizId == entity.viz){
                    activeEntity = entity;
                }
            });
        } else {
            // not defined, just get the first camera viz
            jQuery.each(sysplan.entities, function(i,entity){
                if(entity.dataType == "Photo" && !activeEntity){
                    activeEntity = entity;
                }
            });
        }
        
        if (!activeEntity) {
            if (options.vizId) {
                error('Could not find camera visualisation with visualisation ID <em>' + options.vizId + '</em>.', container);
            } else {
                error('Could not find camera visualisation for that system plan.', container);
            }
        } else {
        	// !!! v2 photo get
        	
        	var currentValue = activeEntity.currentValue;
        	
        	if (!currentValue) {
                error('No current photo found for <em>' + entity.viz + '</em>.', container);
            } else {
                var src = BASE_URL + currentValue + '?_overlay=true&media=jpeg';
                if (options.resAuthKey) {
                	src = src + '&resAuthKey='+options.resAuthKey;
                }
                // If the defaultSize is TRUE
                if(mergedOptions.defaultSize) {
                    $('#'+container).html('<img src="'+src+'" alt="'+ sysplan.label +' '+ activeEntity.secondaryLabel + '" class="obsviz-photo" />');
                } else {
                    var imageWidth = $('#' + container).width() > 0 ? $('#' + container).width() : 480;
                    var imageHeight = $('#' + container).height() > 0 ? $('#' + container).height() : Math.min(360, imageWidth*0.75);
                    
                    // set 4:3 ratio
        			imageHeight = Math.min(imageWidth*0.75);
                    
                    $('#'+container).html('<img src="'+src+'" alt="'+ sysplan.label +' '+ activeEntity.secondaryLabel + '" width="' + imageWidth + '" height="' + imageHeight + '" class="obsviz-photo" />');
                }
            }
        }
    }

    /**
     * Creates the photo gallery after the system plan has been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysInstance the observant system instance
     */
    function photoGalleryCallBack(container, options, sysInstance) {
        // photoGallery options
        var baseOptions = {
            cleartypeNoBg: true
            , cleartype: true
        };

        var empty = {};
        var mergedOptions = {};
        if (options.photoGalleryOptions !== undefined) {
            mergedOptions = jQuery.extend(true, empty, baseOptions, options.photoGalleryOptions);
        } else {
            mergedOptions = jQuery.extend(true, empty, baseOptions);
        }

        // control panel options
        var baseControlPanelOptions = {
            enabled: true
        };

        var mergedControlPanelOptions = {};
        if (options.controlPanelOptions !== undefined) {
            mergedControlPanelOptions = jQuery.extend(true, empty, baseControlPanelOptions, options.controlPanelOptions);
        } else {
            mergedControlPanelOptions = jQuery.extend(true, empty, baseControlPanelOptions);
        }
        // get the image information
		var imageProperties = getImageProperties(sysInstance, options.vizIds, options.resAuthKey, options.photoGalleryOptions.photosToFetch, options.photoGalleryOptions.dailyPhotos, options.photoGalleryOptions.days);
        
        // clear container and add the slideshow class
        $('#'+container).html('');
        $('#'+container).addClass('obsviz-gallery-container');

        // add image container and slideshow class
        $('#'+container).append('<div class="obsviz-image-container slideshow"></div>');

        var imageContainer = $('#' + container + ' .obsviz-image-container');

        // set width and height
        var imageWidth = $('#' + container).width() > 0 ? $('#' + container).width() : 480;
        var imageHeight = $('#' + container).height() > 0 ? $('#' + container).height() : Math.min(360, imageWidth*0.75);
        
        // set to 4:3 ratio instead
        imageHeight = Math.min(imageWidth*0.75);
        
        // add the images (hidden), show most recent photo first
        for (var i=imageProperties.length-1; i >=0 ; i--) {
            var displayType = '';
            if (i == imageProperties.length-1) {
                displayType = 'block';
            } else {
                displayType = 'none';
            }
            $(imageContainer).prepend('<img src="'+imageProperties[i].url+'" alt="'+imageProperties[i].vizId+'" width="'+imageWidth+'" height="'+imageHeight+'" + style="display: '+displayType+';" />');
        }
		
/*
        $.each(imageProperties, function(i, imageProperty) {
            var displayType = '';
            if (i == imageProperties.length-1) {
                displayType = 'block';
            } else {
                displayType = 'none';
            }
            $(imageContainer).append('<img src="'+imageProperty.url+'" alt="'+imageProperty.vizId+'" width="'+imageWidth+'" height="'+imageHeight+'" + style="display: '+displayType+';"></img>');
        });
*/

        // add controls if required
        if (mergedControlPanelOptions.enabled) {
            // add control container and hover event
            $('#'+container).append('<div class="obsviz-control-container"></div>');
            var controlContainer = '#'+container+' .obsviz-control-container';
            $('#'+container).hover(
                function() { $(controlContainer).fadeIn(); },
                function() { $(controlContainer).fadeOut(); }
            );

            // add controls
            $(controlContainer).append('<span><a href="#" class="obsviz-prev"><span>Prev</span></a></span>');
			$(controlContainer).append('<span><a href="#" class="obsviz-pause"><span>Pause</span></a></span>');
            $(controlContainer).append('<span><a href="#" class="obsviz-play"><span>Play</span></a></span>');
            $(controlContainer).append('<span><a href="#" class="obsviz-next"><span>Next</span></a></span>');
            
            // add control events
            $('#'+container + ' .obsviz-pause').click(function() { 
                $(imageContainer).cycle('pause'); $(this).hide(); $(this).parent().parent().find(".obsviz-play").show(); return false;
            });
            $('#'+container + ' .obsviz-play').click(function() { 
                $(imageContainer).cycle('resume'); $(this).hide(); $(this).parent().parent().find(".obsviz-pause").show(); return false;
            });
            $('#'+container + ' .obsviz-next').click(function() {
                $(imageContainer).cycle('next'); return false;
            });
            $('#'+container + ' .obsviz-prev').click(function() {
                $(imageContainer).cycle('prev'); return false;
            });
        }

        // cycle images, 
        $(imageContainer).cycle(mergedOptions);
        
		if (options.photoGalleryOptions.autoStart === undefined || !options.photoGalleryOptions.autoStart) {
			// start from most recent and pause it.
			$(imageContainer).cycle('prev');
			$(imageContainer).cycle('pause')        	
        	$(controlContainer + " .obsviz-pause").hide();
        } else {
			$(controlContainer + " .obsviz-play").hide();
        }
       
        if (options.photoGalleryOptions.photosToFetch !== undefined) {
        } else {
        }
    }

    /**
     * Returns the image properties
     * @param sysInstance the observant system instance
     * @param vizIds optional list of viz IDs
     * @param resAuthKey optional authorisation key
     * @return mixed the image data
     */
    function getImageProperties(sysInstance, vizIds, resAuthKey, photosToFetch, dailyPhotos, days) {
        var imageProperties = [];
        var imagePropertyIndex = 0;
        // run through viz IDs
        $.each(vizIds, function(i, vizId){
            // run through system instance to match the viz ID
            $.each(sysInstance.entities, function(j, entity) {
                // match to vizId
                if (vizId == entity.viz) {
					if(entity.dataType == 'photo') {
						if ((photosToFetch !== undefined) || (days !== undefined)) {
							var photoHistory = entity.history.series;
							var fetch;
							if (photosToFetch === undefined) {
								fetch = photoHistory.length;
							} else {
								fetch = photosToFetch;
							}
							// start from the most recent
							for(var k=photoHistory.length-1; k>=0; k--) {
								// only set the images based on the photosToFetch
								if (photoHistory.length-k <= fetch) {
			                        imageProperties[imagePropertyIndex] = {};
			                        imageProperties[imagePropertyIndex].vizId = vizId;
			                        imageProperties[imagePropertyIndex].dataType = entity.dataType;
			                        imageProperties[imagePropertyIndex].urlFragment = "/photos/"+photoHistory[k].value+"/image";
			                        imageProperties[imagePropertyIndex].url = BASE_URL + imageProperties[imagePropertyIndex].urlFragment + '?_overlay=true&media=jpeg';
			                        if(resAuthKey) {
			                        	imageProperties[imagePropertyIndex].url = imageProperties[imagePropertyIndex].url + '&resAuthKey=' + resAuthKey;
			                        }
			                        imagePropertyIndex++;
								} else {
									break;
								}
							}
						} else if (dailyPhotos !== undefined) {
							var photoHistory = entity.history.series;
							var skip = Math.floor(photoHistory.length / (days*dailyPhotos));
							
							for(var k=photoHistory.length-1; k>=0; k=k-skip) {
		                        imageProperties[imagePropertyIndex] = {};
		                        imageProperties[imagePropertyIndex].vizId = vizId;
		                        imageProperties[imagePropertyIndex].dataType = entity.dataType;
		                        imageProperties[imagePropertyIndex].urlFragment = "/photos/"+photoHistory[k].value+"/image";
		                        imageProperties[imagePropertyIndex].url = BASE_URL + imageProperties[imagePropertyIndex].urlFragment + '?_overlay=true&media=jpeg';
		                        if(resAuthKey) {
		                        	imageProperties[imagePropertyIndex].url = imageProperties[imagePropertyIndex].url + '&resAuthKey=' + resAuthKey;
		                        }
		                        imagePropertyIndex++;
							}
						} else {
	                        // add to image property array
	                        imageProperties[imagePropertyIndex] = {};
	                        imageProperties[imagePropertyIndex].vizId = vizId;
	                        imageProperties[imagePropertyIndex].dataType = entity.dataType;
	                        imageProperties[imagePropertyIndex].urlFragment = entity.currentValue;
	                        imageProperties[imagePropertyIndex].url = BASE_URL + entity.currentValue + '?_overlay=true&media=jpeg';
	                        if(resAuthKey) {
	                        	imageProperties[imagePropertyIndex].url = imageProperties[imagePropertyIndex].url + '&resAuthKey=' + resAuthKey;
	                        }
	/*
	                        imageProperties[imagePropertyIndex].lastCommunicationTime = vizField.currentValue.lastCommunicationTime;
	                        imageProperties[imagePropertyIndex].lastUpdateTime = vizField.currentValue.lastUpdateTime;
	*/
	                        imagePropertyIndex++;
	                    }
                    }
                }
            });
        });
		
		// return the array with the oldest photo first
        return imageProperties.reverse();
    }

    /**
     * Returns the name of the viz based on the vizId
     * @param vizId the viz ID
     * @param sysPlan the observant system plan
     * @return string the name of the viz
     */
    function findNameForViz(vizId, sysPlan) {
    	var name;
        $.each(sysPlan.vizContainer.vizReferences, function(i, vizRef){
        	if(vizRef.vizId == vizId) {
        		name = vizRef.name;
        	}
        });
    	return name;
    }
    /**
     * Returns the field reference that has a history spec for the nominated viz
     * @param viz the viz
     * @return the designated history field
     */
    function findHistoryFieldForViz(viz) {
    	var fld;
    	$.each(viz.fieldReferences, function(i,fldReference){
            if (fldReference.history !== undefined) {
            	fld = fldReference;
            }
        });
    	return fld;
    }

    /**
     * Creates the map after the system plan has been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysInstance the observant system 
     */
    function mapCallBack(container, options, system) {
        // loop through system instance to create markers and map bounds
        var mapPoints = [];
        var mapBounds = new google.maps.LatLngBounds();
        var pointCounter = 0;
        var systemGeo = (system.geolocation !== undefined) ? system.geolocation : "";
        var systemGeoPoint = -1;
		
        $.each(system.entities, function(i, entity){
        	if (entity.geolocation !== undefined) {
        		// when there is geo location on entity
        		mapPoints[pointCounter] = {};
                mapPoints[pointCounter].latitude = entity.geolocation.latitude;
                mapPoints[pointCounter].longitude = entity.geolocation.longitude;
                mapPoints[pointCounter].latlng = new google.maps.LatLng(entity.geolocation.latitude, entity.geolocation.longitude);
                mapPoints[pointCounter].icon = "http://maps.google.com/mapfiles/marker" + String.fromCharCode(pointCounter + 65) + ".png";
                mapPoints[pointCounter].name = entity.label;
                mapBounds.extend(mapPoints[pointCounter].latlng);
                pointCounter++;
        	} else {
        		if (systemGeo && systemGeoPoint == -1) {
        			mapPoints[pointCounter] = {};
	                mapPoints[pointCounter].latitude = systemGeo.latitude;
	                mapPoints[pointCounter].longitude = systemGeo.longitude;
	                mapPoints[pointCounter].latlng = new google.maps.LatLng(systemGeo.latitude, systemGeo.longitude);
	                mapPoints[pointCounter].icon = "http://maps.google.com/mapfiles/marker" + String.fromCharCode(pointCounter + 65) + ".png";
	                mapPoints[pointCounter].name = entity.label;
	                mapBounds.extend(mapPoints[pointCounter].latlng);
	                systemGeoPoint = pointCounter;
	                pointCounter++;
        		} else if (systemGeo) {
        			mapPoints[systemGeoPoint].name = mapPoints[systemGeoPoint].name + ", " + entity.label ;
        		}
        	}
        });

        // create the map using the marker boundaries to define zoom and centre
        var mapOptions = {
          center: mapBounds.getCenter(),
          mapTypeId: google.maps.MapTypeId.HYBRID
        };
        var map = new google.maps.Map(document.getElementById(container), mapOptions);
        if (mapPoints.length > 1) {
            map.fitBounds(mapBounds);
        } else {
            map.setZoom(10);
        }
		
		var infoWindow = new google.maps.InfoWindow({
		    position: map.getCenter()
		});
		
        // add markers to map
        $.each(mapPoints, function(i, mapPoint) {
            var marker = new google.maps.Marker({
               position: mapPoint.latlng
               , map: map
               , title: mapPoint.name
               , icon: mapPoints[i].icon
            });
            if (options.mapOptions && (eval("typeof " + options.mapOptions.markerClickFn + " == 'function'")) ) {
                google.maps.event.addListener(
                    marker
                    , 'click'
                    , function() {
                        options.mapOptions.markerClickFn(mapPoint.latitude, mapPoint.longitude);
                    });
            } else {
            	google.maps.event.addListener(
	                marker
	                , 'click'
	                , function() {
	                	// if you want infoWindow to show
	                	infoWindow.content = mapPoint.name;
	                    infoWindow.open(map, marker);
	            });
            }
        });
    }
    
    

    /**
     * Calls a call back funtion after the system plan and instance have been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysInstance the observant system
     */
    function systemCallBack(container, options, system) {
        debug('systemCallBack', 1);
        options.callBackFn(system);
    }
    
    /**
     * Calls a call back funtion after the system plan and instance have been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysInstance the observant system
     */
    function orgCallBack(container, options, system) {
        debug('orgCallBack', 1);
        options.callBackFn(system);
    }
    
    /**
     * Creates the chart, table or CSV after the system plan has been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysPlan the observant system plan
     * @param renderCallBackFn the call back function to render the visualisation with the signature fn(container, plotData, options)
     */
    function dataVizCallBack(container, options, sysPlan, renderCallBackFn) {
        var undefinedVizIdError = new Error ("No visualisation specified in options.");
        try {
            var activeViz = {};
            var activeField = {};
            var dataUrl = '';

            // vizId required for charts and tables
            if (options.vizId === undefined) {
                throw undefinedVizIdError;
            }

            var notFoundVizIdError = new Error ("Could not find visualisation for vizId <em>" + options.vizId + "</em>.");

            // cycle through sysPlan to find the viz reference
            // !!! v2
            jQuery.each(sysPlan.entities, function(i,entity){
            	// compare vizid first, if found, set ActiveViz
            	if((entity.name == options.fieldId) && (entity.viz == options.vizId)) {
            		activeViz = entity.viz;
            		activeField = entity.name;
            		debug("active: " + options.fieldId, 3);
                }
            });

            // check if viz returned
            if (empty(activeViz)) {
                throw notFoundVizIdError;
            }

            // create the url
            // !!! v2 url
            dataUrl = BASE_URL + '/systems/' + options.orgId + '/' + options.planId + '/' + activeViz + '/' + activeField + '/history?historySpec=' + options.history + '&media=json';
           

            if (options.resAuthKey) {
                dataUrl = dataUrl + '&resAuthKey=' + options.resAuthKey;
            }


            // check if we already have this data
            if (SYSDATA[dataUrl] !== undefined) {
            	debug("SYSDATA[dataUrl] here: " + SYSDATA[dataUrl], 3);
                var sysInstance = SYSDATA[dataUrl];
                var plotData = getPlotData(sysPlan, options, activeViz, activeField, sysInstance);
                if (plotData) {
            		renderCallBackFn(container, plotData, options);
            	} else {
            		error("plotData error", container);
            	}
            } else {
                // go get it
                debug("go get " + dataUrl, 3);
                
                // create the chart or table or download
                jQuery.ajax({
                    type: 'GET',
                    url : dataUrl,
                    success : function(sysInstance) {
                        debug(sysInstance, 3);
                        SYSDATA[dataUrl] = sysInstance;
						
						if (sysInstance.entities[0].errorCode !== undefined) {
							var entityError = sysInstance.entities[0].errorCode +  ": " + sysInstance.entities[0].errorReason;
							debug("Error " + entityError);
                        	error(entityError, container);
                        } else {
                        	var plotData = getPlotData(sysPlan, options, activeViz, activeField, sysInstance);
                        	if (plotData) {
                        		renderCallBackFn(container, plotData, options);
                        	} else {
                        		error("plotData error", container);
                        	}
                        }	
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        error(errorThrown, container);
                        debug(XMLHttpRequest);
                        debug(textStatus);
                        debug(errorThrown);
                    }
                });

            }
            

        }
        catch(e) {
            error(e.message, container);
        }
    }

    /**
     * Creates the chart gallery after the system plan has been obtained
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     * @param sysPlan the observant system plan
     */
    function chartGalleryCallBack(container, options, sysPlan) {
        // clear the container
        $('#'+container).html('');
        GALLERIES[container].activeEntities = [];

        // get the visualisations allowed to use
        // !!! - targeting specific viz
        if(options.vizId){
            jQuery.each(sysPlan.entities, function(i,entity){
                // check if the vizId has been set perform normal loop
                debug("options.orgId : "+options.orgId + " | sysPlan.orgId : " + sysPlan.orgId);
                debug("options.planId : "+options.planId + " | sysPlan.name : " + sysPlan.name);
                debug("options.vizId : "+options.vizId + " | entity.viz : " + entity.viz);
                debug("options.fieldId : "+options.fieldId + " | entity.name : " + entity.name);
                
                if((options.orgId == sysPlan.orgId) && (options.planId == sysPlan.name) && 
                	(options.vizId == entity.viz) && (options.fieldId == entity.name)) {
                	debug("check -");
                	GALLERIES[container].activeEntity = entity;
                }
            });
        }
        
        // !!! v2
        jQuery.each(sysPlan.entities, function(i,entity){
        	if (entity.historySpec !== undefined && entity.dataType != "photo") {
        		GALLERIES[container].activeEntities.push(entity);
        		
        		// Set the first entity as to show
        		if(GALLERIES[container].activeEntity == undefined) {
        			debug("set active entity: " + entity.label, 3);
                    GALLERIES[container].activeEntity = entity;
                }
        	}
        });

        // choose the active viz and the history specification
        GALLERIES[container].activeHistorySpecification = null;                                  // set this later, can be different for each viz

        // these are the IDs for containers that need to be referenced later
        GALLERIES[container].chartContainer = container + 'obsviz-cg-body';
        GALLERIES[container].vizSelectContainer = container + 'obsviz-cg-select';
        GALLERIES[container].historyContainer = container + 'obsviz-cg-history';

        var headerHeight = 58;
        var chartContainerHeight = $('#' + container).height() - 20; // 20 for padding and borders
        
        // Append the wrapper
        $('#'+container).append('<div class="obsviz-cg-wrap"></div>');
        // Append the header to the wrapper
        $('#'+container+' .obsviz-cg-wrap').append('<div class="obsviz-cg-header"></div>');
        // Append the header left wrapper to the header
        $('#'+container+' .obsviz-cg-wrap .obsviz-cg-header').append('<div class="obsviz-cg-header-left"></div>');
        
        // Append the header title to the header left wrapper
		// !!! v2 header
	 	$('#'+container+' .obsviz-cg-wrap .obsviz-cg-header .obsviz-cg-header-left').append('<div class="obsviz-cg-header-title"><h3>'+sysPlan.label+':</h3></div>');

        // Append the viz id select box to the header left wrappers
        $('#'+container+' .obsviz-cg-wrap .obsviz-cg-header .obsviz-cg-header-left').append('<div id="' + GALLERIES[container].vizSelectContainer + '" class="obsviz-cg-select"></div>');
        // Append the header right to the header
        $('#'+container+' .obsviz-cg-wrap .obsviz-cg-header').append('<div id="' + GALLERIES[container].historyContainer + '" class="obsviz-cg-history"><div class="historyDiv"></div></div>');
        // Append the clear div for floats
        $('#'+container+' .obsviz-cg-header').append('<div class="obsviz-cg-clear"></div>');
        // Append the body to the wrapper
        $('#'+container+' .obsviz-cg-wrap').append('<div id="' + GALLERIES[container].chartContainer + '" class="obsviz-cg-body" style="height:' + chartContainerHeight + 'px;"></div>');


        // add select list with change event to refresh chart and history links
        // deep copy the options for the chart
        var chartOptions = {};
        var chartLinkOptions = {};
        jQuery.extend(true, chartOptions, options);
        jQuery.extend(true, chartLinkOptions, options);
        if(!options.vizId){
            // create the select box
            var vizIdSelectHtml = '<select class="obsviz-cg-select-viz">';
            // !!! v2 selection
            jQuery.each(GALLERIES[container].activeEntities, function(i,entity) {
        		if (entity.historySpec !== undefined) {
                	vizIdSelectHtml += '<option value="'+entity.label+':'+entity.name+'">'+entity.label+'</option>';
                }
            });
            vizIdSelectHtml += '</select>';
	        $(vizIdSelectHtml).appendTo('#' + GALLERIES[container].vizSelectContainer).change(function(e) {
	        	// get header for this chart
	        	var titleH3 = $(this).parent().parent().find(".obsviz-cg-header-title h3");
	            // set the entity values
	            jQuery.each(GALLERIES[container].activeEntities, function(i,entity) {
	            	var labels = e.currentTarget.value.split(':');
	                if(entity.label == labels[0]) {
	                	titleH3.text(entity.site);
	                    GALLERIES[container].activeEntity = entity;
	                }
	            });
	
	            // reset history specification
	            GALLERIES[container].activeHistorySpecification = null;
	            // render the links
	            renderChartGalleryHistoryLinks(container, chartLinkOptions, sysPlan);
	            // render the chart
	            renderChartGalleryChart(container, chartOptions);
	            return false;
	        });
        }

        // render the chart and history links for first run
        // deep copy the options for each
        var chartGalleryLinkOptions = {};
        var chartGalleryChartOptions = {};
        jQuery.extend(true, chartGalleryLinkOptions, options);
        jQuery.extend(true, chartGalleryChartOptions, options);
        renderChartGalleryHistoryLinks(container, chartGalleryLinkOptions, sysPlan);
        renderChartGalleryChart(container, chartGalleryChartOptions);
    }

    /**
     * renderChartGalleryHistoryLinks renders the history links for the chart gallery
     * @param container the container div
     * @param options an object representing the options
     * @param sysPlan the system plan
     */
    function renderChartGalleryHistoryLinks(container, options, sysPlan) {
    	debug("renderChartGalleryHistoryLinks", 3);
        // set history specifications
        // !!! v2 history spec
        GALLERIES[container].historySpecifications = GALLERIES[container].activeEntity.historySpec.split(',');

        // set default
        if (!GALLERIES[container].activeHistorySpecification) {
            GALLERIES[container].activeHistorySpecification = GALLERIES[container].historySpecifications[0];
        }

        $('#' + GALLERIES[container].historyContainer).html('').append('<div class="historyDiv"></div>');

        // for the history specifications need click event
        // deep copy the options for the chart
        var chartOptions = {};
        jQuery.extend(true, chartOptions, options);
        jQuery.each(GALLERIES[container].historySpecifications, function(i, historySpecification) {
        	/* get first two chars of the history specs */
        	var historyText = historySpecification.substring(0,2);
        	
			/* if (i > 0) {
                $('#' + GALLERIES[container].historyContainer).append(' - ');
            } */

            if (historySpecification == GALLERIES[container].activeHistorySpecification) {
                $('#' + GALLERIES[container].historyContainer + ' .historyDiv').append('<span class="obsviz-cg-history-text">' + historyText + '</span>');
            } else {
                // need to change this as click event is on the container
                $('<a href="#" class="obsviz-cg-history-text" title="' + historySpecification + '">' + historyText + '</a>').appendTo('#' + GALLERIES[container].historyContainer + ' .historyDiv').click(function() {
                    // redo the links and the chart
                    GALLERIES[container].activeHistorySpecification = historySpecification;
                    renderChartGalleryHistoryLinks(container, chartOptions, sysPlan);
                    renderChartGalleryChart(container, chartOptions);
                    return false;
                });
            }
        });
        
        // add the download link if required
        var showLink = true;
        if (options.showLink !== undefined) {
            showLink = options.showLink;
        }
        
        if (showLink) {
            var spanId = container + '_download_link';
            // add export text so doesn't flash while loading the data
            
            //$('#' + GALLERIES[container].historyContainer).append('<span id="'+ spanId +'" class="obsviz-csv-export"><a>CSV Exportlalala &rarr;</a></span>');
             $('#' + GALLERIES[container].historyContainer).append('<div class="utils_menu"><a class="utils_link" title="Click to view more options"><span>menu</span></a><ul class="utils_ul hide"><li id="'+ spanId +'" class="obsviz-csv-export"></li></ul></div>');
			
			$("a.utils_link").toggle(
				function () {
			        $(this).parent().find("ul.utils_ul").fadeIn();
			        return false;
			    },
			    function () {
			        $(this).parent().find("ul.utils_ul").fadeOut();
			        return false;
			    }
			);
			
            var chartOptions = {};
            jQuery.extend(true, chartOptions, options);
            
            // !!! v2 options
            chartOptions.name = GALLERIES[container].activeEntity.label;
            chartOptions.vizId = GALLERIES[container].activeEntity.viz;
            chartOptions.fieldId = GALLERIES[container].activeEntity.name;

            chartOptions.history = GALLERIES[container].activeHistorySpecification;
            obsviz.DownloadLink(spanId, chartOptions);
        }
    }

    /**
     * renderChartGalleryChart renders the chart for the chart gallery using the Chart object
     * @param container the container div for the gallery
     * @param options an object representing the options, will be passed to the callback function
     * @return void
     */
    function renderChartGalleryChart(container, options) {
    	debug("renderChartGalleryChart", 3);
        // deep copy the options for the chart gallery chart
        var chartOptions = {};
        jQuery.extend(true, chartOptions, options);
        chartOptions.name = GALLERIES[container].activeEntity.label;
        chartOptions.vizId = GALLERIES[container].activeEntity.viz;
        chartOptions.fieldId = GALLERIES[container].activeEntity.name;
        chartOptions.history = GALLERIES[container].activeHistorySpecification;
        chartOptions.showLink = false;
        var chart = new obsviz.Chart(GALLERIES[container].chartContainer, chartOptions);
    }

    /**
     * getSystem get the system plan ANd system instance from observant and runs a callback function
     * @param container the container div, will be passed to the callback function
     * @param options an object representing the options, will be passed to the callback function
     * @param callbackFn the callback funtion which accepts the container, options, and system
     * @returns void
     */
    function getSystem(container, options, callbackFn) {
        debug('getSystem', 1);
        // system gets both plan and instance by chaining the asynchronous json requests
        //getSystemPlan(container, options, getSystemCallBack, callbackFn);
        getSystemPlan(container, options, callbackFn);
    }

    /**
     * getSystemCallBack call back function for getSystem
     * @param container the container div, will be passed to the callback function
     * @param options an object representing the options, will be passed to the callback function
     * @param sysPlan the system plan
     * @param callbackFn the callback funtion which accepts the container, options, system instance and system plan
     * @returns void
     */
    function getSystemCallBack(container, options, sysPlan, callbackFn) {
        debug('getSystemCallBack', 1);
        getSystemInstance(container, options, callbackFn, sysPlan);
    }

    /**
     * getSystemPlan get the system plan from observant and runs a callback function
     * @param container the container div, will be passed to the callback function
     * @param options an object representing the options, will be passed to the callback function
     * @param callbackFn the callback funtion which accepts the container and options parameters, plus the system plan object
     * @param renderCallBackFn the call back function to render the visualisation with the signature fn(container, plotData, options)
     * @returns void
     */
    function getSystemPlan(container, options, callbackFn, renderCallBackFn) {
        debug('getSystemPlan', 1);
        undefinedOrgIdError = new Error ("No organisation ID specified in options.");
        undefinedPlanIdError = new Error ("No system plan ID specified in options.");
        
        try {
            // make sure we have the required fields to get a system plan
            if (options.orgId === undefined) {
                throw undefinedOrgIdError;
            }

            if (options.planId === undefined) {
                throw undefinedPlanIdError;
            }
			
            // check if the system plan has already been retrieved and use object if so
            if (SYSPLANS[options.planId] !== undefined) {
                callbackFn(container, options, SYSPLANS[options.planId], renderCallBackFn);
            } else {
                // url for sysplan
                // !!! v2 Protocol
				var observantSysPlanUrl = BASE_URL + '/systems/' + options.orgId + '/' + options.planId + '/current?media=json';

                if (options.resAuthKey) {
                    observantSysPlanUrl = observantSysPlanUrl + '&resAuthKey=' + options.resAuthKey;
                }

                debug ('getSystemPlan.observantSysPlanUrl: ' + observantSysPlanUrl, 1);
                jQuery.ajax({
                    type: 'GET',
                    url : observantSysPlanUrl,
                    success : function(sysPlan) {
                        debug(sysPlan, 3);
                        SYSPLANS[options.planId] = sysPlan;
                        callbackFn(container, options, sysPlan, renderCallBackFn);
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        error(errorThrown, container);
                        debug(XMLHttpRequest, 4);
                        debug(textStatus, 4);
                        debug(errorThrown, 4);
                    }
                });
            }
        }
        catch(e) {
            error(e.message, container);
        }
    }
    
    /**
     * getSystemPlans get the system plan from observant and runs a callback function
     * @param container the container div, will be passed to the callback function
     * @param options an object representing the options, will be passed to the callback function
     * @param callbackFn the callback funtion which accepts the container and options parameters, plus the system plan object
     * @param renderCallBackFn the call back function to render the visualisation with the signature fn(container, plotData, options)
     * @returns void
     */
    function getSystemPlans(container, options, callbackFn) {
        debug('getSystemPlans', 1);
        
        try {
			
            var observantSysPlansUrl = BASE_URL + '/systems?' + 'summary=true&media=json';

            if (options.resAuthKey) {
                observantSysPlansUrl = observantSysPlansUrl + '&resAuthKey=' + options.resAuthKey;
            }

            debug ('getSystemPlans.observantSysPlansUrl: ' + observantSysPlansUrl, 1);
            jQuery.ajax({
                type: 'GET',
                url : observantSysPlansUrl,
                success : function(sysPlans) {
                    debug(sysPlans, 3);
                    callbackFn(container, options, sysPlans);
                },
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    error(errorThrown, container);
                    debug(XMLHttpRequest, 4);
                    debug(textStatus, 4);
                    debug(errorThrown, 4);
                }
            });
        }
        catch(e) {

            error(e.message, container);
        }
    }
    

    /**
     * getSystemInstance get the system instance from observant and runs a callback function
     * @param container the container div, will be passed to the callback function
     * @param options an object representing the options, will be passed to the callback function
     * @param callbackFn the callback funtion which accepts the container and options parameters, plus the system plan object
     * @param sysPlan the system plan if this is chained together with getSystemPlan
     * @returns void
     */
    function getSystemInstance(container, options, callbackFn, sysPlan, historySpec) {
        undefinedOrgIdError = new Error ("No organisation ID specified in options.");
        undefinedPlanIdError = new Error ("No system plan ID specified in options.");

        try {
            // make sure we have the required fields to get a system plan
            if (options.orgId === undefined) {
                throw undefinedOrgIdError;
            }

            if (options.planId === undefined) {
                throw undefinedPlanIdError;
            }

            // check if the system plan has already been retrieved and use object if so
            var currentPlanId;
            
			if (options.photoGalleryOptions.photosToFetch !== undefined) {
				currentPlanId = options.planId + "_" + options.vizIds[0] ;
			} else {
				currentPlanId = options.planId;
			}
			//debug(SYSINSTANCES[currentPlanId]);

            if (SYSINSTANCES[currentPlanId] !== undefined) {
                if (sysPlan) {
                    var system = {};
                    system.sysPlan = sysPlan;
                    system.sysInstance = SYSINSTANCES[currentPlanId];
                    system.sites = getSites(sysPlan, SYSINSTANCES[currentPlanId]);
                    callbackFn(container, options, system);
                } else {
                    callbackFn(container, options, SYSINSTANCES[currentPlanId]);
                }
            } else {
                // !!! v2 Protocol
				var observantSysInstanceUrl = BASE_URL + '/systems/' + options.orgId + '/' + options.planId + '/current?media=json';
				// !! change URL for getting photo history - check if photoGallery and photosToFetch
				// make sure vizIds is only 1? 
				
				if (historySpec === undefined) {
					// if not defined, set to 7 days
					historySpec = 7;
				} else {
					options.photoGalleryOptions.days = historySpec;
				}
				
				// check if days is specified in options
				if (options.photoGalleryOptions.days !== undefined) {
					historySpec = options.photoGalleryOptions.days;
				}
				
				if (options.photoGalleryOptions.photosToFetch !== undefined || options.photoGalleryOptions.dailyPhotos !== undefined || options.photoGalleryOptions.days !== undefined ) {
					observantSysInstanceUrl = BASE_URL + '/systems/' + options.orgId + '/' + options.planId + '/' + options.vizIds[0] + '/latestImage' + '/history?historySpec=-'+historySpec+'d&media=json';
				}
				if (options.photoGalleryOptions.startTime) {
					observantSysInstanceUrl = observantSysInstanceUrl + '&startTime=' + startUTCTime(options.photoGalleryOptions.startTime);
				}
                if (options.resAuthKey) {
                    observantSysInstanceUrl = observantSysInstanceUrl + '&resAuthKey=' + options.resAuthKey;
                }

                debug ('getSystemInstance.observantSysInstanceUrl: ' + observantSysInstanceUrl, 1);
                jQuery.ajax({
                    type: 'GET',
                    url : observantSysInstanceUrl,
                    success : function(sysInstance) {
                        debug(sysInstance, 3);
                        
	                        
                        // check if there is enough photos to load             
                        if (options.photoGalleryOptions.photosToFetch !== undefined) {
							if (sysInstance.entities[0].history.series === undefined) {
                        		error("There are no history", container);
                       		} else {
		                        if (options.photoGalleryOptions.photosToFetch > sysInstance.entities[0].history.series.length) { 
									// get next 7 days until 90 days
		                        	if (historySpec <= 90) {
		                        		getSystemInstance(container, options, callbackFn, sysPlan, historySpec+7);
		                        	} else {
										SYSINSTANCES[currentPlanId] = sysInstance;
		                        		callbackFn(container, options, sysInstance);
		                        	}
		                        } else {
									SYSINSTANCES[currentPlanId] = sysInstance;
		                        	callbackFn(container, options, sysInstance);
		                        }
		                    }
	                   } else {
	                    	SYSINSTANCES[currentPlanId] = sysInstance;
	                        callbackFn(container, options, sysInstance);
	                    }
                        
                        // after return, check that the number in history is enough, otherwise call this again. Find out how to get the last image..
/*
                        if (sysPlan) {
                        	debug("in sysplan", 3);
                            var system = {};
                            system.sysPlan = sysPlan;
                            system.sysInstance = sysInstance;
                            system.sites = getSites(sysPlan, sysInstance);
                            callbackFn(container, options, system);
                        } else {
                            callbackFn(container, options, sysInstance);
                        }
*/
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        error(errorThrown, container);
                        debug(XMLHttpRequest, 4);
                        debug(textStatus, 4);
                        debug(errorThrown, 4);
                    }
                });
            }
        }
        catch(e) {
            error(e.message, container);
        }
    }

    /**
     * getSites gets a sites object based on the system plan and system instance
     * @param sysPlan the system plan
     * @param sysInstance the system instance
     * @returns sites the sites for the system
     */
    function getSites(sysPlan, sysInstance) {
        var sites = [];

        $.each(sysPlan.vizContainer.vizReferences, function(i, vizReference) {
            // see if site already exists
            var siteExists = false;
            $.each(sites, function(j, site) {
                if (site.name == vizReference.site) {
                    siteExists = true;
                }
            });
            if (!siteExists) {
                // create new site
                var site = {};
                site.name = vizReference.site;
                // get long and lat

                $.each(sysInstance.siteVizs, function(j, siteViz) {
                    if (vizReference.vizId==siteViz.vizId) {
                        if(siteViz.geoLocation){
                        	if(siteViz.geoLocation.latitude&&siteViz.geoLocation.longitude) {
                        		site.latitude = siteViz.geoLocation.latitude;
                        		site.longitude = siteViz.geoLocation.longitude;
                        	}
                        }
                    }
                });

                site.vizs = [];
                site.vizs.push(vizReference.vizId);
                sites.push(site);
            } else {
                // add this viz to the existing site
                $.each(sites, function(j, site) {
                    if (site.name == vizReference.site) {
                        sites[j].vizs.push(vizReference.vizId);
                    }
                });
            }
        });

        return sites;

    }

    /**
     * Viz is the abstract base class for observant visualisations
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Viz(container, options) {
        this.container = container;
        this.options = options;
        if (container) {
            jQuery.ajaxSetup({
                dataType : 'jsonp'
                , cache: true
            });


            // loading indicator
            
            if (options.vizType != 'downloadLink' && options.vizType != 'system' && options.vizType != 'map' && options.vizType != 'organisation') {
                jQuery('#' + container).addClass('obsviz-main-container');
            }
            if (options.vizType != 'downloadLink' && options.vizType != 'system' && options.vizType != 'organisation') {
                jQuery('#' + container).html('<p class="obsviz-loading">Fetching '+options.vizType+'...</p>');
            }
        }
    }

    /**
     * Photo is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Photo(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'photo';

        //call parent construtor
        Viz.call(this, container, dcOptions);
        // get the system plan and run photoCallBack
        getSystem(container, dcOptions, photoCallBack);
    }

    // Photo is a subclass of Viz
    Photo.prototype = new Viz();

    /**
     * PhotoGallery is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function PhotoGallery(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'photo gallery';

        //call parent construtor
        Viz.call(this, container, dcOptions);
        // get the system instance and run photoGalleryCallBack
        getSystemInstance(container, dcOptions, photoGalleryCallBack);
    }

    // Photo is a subclass of Viz
    PhotoGallery.prototype = new Viz();


    /**
     * Map is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Map(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'map';
        
        //call parent construtor
        Viz.call(this, container, dcOptions);

        // get the system (plan and instance) and run mapCallBack
        getSystem(container, dcOptions, mapCallBack);
    }

    // Map is a subclass of Viz
    Map.prototype = new Viz();

	
	/**
     * Creates the map after with system plans has been obtained - tailored for Peep Protocol v2
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Map2(container, options) {
        // loop through system instance to create markers and map bounds
        var mapPoints = [];
        var mapBounds = new google.maps.LatLngBounds();
        var pointCounter = 0;
		
        $.each(options.markers, function(i, marker){
        	if (marker.geolocation !== undefined) {
        		mapPoints[pointCounter] = {};
                mapPoints[pointCounter].latitude = marker.geolocation.latitude;
                mapPoints[pointCounter].longitude = marker.geolocation.longitude;
                mapPoints[pointCounter].latlng = new google.maps.LatLng(marker.geolocation.latitude, marker.geolocation.longitude);
                mapPoints[pointCounter].icon = "http://maps.google.com/mapfiles/marker" + String.fromCharCode(pointCounter + 65) + ".png";
                mapPoints[pointCounter].name = marker.name;
                mapPoints[pointCounter].index = marker.index;
                mapBounds.extend(mapPoints[pointCounter].latlng);
                pointCounter++;
        	} else {
        		debug("no geolocation found for this system plan");
        	}
        });
        // create the map using the marker boundaries to define zoom and centre
        var mapOptions = {
          center: mapBounds.getCenter(),
          mapTypeId: google.maps.MapTypeId.HYBRID
        };
        var map = new google.maps.Map(document.getElementById(container), mapOptions);
        if (mapPoints.length > 1) {
            map.fitBounds(mapBounds);
        } else {
            map.setZoom(10);
        }
		
		var infoWindow = new google.maps.InfoWindow({
		    position: map.getCenter()
		});
		
        // add markers to map
        $.each(mapPoints, function(i, mapPoint) {
            var marker = new google.maps.Marker({
               position: mapPoint.latlng
               , map: map
               , title: mapPoint.name
               , icon: mapPoints[i].icon
            });
            if (eval("typeof " + options.markerClickFn + " == 'function'")) {
                google.maps.event.addListener(
                    marker
                    , 'click'
                    , function() {
                        options.markerClickFn(mapPoint.index);
                    });
            } else {
            	google.maps.event.addListener(
	                marker
	                , 'click'
	                , function() {
	                	// if you want infoWindow to show
/*
	                	infoWindow.content = mapPoint.name;
	                    infoWindow.open(map, marker);
*/
	            });
            }
        });
    }
    
    Map2.prototype = new Viz();

    
    /**
     * System is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function System(options) {
        debug('System Constructor', 1);

        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'system';

        //call parent construtor
        Viz.call(this, '#', dcOptions);

        // get the system (plan and instance) and run mapCallBack
        getSystem('#', dcOptions, systemCallBack);
    }

    System.prototype = new Viz();
    
    
    /**
     * Org is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Org(options) {
        debug('Org Constructor', 1);

        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'organisation';

        //call parent construtor
        Viz.call(this, '#', dcOptions);

        // get the system (plan and instance) and run orgCallBack
        getSystemPlans('#', dcOptions, orgCallBack);
    }

    Org.prototype = new Viz();
    
    
    /**
     * Table is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Table(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'table';

        // call parent constructor
        Viz.call(this, container, dcOptions);

        // get the system plan and run dataVizCallBack
        getSystemPlan(container, dcOptions, dataVizCallBack, renderTableViz);
    }


    // Table is a subclass of Viz
    Table.prototype = new Viz();

    /**
     * DownloadLink is a subclass of Viz
     * @constructor
     * @param container the container element (could be p, span, div etc.)
     * @param options an object literal representing the options of the observant API
     */
    function DownloadLink(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'downloadLink';
        
        // call parent constructor
        Viz.call(this, container, dcOptions);

        // get the system plan and run dataVizCallBack
        getSystemPlan(container, dcOptions, dataVizCallBack, renderDownloadLink);
    }

    // DownloadLink is a subclass of Viz
    DownloadLink.prototype = new Viz();

    /**
     * Chart is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function Chart(container, options) {
        // deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions.vizType = 'chart';

        // call parent constructor
        Viz.call(this, container, dcOptions);

        // get the system plan and run dataVizCallBack
        getSystemPlan(container, dcOptions, dataVizCallBack, renderChartViz);
    }

    // Chart is a subclass of Viz
    Chart.prototype = new Viz();

    /**
     * chartGallery is a subclass of Viz
     * @constructor
     * @param container the container div
     * @param options an object literal representing the options of the observant API
     */
    function ChartGallery(container, options) {       
        // no titles for charts gallery, titles created separately 
        var chartGalleryOptions = {
        	chartOptions: {
        		chart: {
					margin: [40, 30, 60, 70]
        		},
				title: {
					text: ''
				},
				subtitle: {
					text: ''
				}
			}
		}
		
		// deep copy options
        var dcOptions = jQuery.extend({}, options);
        dcOptions = jQuery.extend(true, {}, dcOptions, chartGalleryOptions);
        dcOptions.vizType = 'chart gallery';

        // call parent constructor
        Viz.call(this, container, dcOptions);

        // add an entry to global gallers, will need to maintain state of gallery
        if (GALLERIES[container] === undefined) {
            GALLERIES[container] = {};
        }

        // get the system plan and run chartGalleryCallBack
        dcOptions.vizType = 'chart';
        getSystemPlan(container, dcOptions, chartGalleryCallBack);
    }

    // chartGallery is a subclass of Vizs
    ChartGallery.prototype = new Viz();

    /**
     * getPlotData returns data in a format for charting and tabling
     * @param    sysPlan the system plan from observant
     * @param    options the user options
     * @param    activeViz the viz reference json
     * @param    activeField the field reference json
     * @param    sysInstance the system instance from observant
     * @return   mixed a highcharts object
     */
    function getPlotData(sysPlan, options, activeViz, activeField, sysInstance) {
        var plotData = {};
		
		var planName = sysPlan.label;
		var dataType = sysInstance.entities[0].dataType;
		var label = sysInstance.entities[0].label;
		var secondaryLabel = sysInstance.entities[0].secondaryLabel ? sysInstance.entities[0].secondaryLabel : "";
		var dataSeries = sysInstance.entities[0].history.series;
		var units = sysInstance.entities[0].history.units;
		
		var startTime = convertDate(sysInstance.entities[0].history.startTime);
		var timeInterval = sysInstance.entities[0].history.timeInterval;
		
		// reformat ydata
        var ydata = formatYData(dataSeries);
		
		if (empty(startTime) || empty(timeInterval) || empty(ydata)) {
			return false;
		} else {
		
	        // first decide what the output type will be
	        if (options.vizType == 'table' || options.vizType == 'downloadLink') {
	            plotData.chart = {
	                defaultSeriesType : 'table'
	            };
	        } else {
	            if (dataType == 'continuous') {
	                plotData.chart = {
	                    defaultSeriesType : 'line'
	                };
	            } else if (dataType == 'discrete') {
	                plotData.chart = {
	                    defaultSeriesType : 'column'
	                };
	            }
	        }
	        
	        // ytitle depends on unit specification
	        if (units) {
	            plotData.yAxis = { 
	                title: {
	                    text: label + ' [' + units + ']'
	                }
	            };
	        } else {
	            plotData.yAxis = { 
	                title: {
	                	text: label
	                }
	            };
	        }
	
	        // variables for plotting for all chart types
	        if (secondaryLabel) {
	        	plotData.title = {
					text: label + " (" + secondaryLabel + ")"
	        	};
	        } else {
	        	plotData.title = {
					text: label
	       		};
	        }
	        
	        plotData.subtitle = {
	            text: planName
	        };
	        plotData.xAxis = {
	            dateTimeLabelFormats: {
	                second: '%H:%M:%S',
	                minute: '%H:%M',
	                hour: '%H:%M',
	                day: '%d %b',
	                week: '%d %b',
	                month: '%b %y',
	                year: '%Y'
	            }
	        };
	
	        // tooltip function
	        var xDataFormat;
	        switch (options.history.substring(options.history.length - 1)) {
	            case 'h':
	                xDataFormat = '%d %b %H:%M';
	                break;
	            default:
	                xDataFormat = plotData.xAxis.dateTimeLabelFormats.day;
	                break;
	        }
	
	        
	        plotData.tooltip = {
	            formatter: function() {
	                var toolTipText = '<strong>'+ label +'</strong><br/>'+ Highcharts.dateFormat(xDataFormat, this.x) + '<br/>' + this.y;
	                if (units) {
	                    toolTipText = toolTipText + units;
	                }
	                return toolTipText;
	            }
	        };
	
	
	        // series type specific options
	        if (plotData.chart.defaultSeriesType == 'line' || plotData.chart.defaultSeriesType == 'table' || plotData.chart.defaultSeriesType == 'area') {
	            plotData.xAxis.type = 'datetime';
	
	            plotData.legend = {
	                layout: 'vertical',
	                style: {
	                    left: 'auto',
	                    bottom: 'auto',
	                    right: '30px',
	                    top: '10px'
	                }
	            };
	
	            plotData.series = new Array();
	            plotData.series[0] = {};
	            if (units) {
	                plotData.series[0].name = label + ' (' + units + ')';
	            } else {
	                plotData.series[0].name = label;
	            }
	            plotData.series[0].data = timeSeries(startTime, timeInterval, ydata, true);
	
	        } else if (plotData.chart.defaultSeriesType == 'column' || plotData.chart.defaultSeriesType == 'bar') {
	            plotData.series = new Array();
	            plotData.series[0] = {};
	            // !!! v2 changeover - 
	            if (units) {
	                plotData.series[0].name = label + ' (' + units + ')';
	            } else {
	                plotData.series[0].name = label;
	            }
	            
	            // with categories
	/*
	            plotData.series[0].data = ydata;
	            plotData.xAxis.categories = timeSeries(sysInstance.history.startTime, sysInstance.history.timeInterval, ydata, false);
	            plotData.xAxis.labels = {
	                enabled: false
	            };
	*/
	            
	            // make column same as line
	            plotData.xAxis.type = 'datetime';
	            plotData.series[0].data = timeSeries(startTime, timeInterval, ydata, true);
	                    
	            
	        }
	
	        return plotData;
        }
    }

    /**
    * timeSeries returns an array of time points, with y data if required
    * @param    startTime the UNIX timestamp to commence the datapoints
    * @param    timeInterval the interval in milliseconds to seperate the datapoints
    * @param    ydata the ydata to add to the series
    * @param    embedYData whether to return the y data in the series
    * @return   array the series for plotting with HighCharts or displaying in a table
    */
    function timeSeries(startTime, timeInterval, ydata, embedYData) {
        var series = [];
        var d = new Date();
        var localOffset = d.getTimezoneOffset() * 60000;
        
        for(var i = 0; i<ydata.length; i++) {
            if (embedYData) {
                series[i] = [startTime - localOffset + (i*timeInterval), ydata[i]];
            } else {
                series[i] = [startTime - localOffset + (i*timeInterval)];
            }
        }
        return series;
    }

    /**
    * formatYData returns numeric y data array from mixed data with a fixed precision (currently hardcoded)
    * @param    ydata an array of data points of mixed format
    * @return   an array of data points, with null if input was NaN (which highcharts can handle)
    */
    function formatYData(dataSeries) {        
        // !!! v2 dataSeries, return yData
        var yDataOut = [];
        for(var i = 0; i<dataSeries.length; i++) {
            // if not a number then return null
            if (isNaN(dataSeries[i].value) || dataSeries[i].value == null) {
                yDataOut[i] = null;
            } else {
                yDataOut[i] = parseFloat(Number(dataSeries[i].value).toFixed(5));
            }
        }
        return yDataOut;
    }

    /**
     * renderChartViz renders the highcharts chart object
     * @param    container the ID of the container div
     * @param    plotData the highcharts data to plot
     * @param    userOptions the user defined options for the chart
     * @return   void
     */
    function renderChartViz(container, plotData, userOptions) {
        var chartContainer = container + '_chart';
        jQuery('#' + container).html('<div id="' + chartContainer + '"></div>');

        var chartHeight = $('#' + container).height();
        var chartWidth = $('#' + container).width();

        // base level options for all chart types
        var baseOptions = {
            showLink: false,
            chartOptions: {
                chart: {
                	renderTo: chartContainer
                	, height: chartHeight
                	, width: chartWidth
                },
                credits: {
                    enabled:true
                    , href:"http://observant.com.au/"
                    , text: "Observant"
                },
                plotOptions: {
                	series: {
                		shadow: false,
                		animation: false
                	}
                },
                theme: 'light'
            }
        };

        // add user defined options to default options
        var plotDataOptions = {};
        plotDataOptions.chartOptions = plotData;

        var empty = {};
        var mergedOptions = jQuery.extend(true, empty, plotDataOptions, baseOptions);

        // add base theme
        //mergedOptions = jQuery.extend(true, empty, mergedOptions, THEME.base);
        mergedOptions = jQuery.extend(true, empty, mergedOptions, newBASE);

        // add user theme
        if (userOptions.chartOptions && userOptions.chartOptions.theme) {
           mergedOptions = jQuery.extend(true, empty, mergedOptions, THEME[userOptions.chartOptions.theme]);
        }  else {
           mergedOptions = jQuery.extend(true, empty, mergedOptions, THEME[baseOptions.chartOptions.theme]);
        }

        // add user options
        mergedOptions = jQuery.extend(true, empty, mergedOptions, userOptions);
        
        //console.log(mergedOptions.chartOptions.series.shadow);

        //add the chart download link
        if (mergedOptions.showLink == true) {
            var spanId = container + '_download_link';
            jQuery('#' + container).append('<div class="utils_menu"><a class="utils_link"><span>menu</span></a><ul><li id="'+ spanId +'"></li></ul></div>');
            obsviz.DownloadLink(spanId, userOptions);
        }

        // create the chart
        var chart = new Highcharts.Chart(mergedOptions.chartOptions);
    }

    /**
    * renderTableViz renders the table visualisation
    * @param    container the ID of the container div
    * @param    plotData the data in highcharts format
    * @param    userOptions the options
    * @return   void
    */
    function renderTableViz(container, plotData, userOptions) {
        var baseOptions = {
            sort: 'asc',
            showLink: true
        };
        var empty = {};
        var mergedOptions = jQuery.extend(true, empty, baseOptions, userOptions.tableOptions);

        var tableHtml = '<table>';
        tableHtml = tableHtml + '<caption>'+ plotData.title.text + ' (' + plotData.subtitle.text + ')</caption>';
        tableHtml = tableHtml + '<tr><th>Date</th><th>'+plotData.yAxis.title.text+'</th></tr>';

        var dataPointCount = plotData.series[0].data.length;

        for (var i in plotData.series[0].data) {
            if (mergedOptions.sort == 'desc') {
                tableHtml = tableHtml + '<tr><td>' + Highcharts.dateFormat(plotData.xAxis.dateTimeLabelFormats.day, plotData.series[0].data[dataPointCount -1 - i][0])  + '</td><td>' + plotData.series[0].data[dataPointCount -1 - i][1] + '</td></tr>';
            } else {
                tableHtml = tableHtml + '<tr><td>' + Highcharts.dateFormat(plotData.xAxis.dateTimeLabelFormats.day, plotData.series[0].data[i][0])  + '</td><td>' + plotData.series[0].data[i][1] + '</td></tr>';
            }
        }
        tableHtml = tableHtml + '</table>';

        //add the table
        jQuery('#' + container).html(tableHtml);
        
        //add the table download link
        if (mergedOptions.showLink == true) {
            var spanId = container + '_download_link';
            jQuery('#' + container + ' caption').append('<span id="'+ spanId +'"></span>');
            obsviz.DownloadLink(spanId, userOptions);
        }
    }

    /**
    * renderDownloadLink renders the download link
    * @param    container the ID of the container element
    * @param    plotData the data in highcharts format
    * @param    options the download options
    * @return   void
    */
    function renderDownloadLink(container, plotData, options) {
        // set default options and merge in user options
        var baseOptions = {
            delimiter: ','
            , lineFeed: '\n'
            , stringsEnclosedBy: '"'
            , fileName: 'download.csv'
            , sort: 'asc'
            , linkText : 'Export as CSV...'
            , linkTitle : 'Export as CSV'
        };
        var empty = {};
        var mergedOptions = {};
        if (options.downloadOptions !== undefined) {
            mergedOptions = jQuery.extend(true, empty, baseOptions, options.downloadOptions);
        } else {
            mergedOptions = jQuery.extend(true, empty, baseOptions);
        }

        // create header row
        var payLoad = 'Date' + mergedOptions.delimiter + plotData.yAxis.title.text + mergedOptions.lineFeed;
        
        // create data (ascending or descending)
        var dataPointCount = plotData.series[0].data.length;
        for (var i in plotData.series[0].data) {
            if (mergedOptions.sort == 'desc') {
                payLoad = payLoad + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', plotData.series[0].data[dataPointCount -1 - i][0])  + mergedOptions.delimiter + plotData.series[0].data[dataPointCount -1 - i][1] + mergedOptions.lineFeed;
            } else {
                payLoad = payLoad + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', plotData.series[0].data[i][0])  + mergedOptions.delimiter + plotData.series[0].data[i][1] + mergedOptions.lineFeed;
            }
        }

        // create form with the necessary details
        var formId = container + '_form';
        var dataId = container + '_data';
        var fileNameId = container + '_filename';
        
        // post to generate csv, can't use jQuery.post here
        // because need the response to be handled
        // by the browser, not by the javascript
        $("body").append('<form id="'+formId+'" action="' + EXPORT_URL + '" method="post" target="_blank"><input type="hidden" id="' + dataId + '" name="exportdata" /><input type="hidden" id="'+fileNameId+'" name="exportfilename" /></form>');

        $("#"+dataId).val(payLoad);
        $("#"+fileNameId).val(mergedOptions.fileName);

        // now add a link to submit the form
        // check for link text and title
        // create the link
        
        $('#' + container).html('<a href="#" title="' + mergedOptions.linkTitle + '">' + mergedOptions.linkText + '</a>');

        // add click event
        $('#' + container + ' a').bind('click', function() {
                $("#" + formId).submit();
                return false;
            }
        );

    }
    
    function startUTCTime(startTime) {
/*
		var startTimeArr = startTime.split("-");
		var time = new Date(startTimeArr[0], startTimeArr[1]-1, startTimeArr[2]);
*/
		var newStartTime = startTime.replace(/-/g, "/");
		var time = new Date(newStartTime);
		return time.format("UTC:yyyy-mm-dd'T'HH:MM:ss'Z'");
    }
	
	/**
    * convertDate converts a date string to JS date 
    */
	function convertDate(dateString) {
		var time = new Date();
		time.setISO8601(dateString);
		return time;
	}
	
	
	/*
	 * Date Format 1.2.3
	 * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
	 * MIT license
	 *
	 * Includes enhancements by Scott Trenda <scott.trenda.net>
	 * and Kris Kowal <cixar.com/~kris.kowal/>
	 *
	 * Accepts a date, a mask, or a date and a mask.
	 * Returns a formatted version of the given date.
	 * The date defaults to the current date/time.
	 * The mask defaults to dateFormat.masks.default.
	 */
	
	var dateFormat = function () {
		var	token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
			timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
			timezoneClip = /[^-+\dA-Z]/g,
			pad = function (val, len) {
				val = String(val);
				len = len || 2;
				while (val.length < len) val = "0" + val;
				return val;
			};
	
		// Regexes and supporting functions are cached through closure
		return function (date, mask, utc) {
			var dF = dateFormat;
	
			// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
			if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
				mask = date;
				date = undefined;
			}
	
			// Passing date through Date applies Date.parse, if necessary
			date = date ? new Date(date) : new Date;
			if (isNaN(date)) throw SyntaxError("invalid date");
	
			mask = String(dF.masks[mask] || mask || dF.masks["default"]);
	
			// Allow setting the utc argument via the mask
			if (mask.slice(0, 4) == "UTC:") {
				mask = mask.slice(4);
				utc = true;
			}
	
			var	_ = utc ? "getUTC" : "get",
				d = date[_ + "Date"](),
				D = date[_ + "Day"](),
				m = date[_ + "Month"](),
				y = date[_ + "FullYear"](),
				H = date[_ + "Hours"](),
				M = date[_ + "Minutes"](),
				s = date[_ + "Seconds"](),
				L = date[_ + "Milliseconds"](),
				o = utc ? 0 : date.getTimezoneOffset(),
				flags = {
					d:    d,
					dd:   pad(d),
					ddd:  dF.i18n.dayNames[D],
					dddd: dF.i18n.dayNames[D + 7],
					m:    m + 1,
					mm:   pad(m + 1),
					mmm:  dF.i18n.monthNames[m],
					mmmm: dF.i18n.monthNames[m + 12],
					yy:   String(y).slice(2),
					yyyy: y,
					h:    H % 12 || 12,
					hh:   pad(H % 12 || 12),
					H:    H,
					HH:   pad(H),
					M:    M,
					MM:   pad(M),
					s:    s,
					ss:   pad(s),
					l:    pad(L, 3),
					L:    pad(L > 99 ? Math.round(L / 10) : L),
					t:    H < 12 ? "a"  : "p",
					tt:   H < 12 ? "am" : "pm",
					T:    H < 12 ? "A"  : "P",
					TT:   H < 12 ? "AM" : "PM",
					Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
					o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
					S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
				};
	
			return mask.replace(token, function ($0) {
				return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
			});
		};
	}();
	
	// Some common format strings
	dateFormat.masks = {
		"default":      "ddd mmm dd yyyy HH:MM:ss",
		shortDate:      "m/d/yy",
		mediumDate:     "mmm d, yyyy",
		longDate:       "mmmm d, yyyy",
		fullDate:       "dddd, mmmm d, yyyy",
		shortTime:      "h:MM TT",
		mediumTime:     "h:MM:ss TT",
		longTime:       "h:MM:ss TT Z",
		isoDate:        "yyyy-mm-dd",
		isoTime:        "HH:MM:ss",
		isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
		isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
	};
	
	// Internationalization strings
	dateFormat.i18n = {
		dayNames: [
			"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
			"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
		],
		monthNames: [
			"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
			"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
		]
	};
	
	// For convenience...
	Date.prototype.format = function (mask, utc) {
		return dateFormat(this, mask, utc);
	};
	

	/**
    * empty checks for null, empty string, undefined
    */
	function empty(e) {
        switch(e) {
            case "":
            case 0:
            case "0":
            case null:
            case false:
            case typeof this == "undefined":
                return true;
            default : return false;
        }
    }

    /**
    * debug writes debug messages if in debug mode AND using firebug
    * @param   debug_message the message to display in the console
    * @param   debug_level the level to debug to (see DEBUG_LEVEL)
    */
    function debug(debug_message, debug_level) {
        // 3 is default level
        if (!debug_level) {
            debug_level = 3;
        }

        if (DEBUG && typeof(console) == 'object' && DEBUG_LEVEL <= debug_level) {
            console.log(debug_message);
        }
    }

    /**
     * unrecoverable errors
     * @param   error_message the message to display
     * @param   container the container div to display the message
     */
    function error(error_message, container) {
        if (typeof(console) == 'object') {
            console.log(error_message);
        }
        if (isUndefined(error_message)) {
        	error_message = "There seems to be a problem fetching the widget. Please try again later."
        }
        if (container && container != '#') {
            jQuery('#' + container).html('<div class="obsviz-error"><p class="obsviz-error-text">A small problem has sprung up, but we\'ll get it fixed. <br />Please try again a bit later.</p><p class="obsviz-tech-error"><strong>Error :</strong> ' + error_message + '</p></div>');
            
/*         <img src="http://obsrv.it/jsapi/images/fail-roo.jpg" title="Fail Roo" /> */
        }
    }

    /**
     * checks if a **primitive** object is empty
     * @param   obj the object to check
     */
    function isEmpty(obj){
        for(var i in obj) {
            return false;
        }
        return true;
    }
    
    /* 
     * checks if something is undefined
     */
    function isUndefined(x) {var u; return x === u;}


    return {
        Viz : Viz,
        Table : Table,
        Chart : Chart,
        Photo : Photo,
        PhotoGallery : PhotoGallery,
        Map : Map,
        Map2: Map2,
        ChartGallery : ChartGallery,
        DownloadLink : DownloadLink,
        System : System,
        Org : Org
    };
})();

