From Tiny Agouti, 1 Year ago, written in Text.
Embed
  1. /*! vitalBookAPI.js - v0.1.1 - 2017-05-03
  2. * Copyright (c) 2017 VitalSource */
  3. /*! relies on jQuery v1.8.3 jquery.com | jquery.org/license */
  4. (function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);
  5.  
  6. ;(function($){
  7.   var jQuery = $;
  8.  
  9. (function ($) {
  10.  
  11.     //This is some framework code for more easily writing derived classes
  12.     function method_impl(name, func) {
  13.         this.prototype[name] = func;
  14.         return this;
  15.     }
  16.  
  17.     Function.prototype.method = method_impl;
  18.  
  19.     Function.method('inherits', function (parent) {
  20.         this.prototype = new parent();
  21.         var d = {},
  22.             p = this.prototype;
  23.         this.prototype.constructor = parent;
  24.         this.method('base', function base(name) {
  25.             if (!(name in d)) {
  26.                 d[name] = 0;
  27.             }
  28.             var f, r, t = d[name], v = parent.prototype;
  29.             if (t) {
  30.                 while (t) {
  31.                     v = v.constructor.prototype;
  32.                     t -= 1;
  33.                 }
  34.                 f = v[name];
  35.             } else {
  36.                 f = p[name];
  37.                 if (f == this[name]) {
  38.                     f = v[name];
  39.                 }
  40.             }
  41.             d[name] += 1;
  42.             r = f.apply(this, Array.prototype.slice.apply(arguments, [1]));
  43.             d[name] -= 1;
  44.             return r;
  45.         });
  46.         return this;
  47.     });
  48.     // End of inheritance code
  49.  
  50.   var VST = {
  51.     Models    : {},
  52.     Settings  : {
  53.         enableLogging: false
  54.       , wordsPerPage : 300
  55.     }
  56.   };
  57.  
  58.   VST.enableLogging   = function(){ this.Settings.enableLogging = true; };
  59.   VST.disableLogging = function () { this.Settings.enableLogging = false; };
  60.   VST.enableInsertionPoint = function () { if (this.insertionPoint != null) this.insertionPoint.SetEnabled(true); };
  61.   VST.disableInsertionPoint = function () { if (this.insertionPoint != null) this.insertionPoint.SetEnabled(false); };
  62.  
  63.   VST.setLogLevel = function(level){
  64.     var level = VST.Logger.levels[level];
  65.     if(typeof level === 'undefined') level = VST.Logger.levels['error'];
  66.     this.Settings.logLevel = level;
  67.   };
  68.  
  69.   VST.init = function(win, doc, sharedEpubModule){
  70.     if(win == null) win = window;
  71.     if(doc == null) doc = document;
  72.     if(sharedEpubModule == null) sharedEpubModule = VSTEPUBModule;
  73.  
  74.     // let's just go ahead and save these
  75.     this.window           = win;
  76.     this.document         = doc;
  77.     this.sharedEpubModule = sharedEpubModule;
  78.  
  79.     // call any initialization code we need to
  80.     this.insertionPoint = new VST.Models.InsertionPoint(doc);
  81.     VST.Models.Highlight.init(this.window, this.document);
  82.     VST.Utils.init(this.window, this.document);
  83.   };
  84.  
  85.   VST.eW = function(name, workerFunction){
  86.     var afterFired = false;
  87.  
  88.     this.fire = function(){
  89.       if(!afterFired){
  90.         VST.EventDispatcher.fire(name);
  91.       }
  92.     };
  93.  
  94.     var wrapper = this;
  95.  
  96.     var eventFiringFunction = function(){
  97.       VST.fire(name + ':before');
  98.       var ret = workerFunction.call(wrapper);
  99.       if(!afterFired){ VST.fire(name); }
  100.       return ret;
  101.     };
  102.  
  103.     return setTimeout(eventFiringFunction, 0);
  104.   };
  105.  
  106.   VST.ajax = function(settings, clientCallback, force){
  107.     // eventually, this key will keep us from making subsequent identical requests
  108.     var ajaxKey = VST.Utils.calculateAjaxKey(settings);
  109.  
  110.     if(clientCallback){
  111.       settings.error = settings.error || function(request, status){
  112.         var error = new VST.Error(status);
  113.         clientCallback(error);
  114.       };
  115.     }
  116.  
  117.     return $.ajax(settings);
  118.   };
  119.  
  120.   VST.Error = function(message){
  121.     this.message = message;
  122.   };
  123.  
  124.   this.VST = VST;
  125. }).call(window, jQuery);
  126. /* doc:code
  127.  
  128.   :name:      VST.bind(eventName, callback)
  129.   :summary:   Bind a listener to an event
  130.   :params:    eventName:String
  131.               The name of the event you wish to listen for
  132.   :params:    callback:Function
  133.               The event handler.
  134.  
  135.   == Example: ==
  136.   @code:javascript@
  137.   // VST.bind is also aliased as VST.EventDispatcher.bind for backwards compatibility
  138.   VST.bind('book:nextPage', function(event, optionalData){
  139.     // do something with the notification
  140.   });
  141.   @/code@
  142.   ==
  143.  
  144.   The event handler will receive the event that was fired (a <code class="javascript">VST.Event</code> object) as its first parameter.
  145.   The second parameter will be optional data that may or may not be passed along with the event.
  146.   This data will vary depending on the type of event.
  147. */
  148.  
  149. (function($){
  150.  
  151. VST.EventDispatcher = new function(){
  152.   var listeners       = {}
  153.     , systemListeners = {}
  154.     , batchedEvents   = {}
  155.     , throttling      = {}
  156.     , firedEvents     = {}
  157.     , self = this;
  158.  
  159.   // private
  160.   var hasListeners    = function(name){
  161.     if(listeners[name] && listeners[name].length > 0){
  162.       return true;
  163.     }else{
  164.       return false;
  165.     }
  166.   };
  167.  
  168.   // private
  169.   var hasSystemListeners = function(name){
  170.     if(systemListeners[name] && systemListeners[name].length > 0){
  171.       return true;
  172.     }else{
  173.       return false;
  174.     }
  175.   };
  176.  
  177.   this.init = function(){ firedEvents = {}; return this; }
  178.  
  179.   this.getBatchedEvents = function() { return batchedEvents; };
  180.  
  181.   this.getListeners = function(name){ return (listeners[name] || []); };
  182.   this.firedEvents  = function(){ return firedEvents; }
  183.  
  184.   // for now, this is all or nothing
  185.   this.unbind = function(name){
  186.     if(listeners[name]) listeners[name] = null;
  187.   };
  188.  
  189.   this.bind = function(name, handler, binding, cannotBeCancelled){
  190.     binding = binding || this;
  191.     handler = {handler: handler, binding: binding};
  192.  
  193.     if(cannotBeCancelled){
  194.       systemListeners[name] = systemListeners[name] || [];
  195.       for (var i = systemListeners[name].length - 1; i >= 0; i--) {
  196.         var thisHandler = systemListeners[name][i];
  197.         if(thisHandler.handler === handler.handler && thisHandler.binding === handler.binding){
  198.           // already been bound
  199.           VST.Logger.debug("handler already bound");
  200.           return false;
  201.         }
  202.       }
  203.       systemListeners[name].push(handler);
  204.     }else{
  205.       listeners[name] = listeners[name] || [];
  206.       // only bind a handler once!
  207.       for (var i = listeners[name].length - 1; i >= 0; i--) {
  208.         var thisHandler = listeners[name][i];
  209.         if(thisHandler.handler === handler.handler && thisHandler.binding === handler.binding){
  210.           // already been bound
  211.           VST.Logger.debug("handler already bound");
  212.           return false;
  213.         }
  214.       }
  215.       listeners[name].push(handler);
  216.     }
  217.  
  218.     if(firedEvents.hasOwnProperty(name)){
  219.       VST.Logger.debug(name + ' has already fired; going to call the handler immediately')
  220.       var oneTimeEvent = new VST.Event(name);
  221.       handler.handler.call(handler.binding, name, oneTimeEvent, firedEvents[name]);
  222.     }
  223.     return this;
  224.   };
  225.  
  226.   this.once = function(name, handler, binding, cannotBeCancelled){
  227.     binding = binding || this;
  228.  
  229.     var l            = cannotBeCancelled ? systemListeners : listeners
  230.       , theseList    = l[name] || [];
  231.  
  232.     for (var i = theseList.length - 1; i >= 0; i--) {
  233.       var thisHandler = theseList[i].handler;
  234.       if(thisHandler.handler === handler && thisHandler === binding){
  235.         return this;
  236.       }
  237.     };
  238.  
  239.     return this.bind(name, handler, binding, cannotBeCancelled);
  240.   };
  241.  
  242.   this.cancel = function(name){
  243.     if(!!batchedEvents[name]){
  244.       clearTimeout(batchedEvents[name].timer);
  245.     }
  246.   };
  247.  
  248.   this.fireLater = function(name, data, when){
  249.     // default  to 20 millisecond delay
  250.     if(when == null){ when = 20; }
  251.  
  252.     if(!batchedEvents[name]){ batchedEvents[name] = {}; }
  253.     else                    { clearTimeout(batchedEvents[name].timer); }
  254.  
  255.     // var self = this;
  256.  
  257.     // store the timer
  258.     batchedEvents[name].timer = setTimeout(function(){
  259.       self.fire(name, data);
  260.     }, when);
  261.  
  262.     return this;
  263.   };
  264.  
  265.   this.fire = function(name, data){
  266.     // I think we should maybe fire events asynchronously... maybe
  267.     var e;
  268.     if(name instanceof VST.Event){ e = name; }
  269.     else{ e = new VST.Event(name); }
  270.  
  271.     if(data){ VST.Logger.debug(e.toString(), data); }
  272.     else    { VST.Logger.debug(e.toString()); }
  273.  
  274.     firedEvents[e.name] = data;
  275.  
  276.     if(hasSystemListeners(e.name)){
  277.       for (var i=0; i < systemListeners[e.name].length; i++) {
  278.         var eventHandler = systemListeners[e.name][i];
  279.         eventHandler.handler.call(eventHandler.binding, e, data);
  280.       };
  281.     }
  282.  
  283.     if(hasListeners(e.name)){
  284.       for (var i=0; i < listeners[e.name].length; i++) {
  285.         if(e.shouldPropogate()){
  286.           var eventHandler = listeners[e.name][i];
  287.           eventHandler.handler.call(eventHandler.binding, e, data);
  288.         }
  289.       };
  290.     }
  291.  
  292.     return this;
  293.   };
  294.  
  295.   this.throttle = function(name, data, count, howOften){
  296.     count     = count     || 20;
  297.     howOften  = howOften  || 100;
  298.  
  299.     throttling[name] = throttling[name] || {count:0};
  300.     var tc = throttling[name];
  301.  
  302.     clearTimeout(tc.timer);
  303.  
  304.     var firingFunction = function(){
  305.       throttling[name].lastFired = +(new Date);
  306.       throttling[name].count = 0;
  307.       VST.fire(name, data);
  308.     };
  309.  
  310.     var shouldFire = function(){
  311.       if(tc.count+1 >= count)                     return true;
  312.       if(!tc.lastFired)                           return true;
  313.       if((+(new Date) - tc.lastFired) > howOften) return true;
  314.       return false;
  315.     };
  316.  
  317.     if( shouldFire() ){
  318.       firingFunction();
  319.     }else{
  320.       throttling[name].count += 1;
  321.       throttling[name].timer = setTimeout(firingFunction, howOften);
  322.     }
  323.  
  324.     return this;
  325.   };
  326.  
  327.   // alias fire as trigger
  328.   this.trigger = this.fire;
  329.  
  330.   this.fireBefore = function(name, data){
  331.     this.fire(name + ':before', data);
  332.     return this;
  333.   };
  334.  
  335. }();
  336.  
  337. VST.delayedEventWrapper     = function(name, context, workerFunction, skipTimeout){
  338.   // this is to make the context param optional
  339.   if(typeof workerFunction !== 'function'){
  340.     skipTimeout    = workerFunction;
  341.     workerFunction = context;
  342.     context        = this;
  343.   }
  344.  
  345.   var eventFiringFunction = function(){
  346.     VST.EventDispatcher.fireLater(name + ':before');
  347.     var ret = workerFunction.call(context);
  348.     VST.EventDispatcher.fireLater(name);
  349.     return ret;
  350.   };
  351.  
  352.   if(skipTimeout){ return eventFiringFunction(); }
  353.   // use setTimeout so that we don't block
  354.   else{ setTimeout(eventFiringFunction, 0); }
  355. };
  356.  
  357. VST.eventWrapper            = function(name, context, workerFunction, skipTimeout){
  358.   // this is to make the context param optional
  359.   if(typeof workerFunction !== 'function'){
  360.     skipTimeout    = workerFunction;
  361.     workerFunction = context;
  362.     context = this;
  363.   }
  364.  
  365.   var eventFiringFunction = function(){
  366.     VST.EventDispatcher.fire(name + ':before');
  367.     var ret = workerFunction.call(context);
  368.     VST.EventDispatcher.fire(name);
  369.     return ret;
  370.   };
  371.  
  372.   if(skipTimeout){ return eventFiringFunction(); }
  373.   // use setTimeout so that we don't block
  374.   else{ setTimeout(eventFiringFunction, 0); }
  375. };
  376.  
  377.  
  378. // we should refactor these ajax event wrappers to DRY them up
  379. VST.ajaxEventWrapper        = function(name, settings, clientCallback){
  380.   VST.EventDispatcher.fire(name + ':before');
  381.  
  382.   var clientComplete = settings.complete;
  383.   // if they
  384.   settings.complete = function(){
  385.     // fire the event after the request is completed
  386.     VST.EventDispatcher.fire(name);
  387.     // if they passed in a complete callback, call it
  388.     if(!!clientComplete){ clientComplete.apply(this, arguments); }
  389.   };
  390.  
  391.   // the default error handler is just to forward the error on to the client
  392.   // hrm, the clientCallback won't be fired unless there is an error...
  393.   // unless the client passes in a success callback that includes their
  394.   // clientCallback function. Seems repetitive and strange
  395.   if(clientCallback){
  396.     settings.error = settings.error || function(request, error){
  397.       var error = new VST.Error(status);
  398.       clientCallback(error, undefined);
  399.     };
  400.   }
  401.  
  402.   $.ajax(settings);
  403. };
  404.  
  405. VST.delayedAjaxEventWrapper = function(name, settings, clientCallback){
  406.   VST.EventDispatcher.fireLater(name + ':before');
  407.  
  408.   // we need to do a better job of this
  409.   settings.complete = function(){
  410.     // fire the event after the request is completed
  411.     VST.EventDispatcher.fireLater(name);
  412.   };
  413.  
  414.   // the default error handler is just to forward the error on to the client
  415.   if(clientCallback){
  416.     settings.error = settings.error || function(request, error){
  417.       var error = new VST.Error(status);
  418.       clientCallback(error, undefined);
  419.     };
  420.   }
  421.  
  422.   $.ajax(settings);
  423. };
  424.  
  425. // alias these for easier access
  426. VST.bind      = VST.EventDispatcher.bind;
  427. VST.unbind    = VST.EventDispatcher.unbind;
  428. VST.once      = VST.EventDispatcher.once;
  429. VST.fire      = VST.EventDispatcher.fire;
  430. VST.fireLater = VST.EventDispatcher.fireLater;
  431. VST.throttle  = VST.EventDispatcher.throttle;
  432. VST.trigger   = VST.fire;
  433.  
  434. VST.Event                   = function(name, options){
  435.   VST.Utils.setDefaults(this, options);
  436.   this.name     = name;
  437.   var propagate = true;
  438.  
  439.   this.stop             = function(){ propagate = false; }
  440.   this.shouldPropogate  = function(){ return propagate; }
  441.   this.fire             = function(){ VST.EventDispatcher.fire(this); }
  442.   this.toString         = function(){ return "[Event] : " + this.name; }
  443. };
  444.  
  445. VST.Event.fromjQueryEvent = function(name, jEvent, data){
  446.   data = data || {};
  447.   VST.Utils.setDefaults(data, {target:jEvent.target, originalEvent:jEvent});
  448.   return new VST.Event(name, data);
  449. };
  450.  
  451. }).call(window, jQuery);
  452.  
  453. (function($){
  454.   VST.Utils = {};
  455.  
  456.   // I might move this somewhere else, eventually
  457.   VST.Utils.init = function(){
  458.     VST.Utils.watchCopy();
  459.     VST.Utils.watchScroll();
  460.   };
  461.  
  462.   VST.Utils.watchCopy = function(){
  463.     $(VST.document).find('body').bind('copy', function(e){
  464.       // we only care about the copy event if they're actually in a book
  465.       if(typeof VST.Book !== 'undefined'){ VST.Book.handleCopy(e); }
  466.     });
  467.   };
  468.  
  469.   VST.Utils.pageScrollHandler = function(e){
  470.     VST.fireLater('internal:page:scroll');
  471.     VST.fire('page:scroll:raw');
  472.   };
  473.  
  474.   VST.Utils.throttledPageScrollHandler = function(e){
  475.     VST.fire('page:scroll:raw');
  476.     VST.throttle('internal:page:scroll', (+(new Date)), 20);
  477.   };
  478.  
  479.   var internalPageScrollHandler = function(){
  480.     VST.fire('page:scroll', VST.sharedEpubModule.GetCFIForCurrentScrollPosition());
  481.   };
  482.  
  483.   VST.Utils.watchScroll = function(){
  484.     $(VST.window).unbind('scroll.vst');
  485.     $(VST.window).bind('scroll.vst', VST.Utils.pageScrollHandler);
  486.     VST.bind('internal:page:scroll', internalPageScrollHandler, null, true);
  487.   };
  488.  
  489.   VST.Utils.throttlePageScrollEvent = function(){
  490.     $(VST.window).unbind('scroll.vst');
  491.     $(VST.window).bind('scroll.vst', VST.Utils.throttledPageScrollHandler);
  492.     VST.bind('internal:page:scroll', internalPageScrollHandler, null, true);
  493.   };
  494.  
  495.   VST.Utils.fireScrollOnlyOnStop = function(){
  496.     $(VST.window).unbind('scroll.vst');
  497.     var timer;
  498.     $(VST.window).bind('scroll.vst',function () {
  499.         clearTimeout(timer);
  500.         timer = setTimeout( internalPageScrollHandler, 100 );
  501.     });
  502.   };
  503.  
  504.   VST.Utils.getSelectionObject = function(){
  505.     delete VST.selectionObject;
  506.     if(VST.window && VST.window.getSelection){
  507.       VST.selectionObject = VST.window.getSelection();
  508.     }else if(VST.document && VST.document.selection){
  509.       VST.selectionObject = VST.document.selection.createRange();
  510.     }
  511.  
  512.     return VST.selectionObject;
  513.   };
  514.  
  515.   VST.Utils.getRangeObject = function(selectionObject) {
  516.     if(selectionObject === null) {
  517.       selectionObject = VST.Utils.getSelectionObject();
  518.     }
  519.  
  520.     if (!selectionObject) {
  521.       return null;
  522.     }
  523.  
  524.     if(selectionObject.getRangeAt) {
  525.       return selectionObject.rangeCount > 0 ? selectionObject.getRangeAt(0) : null;
  526.     } else { // Safari 1.3
  527.       var range = VST.document.selection.createRange();
  528.  
  529.       if (!range) {
  530.         return null;
  531.       }
  532.  
  533.       range.setStart(selectionObject.anchorNode, selectionObject.anchorOffset);
  534.       range.setEnd(selectionObject.focusNode, selectionObject.focusOffset);
  535.       return range;
  536.     }
  537.   };
  538.  
  539.   VST.Utils.getSelectedText = function(){
  540.     var userSelection = VST.Utils.getSelectionObject()
  541.       , doc           = VST.document
  542.       , win           = VST.window;
  543.  
  544.     var selectedText = userSelection;
  545.  
  546.     if(userSelection.toString){ selectedText = userSelection.toString(); }
  547.     if(typeof userSelection.text !== 'undefined'){ selectedText = userSelection.text; }
  548.     return selectedText;
  549.   };
  550.  
  551.   VST.Utils.calculateAjaxKey = function(settings){
  552.     var key = settings.url;
  553.  
  554.     if(settings.dataType) { key += (':' + settings.dataType); }
  555.     if(settings.data)     { key += $.param(settings.data); }
  556.  
  557.     return key;
  558.   };
  559.  
  560.   VST.Utils.setDefaults = function(onWhat, settings){
  561.     if(typeof settings === 'undefined'){ return; }
  562.     for(var s in settings){
  563.       if(settings.hasOwnProperty(s)){
  564.         onWhat[s] = settings[s];
  565.       }
  566.     }
  567.   };
  568.  
  569.   VST.Utils.getElementText = function(el){
  570.     var text    = '';
  571.  
  572.     if (!el)
  573.     {
  574.         return '';
  575.     }
  576.  
  577.     // see if we have a node, string or jQuery object
  578.     if(el.length){
  579.       if(el.constructor === String) el = $(VST.document).find(el)[0];
  580.       else                          el = el[0];
  581.     }
  582.  
  583.     for(var i = 0; i < el.childNodes.length; i++){
  584.       var n = el.childNodes[i];
  585.       if(n.nodeType === 3){
  586.         text += n.nodeValue;
  587.       }else if(n.nodeType === 1){
  588.         if(n.nodeName.toLowerCase() === 'img') text += (n.alt || n.title)
  589.  
  590.         if (n.contentDocument)
  591.         {
  592.           text += VST.Utils.getElementText(n.contentDocument.body);
  593.         }
  594.         else if(!(/script|style|object/i).test(n.nodeName)){
  595.           text += VST.Utils.getElementText(n)
  596.         }
  597.       }
  598.     }
  599.     return text;
  600. //    return text.replace(/\s+/g, ' ').replace(/(^\s+)|(\s+$)/g, '');
  601.   };
  602.  
  603.   VST.Utils.LESS_THAN    = -1;
  604.   VST.Utils.EQUAL        =  0;
  605.   VST.Utils.GREATER_THAN =  1;
  606.  
  607.   // this is a down and dirty comparison for now that only kind of works
  608.   VST.Utils.compareCFIs = function(a, b){
  609.     if(a == null){ a = ''; }
  610.     if(b == null){ b = ''; }
  611.  
  612.     // get rid of trailing !'s
  613.     a = a.replace(/!$/, '');
  614.     b = b.replace(/!$/, '');
  615.  
  616.     if(a === b)  { return VST.Utils.EQUAL; }
  617.  
  618.     var splitter  = /[\/@~:!]/
  619.       , replacer  = /(\[.+\]|[^\d])/g
  620.       , aPieces   = a.split(splitter)
  621.       , bPieces   = b.split(splitter);
  622.  
  623.     for(var i=0;;i++){
  624.       var thisA = aPieces[i], thisB = bPieces[i];
  625.  
  626.       if(thisA == null && thisB == null){ return VST.Utils.EQUAL; }
  627.       if(thisA == null)                 { return VST.Utils.LESS_THAN; }
  628.       if(thisB == null)                 { return VST.Utils.GREATER_THAN; }
  629.  
  630.       if(thisA === thisB) continue;
  631.  
  632.       thisA = parseFloat(thisA.replace(replacer, ''), 10);
  633.       thisB = parseFloat(thisB.replace(replacer, ''), 10);
  634.  
  635.       if(thisA < thisB){ return VST.Utils.LESS_THAN; }
  636.       if(thisA > thisB){ return VST.Utils.GREATER_THAN; }
  637.     }
  638.   };
  639.  
  640.   VST.Utils.installCallback = function (callback) {
  641.     if (!VST.Utils.callbackMap)
  642.     {
  643.       VST.Utils.callbackMap = {};
  644.       VST.Utils.callbackID = 1;
  645.     }
  646.     else
  647.     {
  648.       ++VST.Utils.callbackID;
  649.     }
  650.     var callbackID = VST.Utils.callbackID;
  651.     VST.Utils.callbackMap[callbackID] = callback;
  652.  
  653.     return callbackID;
  654.   };
  655.  
  656.   VST.Utils.findCallback = function (callbackID) {
  657.     if (!VST.Utils.callbackMap)
  658.     {
  659.       return;
  660.     }
  661.  
  662.     return VST.Utils.callbackMap[callbackID];
  663.   };
  664.  
  665.   VST.Utils.removeCallback = function (callbackID) {
  666.     if (!VST.Utils.callbackMap)
  667.     {
  668.       return;
  669.     }
  670.  
  671.     delete VST.Utils.callbackMap[callbackID];
  672.   };
  673.  
  674.   // Transfer the rest of the arguments to the callback
  675.   // and remove the callback.
  676.   VST.Utils.fireCallback = function (callbackID) {
  677.     var callback = VST.Utils.findCallback(callbackID);
  678.     if (callback)
  679.     {
  680.       var args = [];
  681.       var i, max = arguments.length;
  682.       for (i = 1; i < max; ++i)
  683.       {
  684.         args.push(arguments[i]);
  685.       }
  686.       callback.apply(this, args);
  687.       VST.Utils.removeCallback(callbackID);
  688.     }
  689.     else
  690.     {
  691.       VST.Logger.error("Callback id not found: " + callbackID);
  692.     }
  693.   };
  694.  
  695.   VST.Utils.isArray = function(obj) {
  696.     return Object.prototype.toString.call(obj) === '[object Array]';
  697.   };
  698.  
  699.   // just for convenience here
  700.   VST.Utility = VST.Utils;
  701. }).call(window, jQuery);
  702. (function(){
  703.   // function that does nothing -- use this as default callback
  704.   this.VST.noop = function(){};
  705.  
  706.   this.VST.Handler = {
  707.     _handlers : []
  708.   };
  709.  
  710.   this.VST.Handler.get = function(name){
  711.     return this._handlers[name] || VST.noop;
  712.   };
  713.  
  714.   this.VST.Handler.set = function(name, func){
  715.     this._handlers[name] = func;
  716.   };
  717.  
  718.   this.VST.Handler.fire = function(name, args, context){
  719.     context = context || this;
  720.     if(VST.Utils.isArray(args)){
  721.       return VST.Handler.get(name).apply(context, args);
  722.     }else{
  723.       return VST.Handler.get(name).call(context, args || VST.noop);
  724.     }
  725.   };
  726. }).call(window);
  727. (function($){
  728.   VST.Logger = {
  729.     levels: {
  730.         debug   : 0
  731.       , info    : 1
  732.       , warn    : 2
  733.       , warning : 2
  734.       , error   : 3
  735.       , ignore  : 4
  736.     }
  737.   };
  738.  
  739.   var levelNames  = [];
  740.  
  741.   for(var l in VST.Logger.levels) {
  742.     (function(level){
  743.       if(level !== 'ignore'){
  744.         levelNames.push(level);
  745.         VST.Logger[level] = function(){
  746.           var args = Array.prototype.slice.call(arguments);
  747.           args.push(level);
  748.           VST.log.apply(VST.log, args);
  749.         };
  750.       }
  751.     })(l);
  752.   };
  753.  
  754.   var levelRegexp = new RegExp('^' + levelNames.join('|') + '$');
  755.  
  756.  
  757.   VST.log = function(){
  758.     var args      = Array.prototype.slice.call(arguments)
  759.       , severity  = 'info';
  760.  
  761.     if(args.length > 1 && levelRegexp.test(args[args.length-1])){ severity = args.pop(); }
  762.  
  763.     if(VST.Logger.levels[severity] >= VST.Settings.logLevel){
  764.       if(console && console.log && console.log.apply){ return console.log.apply(console, args); }
  765.     }
  766.   };
  767.  
  768.   // default log level is 'error'
  769.   VST.setLogLevel('error');
  770.  
  771. }).call(window, jQuery);
  772.  
  773.  
  774. /* doc:code
  775.   :name:      VST.Logger[info|debug|warn|error](messages)
  776.   :summary:   Log a message to the console
  777.   :params:    message:String
  778.               The message to log
  779.  
  780.   == Example: ==
  781.   @code:javascript@
  782.   // will log to the console if the log level is >= debug
  783.   VST.Logger.debug("This is a debug message");
  784.  
  785.   // will log to the console if the log level is >= info
  786.   VST.Logger.info("This is an info message");
  787.   @/code@
  788.   ==
  789. */
  790.  
  791. /* doc:code
  792.   :name:      VST.setLogLevel(level)
  793.   :summary:   Set the log level
  794.   :params:    level:String
  795.               The name of the log level. Must be one of 'debug', 'info', 'warn', 'error', or 'ignore'
  796.  
  797.   == Example: ==
  798.   @code:javascript@
  799.   VST.setLogLevel("debug");
  800.   @/code@
  801.   ==
  802.  
  803.   By default, the log level is set to <code>error</code>. The levels in order from most verbose to least are
  804.   <code>debug</code>, <code>info</code>, <code>warn</code>, <code>error</code>, <code>ignore</code>
  805. */
  806. (function(){
  807.   VST.Reader = function(name, version){
  808.     this.name         = name;
  809.     this.version      = version || "1.0";
  810.     this.layoutStyle  = "scrolling";
  811.   };
  812.  
  813.   VST.Reader.prototype.hasFeature = function(feature, version){
  814.     // AVAILABLE FEATURES:
  815.     //  --------------------------------- //
  816.     //  * dom-manipulation:
  817.     //    Scripts may make structural changes to the document’s DOM (applies to spine-level scripting only).
  818.     //  --------------------------------- //
  819.     //  * layout-changes:
  820.     //    Scripts may modify attributes and CSS styles that affect content layout (applies to spine-level scripting only).
  821.     //  --------------------------------- //
  822.     //  * touch-events:
  823.     //    The device supports touch events and the Reading System passes touch events to the content.
  824.     //  --------------------------------- //
  825.     //  * mouse-events:
  826.     //    The device supports mouse events and the Reading System passes mouse events to the content.
  827.     //  --------------------------------- //
  828.     //  * keyboard-events:
  829.     //    The device supports keyboard events and the Reading System passes keyboard events to the content.
  830.     //  --------------------------------- //
  831.     //  * spine-scripting:
  832.     //    Spine-level scripting is supported.
  833.     //  --------------------------------- //
  834.  
  835.     switch(feature){
  836.       case 'mouse-events':
  837.         return true;
  838.       case 'keyboard-events':
  839.         return true;
  840.       case 'spine-scripting':
  841.         return true;
  842.       case 'touch-events':
  843.         return true;
  844.       case 'layout-changes':
  845.         return true;
  846.       default:
  847.         return false
  848.     }
  849.   };
  850.  
  851.   VST.Reader.prototype.isOnline   = function(){ return (/online/i).test(this.name); };
  852.   VST.Reader.prototype.isDesktop  = function(){ return (/desktop/i).test(this.name); };
  853. }).call(window);
  854.  
  855. (function($){
  856.  
  857.   var Binding = function(mediaType, href){
  858.     this.mediaType = mediaType;
  859.     this.href      = href;
  860.   };
  861.  
  862.   Binding.prototype.render = function(doc, obj){
  863.     if(obj){
  864.       return this.replaceObjectTag(obj, doc);
  865.     }else{
  866.       return new BindingsCollection([this]).render(doc);
  867.     }
  868.   };
  869.  
  870.   Binding.prototype.replaceObjectTag = function(obj, doc){
  871.     if(!obj)       { return; }
  872.     if(doc == null){ doc = VST.document; }
  873.  
  874.     // make sure we don't have jquery objects
  875.     if(obj && obj.jquery){ obj = obj[0]; }
  876.     if(doc.jquery)       { doc = doc[0]; }
  877.  
  878.     el = doc.createElement('iframe');
  879.     el.style.width = '100%';
  880.     el.style.border= 'none';
  881.     el.setAttribute("allowtransparency", "true");
  882.     el.setAttribute("frameBorder", "0");
  883.     el.setAttribute('class', 'vst-epub-binding');
  884.  
  885.     el.onload = function(){
  886.       try {
  887.         this.style.height = $(this.contentDocument).height() + 'px';
  888.       }catch(e){
  889.         // don't do anything
  890.       }
  891.     }
  892.  
  893.     var parent = obj.parentNode
  894.       , data   = obj.getAttribute('data')
  895.       , params = [];
  896.  
  897.     if(typeof data !== 'undefined'){
  898.       params.push('src='+data);
  899.     }
  900.  
  901.     params.push('type='+this.mediaType);
  902.  
  903.     // need to add the params found
  904.     var paramLength = obj.childNodes.length;
  905.     for (var i = 0; i < paramLength; i++) {
  906.       var thisChild = obj.childNodes[i];
  907.       if(thisChild.nodeName.toLowerCase() === 'param'){
  908.         var name = thisChild.getAttribute('name')
  909.           , val  = thisChild.getAttribute('value');
  910.         if(name && val){
  911.           params.push(name + '=' + val);
  912.         }
  913.       }
  914.     }
  915.  
  916.     var query = (params.length > 0 ? ('?' + params.join('&')) : '');
  917.     el.setAttribute('src', this.href + query);
  918.     parent.replaceChild(el, obj);
  919.  
  920.     return el;
  921.   };
  922.  
  923.   var BindingsCollection = function(bindings){
  924.     this.bindings    = bindings || [];
  925.  
  926.     for (var i = this.bindings.length - 1; i >= 0; i--) {
  927.       // make sure we have Binding objects
  928.       if(!this.bindings[i].render){
  929.         this.bindings[i] = new Binding(this.bindings[i].mediaType, this.bindings[i].href);
  930.       }
  931.     }
  932.  
  933.     this.bindingsMap = {};
  934.     this.length      = bindings.length;
  935.  
  936.     for (var i = this.bindings.length - 1; i >= 0; i--) {
  937.       this.bindingsMap[this.bindings[i].mediaType] = this.bindings[i];
  938.     }
  939.   };
  940.  
  941.   BindingsCollection.prototype.findBinding = function(mt){
  942.     return this.bindingsMap[mt];
  943.   };
  944.  
  945.   BindingsCollection.prototype.render = function(doc){
  946.     if(doc == null){ doc = VST.document; }
  947.  
  948.     var objs = doc.getElementsByTagName('object');
  949.     for (var i = objs.length - 1; i >= 0; i--) {
  950.       var bd = this.findBinding(objs[i].getAttribute('type'));
  951.       if(typeof bd !== 'undefined'){
  952.         bd.render(doc, objs[i]);
  953.       }
  954.     }
  955.  
  956.     VST.fire('bindings:render');
  957.   };
  958.  
  959.   VST.Models.Binding            = Binding;
  960.   VST.Models.BindingsCollection = BindingsCollection;
  961.  
  962. }).call(window, jQuery);
  963. (function($){
  964.   VST.Models.Book = function(settings){
  965.     settings = settings || {};
  966.     VST.Logger.debug("here is what we know about the book: ", settings);
  967.     var isbn          = settings.isbn
  968.       , author        = settings.author
  969.       , title         = settings.title
  970.       , copyLimit     = settings.copyLimit
  971.       , printLimit    = settings.printLimit
  972.       , format        = settings.format || 'epub'
  973.       , hasPageBreaks = settings.hasPageBreaks || false
  974.       , isFixedLayout = settings.isFixedLayout || false
  975.       , self          = this
  976.       , bindings;
  977.  
  978.     // for protected attributes, methods need to be defined here in the constructor
  979.     this.getISBN       = function() { return isbn; };
  980.     this.getAuthor     = function() { return author; };
  981.     this.getTitle      = function() { return title; };
  982.     this.dashlessISBN  = function() { return this.getISBN().replace(/-/g, ''); };
  983.     this.hasPageBreaks = function() { return hasPageBreaks; };
  984.     this.isFixedLayout = function() { return isFixedLayout; };
  985.  
  986.     this.hasCopyLimit = function(){
  987.       return this.getCopyLimit() >= 0;
  988.     };
  989.  
  990.     this.getCopyLimit = function(){
  991.       if(typeof copyLimit === 'undefined') return 0;
  992.       return parseInt(copyLimit);
  993.     };
  994.  
  995.     this.hasPrintLimit = function() {
  996.       return this.getPrintLimit() >= 0;
  997.     };
  998.  
  999.     this.getPrintLimit = function(){
  1000.       // not sure we really need this, but whatever
  1001.       if(typeof printLimit === 'undefined') return 0;
  1002.       return parseInt(printLimit);
  1003.     };
  1004.  
  1005.     this.isEpub = function(){
  1006.       return (/epub/i).test(this.format);
  1007.     };
  1008.  
  1009.     this.renderBindings = function(doc){ return bindings.render(doc); }
  1010.     this.getBindings    = function()   { return bindings; }
  1011.  
  1012.     this.setFixedLayout = function(fixed){ isFixedLayout = fixed; };
  1013.  
  1014.     this.setFixedLayoutDimensions = function(doc){
  1015.       if(!this.isFixedLayout()){ return; }
  1016.       if(doc == null){ doc = VST.document; }
  1017.       doc = $(doc);
  1018.       var viewport = doc.find('meta[name=viewport]');
  1019.       if(viewport.length == 0){ return; }
  1020.  
  1021.       var dimensions = viewport.attr('content')
  1022.         , h          = dimensions.match(/height=(\d+)/)
  1023.         , w          = dimensions.match(/width=(\d+)/);
  1024.       if(h && w){
  1025.         h = h[1];
  1026.         w = w[1];
  1027.         var html = doc.find('html')
  1028.           , body = doc.find('body');
  1029.  
  1030.         // so, if there's not a body
  1031.         // or, if the height/width is already set on the body
  1032.         // don't do anything
  1033.         if(body.length == 0 || body[0].style.width != '' || body[0].style.height != ''){ return; }
  1034.  
  1035.         html.css({overflow:'auto'});
  1036.         body.css({overflow: 'hidden', height: h, width: w});
  1037.       }
  1038.     };
  1039.  
  1040.     this.setBindings    = function(bds){
  1041.       bindings = new VST.Models.BindingsCollection(bds)
  1042.     };
  1043.  
  1044.     this.setBindings(settings.bindings || []);
  1045.     if (hasPageBreaks){ this.setupPageBreaks(); }
  1046.   };
  1047.  
  1048.   VST.Models.Book.prototype.buildURL = function(path){
  1049.     return '/books/' + this.getISBN() + path;
  1050.   }
  1051.  
  1052.   /* doc:code
  1053.  
  1054.     :name:      VST.Book.getTOC(callback)
  1055.     :summary:   Retrieve an HTML representation of the current book's table of contents
  1056.     :params:    callback:Function
  1057.                 The function to call when the response is received
  1058.  
  1059.     == Example: ==
  1060.     @code:javascript@
  1061.     VST.Book.getTOC(function(err, toc){
  1062.       if(err){
  1063.         VST.Logger.debug("there was an error: " + err.message);
  1064.       }else{
  1065.         VST.Logger.debug(toc);
  1066.       }
  1067.     });
  1068.     @/code@
  1069.   */
  1070.  
  1071.   VST.Models.Book.prototype.getTOC = function(callback){
  1072.     VST.EventDispatcher.trigger('book:getTOC:before');
  1073.     VST.Handler.fire('book:getTOC', callback, this);
  1074.   };
  1075.  
  1076.   VST.Models.Book.prototype.setPages = function(p){
  1077.     this.pages = p;
  1078.   };
  1079.  
  1080.   /* doc:code
  1081.  
  1082.     :name:      VST.Book.getPages(callback)
  1083.     :summary:   Retrieve the list of "pages" within the book.
  1084.     :params:    callback:Function
  1085.                 The function to call when the response is received
  1086.  
  1087.     == Example: ==
  1088.     @code:javascript@
  1089.     VST.Book.getPages(function(err, pages){
  1090.       if(err){
  1091.         VST.Logger.debug("there was an error: " + err.message);
  1092.       }else{
  1093.         VST.Logger.debug(pages);
  1094.       }
  1095.     });
  1096.     @/code@
  1097.     ==
  1098.  
  1099.     <p>
  1100.     The callback function will receive any error that occurred as the first parameter
  1101.     and an array of <code class="javascript">VST.Models.Page</code> objects as the second parameter.
  1102.     </p>
  1103.  
  1104.     <p>
  1105.     This method is different from <code class="javascript">Book.getTOC()</code> in that
  1106.     <code class="javascript">Book.getPages()</code> retrieves an array, whereas <code class="javascript">Book.getTOC()</code>
  1107.     retrieves an HTML representation of the book's table of contents. Furthermore, not every link listed in the TOC
  1108.     is guaranteed to be in the <code class="javascript">Book.getPages()</code> call.
  1109.     </p>
  1110.   */
  1111.   VST.Models.Book.prototype.getPages = function(callback){
  1112.     VST.EventDispatcher.trigger('book:getPages:before');
  1113.     VST.Handler.fire('book:getPages', callback, this);
  1114.   };
  1115.  
  1116.   VST.Models.Book.prototype.getCurrentPageURL = function(){
  1117.     VST.EventDispatcher.trigger('book:getCurrentPageURL:before');
  1118.     return VST.Handler.fire('book:getCurrentPageURL');
  1119.   };
  1120.  
  1121.   VST.Models.Book.prototype.goToNextPage = function(callback){
  1122.     VST.EventDispatcher.trigger('book:goToNextPage:before');
  1123.     VST.Handler.fire('book:goToNextPage', callback, this);
  1124.   };
  1125.  
  1126.   VST.Models.Book.prototype.goToPreviousPage = function(callback){
  1127.     VST.EventDispatcher.trigger('book:goToPreviousPage:before');
  1128.     VST.Handler.fire('book:goToPreviousPage', callback, this);
  1129.   };
  1130.  
  1131.   VST.Models.Book.prototype.getNextPage = function(callback){
  1132.     VST.EventDispatcher.trigger('book:getNextPage:before');
  1133.     VST.Handler.fire('book:getNextPage', callback, this);
  1134.   };
  1135.  
  1136.   VST.Models.Book.prototype.getPageBreaks = function(callback){
  1137.     VST.EventDispatcher.trigger('book:getPageBreaks:before');
  1138.     VST.Handler.fire('book:getPageBreaks', callback, this);
  1139.   };
  1140.  
  1141.   /* doc:code
  1142.  
  1143.     :name:      VST.Book.reportScores(scores, callback)
  1144.     :summary:   Retrieve scores from the Business Center
  1145.     :params:    scores:Array
  1146.                 An array of scores to report
  1147.     :params:    callback:Function
  1148.                 The function to call when the response is received
  1149.  
  1150.     == Example: ==
  1151.     @code:javascript@
  1152.     VST.Book.reportScores([firstScore, secondScore], function(err){
  1153.       if(err){
  1154.         VST.Logger.debug("there was an error: " + err.message);
  1155.       }else{
  1156.         VST.Logger.debug("success!");
  1157.       }
  1158.     });
  1159.     @/code@
  1160.   */
  1161.  
  1162.   VST.Models.Book.prototype.reportScores = function(data, callback){
  1163.     if (VST.Utils.isArray(data))
  1164.     {
  1165.       for (var i = data.length - 1; i >= 0; i--) {
  1166.         data[i] = new VST.Models.Score(data[i]);
  1167.       }
  1168.     }
  1169.     else
  1170.     {
  1171.       data = new VST.Models.Score(data);
  1172.     }
  1173.  
  1174.     VST.Handler.fire('book:reportScores', [data, callback], this);
  1175.   };
  1176.  
  1177.   // alias reportScores as reportScore
  1178.   VST.Models.Book.prototype.reportScore = VST.Models.Book.prototype.reportScores;
  1179.  
  1180.   /* doc:code
  1181.  
  1182.     :name:      VST.Book.getScores(locations, callback)
  1183.     :summary:   Retrieve scores from the Business Center
  1184.     :params:    locations:Array
  1185.                 An array of locations / ids of the scores you wish to retrieve
  1186.     :params:    callback:Function
  1187.                 The function to call when the response is received
  1188.  
  1189.     :callbackParams: error:VST.Error
  1190.                      Any error that was raised
  1191.     :callbackParams: scores:Array
  1192.                      The scores requested
  1193.  
  1194.  
  1195.     == Example: ==
  1196.     @code:javascript@
  1197.     VST.Book.getScores(["unique/identifier", "another_unique_id"], function(err, scores){
  1198.       if(err){
  1199.         VST.Logger.debug("there was an error: " + err.message);
  1200.       }else{
  1201.         VST.Logger.debug(scores);
  1202.       }
  1203.     });
  1204.     @/code@
  1205.   */
  1206.  
  1207.   VST.Models.Book.prototype.getScores = function(ids, callback){
  1208.     var cb = function(err, scores){
  1209.       if(scores && scores.length){
  1210.         // ensure all scores returned are VST.Models.Score objects
  1211.         for (var i = scores.length - 1; i >= 0; i--) {
  1212.           scores[i] = new VST.Models.Score(scores[i]);
  1213.         };
  1214.       }
  1215.       callback(err, scores);
  1216.     };
  1217.  
  1218.     VST.Handler.fire('book:getScores', [ids, cb], this);
  1219.   };
  1220.   // alias getScores as getScore
  1221.   VST.Models.Book.prototype.getScore = VST.Models.Book.prototype.getScores;
  1222.  
  1223.     /* doc:code
  1224.     :name:      VST.Book.launchActivity(data, callback)
  1225.     :summary:   Launch an external activity via the VST Business Center
  1226.     :params:    data:Object
  1227.                 The object containing all the configuration options for the launch
  1228.     :params:    data.tool:String
  1229.                 The name of the LTI tool to be invoked
  1230.     :params:    data.type:String
  1231.                 Identifies an LTI resource within the tool
  1232.     :params:    data.id:String
  1233.                 An arbitrary unique identifier of this link
  1234.     :params:    callback:Function
  1235.                 The funciton to call after the activity URL has been created.
  1236.                 The callback receives any error as the first argument, and the URL as the second.
  1237.  
  1238.     == Example: ==
  1239.     @code:javascript@
  1240.     VST.Book.launchActivity({}, function(err, url){
  1241.       if(err){ VST.Logger.debug("Ooops: " + err.message); }
  1242.       else   { window.open(url); }
  1243.     });
  1244.     @/code@
  1245.   */
  1246.  
  1247.   VST.Models.Book.prototype.launchActivity = function(data, callback){
  1248.     var obj = {
  1249.       tool_name    : data.tool,
  1250.       resource_type: data.type,
  1251.       link_id      : data.id,
  1252.       vbid         : this.getISBN()
  1253.     };
  1254.  
  1255.     VST.EventDispatcher.trigger('book:launchActivity:before');
  1256.     VST.Handler.fire('book:launchActivity', [obj, callback], this);
  1257.   };
  1258.  
  1259.   /* doc:code
  1260.  
  1261.     :name:      VST.Book.hideTOC(callback)
  1262.     :summary:   Hide the native Table of Contents
  1263.     :params:    callback:Function
  1264.                 The function to call after the TOC has been hidden
  1265.  
  1266.     == Example: ==
  1267.     @code:javascript@
  1268.     VST.Book.hideTOC(function(err){
  1269.       if(err){
  1270.         VST.Logger.debug("there was an error: " + err.message);
  1271.       }else{
  1272.         // do something now that the TOC is hidden
  1273.       }
  1274.     });
  1275.     @/code@
  1276.   */
  1277.  
  1278.   VST.Models.Book.prototype.hideTOC = function(callback){
  1279.     VST.EventDispatcher.trigger('book:hideTOC:before');
  1280.     VST.Handler.fire('book:hideTOC', callback, this);
  1281.   };
  1282.  
  1283.   /* doc:code
  1284.  
  1285.     :name:      VST.Book.showTOC(callback)
  1286.     :summary:   Show the native Table of Contents
  1287.     :params:    callback:Function
  1288.                 The function to call after the TOC has been become visible
  1289.  
  1290.     == Example: ==
  1291.     @code:javascript@
  1292.     VST.Book.showTOC(function(err){
  1293.       if(err){
  1294.         VST.Logger.debug("there was an error: " + err.message);
  1295.       }else{
  1296.         // do something now that the TOC is visible
  1297.       }
  1298.     });
  1299.     @/code@
  1300.   */
  1301.  
  1302.   VST.Models.Book.prototype.showTOC = function(callback){
  1303.     VST.EventDispatcher.trigger('book:showTOC:before');
  1304.     VST.Handler.fire('book:showTOC', callback, this);
  1305.   };
  1306.  
  1307.   VST.Models.Book.prototype.getPreviousPage = function(callback){
  1308.     VST.EventDispatcher.trigger('book:getPreviousPage:before');
  1309.     VST.Handler.fire('book:getPreviousPage', callback, this);
  1310.   };
  1311.  
  1312.   VST.Models.Book.prototype.getNextPageURL = function(callback){
  1313.     VST.EventDispatcher.trigger('book:getNextPageURL:before');
  1314.     VST.Handler.fire('book:getNextPageURL', callback, this);
  1315.   };
  1316.  
  1317.   VST.Models.Book.prototype.getPreviousPageURL = function(callback){
  1318.     VST.EventDispatcher.trigger('book:getPreviousPageURL:before');
  1319.     VST.Handler.fire('book:getPreviousPageURL', callback, this);
  1320.   };
  1321.  
  1322.   VST.Models.Book.prototype.getCurrentPage = function(callback){
  1323.     VST.EventDispatcher.trigger('book:getCurrentPage:before');
  1324.     VST.Handler.fire('book:getCurrentPage', callback, this);
  1325.   };
  1326.  
  1327.   VST.Models.Book.prototype.hasNextPage = function(callback){
  1328.     VST.Handler.fire('book:hasNextPage', callback, this);
  1329.   };
  1330.  
  1331.   VST.Models.Book.prototype.hasPreviousPage = function(callback){
  1332.     VST.Handler.fire('book:hasPreviousPage', callback, this);
  1333.   };
  1334.  
  1335.   VST.Models.Book.prototype.pageForCFI = function(cfi){
  1336.     var pageBreakTitle = function(node){
  1337.       return node.getAttribute('title') || node.textContent || node.innerText;
  1338.     };
  1339.  
  1340.     var prefix = '';
  1341.     if(!cfi || !cfi.indexOf){ return null; }
  1342.  
  1343.     if(this.pageBreakList){
  1344.       for (var i = this.pageBreakList.length - 1; i >= 0; i--) {
  1345.         var thisCFI = this.pageBreakList[i].cfi || ""
  1346.           , result = VST.Utils.compareCFIs(cfi, thisCFI);
  1347.         if(result === VST.Utils.GREATER_THAN || result === VST.Utils.EQUAL){ return this.pageBreakList[i]; }
  1348.       };
  1349.       return null;
  1350.     }else{
  1351.       // this is hacky, but Online needs it
  1352.       // if the passed in CFI is a full path (instead of relative to this doc)
  1353.       // we need to prepend the current page's CFI to the CFIs we compare
  1354.       if(cfi.indexOf('!') !== -1){
  1355.         if(typeof EpubBook !== 'undefined'){
  1356.           prefix = EpubBook.pageCFI + '!';
  1357.         }
  1358.       }
  1359.  
  1360.       var iter = this.createPageBreakIterator(VST.document);
  1361.       var n, thisCFI, prevCFI, result;
  1362.  
  1363.       while(n = iter.nextNode()){
  1364.         thisCFI = prefix + (VST.sharedEpubModule.GetCFIForNode(n) || '')
  1365.         result  = VST.Utils.compareCFIs(cfi, thisCFI);
  1366.         if(result === VST.Utils.LESS_THAN){
  1367.           if(prevCFI){
  1368.             return {
  1369.               title: pageBreakTitle(iter.previousNode()),
  1370.               cfi:   prevCFI
  1371.             };
  1372.           }else{
  1373.             // must be before the first page break
  1374.             return {
  1375.               title: pageBreakTitle(n),
  1376.               cfi: thisCFI
  1377.             };
  1378.           }
  1379.         }else if(result === VST.Utils.EQUAL){
  1380.           return {
  1381.             title: pageBreakTitle(n),
  1382.             cfi: thisCFI
  1383.           }
  1384.         }
  1385.         prevCFI = thisCFI;
  1386.       };
  1387.  
  1388.       return null;
  1389.     }
  1390.   };
  1391.  
  1392.   /* doc:code
  1393.  
  1394.     :name:      VST.Book.getHighlights(callback)
  1395.     :summary:   Get the highlights for the current book
  1396.     :params:    callback:Function
  1397.                 The function to call when the highlights are retreived
  1398.  
  1399.     == Example ==
  1400.     @code:javascript@
  1401.     VST.Book.getHighlights(function(error, highlights){
  1402.       // do something with the highlights
  1403.     });
  1404.     @/code@
  1405.     ==
  1406.  
  1407.     The callback will receive a <code class="javascript">VST.Error</code> object (if one occurred) as the first parameter
  1408.     and an array of <code class="javascript">VST.Models.Highlight</code> objects as the second parameter.
  1409.  
  1410.   */
  1411.  
  1412.   VST.Models.Book.prototype.getHighlights = function(callback){
  1413.     VST.EventDispatcher.trigger('book:getHighlights:before');
  1414.     VST.Handler.fire('book:getHighlights', callback, this);
  1415.   };
  1416.  
  1417.   VST.Models.Book.prototype.clearSelection = function(callback){
  1418.     var win = VST.window   || window
  1419.       , doc = VST.document || document;
  1420.  
  1421.     if(doc.selection && doc.selection.empty) {
  1422.       doc.selection.empty();
  1423.     } else if(win.getSelection) {
  1424.       win.getSelection().removeAllRanges();
  1425.     }
  1426.  
  1427.     VST.fire('book:selectionCancelled');
  1428.   };
  1429.  
  1430.   VST.Models.Book.prototype.setupPageBreaks = function () {
  1431.     if (this.hasPageBreaks() && !this.hasEPUB3PagebreakAttributes())
  1432.     {
  1433.       // todo- don't allow copy / print until callback fires? Only for
  1434.       // online if getPageBreaks uses ajax.
  1435.       this.getPageBreaks(null);
  1436.  
  1437.       // FWIW, I feel like maybe we should just ask for the list back
  1438.       // and save the page list here in this method instead of relying
  1439.       // on the handler to retrieve AND save them. For example, do this instead:
  1440.       //
  1441.       // var self = this;
  1442.       // this.getPageBreaks(function(err, data){
  1443.       //   self.setPageBreaks(data);
  1444.       // });
  1445.     }
  1446.   };
  1447.  
  1448.   VST.Models.Book.prototype.hasEPUB3PagebreakAttributes = function () {
  1449.     var doc = VST.document  || document;
  1450.     var iter = this.createPageBreakIterator(doc);
  1451.     return (iter && iter.nextNode() != null);
  1452.   };
  1453.  
  1454.   // The page breaks are a list of all of the cfis
  1455.   // and pagebreak titles for the page breaks in this chapter.
  1456.   // eg: { "cfi":"/2/4/2", "title":"1" }
  1457.   // CFI is just the partial CFI within this chapter. Or you
  1458.   // can specify "fragment" which is an id or name; the fragment of
  1459.   // an anchor. Or if neither is specified the page break is
  1460.   // at the top of the body.
  1461.   VST.Models.Book.prototype.setPageBreaks = function (pageBreakList) {
  1462.     this.pageBreakList = pageBreakList;
  1463.   };
  1464.  
  1465.   var IEPageBreakIterator = function(root) {
  1466.     // wondering if we should filter these on the fly or when we create the object...
  1467.     this.currentNode  = root;
  1468.     var index         = -1
  1469.       , found         = [];
  1470.  
  1471.     var isPagebreak = function(n){
  1472.       if(!n || n.nodeType !== 1){ return false; }
  1473.       for (var i = n.attributes.length - 1; i >= 0; i--) {
  1474.         if(n.attributes[i].nodeName == 'epub:type' && n.attributes[i].nodeValue == 'pagebreak'){
  1475.           return true;
  1476.         }
  1477.       };
  1478.  
  1479.       return false;
  1480.     };
  1481.  
  1482.     var all = this.currentNode.getElementsByTagName('*');
  1483.  
  1484.     for (var i = 0; i < all.length; i++) {
  1485.       if(isPagebreak(all[i])){
  1486.         found.push(all[i]);
  1487.       }
  1488.     }
  1489.  
  1490.     this.nextNode = function(){
  1491.       VST.Logger.debug("IE next node called");
  1492.       if(index < found.length-1){
  1493.         index++;
  1494.         this.currentNode = found[index];
  1495.         return this.currentNode;
  1496.       }
  1497.     };
  1498.  
  1499.     this.previousNode = function(){
  1500.       if(index < 0){
  1501.         return null;
  1502.       }else if (index == 0){
  1503.         index--;
  1504.         this.currentNode = root;
  1505.         return null;
  1506.       }
  1507.  
  1508.       index--;
  1509.       this.currentNode = found[index];
  1510.       return found[index+1];
  1511.     };
  1512.   };
  1513.  
  1514.   function PageBreakListIterator (pageBreakList) {
  1515.     this.pageBreakList = pageBreakList;
  1516.     this.index = 0;
  1517.   }
  1518.  
  1519.   PageBreakListIterator.prototype.doFindNodeForEntry = function(entry) {
  1520.     var win = VST.window   || window
  1521.       , doc = VST.document || document;
  1522.  
  1523.     var node = null;
  1524.  
  1525.     if (entry.cfi)
  1526.     {
  1527.       var loc = VST.sharedEpubModule.locateCFI(entry.cfi);
  1528.       if (loc)
  1529.       {
  1530.         node = loc.node;
  1531.       }
  1532.     }
  1533.     else if (entry.fragment)
  1534.     {
  1535.       if (/^epubcfi/.test(fragment))
  1536.       {
  1537.         var cfi = fragment.slice(8,fragment.length - 1);
  1538.         var loc = VST.sharedEpubModule.locateCFI(cfi);
  1539.         if (loc)
  1540.         {
  1541.           node = loc.node;
  1542.         }
  1543.       }
  1544.       else
  1545.       {
  1546.         node = doc.getElementById(decodeURIComponent(fragment));
  1547.         if (!node)
  1548.         {
  1549.           var nodes = doc.getElementsByName(fragment);
  1550.           if (nodes.length > 0)
  1551.           {
  1552.             node = nodes[0];
  1553.           }
  1554.         }
  1555.       }
  1556.     }
  1557.     else
  1558.     {
  1559.       node = doc.body;
  1560.     }
  1561.  
  1562.     return node;
  1563.   };
  1564.  
  1565.   PageBreakListIterator.prototype.findNode = function (index) {
  1566.  
  1567.     var entry = this.pageBreakList[index];
  1568.     if (!entry.node)
  1569.     {
  1570.       entry.node = this.doFindNodeForEntry(entry);
  1571.     }
  1572.  
  1573.     return entry;
  1574.   };
  1575.  
  1576.   PageBreakListIterator.prototype.titleForNode = function (n) {
  1577.     var i = this.index;
  1578.     if (i >= this.pageBreakList.length)
  1579.     {
  1580.       i = this.pageBreakList.length - 1;
  1581.     }
  1582.  
  1583.     for (; i >= 0; --i)
  1584.     {
  1585.       var entry = this.pageBreakList[i];
  1586.       if (entry.node == n)
  1587.       {
  1588.         return entry.title;
  1589.       }
  1590.     }
  1591.  
  1592.     var max = this.pageBreakList.length;
  1593.     for (i = this.index; i < max; ++i)
  1594.     {
  1595.       var entry = this.pageBreakList[i];
  1596.       if (entry.node == n)
  1597.       {
  1598.         return entry.title;
  1599.       }
  1600.     }
  1601.  
  1602.     return null;
  1603.   };
  1604.  
  1605.   PageBreakListIterator.prototype.nextNode = function () {
  1606.     if (this.index >= this.pageBreakList.length)
  1607.     {
  1608.       return null;
  1609.     }
  1610.  
  1611.     var entry = this.findNode(this.index);
  1612.     ++this.index;
  1613.     return entry.node;
  1614.   };
  1615.  
  1616.   VST.Models.Book.prototype.createPageBreakIterator = function (doc, root) {
  1617.     var rootNode = root ? root : doc.body;
  1618.  
  1619.     // older versions of IE don't have NodeFilter
  1620.     if (!NodeFilter){
  1621.       var NodeFilter = {
  1622.           "SHOW_ELEMENT" : 1
  1623.         , "FILTER_ACCEPT": 1
  1624.         , "FILTER_REJECT": 2
  1625.         , "FILTER_SKIP"  : 3
  1626.       };
  1627.     }
  1628.  
  1629.     if(doc.createNodeIterator){
  1630.       var iter = doc.createNodeIterator (rootNode, NodeFilter.SHOW_ELEMENT,
  1631.         function(node) {
  1632.           if (node.getAttributeNS("http://www.idpf.org/2007/ops", "type") == "pagebreak")
  1633.           {
  1634.             return NodeFilter.FILTER_ACCEPT;
  1635.           }
  1636.  
  1637.           return NodeFilter.FILTER_REJECT;
  1638.         },
  1639.       false);
  1640.     }else{
  1641.       var iter = new IEPageBreakIterator(rootNode);
  1642.     }
  1643.  
  1644.     if (this.pageBreakList) {
  1645.       if (iter.nextNode() != null) {
  1646.         iter.previousNode();
  1647.       } else {
  1648.         iter = new PageBreakListIterator (this.pageBreakList);
  1649.       }
  1650.     }
  1651.     this.pageBreakIterator = iter;
  1652.     return iter;
  1653.   };
  1654.  
  1655.   VST.Models.Book.prototype.isSelectionTooLong = function (limit) {
  1656.     var win       = VST.window    || window
  1657.       , doc       = VST.document  || document
  1658.       , wordLimit = VST.Settings.wordsPerPage * limit
  1659.       , selection = VST.Utils.getSelectionObject();
  1660.  
  1661.     if (this.hasPageBreaks())
  1662.     {
  1663.       if (win.getSelection)
  1664.       {
  1665.         if (selection && !selection.isCollapsed && selection.rangeCount > 0)
  1666.         {
  1667.           var range = selection.getRangeAt(0);
  1668.  
  1669.           // Iterate through all of the elements whose start is within the range and that
  1670.           // contain an epub:type attribute.
  1671.           var ancestor = range.commonAncestorContainer;
  1672.           var iter = this.createPageBreakIterator(doc, ancestor);
  1673.  
  1674.           var breakCount = 0;
  1675.           var n = null;
  1676.           var nodeRange = range.cloneRange();
  1677.           while (n = iter.nextNode())
  1678.           {
  1679.             nodeRange.selectNode(n);
  1680.             if (range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
  1681.                 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) > 0)
  1682.             {
  1683.               ++breakCount;
  1684.               if (breakCount > limit)
  1685.               {
  1686.                 return true;
  1687.               }
  1688.             }
  1689.           }
  1690.  
  1691.           return false;
  1692.         }
  1693.       }
  1694. //      else
  1695. //      {
  1696. //        // IE < 9
  1697. //        return true;
  1698. //      }
  1699.     }
  1700.  
  1701.     // otherwise, grab the selected text, and calculate its length
  1702.     var selectedText = VST.Utils.getSelectedText();
  1703.     return (selectedText.split(/\s+/).length > wordLimit);
  1704.   }
  1705.  
  1706.   VST.Models.Book.prototype.isSelectionTooLongForCopy = function () {
  1707.  
  1708.     if (!this.hasCopyLimit())
  1709.     {
  1710.       return false;
  1711.     }
  1712.  
  1713.     var copyLimit = this.getCopyLimit();
  1714.     if (copyLimit == 0)
  1715.     {
  1716.       return true;
  1717.     }
  1718.  
  1719.     return this.isSelectionTooLong(copyLimit);
  1720.   }
  1721.  
  1722.   VST.Models.Book.prototype.limitSelection = function (limit, operation) {
  1723.     var win       = VST.window    || window
  1724.       , doc       = VST.document  || document
  1725.       , wordLimit = VST.Settings.wordsPerPage * limit
  1726.       , selection = VST.Utils.getSelectionObject();
  1727.  
  1728.     if (this.hasPageBreaks())
  1729.     {
  1730.       if (win.getSelection)
  1731.       {
  1732.         if (selection && !selection.isCollapsed && selection.rangeCount > 0)
  1733.         {
  1734.           var range = selection.getRangeAt(0);
  1735.  
  1736.           // Iterate through all of the elements whose start is within the range and that
  1737.           // contain an epub:type attribute.
  1738.           var ancestor = range.commonAncestorContainer;
  1739.           var iter = this.createPageBreakIterator(doc, ancestor);
  1740.  
  1741.           var breakCount = 0;
  1742.           var n = null;
  1743.           var nodeRange = range.cloneRange();
  1744.           while (n = iter.nextNode())
  1745.           {
  1746.             nodeRange.selectNode(n);
  1747.             if (range.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
  1748.                 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) > 0)
  1749.             {
  1750.               ++breakCount;
  1751.               if (breakCount > limit)
  1752.               {
  1753.                 // Cut the selection off at n.
  1754.                 range = range.cloneRange();
  1755.                 range.setEndBefore(n);
  1756.                 break;
  1757.               }
  1758.             }
  1759.           }
  1760.  
  1761.           selection.removeAllRanges();
  1762.           selection.addRange(range);
  1763.           return selection.toString();
  1764.         }
  1765.       }
  1766.       else
  1767.       {
  1768.         // IE < 9
  1769.         var iter           = this.createPageBreakIterator(doc)
  1770.           , comparingRange = doc.body.createTextRange()
  1771.           , clonedRange    = VST.Utils.getSelectionObject()
  1772.           , pages          = 0
  1773.           , n;
  1774.  
  1775.         selection.collapse(true);
  1776.  
  1777.         while(n = iter.nextNode()){
  1778.           comparingRange.moveToElementText(n);
  1779.           // console.log("moved to the element text");
  1780.           if(selection.compareEndPoints('StartToStart', comparingRange) <= 0){
  1781.             // this means we are in the page
  1782.             // console.log("let's iterate now (clonedRange:)", clonedRange);
  1783.             pages++;
  1784.             while(selection.compareEndPoints('EndToStart', comparingRange) < 0 &&
  1785.                   selection.compareEndPoints('EndToEnd',   clonedRange)     < 0 ) {
  1786.               // move by sentence so we don't loop more than necessary
  1787.               selection.moveEnd("sentence", 1);
  1788.             }
  1789.             // if we've gone too far because a partial sentence was selected at the end, ba
  1790.             while(selection.compareEndPoints('EndToEnd', clonedRange) === 1 ||
  1791.                   selection.compareEndPoints('EndToEnd', comparingRange) === 1) {
  1792.               selection.moveEnd("word", -1);
  1793.             }
  1794.             if(pages > limit){ break; }
  1795.           }
  1796.         }
  1797.  
  1798.         this.clearSelection();
  1799.         selection.select();
  1800.         window.select = selection;
  1801.         window.iter = iter;
  1802.         return selection.text;
  1803.       }
  1804.     }
  1805.     else
  1806.     {
  1807.       // otherwise, grab the selected text, and calculate its length
  1808.       var selectedText = VST.Utils.getSelectedText();
  1809.       if(selectedText.split(/\s+/).length <= wordLimit) {
  1810.         // don't need to do anything
  1811.         VST.Logger.debug("acceptable " + operation + " length");
  1812.       }else{
  1813.         VST.Logger.debug(operation + " text too long");
  1814.         selection = VST.Utils.getSelectionObject();
  1815.         if(selection.collapseToStart && selection.modify){
  1816.           selection.collapseToStart();
  1817.           for(var i=0; i<wordLimit; i++){
  1818.             selection.modify("extend", "forward", "word");
  1819.           }
  1820.         }else{
  1821.           // ugh, IE
  1822.           selection.collapse(true);
  1823.           selection.moveEnd("word", wordLimit);
  1824.           this.clearSelection();
  1825.           selection.select();
  1826.         }
  1827.       }
  1828.     }
  1829.     // return the text we have, instead of just `true` here
  1830.     return (selection.toString ? selection.toString() : selection.text);
  1831.   };
  1832.  
  1833.   VST.Models.Book.prototype.handleCopy = function(event){
  1834.     var copyLimit = this.getCopyLimit();
  1835.     if(copyLimit == 0){
  1836.       VST.Logger.debug("copy not allowed");
  1837.       event.preventDefault();
  1838.       return false;
  1839.     }
  1840.  
  1841.     if (this.hasCopyLimit())
  1842.     {
  1843.       this.limitSelection(copyLimit, "copy");
  1844.     }
  1845.  
  1846.     this.appendBibliography();
  1847.     return true;
  1848.   };
  1849.  
  1850.   VST.Models.Book.prototype.setBibliographicHTML = function (info) {
  1851.     this.bibliographicInfo = info;
  1852.   };
  1853.  
  1854.   VST.Models.Book.prototype.appendBibliographyHTML = function (biblioHTML) {
  1855.     var win       = VST.window    || window
  1856.       , doc       = VST.document  || document;
  1857.  
  1858.     var selection = win.getSelection();
  1859.  
  1860.     if (selection && !selection.isCollapsed && selection.rangeCount > 0) {
  1861.       if ($("#vst_newcopyelement_temp").length > 0) {
  1862.         return; // Workaround for a weird problem with Awesomium where the copy handler gets called twice in rapid succession (or once inside the other?) causing the bibliography to get appended twice.
  1863.       }
  1864.       else {
  1865.         var range = selection.getRangeAt(0);
  1866.         var newCopyElement = $('<div id="vst_newcopyelement_temp" style="overflow:hidden;color:#000000;backgroundColor:transparent;textAlign:left;textDecoration:none;width:0.1;height:0.1"></div>', doc);
  1867.         $(range.cloneContents()).appendTo(newCopyElement);
  1868.         var biblio = $('<div>' + biblioHTML + '</div>', doc);
  1869.         biblio.appendTo(newCopyElement);
  1870.  
  1871.         newCopyElement.appendTo($(doc.body));
  1872.  
  1873.         var newRange = doc.createRange();
  1874.         var newCopyDOMElement = newCopyElement.get(0);
  1875.         newRange.selectNode(newCopyDOMElement);
  1876.         selection.removeAllRanges();
  1877.         selection.addRange(newRange);
  1878.  
  1879.         win.setTimeout(function () {
  1880.           newCopyDOMElement.parentNode.removeChild(newCopyDOMElement);
  1881.  
  1882.           var sel = win.getSelection();
  1883.           sel.removeAllRanges();
  1884.           sel.addRange(range);
  1885.         }, 0);
  1886.       }
  1887.     }
  1888.   };
  1889.  
  1890.   VST.Models.Book.prototype.appendBibliography = function () {
  1891.     if (this.bibliographicInfo && this.bibliographicInfo.length > 0)
  1892.     {
  1893.       this.appendBibliographyHTML(this.bibliographicInfo);
  1894.     }
  1895.     else
  1896.     {
  1897.       var cfirange = VST.sharedEpubModule.GetCFIRangeStringForSelection();
  1898.       var html = VST.Handler.fire('book:getBibliographyHTML', cfirange, this);
  1899.  
  1900.       if (html && html.length > 0)
  1901.       {
  1902.         this.appendBibliographyHTML(html);
  1903.       }
  1904.     }
  1905.   };
  1906.  
  1907.   VST.Models.Book.prototype.getPrintXMLForRange = function(range) {
  1908.     var win = VST.window    || window
  1909.       , doc = VST.document  || document;
  1910.  
  1911.     var xml = null;
  1912.  
  1913.     if (range.cloneContents)
  1914.     {
  1915.       var selectionFragment = range.cloneContents();
  1916.       var newHTML = doc.createElement("html");
  1917.  
  1918. /*
  1919.       if (doc.doctype)
  1920.       {
  1921.         newHTML.appendChild(doc.doctype.cloneNode(true));
  1922.       }
  1923.  */
  1924.       if (doc.head)
  1925.       {
  1926.         newHTML.appendChild(doc.head.cloneNode(true));
  1927.       }
  1928.  
  1929.       var newBody = doc.body.cloneNode(false);
  1930.       newBody.appendChild(selectionFragment);
  1931.       newHTML.appendChild(newBody);
  1932.  
  1933.       // Add a blocking div to disable user interaction. I looked at a jquery
  1934.       // plugin called BlockUI to get an idea how this might be done:
  1935.       // http://malsup.com/jquery/block
  1936.       var opacityHack = $.browser.msie ? "opacity:0.001;background-color:rgb(255,255,255);" : "";
  1937.       var hideBlock = $('<style type="text/css" media="print">#printUIBlocker { display:none; } </style>');
  1938.       var iframeLayer = $('<iframe class="printUIBlocker" style="z-index:1000;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0;opacity:0.0;" src="about:blank"></iframe>');
  1939.       var divLayer = $('<div class="printUIBlocker" style="z-index:1001;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0;position:fixed;' + opacityHack + '"></div>');
  1940.  
  1941.       var $par = $(newBody);
  1942.       hideBlock.appendTo($par);
  1943.       iframeLayer.appendTo($par);
  1944.       divLayer.appendTo($par);
  1945.  
  1946.       $(newHTML).find('script').remove();
  1947.  
  1948.       xml = new XMLSerializer().serializeToString(newHTML);
  1949.     }
  1950.     else
  1951.     {
  1952.       // IE < 9
  1953.     }
  1954.  
  1955.     return xml;
  1956.   };
  1957.  
  1958.   VST.Models.Book.prototype.getPrintXMLForSelection = function () {
  1959.     var win        = VST.window    || window
  1960.       , doc        = VST.document  || document
  1961.       , printLimit = this.getPrintLimit();
  1962.  
  1963.     if (printLimit == 0)
  1964.     {
  1965.       VST.log("print not allowed");
  1966.       return null;
  1967.     }
  1968.  
  1969.     if (this.hasPrintLimit())
  1970.     {
  1971.       this.limitSelection(printLimit, "print");
  1972.     }
  1973.  
  1974.     if (win.getSelection)
  1975.     {
  1976.       var selection = win.getSelection();
  1977.       if (selection && !selection.isCollapsed && selection.rangeCount > 0)
  1978.       {
  1979.         var range = selection.getRangeAt(0);
  1980.         return this.getPrintXMLForRange(range);
  1981.       }
  1982.     }
  1983.     else if (doc.selection)
  1984.     {
  1985.       var textrange = doc.selection.createRange();
  1986.       return this.getPrintXMLForRange(textrange);
  1987.     }
  1988.  
  1989.     return null;
  1990.   };
  1991.  
  1992.   // Note: indexes are 0-based. The first page break is always "at the top" even if there's
  1993.   // something above it, because otherwise anything before the first page break will be
  1994.   // unprintable.
  1995.   // An end index past the end of the index range will print to the end of the chapter.
  1996.   // An index < 0 means from the start or to the end.
  1997.   VST.Models.Book.prototype.getPrintXMLForPageRange = function (startPageIndex, endPageIndex) {
  1998.     var win        = VST.window    || window
  1999.       , doc        = VST.document  || document;
  2000.  
  2001.     // Find the range for the specified page breaks.
  2002.     var range = doc.createRange();
  2003.     range.selectNodeContents(doc.body);
  2004.  
  2005.     if (startPageIndex >= endPageIndex && endPageIndex >= 0)
  2006.     {
  2007.       return null;
  2008.     }
  2009.  
  2010.     if (startPageIndex == 0)
  2011.     {
  2012.       // Make sure we don't miss any content at the top.
  2013.       startPageIndex = -1;
  2014.     }
  2015.  
  2016.     if (startPageIndex >= 0 || endPageIndex >= 0)
  2017.     {
  2018.       var iter = this.createPageBreakIterator(doc);
  2019.       var n = null;
  2020.       var index = 0;
  2021.       while (n = iter.nextNode())
  2022.       {
  2023.         if (index == startPageIndex)
  2024.         {
  2025.           range.setStartBefore(n);
  2026.           if (endPageIndex < 0)
  2027.           {
  2028.             break;
  2029.           }
  2030.         }
  2031.  
  2032.         if (index == endPageIndex)
  2033.         {
  2034.           range.setEndBefore(n);
  2035.           break;
  2036.         }
  2037.  
  2038.         ++index;
  2039.       }
  2040.     }
  2041.  
  2042.     return this.getPrintXMLForRange(range);
  2043.   };
  2044.  
  2045.   // Convoluted crap for getting the arguments to EPUBPrintRangeChooser,
  2046.   // probably only useful for desktop.
  2047.   VST.Models.Book.prototype.getPrintSetupInfo = function () {
  2048.     var win = VST.window    || window
  2049.       , doc = VST.document  || document;
  2050.  
  2051.     var result = {
  2052.       pageBreaks: new Array(),
  2053.       currentPageIndex: 0,
  2054.       hasSelection: false,
  2055.       selectionStartIndex: null,
  2056.       selectionEndIndex: null,
  2057.       error: null
  2058.     };
  2059.  
  2060.     try {
  2061.       var iter = this.createPageBreakIterator(doc);
  2062.  
  2063.       if (this.hasPrintLimit())
  2064.       {
  2065.         this.limitSelection(this.getPrintLimit(), "print");
  2066.       }
  2067.  
  2068.       var selectionRange = null;
  2069.       if (win.getSelection)
  2070.       {
  2071.         var selection = win.getSelection();
  2072.         if (selection && !selection.isCollapsed && selection.rangeCount > 0)
  2073.         {
  2074.           selectionRange = selection.getRangeAt(0);
  2075.           result.selectionStartIndex = 0;
  2076.           result.selectionEndIndex = 0;
  2077.           result.hasSelection = true;
  2078.         }
  2079.       }
  2080.  
  2081.       var n = null;
  2082.       var pos = VST.sharedEpubModule.FindDOMNodeAndOffsetIntersectingViewportRect(doc.body, { top:0, left:0, bottom:10, right:win.innerWidth });
  2083.       var posRange = null;
  2084.       if (pos)
  2085.       {
  2086.         posRange = doc.createRange();
  2087.         posRange.setStart(doc.body, 0);
  2088.         posRange.setEnd(pos.node, pos.offset);
  2089.       }
  2090.       var index = 0;
  2091.       var nodeRange = doc.createRange();
  2092.  
  2093.       while (n = iter.nextNode())
  2094.       {
  2095.         nodeRange.selectNode(n);
  2096.         if (posRange && posRange.compareBoundaryPoints(Range.START_TO_START, nodeRange) <= 0 &&
  2097.             posRange.compareBoundaryPoints(Range.START_TO_END, nodeRange) > 0)
  2098.         {
  2099.           result.currentPageIndex = index;
  2100.         }
  2101.  
  2102.         if (selectionRange)
  2103.         {
  2104.           if (nodeRange.compareBoundaryPoints(Range.START_TO_START, selectionRange) <=0)
  2105.           {
  2106.             result.selectionStartIndex = index;
  2107.             result.selectionEndIndex = index;
  2108.           }
  2109.           else if (nodeRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) < 0)
  2110.           {
  2111.             result.selectionEndIndex = index;
  2112.           }
  2113.         }
  2114.  
  2115.         ++index;
  2116.  
  2117.         var title = null;
  2118.  
  2119.         if (iter.titleForNode)
  2120.         {
  2121.           title = iter.titleForNode(n);
  2122.         }
  2123.         else
  2124.         {
  2125.           title = n.getAttribute("title");
  2126.           if (!title)
  2127.           {
  2128.               title = n.textContent;
  2129.           }
  2130.         }
  2131.  
  2132.         result.pageBreaks.push(title);
  2133.       }
  2134.     }
  2135.     catch (err) {
  2136.       result.error = err.message;
  2137.     }
  2138.  
  2139.     return JSON.stringify(result);
  2140.   };
  2141.  
  2142. }).call(window, jQuery);
  2143.  
  2144.  
  2145. (function ($) {
  2146.     var g_keyboardEventActive = false;
  2147.  
  2148.   VST.Models.Highlight = function(settings){
  2149.     settings    = settings || {};
  2150.  
  2151.     var book         = settings.book
  2152.       , offset       = settings.offset
  2153.       , selectedText = settings.selectedText
  2154.       , CFI          = settings.cfi || settings.CFI
  2155.       , id           = settings.id  || settings.sync_id
  2156.       , color        = settings.color;
  2157.  
  2158.     this.getBook         = function(){ return book; };
  2159.     this.getOffset       = function(){ return offset; };
  2160.     this.getCFI          = function(){ return CFI; };
  2161.     this.getSelectedText = function(){ return selectedText; };
  2162.   };
  2163.  
  2164.   VST.Models.Highlight.Settings = {
  2165.     highlightClass : 'vsthighlight'
  2166.   };
  2167.  
  2168.   VST.Models.Highlight.init = function(win, doc){
  2169.     if(doc == null) doc = document;
  2170.     if(win == null) win = window;
  2171.  
  2172.     this.setupEventHandlers(win, doc);
  2173.   };
  2174.  
  2175.   VST.Models.Highlight.setupEventHandlers = function(win, doc){
  2176.     this.watchForSelection(win, doc);
  2177.     this.watchHovers(win, doc);
  2178.     this.watchForHighlightClicks(win, doc);
  2179.   };
  2180.  
  2181.   VST.Models.Highlight.watchHovers = function(win, doc){
  2182.     var query = '.' + VST.Models.Highlight.Settings.highlightClass;
  2183.     $(doc).delegate(query, 'mouseover', function(e){
  2184.       VST.fire(VST.Event.fromjQueryEvent('highlight:mouseover', e), this);
  2185.     }).delegate(query, 'mouseout', function(e){
  2186.       VST.fire(VST.Event.fromjQueryEvent('highlight:mouseout', e), this);
  2187.     });
  2188.   };
  2189.  
  2190.   VST.Models.Highlight.watchForHighlightClicks = function(win, doc){
  2191.     var query = '.' + VST.Models.Highlight.Settings.highlightClass;
  2192.     if(navigator.epubReadingSystem && navigator.epubReadingSystem.isDesktop()){
  2193.       $(doc).delegate(query, 'dblclick', function(e){
  2194.         VST.Book.clearSelection();
  2195.         VST.fire(VST.Event.fromjQueryEvent('highlight:click', e), this);
  2196.       });
  2197.     }else{
  2198.       $(doc).delegate(query, 'click', function(e){
  2199.         VST.fire(VST.Event.fromjQueryEvent('highlight:click', e), this);
  2200.       });
  2201.     }
  2202.   };
  2203.  
  2204.   VST.Models.Highlight.makeHighlightFromSelection = function(callback){
  2205.     VST.Handler.fire('highlight:makeHighlightFromSelection', callback, this);
  2206.   };
  2207.  
  2208.   VST.Models.Highlight.watchForSelection = function (win, doc) {
  2209.       var keyHandler = function (e, data) {
  2210.           data = data || {};
  2211.           setTimeout(function () {
  2212.               if (!g_keyboardEventActive) {
  2213.                   g_keyboardEventActive = true;
  2214.                   setTimeout(function () { g_keyboardEventActive = false; }, 10);
  2215.                   var event = VST.Event.fromjQueryEvent('book:keyPressed', e, data);
  2216.                   VST.EventDispatcher.fire(event);
  2217.               }
  2218.           }, 10);
  2219.       };
  2220.       var mousedownHandler = function (e, data) {
  2221.           data = data || {};
  2222.           setTimeout(function () {
  2223.               var event = VST.Event.fromjQueryEvent('book:mousedown', e, data);
  2224.               VST.EventDispatcher.fire(event);
  2225.           }, 10);
  2226.       };
  2227.       var mouseupHandler = function (e, data) {
  2228.           data = data || {};
  2229.           setTimeout(function () {
  2230.               var event = VST.Event.fromjQueryEvent('book:mouseup', e, data);
  2231.               VST.EventDispatcher.fire(event);
  2232.           }, 10);
  2233.       };
  2234.     var selectionHandler = function(e, data){
  2235.       data = data || {};
  2236.       setTimeout(function(){
  2237.         var selectedText = VST.Utils.getSelectedText();
  2238.         if(selectedText === ''){
  2239.           var event = VST.Event.fromjQueryEvent('book:selectionCancelled', e, data);
  2240.           VST.EventDispatcher.fire(event);
  2241.         }else{
  2242.           // we have to do this w/typeof because it get's super weird if we don't
  2243.           if( typeof VST.Book !== 'undefined' && (VST.Book.getISBN() !== '') ){
  2244.             // fire the event and pass the selection data
  2245.             // I think maybe the selection data should include the CFI of the selected text?
  2246.             var event = VST.Event.fromjQueryEvent('book:selectionMade', e, data);
  2247.             VST.EventDispatcher.fire(event, selectedText);
  2248.           }
  2249.         }
  2250.       }, 10);
  2251.     };
  2252.  
  2253.     $(doc).delegate('body', 'mousedown', function (e) {
  2254.         mousedownHandler(e, { originalEventType: 'mousedown' });
  2255.     });
  2256.  
  2257.     $(doc).delegate('body', 'mouseup', function(e){
  2258.         mouseupHandler(e, { originalEventType: 'mouseup' });
  2259.         if (e.button == '0')
  2260.             selectionHandler(e, { originalEventType: 'mouseup' });
  2261.     });
  2262.  
  2263.     $(doc).keydown(function (e) {
  2264.         keyHandler(e, { originalEventType: 'keydown' });
  2265.     });
  2266.    
  2267.     $(doc).delegate('body', 'mouseleave', function (e) {
  2268.         var event = VST.Event.fromjQueryEvent('book:mouseleave', e, {});
  2269.         var text = '';
  2270.         if (VST.insertionPoint.isEnabled) {
  2271.             if (!VST.insertionPoint.range.IsCollapsed()) {
  2272.                 text = VST.Utils.getSelectedText();
  2273.             }
  2274.         }
  2275.         else {
  2276.             text = VST.Utils.getSelectedText();
  2277.         }
  2278.         VST.EventDispatcher.fire(event, text);
  2279.     });
  2280.  
  2281.  
  2282.     $(doc).keyup(function (e) {
  2283.         // we don't need this right now because we aren't allowing keyboard selection
  2284.         //selectionHandler(e, { originalEventType: 'keyup' });
  2285.     });
  2286.   };
  2287.  
  2288. }).call(window, jQuery);
  2289. (function ($) {
  2290.  
  2291.     VST.Models.InsertionPoint = function InsertionPoint(doc) {
  2292.         this.Initialize(doc);
  2293.     };
  2294.  
  2295.     function IsTextNode(node) {
  2296.         if (!node) {
  2297.             return false;
  2298.         }
  2299.  
  2300.         var type = node.nodeType;
  2301.         return (type === 3 || type === 4 || type === 5);
  2302.     }
  2303.  
  2304.     function Overlay(doc, width, height) {
  2305.         this.Initialize(doc, width, height);
  2306.         this.SetUpEventHandlers();
  2307.     };
  2308.  
  2309.     Overlay.method('Initialize', function (doc, width, height) {
  2310.  
  2311.         this.max = 8192;
  2312.         this.width = width;
  2313.         this.height = height;
  2314.         this.document = doc;
  2315.  
  2316.        
  2317.         this.gridWidth = Math.ceil(width / this.max);
  2318.         this.gridHeight = Math.ceil(height / this.max);
  2319.         this.canvasWidth = this.max;
  2320.         this.canvasHeight = this.max;
  2321.  
  2322.         if (this.gridWidth == 1)
  2323.             this.canvasWidth = width;
  2324.  
  2325.         if (this.gridHeight == 1)
  2326.             this.canvasHeight = height;
  2327.  
  2328.         this.canvasArray = new Array();
  2329.         var i = 0;
  2330.         var j = 0;
  2331.         for (i = 0; i < this.gridHeight; i++) {
  2332.             for (j = 0; j < this.gridWidth; j++) {
  2333.  
  2334.                 //NOTE: the actual area of the canvases may be larger than the area requested by
  2335.                 // [width] and [height] parameters.
  2336.                 var canvas = this.MakeCanvas(j, i);
  2337.                 this.canvasArray.push(canvas);
  2338.                 this.document.body.appendChild(canvas);
  2339.             }
  2340.         }
  2341.  
  2342.         return this;
  2343.     });
  2344.  
  2345.     Overlay.method('OnZoomChanged', function () {
  2346.         var i = 0;
  2347.         for (i = 0; i < this.canvasArray.length; i++) {
  2348.             this.document.body.removeChild(this.canvasArray[i]);
  2349.         }
  2350.         delete this.canvasArray;
  2351.  
  2352.         var width = Math.max(this.document.documentElement.clientWidth, this.document.body.getClientRects()[0].width);
  2353.         var height = Math.max(this.document.documentElement.clientHeight, this.document.body.getClientRects()[0].height);
  2354.         this.Initialize(this.document, width, height);
  2355.     });
  2356.  
  2357.     Overlay.method('CheckZoom', function () {
  2358.  
  2359.         if (this.zoom != this.document.documentElement.clientWidth) {
  2360.  
  2361.             this.zoom = this.document.documentElement.clientWidth;
  2362.             this.OnZoomChanged();
  2363.         }
  2364.     });
  2365.  
  2366.     Overlay.method('SetUpEventHandlers', function () {
  2367.         this.zoom = this.document.documentElement.clientWidth;
  2368.  
  2369.         // polling like this sucks, but there doesn't seem to be a better way
  2370.         setInterval(this.CheckZoom.bind(this), 500);
  2371.     });
  2372.  
  2373.     Overlay.method('MakeCanvas', function(gridX, gridY) {
  2374.         var canvas = this.document.createElement("canvas");
  2375.         canvas.width = this.canvasWidth;
  2376.         canvas.height = this.canvasHeight;
  2377.         var xPos = gridX*this.canvasWidth;
  2378.         var yPos = gridY*this.canvasHeight;
  2379.         canvas.style.cssText += ";position:absolute; left:" + xPos.toString() + "px; top:" + yPos.toString() + "px; z-index:10;" + " max-width:" + this.canvasWidth + "px;";
  2380.         canvas.prop
  2381.         return canvas;
  2382.     });
  2383.  
  2384.     Overlay.method('FillRect', function (left, top, width, height) {
  2385.  
  2386.         // NOTE: Since this object is only currently used for drawing the insertion point
  2387.         // we are not currently handling the case of a rectangle that spans multiple canvases
  2388.  
  2389.         var p1 = {x: left, y: top};
  2390.         //var p2 = {x: left + width, y: top};
  2391.         //var p3 = {x: left + width, y: top + height};
  2392.         //var p4 = {x: left, y: top + height};
  2393.  
  2394.         var p1Idx = this.DocCoordsToGridIdx(p1.x, p1.y);
  2395.         //var p2Idx = this.DocCoordsToGridIdx(p2.x, p2.y);
  2396.         //var p3Idx = this.DocCoordsToGridIdx(p3.x, p3.y);
  2397.         //var p4Idx = this.DocCoordsToGridIdx(p4.x, p4.y);
  2398.  
  2399.         var ctx = this.canvasArray[p1Idx].getContext("2d");
  2400.         var offsetX = this.canvasArray[p1Idx].offsetLeft;
  2401.         var offsetY = this.canvasArray[p1Idx].offsetTop;
  2402.         ctx.fillRect(left - offsetX, top - offsetY, width, height);
  2403.     });
  2404.  
  2405.     Overlay.method('Clear', function () {
  2406.  
  2407.         for (var i = 0; i < this.canvasArray.length; i++) {
  2408.             var canvas = this.canvasArray[i];
  2409.             canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
  2410.         }
  2411.  
  2412.         return this;
  2413.     });
  2414.  
  2415.     Overlay.method('DocCoordsToGridIdx', function (inX, inY) {
  2416.         return Math.floor(inY / this.canvasHeight) * this.gridWidth + Math.floor(inX / this.canvasWidth);
  2417.     });
  2418.  
  2419.  
  2420.  
  2421.     function DOMWalker(doc) {
  2422.         this.Initialize(doc, doc.firstChild, 0);
  2423.     }
  2424.  
  2425.     DOMWalker.method('Initialize', function (doc, node, index) {
  2426.         this.index = index;
  2427.         this.document = doc;
  2428.         this.SetNode(node);
  2429.  
  2430.         this.nodeArray = new Array();
  2431.  
  2432.         return this;
  2433.     });
  2434.  
  2435.     DOMWalker.method('FirstChild', function () {
  2436.         if (sOriginalFirstBodyNode) {
  2437.             if (this.node == document.body && this.node == sOriginalFirstBodyNode.parentNode) {
  2438.                 return sOriginalFirstBodyNode;
  2439.             }
  2440.         }
  2441.  
  2442.         var firstChild = this.node.firstChild;
  2443.         while (firstChild && NodeShouldBeSkipped(firstChild)) {
  2444.             firstChild = firstChild.nextSibling;
  2445.         }
  2446.  
  2447.         return firstChild;
  2448.     });
  2449.  
  2450.     DOMWalker.method('toString', function () {
  2451.         return "DOMWalker, node: " + this.node + " index: " + this.index + " document: " + this.document;
  2452.     });
  2453.  
  2454.     DOMWalker.method('Clone', function () {
  2455.         var clone = new DOMWalker(this.document);
  2456.         clone.SetNode(this.node);
  2457.         return clone;
  2458.     });
  2459.  
  2460.     DOMWalker.method('WalkChildren', function () {
  2461.         if (!this.FirstChild()) {
  2462.             return false;
  2463.         }
  2464.  
  2465.         this.Initialize(this.FirstChild(), 0, this.document);
  2466.         return true;
  2467.     });
  2468.  
  2469.     DOMWalker.method('CreateChildWalker', function () {
  2470.         var child = this.FirstChild();
  2471.         if (!child) {
  2472.             return null;
  2473.         }
  2474.  
  2475.         var clone = new DOMWalker(child, 0, this.document);
  2476.         return clone;
  2477.     });
  2478.  
  2479.     DOMWalker.method('WalkContentDocumentChildren', function () {
  2480.         var doc = this.node.contentDocument;
  2481.         if (!doc) {
  2482.             return false;
  2483.         }
  2484.  
  2485.         var node = FindDocumentRoot(doc);
  2486.         if (!node) {
  2487.             return false;
  2488.         }
  2489.  
  2490.         this.Initialize(node, 0, doc);
  2491.  
  2492.         return true;
  2493.     });
  2494.  
  2495.     DOMWalker.method('CreateContentDocumentChildWalker', function () {
  2496.         var clone = this.Clone();
  2497.         if (!clone.WalkContentDocumentChildren()) {
  2498.             return null;
  2499.         }
  2500.  
  2501.         return clone;
  2502.     });
  2503.  
  2504.     DOMWalker.method('PreviousNode', function () {
  2505.         this.node = this.nodeArray.pop();
  2506.  
  2507.         return this.node;
  2508.     });
  2509.  
  2510.     DOMWalker.method('NextNode', function () {
  2511.         var prevNode = this.node;
  2512.  
  2513.         if (this.node == null)
  2514.             return null;
  2515.  
  2516.         if (this.node.firstChild && !/\bscript\b/.test(this.node.nodeName)) {
  2517.             this.node = this.node.firstChild;
  2518.         }
  2519.         else if (this.node.nextSibling) {
  2520.             this.node = this.node.nextSibling;
  2521.         }
  2522.         else {
  2523.             this.node = this.node.parentNode;
  2524.  
  2525.             if (this.node == null)
  2526.                 return null;
  2527.  
  2528.             while (this.node && this.node.nextSibling == null) {
  2529.                 this.node = this.node.parentNode;
  2530.             }
  2531.  
  2532.             if (this.node == null)
  2533.                 return null;
  2534.  
  2535.             this.node = this.node.nextSibling;
  2536.         }
  2537.  
  2538.         if (this.node)
  2539.             this.nodeArray.push(prevNode);
  2540.  
  2541.         return this.node;
  2542.     });
  2543.  
  2544.     DOMWalker.method('SetNode', function (node) {
  2545.  
  2546.         this.node = this.document.firstChild;
  2547.         while (this.node && this.node != node) {
  2548.             if (this.node == null)
  2549.                 break;
  2550.             this.NextNode();
  2551.         }
  2552.  
  2553.         return (this.node == node);
  2554.     });
  2555.  
  2556.     DOMWalker.method('CurrentNodeIsElement', function () {
  2557.         if (!this.node) {
  2558.             return false;
  2559.         }
  2560.  
  2561.         return this.node.nodeType === 1;
  2562.     });
  2563.  
  2564.     DOMWalker.method('CurrentNodeIsText', function () {
  2565.         return IsTextNode(this.node);
  2566.     });
  2567.  
  2568.     DOMWalker.method('CurrentNodeIsIgnored', function () {
  2569.         if (!this.node) {
  2570.             return true;
  2571.             //return false;
  2572.         }
  2573.  
  2574.         var type = this.node.nodeType;
  2575.         return !(type === 1 || type === 3 || type === 4 || type === 5);
  2576.     });
  2577.  
  2578.     DOMWalker.method('CurrentNodeHasContentDocument', function () {
  2579.         if (!this.node) {
  2580.             return false;
  2581.         }
  2582.  
  2583.         return this.node.contentDocument != null;
  2584.     });
  2585.  
  2586.     // If the current node is text, returns the next text node.
  2587.     // Stops when it gets to an element and returns null.
  2588.     // Skips anything that's not an element or text.
  2589.     DOMWalker.method('NextTextNode', function () {
  2590.         this.NextNode();
  2591.  
  2592.         while ((this.node && !this.CurrentNodeIsText()) || (this.node && this.node.length <= 0)) {
  2593.             this.NextNode();
  2594.         }
  2595.  
  2596.         return this.node;
  2597.     });
  2598.  
  2599.     DOMWalker.method('PreviousTextNode', function () {
  2600.         this.PreviousNode();
  2601.  
  2602.         while (this.node != null && !this.CurrentNodeIsText()) {
  2603.             this.PreviousNode();
  2604.         }
  2605.  
  2606.         return this.node;
  2607.     });
  2608.  
  2609.     DOMWalker.method('FirstTextNode', function () {
  2610.         this.SetNode(this.document.body);
  2611.         this.NextTextNode();
  2612.         return this.node;
  2613.     });
  2614.  
  2615.     function ReversibleRange(doc, container, offset) {
  2616.         this.Initialize(doc, container, offset);
  2617.     }
  2618.  
  2619.     ReversibleRange.method('Initialize', function (doc, container, offset) {
  2620.  
  2621.         this.document = doc;
  2622.         this.startContainer = container;
  2623.         this.startOffset = offset;
  2624.         this.endContainer = container;
  2625.         this.endOffset = offset;
  2626.         this.reversed = false;
  2627.  
  2628.         return this;
  2629.     });
  2630.  
  2631.     ReversibleRange.method('IsCollapsed', function() {
  2632.         return (this.startContainer == this.endContainer && this.startOffset == this.endOffset);
  2633.     });
  2634.  
  2635.     ReversibleRange.method('SetStart', function (startContainer, startOffset) {
  2636.  
  2637.         this.startContainer = startContainer;
  2638.         this.startOffset = startOffset;
  2639.     });
  2640.  
  2641.     ReversibleRange.method('SetEnd', function (endContainer, endOffset) {
  2642.  
  2643.         this.endContainer = endContainer;
  2644.         this.endOffset = endOffset;
  2645.     });
  2646.  
  2647.     ReversibleRange.method('ToRange', function () {
  2648.  
  2649.         var range = this.document.createRange();
  2650.  
  2651.         if (this.reversed) {
  2652.             range.setStart(this.endContainer, this.endOffset);
  2653.             range.setEnd(this.startContainer, this.startOffset);
  2654.         } else {
  2655.             range.setStart(this.startContainer, this.startOffset);
  2656.             range.setEnd(this.endContainer, this.endOffset);
  2657.         }
  2658.         return range;
  2659.     });
  2660.  
  2661.     ReversibleRange.method('MoveEndpointLeft', function () {
  2662.  
  2663.         var tempWalker = new DOMWalker(this.document);
  2664.         tempWalker.SetNode(this.endContainer);
  2665.  
  2666.         var node = this.endContainer;
  2667.         var offset = this.endOffset;
  2668.         var startChar = node.textContent[offset];
  2669.  
  2670.         // advance the offset. If we run over the end of the text, go to the next node
  2671.         offset--;
  2672.         if (offset < 0) {
  2673.             node = tempWalker.PreviousTextNode();
  2674.             offset = node.length - 1;
  2675.         }
  2676.  
  2677.         var char = node.textContent[offset];
  2678.  
  2679.         // If we started with a whitespace and the new offset is at a whitespace, keep looking for the first non-whitespace offset
  2680.         while ((/\s/.test(startChar) && /\s/.test(char)) || /\r/.test(char) || /\n/.test(char)) {
  2681.  
  2682.             offset--;
  2683.             if (offset < 0) {
  2684.                 node = tempWalker.PreviousTextNode();
  2685.                 offset = node.length - 1;
  2686.             }
  2687.             char = node.textContent[offset];
  2688.         }
  2689.  
  2690.         if (node && offset >= 0 && offset < node.length) {
  2691.             this.endContainer = node;
  2692.             this.endOffset = offset;
  2693.         }
  2694.  
  2695.         this.CalculateReversed();
  2696.  
  2697.         return this;
  2698.     });
  2699.  
  2700.     ReversibleRange.method('MoveEndpointRight', function () {
  2701.  
  2702.         var tempWalker = new DOMWalker(this.document);
  2703.         tempWalker.SetNode(this.endContainer);
  2704.  
  2705.         var node = this.endContainer;
  2706.         var offset = this.endOffset;
  2707.         var startChar = node.textContent[offset];
  2708.  
  2709.         // advance the offset. If we run over the end of the text, go to the next node
  2710.         offset++;
  2711.         if (node.length <= offset) {
  2712.             node = tempWalker.NextTextNode();
  2713.             offset = 0;
  2714.         }
  2715.  
  2716.         var char = node.textContent[offset];
  2717.  
  2718.         // If we started with a whitespace and the new offset is at a whitespace, keep looking for the first non-whitespace offset
  2719.         // also keep going if we hit a new line
  2720.         while ((/\s/.test(startChar) && /\s/.test(char)) || /\r/.test(char) || /\n/.test(char)) {
  2721.  
  2722.             offset++;
  2723.             if (node.length <= offset) {
  2724.                 node = tempWalker.NextTextNode();
  2725.                 offset = 0;
  2726.             }
  2727.             char = node.textContent[offset];
  2728.         }
  2729.  
  2730.         if (node && offset >= 0 && offset < node.length) {
  2731.             this.endContainer = node;
  2732.             this.endOffset = offset;
  2733.         }
  2734.  
  2735.         this.CalculateReversed();
  2736.  
  2737.         return this;
  2738.     });
  2739.  
  2740.     ReversibleRange.method('MoveEndpointUp', function (desiredX) {
  2741.  
  2742.         var offset = this.endOffset;
  2743.         var node = this.endContainer;
  2744.  
  2745.         // use the coordinates at the middle of the endpoint (because the edges of rects are coincident)
  2746.         var endpointX = this.GetEndpointX();
  2747.         var endpointY = this.GetEndpointY();
  2748.  
  2749.         // Get a range that encompasses the current node
  2750.         var tempRange = this.document.createRange();
  2751.         tempRange.selectNode(node);
  2752.  
  2753.         // get all of the client rects for the current node
  2754.         var rects = tempRange.getClientRects();
  2755.         var rectIdx = rects.length - 1;
  2756.  
  2757.         // Find the rect that contains the current endpoint
  2758.         for (var i = 0; i < rects.length; i++) {
  2759.             var rect = rects[i];
  2760.             if (IsPointInRect(endpointX, endpointY, rect)) {
  2761.                 rectIdx = i;
  2762.                 break;
  2763.             }
  2764.         }
  2765.         var currentRect = rects[rectIdx];
  2766.         var rectY = currentRect.bottom;
  2767.  
  2768.         if (desiredX != null)
  2769.             endpointX = desiredX;
  2770.  
  2771.         var prevRectIdx = rectIdx;
  2772.         var prevRectY = rectY;
  2773.         var prevNode = node;
  2774.  
  2775.         var tempWalker = new DOMWalker(this.document);
  2776.         tempWalker.SetNode(node);
  2777.  
  2778.         var xDiff = null;
  2779.         var rectFound = false;
  2780.         var prevRowComplete = false;
  2781.         var testNode = node;
  2782.         var testRect = rectIdx - 1;
  2783.         tempRange.selectNode(testNode);
  2784.         rects = tempRange.getClientRects();
  2785.         while (!rectFound && !prevRowComplete && prevNode) {
  2786.  
  2787.             for (var i = testRect; i >= 0; i--) {
  2788.  
  2789.                 // still looking for the Y-coordinate of the prev row
  2790.                 if (rectY == prevRectY && rects[i].bottom < rectY) {
  2791.  
  2792.                     prevRectY = rects[i].bottom;
  2793.  
  2794.                     // we found the next row; ignore any offsets examined in the same row as the original point
  2795.                     xDiff = null;
  2796.                 }
  2797.  
  2798.                 // we've gone beyond the prev row; stop looking
  2799.                 if (prevRectY < rectY && rects[i].bottom < prevRectY) {
  2800.                     prevRowComplete = true;
  2801.                     break;
  2802.                 }
  2803.  
  2804.                 if (rects[i].bottom == prevRectY) {
  2805.  
  2806.                     var diffLeft = Math.abs(endpointX - rects[i].left);
  2807.                     var diffRight = Math.abs(endpointX - rects[i].right);
  2808.                     var diff = Math.min(diffLeft, diffRight);
  2809.  
  2810.                     if (IsPointInRect(endpointX, prevRectY, rects[i])) {
  2811.  
  2812.                         prevNode = testNode;
  2813.                         prevRectIdx = i;
  2814.                         rectFound = true;
  2815.                         break;
  2816.                     }
  2817.                     else if (xDiff == null || diff < xDiff) {
  2818.  
  2819.                         prevNode = testNode;
  2820.                         prevRectIdx = i;
  2821.                         xDiff = diff;
  2822.                     }
  2823.                 }
  2824.             }
  2825.  
  2826.             // we ran out of rects and are still in the same row; check to see if the row continues in the prev text node
  2827.             if (!prevRowComplete) {
  2828.  
  2829.                 testNode = tempWalker.PreviousTextNode();
  2830.  
  2831.                 if (!testNode) break;
  2832.  
  2833.                 tempRange.selectNode(testNode);
  2834.                 rects = tempRange.getClientRects();
  2835.                 testRect = rects.length - 1;
  2836.             }
  2837.  
  2838.         }
  2839.  
  2840.         tempRange.selectNode(prevNode);
  2841.         rects = tempRange.getClientRects();
  2842.         offset = NodeOffsetFromPoint(this.document, prevNode, endpointX, rects[prevRectIdx].bottom);
  2843.  
  2844.         this.endContainer = prevNode;
  2845.         this.endOffset = offset;
  2846.  
  2847.         this.CalculateReversed();
  2848.  
  2849.         tempRange.detach();
  2850.         return this;
  2851.     });
  2852.  
  2853.     ReversibleRange.method('MoveEndpointDown', function (desiredX) {
  2854.         var offset = this.endOffset;
  2855.         var node = this.endContainer;
  2856.  
  2857.         // use the coordinates at the middle of the endpoint (because the edges of rects are coincident)
  2858.         var endpointX = this.GetEndpointX();
  2859.         var endpointY = this.GetEndpointY();
  2860.  
  2861.         // Get a range that encompasses the current node
  2862.         var tempRange = this.document.createRange();
  2863.         tempRange.selectNode(node);
  2864.  
  2865.         // get all of the client rects for the current node
  2866.         var rects = tempRange.getClientRects();
  2867.         var rectIdx = rects.length - 1;
  2868.  
  2869.         // Find the rect that contains the current endpoint
  2870.         for (var i = 0; i < rects.length; i++) {
  2871.             var rect = rects[i];
  2872.             if (IsPointInRect(endpointX, endpointY, rect)) {
  2873.                 rectIdx = i;
  2874.                 break;
  2875.             }
  2876.         }
  2877.         var currentRect = rects[rectIdx];
  2878.         var rectY = currentRect.bottom;
  2879.  
  2880.         if (desiredX != null)
  2881.             endpointX = desiredX;
  2882.  
  2883.         var nextRectIdx = rectIdx;
  2884.         var nextRectY = rectY;
  2885.         var nextNode = node;
  2886.  
  2887.         var tempWalker = new DOMWalker(this.document);
  2888.         tempWalker.SetNode(node);
  2889.  
  2890.         var xDiff = null;
  2891.         var rectFound = false;
  2892.         var nextRowComplete = false;
  2893.         var testNode = node;
  2894.         var testRect = rectIdx + 1;
  2895.         while (!rectFound && !nextRowComplete && nextNode) {
  2896.  
  2897.             if (testNode) {
  2898.  
  2899.                 tempRange.selectNode(testNode);
  2900.                 rects = tempRange.getClientRects();
  2901.  
  2902.                 for (var i = testRect; i < rects.length; i++) {
  2903.  
  2904.                     // still looking for the Y-coordinate of the next row
  2905.                     if (rectY == nextRectY && rects[i].bottom > rectY) {
  2906.  
  2907.                         nextRectY = rects[i].bottom;
  2908.  
  2909.                         // we found the next row; ignore any offsets examined in the same row as the original point
  2910.                         xDiff = null;
  2911.                     }
  2912.  
  2913.                     // we've gone beyond the next row; stop looking
  2914.                     if (nextRectY > rectY && rects[i].bottom > nextRectY) {
  2915.                         nextRowComplete = true;
  2916.                         break;
  2917.                     }
  2918.  
  2919.                     if (rects[i].bottom == nextRectY) {
  2920.  
  2921.                         if (IsPointInRect(endpointX, nextRectY, rects[i])) {
  2922.  
  2923.                             nextNode = testNode;
  2924.                             nextRectIdx = i;
  2925.                             xDiff = diff;
  2926.                             rectFound = true;
  2927.                             break;
  2928.                         }
  2929.                         else if (xDiff == null || diff < xDiff) {
  2930.  
  2931.                             var diffLeft = Math.abs(endpointX - rects[i].left);
  2932.                             var diffRight = Math.abs(endpointX - rects[i].right);
  2933.                             var diff = Math.min(diffLeft, diffRight);
  2934.  
  2935.                             nextNode = testNode;
  2936.                             nextRectIdx = i;
  2937.                             xDiff = diff;
  2938.                         }
  2939.                     }
  2940.                 }
  2941.             }
  2942.  
  2943.  
  2944.             // we ran out of rects and are still in the same row; check to see if the row continues in the next text node
  2945.             if (!rectFound && !nextRowComplete) {
  2946.  
  2947.                 testNode = tempWalker.NextTextNode();
  2948.                 testRect = 0;
  2949.             }
  2950.  
  2951.         }
  2952.  
  2953.         tempRange.selectNode(nextNode);
  2954.         rects = tempRange.getClientRects();
  2955.         offset = NodeOffsetFromPoint(this.document, nextNode, endpointX, rects[nextRectIdx].bottom);
  2956.  
  2957.         if (nextNode && offset >= 0 && offset <= nextNode.length) {
  2958.             this.endContainer = nextNode;
  2959.             this.endOffset = offset;
  2960.         }
  2961.  
  2962.         this.CalculateReversed();
  2963.  
  2964.         tempRange.detach();
  2965.         return this;
  2966.     });
  2967.  
  2968.     ReversibleRange.method('GetEndpointX', function () {
  2969.         // Get a range that represents the endpoint
  2970.         var endpointRange = this.document.createRange();
  2971.         endpointRange.setEnd(this.endContainer, this.endOffset);
  2972.         endpointRange.collapse(false);
  2973.         var endpointRect = endpointRange.getClientRects()[0];
  2974.  
  2975.         if (!endpointRect) {
  2976.  
  2977.             var start = this.startContainer;
  2978.             var startOffset = this.startOffset;
  2979.             var end = this.endContainer;
  2980.             var endOffset = this.endOffset;
  2981.  
  2982.             var nodeAfter = this.endContainer.nextSibling;
  2983.  
  2984.             var textNode = end;
  2985.             var parentNode = textNode.parentNode;
  2986.             var tempSpan = document.createElement("span");
  2987.  
  2988.             if (textNode.splitText) {
  2989.                 var copyNode = textNode.cloneNode(true);
  2990.                 var secondHalf = copyNode.splitText(endOffset);
  2991.  
  2992.                 //remove the original node and insert the split copy with the caret span in between
  2993.                 if (parentNode)
  2994.                     parentNode.removeChild(textNode);
  2995.  
  2996.                 if (nodeAfter) {
  2997.                     var rangeAfter = document.createRange();
  2998.                     rangeAfter.selectNode(nodeAfter);
  2999.                     rangeAfter.insertNode(secondHalf);
  3000.                     rangeAfter.insertNode(tempSpan);
  3001.                     rangeAfter.insertNode(copyNode);
  3002.                     rangeAfter.detach();
  3003.                 }
  3004.                 else if (parentNode) {
  3005.                     parentNode.appendChild(copyNode);
  3006.                     parentNode.appendChild(tempSpan);
  3007.                     parentNode.appendChild(secondHalf);
  3008.                 }
  3009.             }
  3010.             else {
  3011.                 if (nodeAfter) {
  3012.                     var rangeAfter = this.document.createRange();
  3013.                     rangeAfter.selectNode(nodeAfter);
  3014.                     rangeAfter.insertNode(tempSpan);
  3015.                     rangeAfter.detach();
  3016.                 }
  3017.                 else if (parentNode) {
  3018.                     parentNode.appendChild(tempSpan);
  3019.                 }
  3020.             }
  3021.  
  3022.             endpointRect = GetClientRects(tempSpan)[0];
  3023.  
  3024.             //remove the caret span and split text nodes and re-insert the original node so that we don't mess up any positioning
  3025.             if (tempSpan.parentNode) {
  3026.  
  3027.                 if (copyNode && secondHalf) {
  3028.  
  3029.                     if (copyNode.parentNode) {
  3030.                         copyNode.parentNode.insertBefore(textNode, copyNode);
  3031.                         copyNode.parentNode.removeChild(copyNode);
  3032.                     }
  3033.  
  3034.                     tempSpan.parentNode.removeChild(tempSpan);
  3035.  
  3036.                     if (secondHalf.parentNode)
  3037.                         secondHalf.parentNode.removeChild(secondHalf);
  3038.                 }
  3039.                 else {
  3040.                     tempSpan.parentNode.removeChild(tempSpan);
  3041.                 }
  3042.             }
  3043.  
  3044.         }
  3045.  
  3046.         // use the coordinates at the middle of the endpoint (because the edges of rects are coincident)
  3047.         var endpointX = (endpointRect.left + endpointRect.right) / 2;
  3048.  
  3049.         endpointRange.detach();
  3050.         return endpointX;
  3051.     });
  3052.  
  3053.     ReversibleRange.method('GetEndpointY', function () {
  3054.         // Get a range that represents the endpoint
  3055.         var endpointRange = this.document.createRange();
  3056.         endpointRange.setEnd(this.endContainer, this.endOffset);
  3057.         endpointRange.collapse(false);
  3058.         var endpointRect = endpointRange.getClientRects()[0];
  3059.  
  3060.         if (!endpointRect) {
  3061.  
  3062.             var start = this.startContainer;
  3063.             var startOffset = this.startOffset;
  3064.             var end = this.endContainer;
  3065.             var endOffset = this.endOffset;
  3066.  
  3067.             var nodeAfter = this.endContainer.nextSibling;
  3068.  
  3069.             var textNode = end;
  3070.             var parentNode = textNode.parentNode;
  3071.             var tempSpan = document.createElement("span");
  3072.  
  3073.             if (textNode.splitText) {
  3074.                 var copyNode = textNode.cloneNode(true);
  3075.                 var secondHalf = copyNode.splitText(endOffset);
  3076.  
  3077.                 //remove the original node and insert the split copy with the caret span in between
  3078.                 if (parentNode)
  3079.                     parentNode.removeChild(textNode);
  3080.  
  3081.                 if (nodeAfter) {
  3082.                     var rangeAfter = document.createRange();
  3083.                     rangeAfter.selectNode(nodeAfter);
  3084.                     rangeAfter.insertNode(secondHalf);
  3085.                     rangeAfter.insertNode(tempSpan);
  3086.                     rangeAfter.insertNode(copyNode);
  3087.                     rangeAfter.detach();
  3088.                 }
  3089.                 else if (parentNode) {
  3090.                     parentNode.appendChild(copyNode);
  3091.                     parentNode.appendChild(tempSpan);
  3092.                     parentNode.appendChild(secondHalf);
  3093.                 }
  3094.             }
  3095.             else {
  3096.                 if (nodeAfter) {
  3097.                     var rangeAfter = this.document.createRange();
  3098.                     rangeAfter.selectNode(nodeAfter);
  3099.                     rangeAfter.insertNode(tempSpan);
  3100.                     rangeAfter.detach();
  3101.                 }
  3102.                 else if (parentNode) {
  3103.                     parentNode.appendChild(tempSpan);
  3104.                 }
  3105.             }
  3106.  
  3107.             endpointRect = GetClientRects(tempSpan)[0];
  3108.  
  3109.             //remove the caret span and split text nodes and re-insert the original node so that we don't mess up any positioning
  3110.             if (tempSpan.parentNode) {
  3111.  
  3112.                 if (copyNode && secondHalf) {
  3113.  
  3114.                     if (copyNode.parentNode) {
  3115.                         copyNode.parentNode.insertBefore(textNode, copyNode);
  3116.                         copyNode.parentNode.removeChild(copyNode);
  3117.                     }
  3118.  
  3119.                     tempSpan.parentNode.removeChild(tempSpan);
  3120.  
  3121.                     if (secondHalf.parentNode)
  3122.                         secondHalf.parentNode.removeChild(secondHalf);
  3123.                 }
  3124.                 else {
  3125.                     tempSpan.parentNode.removeChild(tempSpan);
  3126.                 }
  3127.             }
  3128.  
  3129.         }
  3130.  
  3131.         // use the coordinates at the middle of the endpoint (because the edges of rects are coincident)
  3132.         var endpointY = (endpointRect.top + endpointRect.bottom) / 2;
  3133.  
  3134.         endpointRange.detach();
  3135.         return endpointY;
  3136.     });
  3137.  
  3138.     function GetClientRects(node) {
  3139.         var rects = null;
  3140.         var tempRange = document.createRange();
  3141.  
  3142.         if (node)
  3143.             tempRange.selectNode(node);
  3144.  
  3145.         if (tempRange.getClientRects) {
  3146.             rects = tempRange.getClientRects();
  3147.         }
  3148.  
  3149.         tempRange.detach();
  3150.  
  3151.         if (!rects || rects.length <= 0) {
  3152.  
  3153.             if (node.getClientRects) {
  3154.                 rects = node.getClientRects();
  3155.             }
  3156.             else if (node.parentNode && node.parentNode.getClientRects) {
  3157.                 rects = node.parentNode.getClientRects();
  3158.             }
  3159.         }
  3160.         return rects;
  3161.     }
  3162.  
  3163.     ReversibleRange.method('CalculateReversed', function () {
  3164.  
  3165.         var startRange = this.document.createRange();
  3166.         var endRange = this.document.createRange();
  3167.  
  3168.         startRange.setStart(this.startContainer, this.startOffset);
  3169.         startRange.setEnd(this.startContainer, this.startOffset);
  3170.         endRange.setStart(this.endContainer, this.endOffset);
  3171.         endRange.setEnd(this.endContainer, this.endOffset);
  3172.         var compare = endRange.compareBoundaryPoints(Range.START_TO_START, startRange);
  3173.  
  3174.         this.reversed = (compare < 0);
  3175.  
  3176.         startRange.detach();
  3177.         endRange.detach();
  3178.     });
  3179.  
  3180.     ReversibleRange.method('Collapse', function (collapseToStart) {
  3181.  
  3182.         if (collapseToStart) {
  3183.             this.endContainer = this.startContainer;
  3184.             this.endOffset = this.startOffset;
  3185.         } else {
  3186.             this.startContainer = this.endContainer;
  3187.             this.startOffset = this.endOffset;
  3188.         }
  3189.         this.reversed = false;
  3190.  
  3191.         return this;
  3192.     });
  3193.  
  3194.     VST.Models.InsertionPoint.method('Initialize', function (doc) {
  3195.         this.doc = doc;
  3196.         this.enabled = false;
  3197.  
  3198.         this.caret = doc.createElement("span");
  3199.         this.caret.id = "caret";
  3200.  
  3201.         this.caretDiv = doc.createElement("div");
  3202.         this.caretDiv.id = "caretDiv";
  3203.         this.caretDiv.style.cssText += "; position:absolute; overflow-x:visible; overflow-y:hidden; font-weight:bold; z-index:10; left:-10px; top:-10px;";
  3204.         this.caretDiv.appendChild(doc.createTextNode("|"));
  3205.         this.doc.body.appendChild(this.caretDiv);
  3206.  
  3207.         this.walker = new DOMWalker(doc);
  3208.         this.walker.FirstTextNode();
  3209.  
  3210.         this.range = new ReversibleRange(doc, this.walker.node, 0);
  3211.         this.Update();
  3212.     });
  3213.  
  3214.     VST.Models.InsertionPoint.method('SetEnabled', function (isEnabled) {
  3215.         this.enabled = isEnabled;
  3216.  
  3217.         if (!isEnabled)
  3218.             $("#caretDiv").hide();
  3219.         else
  3220.             $("#caretDiv").show();
  3221.     });
  3222.  
  3223.     VST.Models.InsertionPoint.method('UpdateCaret', function () {
  3224.  
  3225.         if (!this.enabled)
  3226.             return;
  3227.  
  3228.         var start = this.range.startContainer;
  3229.         var startOffset = this.range.startOffset;
  3230.         var end = this.range.endContainer;
  3231.         var endOffset = this.range.endOffset;
  3232.  
  3233.         var selectionRange = VST.Utils.getRangeObject();
  3234.         if (selectionRange) {
  3235.             var selectionStartNode = selectionRange.startContainer;
  3236.             var selectionStartOffset = selectionRange.startOffset;
  3237.         }
  3238.  
  3239.         var nodeAfter = this.range.endContainer.nextSibling;
  3240.  
  3241.         var textNode = end;
  3242.         var parentNode = textNode.parentNode;
  3243.         var caret = this.caret;
  3244.  
  3245.         if (textNode.splitText) {
  3246.             var copyNode = textNode.cloneNode(true);
  3247.             var secondHalf = copyNode.splitText(endOffset);
  3248.  
  3249.             //remove the original node and insert the split copy with the caret span in between
  3250.             parentNode.removeChild(textNode);
  3251.             if (nodeAfter) {
  3252.                 var rangeAfter = this.doc.createRange();
  3253.                 rangeAfter.selectNode(nodeAfter);
  3254.                 rangeAfter.insertNode(secondHalf);
  3255.  
  3256.                 if (caret)
  3257.                     rangeAfter.insertNode(caret);
  3258.  
  3259.                 rangeAfter.insertNode(copyNode);
  3260.                 rangeAfter.detach();
  3261.             }
  3262.             else {
  3263.                 parentNode.appendChild(copyNode);
  3264.  
  3265.                 if (caret)
  3266.                     parentNode.appendChild(caret);
  3267.  
  3268.                 parentNode.appendChild(secondHalf);
  3269.             }
  3270.         }
  3271.         else {
  3272.             if (nodeAfter) {
  3273.                 var rangeAfter = this.doc.createRange();
  3274.                 rangeAfter.selectNode(nodeAfter);
  3275.  
  3276.                 if (caret)
  3277.                     rangeAfter.insertNode(caret);
  3278.  
  3279.                 rangeAfter.detach();
  3280.             }
  3281.             else {
  3282.                
  3283.                 if (caret)
  3284.                     parentNode.appendChild(caret);
  3285.             }
  3286.         }
  3287.  
  3288.         this.DrawCaret();
  3289.  
  3290.         //if (!IsElementInViewport(this.caret)) {
  3291.         //    ScrollIntoView(this.caret);
  3292.         //}
  3293.  
  3294.         //remove the caret span and split text nodes and re-insert the original node so that we don't mess up any positioning
  3295.         if (caret && caret.parentNode) {
  3296.  
  3297.             if (copyNode && secondHalf) {
  3298.  
  3299.                 if (copyNode.parentNode) {
  3300.                     copyNode.parentNode.insertBefore(textNode, copyNode);
  3301.                     copyNode.parentNode.removeChild(copyNode);
  3302.                 }
  3303.  
  3304.                 caret.parentNode.removeChild(caret);
  3305.  
  3306.                 if (secondHalf.parentNode)
  3307.                     secondHalf.parentNode.removeChild(secondHalf);
  3308.             }
  3309.             else {
  3310.  
  3311.                 caret.parentNode.removeChild(caret);
  3312.             }
  3313.         }
  3314.  
  3315.         this.range.startContainer = start;
  3316.         this.range.startOffset = startOffset;
  3317.         this.range.endContainer = end;
  3318.         this.range.endOffset = endOffset;
  3319.  
  3320.         var range = this.range.ToRange();
  3321.  
  3322.         var selectionObj = VST.Utils.getSelectionObject();
  3323.         if (selectionObj.rangeCount > 0) {
  3324.             if (selectionObj.getRangeAt(0).getClientRects().length > 0)
  3325.                 selectionObj.removeAllRanges();
  3326.             else
  3327.                 selectionObj.removeRange(selectionObj.getRangeAt(0));
  3328.         }
  3329.         selectionObj.addRange(range);
  3330.     });
  3331.  
  3332.     VST.Models.InsertionPoint.method('Update', function () {
  3333.  
  3334.         if (!this.enabled)
  3335.             return;
  3336.  
  3337.         if (this.range.endContainer != this.walker.node)
  3338.             this.walker.SetNode(this.range.endContainer);
  3339.         this.UpdateCaret();
  3340.     });
  3341.  
  3342.     VST.Models.InsertionPoint.method('UpdateSelection', function () {
  3343.  
  3344.         if (!this.enabled)
  3345.             return;
  3346.  
  3347.         var selectionObj = VST.Utils.getSelectionObject();
  3348.         if (selectionObj.rangeCount > 0) {
  3349.             if (selectionObj.getRangeAt(0).getClientRects().length > 0)
  3350.                 selectionObj.removeAllRanges();
  3351.             else
  3352.                 selectionObj.removeRange(selectionObj.getRangeAt(0));
  3353.         }
  3354.         selectionObj.addRange(this.range.ToRange());
  3355.     });
  3356.  
  3357.     VST.Models.InsertionPoint.method('MoveLeft', function (modifySelection) {
  3358.  
  3359.         if (!this.enabled)
  3360.             return;
  3361.  
  3362.         this.range.MoveEndpointLeft();
  3363.  
  3364.         // if we are not modifying the selection, collapse the range
  3365.         if (!modifySelection) {
  3366.             this.range.Collapse(false);
  3367.             this.UpdateSelection();
  3368.         }
  3369.         else if (this.range.reversed) {
  3370.             this.UpdateSelection();
  3371.         }
  3372.         this.Update();
  3373.         this.desiredX = this.range.GetEndpointX();
  3374.     });
  3375.  
  3376.     VST.Models.InsertionPoint.method('MoveRight', function (modifySelection) {
  3377.  
  3378.         if (!this.enabled)
  3379.             return;
  3380.  
  3381.         this.range.MoveEndpointRight();
  3382.  
  3383.         // if we are not modifying the selection collapse the range (start-to-end)
  3384.         if (!modifySelection) {
  3385.             this.range.Collapse(false);
  3386.             this.UpdateSelection();
  3387.         }
  3388.         else if (this.range.reversed) {
  3389.             this.UpdateSelection();
  3390.         }
  3391.         this.Update();
  3392.         this.desiredX = this.range.GetEndpointX();
  3393.     });
  3394.  
  3395.     VST.Models.InsertionPoint.method('MoveDown', function (modifySelection) {
  3396.  
  3397.         if (!this.enabled)
  3398.             return;
  3399.  
  3400.         this.range.MoveEndpointDown(this.desiredX);
  3401.  
  3402.         // if we are not modifying the selection collapse the range (start-to-end)
  3403.         if (!modifySelection) {
  3404.             this.range.Collapse(false);
  3405.         }
  3406.  
  3407.         this.Update();
  3408.     });
  3409.  
  3410.     VST.Models.InsertionPoint.method('MoveUp', function (modifySelection) {
  3411.  
  3412.         if (!this.enabled)
  3413.             return;
  3414.  
  3415.         this.range.MoveEndpointUp(this.desiredX);
  3416.  
  3417.         // if we are not modifying the selection collapse the range (start-to-end)
  3418.         if (!modifySelection) {
  3419.             this.range.Collapse(false);
  3420.         }
  3421.  
  3422.         this.Update();
  3423.     });
  3424.  
  3425.     VST.Models.InsertionPoint.method('SetClick', function (x, y) {
  3426.  
  3427.         if (!this.enabled)
  3428.             return;
  3429.  
  3430.         this.clickX = x;
  3431.         this.clickY = y;
  3432.     });
  3433.  
  3434.     VST.Models.InsertionPoint.method('ReleaseClick', function (x, y) {
  3435.  
  3436.         if (!this.enabled)
  3437.             return;
  3438.  
  3439.         var selection = VST.Utils.getRangeObject(VST.Utils.getSelectionObject());
  3440.         var releaseX = x;
  3441.         var releaseY = y;
  3442.  
  3443.         var clickNode = this.doc.elementFromPoint(this.clickX, this.clickY);
  3444.         var releaseNode = this.doc.elementFromPoint(releaseX, releaseY);
  3445.  
  3446.         if (clickNode == null || releaseNode == null) return;
  3447.  
  3448.         var tempRange = this.doc.createRange();
  3449.         tempRange.selectNode(clickNode);
  3450.         var rects = tempRange.getClientRects();
  3451.  
  3452.         var clickRect = this.clickY;
  3453.         var releaseRect = releaseY;
  3454.  
  3455.         for (var i = 0; i < rects.length; i++) {
  3456.             if (IsPointInRect(this.clickX, this.clickY, rects[i]))
  3457.                 clickRect = rects[i].bottom;
  3458.         }
  3459.  
  3460.         if (clickNode != releaseNode) {
  3461.             tempRange.selectNode(releaseNode);
  3462.             rects = tempRange.getClientRects();
  3463.         }
  3464.  
  3465.         for (var i = 0; i < rects.length; i++) {
  3466.             if (IsPointInRect(releaseX, releaseY, rects[i]))
  3467.                 releaseRect = rects[i].bottom;
  3468.         }
  3469.  
  3470.         if (clickRect < releaseRect) {
  3471.             this.range.SetEnd(selection.endContainer, selection.endOffset);
  3472.             this.range.SetStart(selection.startContainer, selection.startOffset);
  3473.             this.range.reversed = false;
  3474.         }
  3475.         else if (clickRect == releaseRect) {
  3476.  
  3477.             if (this.clickX <= releaseX) {
  3478.                 this.range.SetEnd(selection.endContainer, selection.endOffset);
  3479.                 this.range.SetStart(selection.startContainer, selection.startOffset);
  3480.                 this.range.reversed = false;
  3481.             } else {
  3482.                 this.range.SetStart(selection.endContainer, selection.endOffset);
  3483.                 this.range.SetEnd(selection.startContainer, selection.startOffset);
  3484.                 this.range.reversed = true;
  3485.             }
  3486.         } else {
  3487.             this.range.SetStart(selection.endContainer, selection.endOffset);
  3488.             this.range.SetEnd(selection.startContainer, selection.startOffset);
  3489.             this.range.reversed = true;
  3490.         }
  3491.  
  3492.         this.UpdateSelection();
  3493.         this.Update();
  3494.         tempRange.detach();
  3495.  
  3496.         this.desiredX = this.range.GetEndpointX();
  3497.     });
  3498.  
  3499.     VST.Models.InsertionPoint.method('SetToPoint', function (x, y) {
  3500.  
  3501.         if (!this.enabled)
  3502.             return;
  3503.  
  3504.         var clientX = x - window.pageXOffset;
  3505.         var clientY = y - window.pageYOffset;
  3506.         var startNode = this.doc.elementFromPoint(clientX, clientY);
  3507.         var text = startNode;
  3508.  
  3509.         //find the appropriate child text node
  3510.         for (var i = 0; i < startNode.childNodes.length; i++) {
  3511.             var node = startNode.childNodes[i];
  3512.             var range = this.doc.createRange();
  3513.             range.selectNode(node);
  3514.             var rects = range.getClientRects();
  3515.  
  3516.             //check whether the coordinates are in one of the client rects of the node
  3517.             for (var j = 0; j < rects.length; j++) {
  3518.                 var rect = rects[j];
  3519.                 //we found the text node that the coordinates are in
  3520.                 if (IsPointInRect(clientX, clientY, rect) && IsTextNode(node)) {
  3521.                     text = node;
  3522.                     break;
  3523.                 }
  3524.             }
  3525.             range.detach();
  3526.         }
  3527.  
  3528.         var offset = NodeOffsetFromPoint(this.doc, text, clientX, clientY);
  3529.         //this.range.setStart(text, offset);
  3530.         //this.range.setEnd(text, offset);
  3531.         this.range.startContainer = text;
  3532.         this.range.startOffset = offset;
  3533.         this.range.endContainer = text;
  3534.         this.range.endOffset = offset;
  3535.  
  3536.         this.Update();
  3537.     });
  3538.  
  3539.     VST.Models.InsertionPoint.method('GetText', function () {
  3540.  
  3541.         if (!this.enabled)
  3542.             return '';
  3543.  
  3544.         var text = '';
  3545.  
  3546.         var selection = VST.Utils.getSelectionObject();
  3547.  
  3548.         if (selection.isCollapsed) {
  3549.  
  3550.             var range = document.createRange();
  3551.             range.setStart(this.range.startContainer, this.range.startOffset);
  3552.             range.setEndAfter(document.body);
  3553.             text = range.toString();
  3554.         }
  3555.         else {
  3556.             text += selection.toString();
  3557.         }
  3558.  
  3559.         return text;
  3560.     });
  3561.  
  3562.     VST.Models.InsertionPoint.method('SetCaret', function (node, offset) {
  3563.  
  3564.         if (!this.enabled)
  3565.             return;
  3566.  
  3567.         if (node) {
  3568.             var tempNode = node;
  3569.             var tempOffset = offset;
  3570.             this.walker.SetNode(tempNode);
  3571.  
  3572.             if (!IsTextNode(tempNode)) {
  3573.                 tempNode = this.walker.NextTextNode();
  3574.                 tempOffset = 0;
  3575.             }
  3576.  
  3577.             this.range.SetStart(tempNode, tempOffset);
  3578.             this.range.SetEnd(tempNode, tempOffset);
  3579.             this.range.reversed = false;
  3580.             this.Update();
  3581.         }
  3582.     });
  3583.  
  3584.     VST.Models.InsertionPoint.method('DrawCaret', function () {
  3585.  
  3586.         if (!this.enabled)
  3587.             return;
  3588.  
  3589.         var caret = this.doc.getElementById("caret");
  3590.         if (caret) {
  3591.             var rect = caret.getClientRects()[0];
  3592.             if (rect) {
  3593.                 //VST.Logger.debug('cursor rect: ' + rect.top + ', ' + rect.left + ', ' + rect.bottom + ', ' + rect.right);
  3594.                 var offsetX = parent.pageXOffset;
  3595.                 var offsetY = parent.pageYOffset;
  3596.                 this.caretDiv.style.cssText += "; left:" + (rect.left + offsetX - 2).toString() + "px; top:" + (rect.top + offsetY - 2).toString() + "px; font-size:" + rect.height.toString() + "px;";
  3597.             }
  3598.         }
  3599.     });
  3600.  
  3601.     VST.Models.InsertionPoint.method('GetNextPosition', function () {
  3602.  
  3603.         if (!this.enabled)
  3604.             return null;
  3605.  
  3606.         var nextPos = this.range.cloneRange();
  3607.  
  3608.         nextPos.collapse(false);
  3609.  
  3610.         return nextPos;
  3611.     });
  3612.  
  3613.     function IsElementInViewport(el) {
  3614.  
  3615.         if (typeof jQuery === "function" && el instanceof jQuery) {
  3616.             el = el[0];
  3617.         }
  3618.  
  3619.         var rect = el.getBoundingClientRect();
  3620.  
  3621.         return (
  3622.             rect.top >= 0 &&
  3623.             rect.left >= 0 &&
  3624.             rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
  3625.             rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
  3626.         );
  3627.     }
  3628.  
  3629.     function ScrollIntoView(el) {
  3630.  
  3631.         if (typeof jQuery === "function" && el instanceof jQuery) {
  3632.             el = el[0];
  3633.         }
  3634.  
  3635.         var rect = el.getBoundingClientRect();
  3636.  
  3637.         while (rect.top < 0) {
  3638.  
  3639.             window.scrollTo(window.pageXOffset, window.pageYOffset - 16);
  3640.             rect = el.getBoundingClientRect();
  3641.         }
  3642.  
  3643.         while (rect.bottom > (window.innerHeight || document.documentElement.clientHeight)) {
  3644.  
  3645.             window.scrollTo(window.pageXOffset, window.pageYOffset + 16);
  3646.             rect = el.getBoundingClientRect();
  3647.         }
  3648.  
  3649.         while (rect.left < 0) {
  3650.  
  3651.             window.scrollTo(window.pageXOffset - 16, window.pageYOffset);
  3652.             rect = el.getBoundingClientRect();
  3653.         }
  3654.  
  3655.         while (rect.right > (window.innerWidth || document.documentElement.clientWidth)) {
  3656.  
  3657.             window.scrollTo(window.pageXOffset + 16, window.pageYOffset);
  3658.             rect = el.getBoundingClientRect();
  3659.         }
  3660.  
  3661.     }
  3662.  
  3663.     function NodeOffsetFromPoint(document, node, x, y) {
  3664.  
  3665.         var offset = 0;
  3666.         var best = null;
  3667.         var tempRange = document.createRange();
  3668.         tempRange.setStart(node, offset);
  3669.         tempRange.setEnd(node, offset);
  3670.         var rangeBox = GetRectForOffset(node, offset);
  3671.  
  3672.         if (!rangeBox) return offset;
  3673.  
  3674.         var inRow = y > rangeBox.top && y <= rangeBox.bottom;
  3675.         var wasInRow = false;
  3676.         var diff;
  3677.         while (offset != node.length) {
  3678.  
  3679.             if (inRow) {
  3680.  
  3681.                 best = offset;
  3682.                 var xDiff = rangeBox.left - x;
  3683.                 // we passed the coordinates of the mouse click; choose the closer of two neighboring offsets and break out
  3684.                 if (xDiff >= 0) {
  3685.                     //if the last offset was closer, go back to it
  3686.                     if (Math.abs(xDiff) > Math.abs(diff))
  3687.                         offset--;
  3688.                     best = offset;
  3689.                     break;
  3690.                 }
  3691.                 diff = xDiff;
  3692.             }
  3693.             else if (wasInRow) {
  3694.                 break;
  3695.             }
  3696.  
  3697.             offset++;
  3698.             tempRange.setStart(node, offset);
  3699.             tempRange.setEnd(node, offset);
  3700.             var prevRangeBox = rangeBox;
  3701.             rangeBox = GetRectForOffset(node, offset);
  3702.             inRow = rangeBox && y > rangeBox.top && y <= rangeBox.bottom;
  3703.         }
  3704.  
  3705.         if (best != null) {
  3706.             offset = best;
  3707.         }
  3708.  
  3709.         return offset;
  3710.     }
  3711.  
  3712.     function GetRectForOffset(node, nodeOffset) {
  3713.        
  3714.         var tempRange = document.createRange();
  3715.         tempRange.setStart(node, nodeOffset);
  3716.         tempRange.setEnd(node, nodeOffset);
  3717.         var endpointRect = tempRange.getClientRects()[0];
  3718.  
  3719.         if (!endpointRect) {
  3720.  
  3721.             var nodeAfter = node.nextSibling;
  3722.  
  3723.             var textNode = node;
  3724.             var copyNode = textNode.cloneNode(true);
  3725.             var secondHalf = copyNode.splitText(nodeOffset);
  3726.  
  3727.             //remove the original node and insert the split copy with the caret span in between
  3728.             var parentNode = textNode.parentNode;
  3729.             parentNode.removeChild(textNode);
  3730.             var tempSpan = document.createElement("span");
  3731.             if (nodeAfter) {
  3732.                 var rangeAfter = document.createRange();
  3733.                 rangeAfter.selectNode(nodeAfter);
  3734.                 rangeAfter.insertNode(secondHalf);
  3735.                 rangeAfter.insertNode(tempSpan);
  3736.                 rangeAfter.insertNode(copyNode);
  3737.                 rangeAfter.detach();
  3738.             }
  3739.             else {
  3740.                 parentNode.appendChild(copyNode);
  3741.                 parentNode.appendChild(tempSpan);
  3742.                 parentNode.appendChild(secondHalf);
  3743.             }
  3744.  
  3745.             endpointRect = GetClientRects(tempSpan)[0];
  3746.  
  3747.             //remove the caret span and split text nodes and re-insert the original node so that we don't mess up any positioning
  3748.             if (tempSpan.parentNode) {
  3749.                 copyNode.parentNode.insertBefore(textNode, copyNode);
  3750.  
  3751.                 copyNode.parentNode.removeChild(copyNode);
  3752.                 tempSpan.parentNode.removeChild(tempSpan);
  3753.                 secondHalf.parentNode.removeChild(secondHalf);
  3754.             }
  3755.         }
  3756.         return endpointRect;
  3757.     }
  3758.  
  3759.     function IsPointInRect(x, y, rect) {
  3760.         return (rect.left <= x && rect.right >= x && rect.top <= y && rect.bottom >= y);
  3761.     }
  3762. }).call(window, jQuery);
  3763. (function($){
  3764.   VST.Models.Page = function(settings){
  3765.     settings  = settings || {};
  3766.  
  3767.     var title     = settings.title
  3768.       , fullPath  = settings.path
  3769.       , linear    = settings.linear;
  3770.  
  3771.       var u       = $.url.setUrl(fullPath)
  3772.         , path    = u.attr('path');
  3773.  
  3774.     this.getPath  = function(){ return path; }
  3775.     this.getTitle = function(){ return title; }
  3776.   };
  3777. }).call(window, jQuery);
  3778. (function($){
  3779.   var Score = function(settings){
  3780.     if(settings == null) settings = {};
  3781.  
  3782.     for(key in settings){
  3783.       this[key] = settings[key];
  3784.     };
  3785.  
  3786.     // cast location to a string
  3787.     if(typeof this.location !== 'undefined'){
  3788.       this.location = this.location + "";
  3789.     }
  3790.  
  3791.     if(typeof this.timestamp === 'undefined'){
  3792.       var d = new Date()
  3793.         , ts;
  3794.  
  3795.       if(d.toISOString){ ts = d.toISOString(); }
  3796.       else             { ts = d.valueOf(); }
  3797.  
  3798.       this.timestamp = ts;
  3799.     }
  3800.  
  3801.     // cast scores to numbers
  3802.     var numberValues = ['score', 'maxscore'];
  3803.     for (var i = numberValues.length - 1; i >= 0; i--) {
  3804.       var prop = numberValues[i];
  3805.       this[prop] = Number(this[prop]);
  3806.       if(isNaN(this[prop])){
  3807.         this[prop] = 0;
  3808.       }
  3809.     };
  3810.   };
  3811.  
  3812.   VST.Models.Score = Score;
  3813. }).call(window, jQuery);
  3814. (function($){
  3815.  
  3816.   VST.Models.User = function(s){
  3817.     var settings = s || {};
  3818.   };
  3819.  
  3820.   /* doc:code
  3821.     :name:      VST.User.hasBook(isbn, callback)
  3822.     :summary:   Check to see if a user has a license for a book
  3823.     :params:    isbn:String
  3824.                 the ISBN of the book you wish to check for
  3825.     :params:    callback:Function
  3826.                 the function that is to be called when the response is received
  3827.  
  3828.     == Example: ==
  3829.     @code:javascript@
  3830.     VST.User.hasBook('L-999-123', function(error, hasBook){
  3831.       if(error){
  3832.         VST.Logger.debug("there was an error: " + error.message);
  3833.         return;
  3834.       }
  3835.  
  3836.       if(hasBook) { VST.Logger.debug("yes!"); }
  3837.       else        { VST.Logger.debug("nope."); }
  3838.     });
  3839.     @/code@
  3840.     ==
  3841.  
  3842.   */
  3843.  
  3844.   VST.Models.User.prototype.hasBook = function(isbn, callback){
  3845.     VST.Handler.fire('user:hasBook', [isbn, callback], this);
  3846.   };
  3847.  
  3848.   /* doc:code
  3849.  
  3850.     :name:      VST.User.getFirstName(callback)
  3851.     :summary:   Retrieve the first name of the current user
  3852.     :params:    callback:Function
  3853.                 the function that is to be called when the firstName is retrieved
  3854.  
  3855.     == Example: ==
  3856.     @code:javascript@
  3857.     VST.User.getFirstName(function(error, name){
  3858.       if(error){
  3859.         VST.Logger.debug("there was an error: " + error.message);
  3860.         return;
  3861.       }
  3862.       VST.Logger.debug("Hello, " + name);
  3863.     });
  3864.     @/code@
  3865.   */
  3866.  
  3867.   VST.Models.User.prototype.getFirstName = function(callback) {
  3868.     VST.EventDispatcher.fireBefore('user:getFirstName');
  3869.     VST.Handler.fire('user:getFirstName', callback, this);
  3870.   };
  3871.  
  3872.   /* doc:code
  3873.  
  3874.     :name:    VST.User.getLastName(callback)
  3875.     :summary: Get the last name of the current User
  3876.     :params:  callback:Function
  3877.               the function to be called when the last name is retreived
  3878.  
  3879.     == Example: ==
  3880.     @code:javascript@
  3881.     VST.User.lastName(function(err, lastName){
  3882.       if(err){
  3883.         VST.Logger.debug("there was an error: " + err.message);
  3884.       }else{
  3885.         VST.Logger.debug("the user's last name: " + lastName);
  3886.       }
  3887.     });
  3888.     @/code@
  3889.  
  3890.   */
  3891.  
  3892.   VST.Models.User.prototype.getLastName = function(callback){
  3893.     VST.EventDispatcher.fireBefore('user:getLastName');
  3894.     VST.Handler.fire('user:getLastName', callback, this);
  3895.   };
  3896.  
  3897.   /* doc:code
  3898.  
  3899.     :name:    VST.User.getFullName(callback)
  3900.     :summary: Get the full name of the current User
  3901.     :params:  callback:Function
  3902.               the function to be called when the full name is retreived
  3903.  
  3904.     == Example: ==
  3905.     @code:javascript@
  3906.     VST.User.getFullName(function(err, name){
  3907.       if(err){
  3908.         VST.Logger.debug("there was an error: " + err.message);
  3909.       }else{
  3910.         VST.Logger.debug("Hello, " + name.first + " " + name.last);
  3911.       }
  3912.     });
  3913.     @/code@
  3914.  
  3915.   */
  3916.   VST.Models.User.prototype.getFullName = function(callback){
  3917.     VST.EventDispatcher.fireBefore('user:getFullName');
  3918.     VST.Handler.fire('user:getFullName', callback, this);
  3919.   };
  3920.  
  3921.   /* doc:code
  3922.  
  3923.     :name:      VST.User.books(callback)
  3924.     :summary:   Retrieve the books to which the current user has access
  3925.     :params:    callback:Function
  3926.                 the function to be called when the books are retrieved
  3927.  
  3928.     == Example: ==
  3929.     @code:javascript@
  3930.     VST.User.books(function(error, books){
  3931.       if(error){
  3932.         VST.Logger.debug("there was an error: " + error.message);
  3933.       }else{
  3934.         // do something with the books
  3935.       }
  3936.     });
  3937.     @/code@
  3938.     ==
  3939.  
  3940.     The callback will receive an error (if one occured) along with an array of <code>VST.Models.Book</code> objects
  3941.   */
  3942.  
  3943.   VST.Models.User.prototype.books = function(callback){
  3944.     VST.EventDispatcher.fireBefore('user:getBooks');
  3945.     VST.Handler.fire('user:books', callback, this);
  3946.   };
  3947.  
  3948.   VST.Models.User.prototype.getBooks = VST.Models.User.prototype.books;
  3949.  
  3950.   /* doc:code
  3951.  
  3952.     :name:      VST.User.getScoreURL(callback)
  3953.     :summary:   Retrieve the URL to which FLOE activity scores should be posted
  3954.     :params:    callback:Function
  3955.                 the function to be called when the URL is retreived
  3956.  
  3957.     == Example: ==
  3958.     @code:javascript@
  3959.     VST.User.getScoreURL(function(error, url){
  3960.       if(error){
  3961.         VST.Logger.debug("there was an error: " + error.message);
  3962.       }else{
  3963.         // do something with the URL
  3964.       }
  3965.     });
  3966.     @/code@
  3967.     ==
  3968.  
  3969.     The callback will receive an error (if one occured) along with the URL (a <code>String</code>)
  3970.   */
  3971.  
  3972.   VST.Models.User.prototype.getScoreURL = function(callback){
  3973.     VST.EventDispatcher.fireBefore('user:getScoreURL');
  3974.     VST.Handler.fire('user:getScoreURL', callback, this);
  3975.   };
  3976.  
  3977.   // don't pollute the global namespace
  3978.   VST.User = new VST.Models.User();
  3979.  
  3980. }).call(window, jQuery);
  3981.  
  3982. }.call(this, $));
  3983. VST.$ = $.noConflict(true);
  3984.  
  3985. var VSTEPUBModule = function (window, document) {
  3986.  
  3987.   var zoom = 1;
  3988.  
  3989.   function setZoom(z) {
  3990.     zoom = z;
  3991.   }
  3992.  
  3993.   function logMessage(message) {
  3994.     if(typeof VST !== 'undefined'){
  3995.       VST.Logger.info(message);
  3996.     }
  3997.   }
  3998.  
  3999.   function logError(error) {
  4000.     if(typeof VST !== 'undefined'){
  4001.       VST.Logger.error(error);
  4002.     }
  4003.   }
  4004.  
  4005.   // Assertion utilities
  4006.   function EscapeCFIAssertion (str) {
  4007.     return str.replace(/[\[\]\^\(\)\,\;]/g, "^$&");
  4008.   }
  4009.  
  4010.   function UnescapeCFIAssertion (str) {
  4011.     return str.replace(/\^([\[\]\^\(\)\,\;])/g,"$1");
  4012.   }
  4013.  
  4014.   function ParseCFIAssertion (str) {
  4015.     if (str.charAt(0) != "[")
  4016.     {
  4017.       return null;
  4018.     }
  4019.  
  4020.     // Find the first closing bracket that is not preceeded by ^
  4021.     // Offset returned is actually the character before the close bracket.
  4022.     var offset = str.search(/[^\^]\]/);
  4023.     if (offset == -1)
  4024.     {
  4025.       return null;
  4026.     }
  4027.  
  4028.     var match = str.slice(1, offset + 1);
  4029.  
  4030.     return { endOffset:offset + 2, assert:UnescapeCFIAssertion(match) };
  4031.   }
  4032.  
  4033.   function StripCFIAssertions (str) {
  4034.     return str.replace(/\[(.*?)[^\^]\]/g, "");
  4035.   }
  4036.  
  4037.   function CreateNextNodeRegex () {
  4038.     return new RegExp("(?:\\/(\\d+))(?:(?:\\[(.*?[^\\^])\\])?)|(?:!)|(?:\\:(\\d+))|(?:@([\\d.]+):([\\d.]+))", "g");
  4039.   }
  4040.  
  4041.   // Automated testing
  4042.   function TestCommand (command, expectedResult, testResults) {
  4043.  
  4044.     var cmdObject = null;
  4045.     if (typeof(command) == "string")
  4046.     {
  4047.       cmdObject = { test:function() { return eval(command); }, title:command };
  4048.     }
  4049.     else
  4050.     {
  4051.       cmdObject = command;
  4052.     }
  4053.  
  4054.     var result = cmdObject.test();
  4055.     var success = true;
  4056.  
  4057.     if (typeof(expectedResult) == "string")
  4058.     {
  4059.       if (result != expectedResult)
  4060.       {
  4061.         testResults.TestFail("Test " + cmdObject.title + " failed", expectedResult, result);
  4062.         success = false;
  4063.       }
  4064.       else
  4065.       {
  4066.         logMessage(cmdObject.title + " returned " + result + " as expected - YAY!");
  4067.         testResults.TestSuccess();
  4068.       }
  4069.     }
  4070.     else
  4071.     {
  4072.       // Treat expetedResult as an associative array of strings.
  4073.       for (expectedKey in expectedResult)
  4074.       {
  4075.         var test = cmdObject.title + "." + expectedKey;
  4076.         var actual = result[expectedKey];
  4077.         var expected = expectedResult[expectedKey];
  4078.  
  4079.         if (actual != expected)
  4080.         {
  4081.           testResults.TestFail("Test " + test + " failed", expected, actual);
  4082.           success = false;
  4083.         }
  4084.         else
  4085.         {
  4086.           logMessage(test + " returned " + actual + " as expected - YAY!");
  4087.           testResults.TestSuccess();
  4088.         }
  4089.       }
  4090.     }
  4091.  
  4092.     return success;
  4093.   }
  4094.  
  4095.   function TestResults () {
  4096.     this.successCount = 0;
  4097.     this.failCount = 0;
  4098.     this.messages = [];
  4099.   }
  4100.  
  4101.   TestResults.prototype.TestFail = function(message, expected, actual) {
  4102.     this.failCount += 1;
  4103.     if (message)
  4104.     {
  4105.       this.AddErrorMessage(message);
  4106.     }
  4107.  
  4108.     if (expected)
  4109.     {
  4110.       this.AddErrorMessage("Expected: " + expected);
  4111.       if (actual)
  4112.       {
  4113.         this.AddErrorMessage("Actual: " + actual);
  4114.       }
  4115.       else
  4116.       {
  4117.         this.AddErrorMessage("Actual: (null)");
  4118.       }
  4119.     }
  4120.   }
  4121.  
  4122.   TestResults.prototype.TestSuccess = function(message) {
  4123.     this.successCount += 1;
  4124.     if (message)
  4125.     {
  4126.       this.AddMessage(message);
  4127.     }
  4128.   }
  4129.  
  4130.   TestResults.prototype.AddMessage = function(message) {
  4131.     this.messages.push(message);
  4132.     logMessage(message);
  4133.   }
  4134.  
  4135.   TestResults.prototype.AddErrorMessage = function(message) {
  4136.     this.messages.push(message);
  4137.     logError(message);
  4138.   }
  4139.  
  4140.   TestResults.prototype.JoinMessages = function() {
  4141.     return this.messages.join("\n");
  4142.   }
  4143.  
  4144.   TestResults.prototype.ResultSummary = function() {
  4145.     return "Succeeded: " + this.successCount +
  4146.           "; Failed: " + this.failCount;
  4147.   }
  4148.  
  4149.   function TestCFIAssertionUtilities (testResults) {
  4150.  
  4151.     TestCommand("EscapeCFIAssertion(\"abcd1234\");", "abcd1234", testResults);
  4152.     TestCommand("EscapeCFIAssertion(\"test[some]^weird;(stuff),\");",
  4153.         "test^[some^]^^weird^;^(stuff^)^,", testResults);
  4154.  
  4155.     TestCommand("UnescapeCFIAssertion(\"abcd1234\");", "abcd1234", testResults);
  4156.     TestCommand("UnescapeCFIAssertion(\"test^[some^]^^weird^;^(stuff^)^,\");",
  4157.         "test[some]^weird;(stuff),", testResults);
  4158.  
  4159.     TestCommand("ParseCFIAssertion(\"[test^[some^]^^weird^;^(stuff^)^,]/2/3/4[abcd1234]/1:3\").assert",
  4160.         "test[some]^weird;(stuff),", testResults);
  4161.     TestCommand("var s = \"[test^[some^]^^weird^;^(stuff^)^,]/2/3/4[abcd1234]/1:3\"; s.slice(ParseCFIAssertion(s).endOffset)",
  4162.         "/2/3/4[abcd1234]/1:3", testResults);
  4163.  
  4164.     TestCommand("StripCFIAssertions(\"/2[test^[some^]^^weird^;^(stuff^)^,]/2/3/4[abcd1234]/1:3\");",
  4165.         "/2/2/3/4/1:3", testResults);
  4166.   }
  4167.  
  4168.   function TestNextNodeRegex (testResults) {
  4169.     var findNode = CreateNextNodeRegex();
  4170.     var testToParse = "/4/2/6[chapter02]/12[sec^[01^]]/2[test^[some^]^^weird^;^(stuff^)^,]/1:3";
  4171.  
  4172.     var testFindNextNode = function() {
  4173.       var nextMatch;
  4174.       if ((nextMatch = findNode.exec(testToParse)) != null)
  4175.       {
  4176.         switch (nextMatch[0].charAt(0)) {
  4177.           case "/":
  4178.             var result = {};
  4179.             result.targetIndex = parseInt(nextMatch[1]);
  4180.             if (nextMatch[2])
  4181.             {
  4182.               result.id = UnescapeCFIAssertion(nextMatch[2]);
  4183.             }
  4184.             return result;
  4185.           break;
  4186.           case ":":
  4187.             return { offset:parseInt(nextMatch[3]) };
  4188.           break;
  4189.         }
  4190.       }
  4191.  
  4192.       return null;
  4193.     }
  4194.  
  4195.     TestCommand({ test:testFindNextNode, title:"testFindNextNode 1&