").append(b.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},b.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){b.fn[t]=function(e){return this.on(t,e)}}),b.each(["get","post"],function(e,n){b[n]=function(e,r,i,o){return b.isFunction(r)&&(o=o||i,i=r,r=t),b.ajax({url:e,type:n,dataType:o,data:r,success:i})}}),b.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Nn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":b.parseJSON,"text xml":b.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Mn(Mn(e,b.ajaxSettings),t):Mn(b.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,u,l,c,p=b.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?b(f):b.event,h=b.Deferred(),g=b.Callbacks("once memory"),m=p.statusCode||{},y={},v={},x=0,T="canceled",N={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return x||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>x)for(t in e)m[t]=[m[t],e[t]];else N.always(e[N.status]);return this},abort:function(e){var t=e||T;return l&&l.abort(t),k(0,t),this}};if(h.promise(N).complete=g.add,N.success=N.done,N.error=N.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=b.trim(p.dataType||"*").toLowerCase().match(w)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?80:443))==(mn[3]||("http:"===mn[1]?80:443)))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=b.param(p.data,p.traditional)),qn(An,p,n,N),2===x)return N;u=p.global,u&&0===b.active++&&b.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Cn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(b.lastModified[o]&&N.setRequestHeader("If-Modified-Since",b.lastModified[o]),b.etag[o]&&N.setRequestHeader("If-None-Match",b.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&N.setRequestHeader("Content-Type",p.contentType),N.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)N.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,N,p)===!1||2===x))return N.abort();T="abort";for(i in{success:1,error:1,complete:1})N[i](p[i]);if(l=qn(jn,p,n,N)){N.readyState=1,u&&d.trigger("ajaxSend",[N,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){N.abort("timeout")},p.timeout));try{x=1,l.send(y,k)}catch(C){if(!(2>x))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,C=n;2!==x&&(x=2,s&&clearTimeout(s),l=t,a=i||"",N.readyState=e>0?4:0,r&&(w=_n(p,N,r)),e>=200&&300>e||304===e?(p.ifModified&&(T=N.getResponseHeader("Last-Modified"),T&&(b.lastModified[o]=T),T=N.getResponseHeader("etag"),T&&(b.etag[o]=T)),204===e?(c=!0,C="nocontent"):304===e?(c=!0,C="notmodified"):(c=Fn(p,w),C=c.state,y=c.data,v=c.error,c=!v)):(v=C,(e||!C)&&(C="error",0>e&&(e=0))),N.status=e,N.statusText=(n||C)+"",c?h.resolveWith(f,[y,C,N]):h.rejectWith(f,[N,C,v]),N.statusCode(m),m=t,u&&d.trigger(c?"ajaxSuccess":"ajaxError",[N,p,c?y:v]),g.fireWith(f,[N,C]),u&&(d.trigger("ajaxComplete",[N,p]),--b.active||b.event.trigger("ajaxStop")))}return N},getScript:function(e,n){return b.get(e,t,n,"script")},getJSON:function(e,t,n){return b.get(e,t,n,"json")}});function _n(e,n,r){var i,o,a,s,u=e.contents,l=e.dataTypes,c=e.responseFields;for(s in c)s in r&&(n[c[s]]=r[s]);while("*"===l[0])l.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in u)if(u[s]&&u[s].test(o)){l.unshift(s);break}if(l[0]in r)a=l[0];else{for(s in r){if(!l[0]||e.converters[s+" "+l[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==l[0]&&l.unshift(a),r[a]):t}function Fn(e,t){var n,r,i,o,a={},s=0,u=e.dataTypes.slice(),l=u[0];if(e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u[1])for(i in e.converters)a[i.toLowerCase()]=e.converters[i];for(;r=u[++s];)if("*"!==r){if("*"!==l&&l!==r){if(i=a[l+" "+r]||a["* "+r],!i)for(n in a)if(o=n.split(" "),o[1]===r&&(i=a[l+" "+o[0]]||a["* "+o[0]])){i===!0?i=a[n]:a[n]!==!0&&(r=o[0],u.splice(s--,0,r));break}if(i!==!0)if(i&&e["throws"])t=i(t);else try{t=i(t)}catch(c){return{state:"parsererror",error:i?c:"No conversion from "+l+" to "+r}}}l=r}return{state:"success",data:t}}b.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return b.globalEval(e),e}}}),b.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),b.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=o.head||b("head")[0]||o.documentElement;return{send:function(t,i){n=o.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var On=[],Bn=/(=)\?(?=&|$)|\?\?/;b.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=On.pop()||b.expando+"_"+vn++;return this[e]=!0,e}}),b.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,u=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return u||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=b.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,u?n[u]=n[u].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||b.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,On.push(o)),s&&b.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}b.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=b.ajaxSettings.xhr(),b.support.cors=!!Rn&&"withCredentials"in Rn,Rn=b.support.ajax=!!Rn,Rn&&b.ajaxTransport(function(n){if(!n.crossDomain||b.support.cors){var r;return{send:function(i,o){var a,s,u=n.xhr();if(n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)u[s]=n.xhrFields[s];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)u.setRequestHeader(s,i[s])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var s,l,c,p;try{if(r&&(i||4===u.readyState))if(r=t,a&&(u.onreadystatechange=b.noop,$n&&delete Pn[a]),i)4!==u.readyState&&u.abort();else{p={},s=u.status,l=u.getAllResponseHeaders(),"string"==typeof u.responseText&&(p.text=u.responseText);try{c=u.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,l)},n.async?4===u.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},b(e).unload($n)),Pn[a]=r),u.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+x+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n,r,i=this.createTween(e,t),o=Yn.exec(t),a=i.cur(),s=+a||0,u=1,l=20;if(o){if(n=+o[2],r=o[3]||(b.cssNumber[e]?"":"px"),"px"!==r&&s){s=b.css(i.elem,e,!0)||n||1;do u=u||".5",s/=u,b.style(i.elem,e,s+r);while(u!==(u=i.cur()/a)&&1!==u&&--l)}i.unit=r,i.start=s,i.end=o[1]?s+(o[1]+1)*n:n}return i}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=b.now()}function Zn(e,t){b.each(t,function(t,n){var r=(Qn[t]||[]).concat(Qn["*"]),i=0,o=r.length;for(;o>i;i++)if(r[i].call(e,t,n))return})}function er(e,t,n){var r,i,o=0,a=Gn.length,s=b.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,a=0,u=l.tweens.length;for(;u>a;a++)l.tweens[a].run(o);return s.notifyWith(e,[l,o,n]),1>o&&u?n:(s.resolveWith(e,[l]),!1)},l=s.promise({elem:e,props:b.extend({},t),opts:b.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=b.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?s.resolveWith(e,[l,t]):s.rejectWith(e,[l,t]),this}}),c=l.props;for(tr(c,l.opts.specialEasing);a>o;o++)if(r=Gn[o].call(l,e,c,l.opts))return r;return Zn(l,c),b.isFunction(l.opts.start)&&l.opts.start.call(e,l),b.fx.timer(b.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function tr(e,t){var n,r,i,o,a;for(i in e)if(r=b.camelCase(i),o=t[r],n=e[i],b.isArray(n)&&(o=n[1],n=e[i]=n[0]),i!==r&&(e[r]=n,delete e[i]),a=b.cssHooks[r],a&&"expand"in a){n=a.expand(n),delete e[r];for(i in n)i in e||(e[i]=n[i],t[i]=o)}else t[r]=o}b.Animation=b.extend(er,{tweener:function(e,t){b.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,u,l,c,p,f=this,d=e.style,h={},g=[],m=e.nodeType&&nn(e);n.queue||(c=b._queueHooks(e,"fx"),null==c.unqueued&&(c.unqueued=0,p=c.empty.fire,c.empty.fire=function(){c.unqueued||p()}),c.unqueued++,f.always(function(){f.always(function(){c.unqueued--,b.queue(e,"fx").length||c.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[d.overflow,d.overflowX,d.overflowY],"inline"===b.css(e,"display")&&"none"===b.css(e,"float")&&(b.support.inlineBlockNeedsLayout&&"inline"!==un(e.nodeName)?d.zoom=1:d.display="inline-block")),n.overflow&&(d.overflow="hidden",b.support.shrinkWrapBlocks||f.always(function(){d.overflow=n.overflow[0],d.overflowX=n.overflow[1],d.overflowY=n.overflow[2]}));for(i in t)if(a=t[i],Vn.exec(a)){if(delete t[i],u=u||"toggle"===a,a===(m?"hide":"show"))continue;g.push(i)}if(o=g.length){s=b._data(e,"fxshow")||b._data(e,"fxshow",{}),"hidden"in s&&(m=s.hidden),u&&(s.hidden=!m),m?b(e).show():f.done(function(){b(e).hide()}),f.done(function(){var t;b._removeData(e,"fxshow");for(t in h)b.style(e,t,h[t])});for(i=0;o>i;i++)r=g[i],l=f.createTween(r,m?s[r]:0),h[r]=s[r]||b.style(e,r),r in s||(s[r]=l.start,m&&(l.end=l.start,l.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}b.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(b.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?b.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):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):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=b.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){b.fx.step[e.prop]?b.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[b.cssProps[e.prop]]||b.cssHooks[e.prop])?b.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},b.each(["toggle","show","hide"],function(e,t){var n=b.fn[t];b.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),b.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=b.isEmptyObject(e),o=b.speed(t,n,r),a=function(){var t=er(this,b.extend({},e),o);a.finish=function(){t.stop(!0)},(i||b._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=b.timers,a=b._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&b.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=b._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=b.timers,a=r?r.length:0;for(n.finish=!0,b.queue(this,e,[]),i&&i.cur&&i.cur.finish&&i.cur.finish.call(this),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}b.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){b.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),b.speed=function(e,t,n){var r=e&&"object"==typeof e?b.extend({},e):{complete:n||!n&&t||b.isFunction(e)&&e,duration:e,easing:n&&t||t&&!b.isFunction(t)&&t};return r.duration=b.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in b.fx.speeds?b.fx.speeds[r.duration]:b.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){b.isFunction(r.old)&&r.old.call(this),r.queue&&b.dequeue(this,r.queue)},r},b.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},b.timers=[],b.fx=rr.prototype.init,b.fx.tick=function(){var e,n=b.timers,r=0;for(Xn=b.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||b.fx.stop(),Xn=t},b.fx.timer=function(e){e()&&b.timers.push(e)&&b.fx.start()},b.fx.interval=13,b.fx.start=function(){Un||(Un=setInterval(b.fx.tick,b.fx.interval))},b.fx.stop=function(){clearInterval(Un),Un=null},b.fx.speeds={slow:600,fast:200,_default:400},b.fx.step={},b.expr&&b.expr.filters&&(b.expr.filters.animated=function(e){return b.grep(b.timers,function(t){return e===t.elem}).length}),b.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){b.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,b.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},b.offset={setOffset:function(e,t,n){var r=b.css(e,"position");"static"===r&&(e.style.position="relative");var i=b(e),o=i.offset(),a=b.css(e,"top"),s=b.css(e,"left"),u=("absolute"===r||"fixed"===r)&&b.inArray("auto",[a,s])>-1,l={},c={},p,f;u?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),b.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(l.top=t.top-o.top+p),null!=t.left&&(l.left=t.left-o.left+f),"using"in t?t.using.call(e,l):i.css(l)}},b.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===b.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),b.nodeName(e[0],"html")||(n=e.offset()),n.top+=b.css(e[0],"borderTopWidth",!0),n.left+=b.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-b.css(r,"marginTop",!0),left:t.left-n.left-b.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||o.documentElement;while(e&&!b.nodeName(e,"html")&&"static"===b.css(e,"position"))e=e.offsetParent;return e||o.documentElement})}}),b.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);b.fn[e]=function(i){return b.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?b(a).scrollLeft():o,r?o:b(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return b.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}b.each({Height:"height",Width:"width"},function(e,n){b.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){b.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return b.access(this,function(n,r,i){var o;return b.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?b.css(n,r,s):b.style(n,r,i,s)},n,a?i:t,a,null)}})}),e.jQuery=e.$=b,"function"==typeof define&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return b})})(window);
--------------------------------------------------------------------------------
/js/options.js:
--------------------------------------------------------------------------------
1 | $("select").each(function () {
2 | $(this)
3 | .append('
<none> ')
4 | .append('
click ')
5 | .append('
shift+click ')
6 | .append('
ctrl/cmd+click ')
7 | .append('
alt/opt+click ')
8 | .find("option[value='" + JSON.parse(localStorage.open)[this.id.split("-")[1]] + "']").prop("selected", true);
9 | }).change(function () {
10 | var open = JSON.parse(localStorage.open);
11 | open[this.id.split("-")[1]] = this.value;
12 | localStorage.open = JSON.stringify(open);
13 | });
14 |
15 | $("[name='pinned-save']").change(function () {
16 | localStorage.pinned = this.value;
17 | }).filter("[value='" + localStorage.pinned + "']").prop("checked", true);
18 |
19 | $("#pinned-noreplace").change(function () {
20 | if (this.checked) {
21 | localStorage.noreplacingpinned = true;
22 | } else {
23 | delete localStorage.noreplacingpinned;
24 | }
25 | }).prop("checked", localStorage.noreplacingpinned === "true");
26 |
27 | chrome.extension.getBackgroundPage().ga("send", "pageview", "/options");
28 |
--------------------------------------------------------------------------------
/js/popup.js:
--------------------------------------------------------------------------------
1 | (function(){ "use strict";
2 |
3 | /*** utils ***/
4 | var utils = {
5 | view: function(name){
6 | $("body").children().hide();
7 | $("#" + name).show();
8 | },
9 | confirm: function(html, index){
10 | var yes = $("#confirm-text").html(html).siblings().children().eq(0).attr("data-actionindex", typeof index === "number" ? index : 1);
11 | utils.view("confirm");
12 | yes.focus();
13 | },
14 | action: function(name, index){
15 | state.action = name || state.action;
16 | actions[state.action][index || 0](state.name);
17 | sessions.load();
18 | },
19 | escape: function(text){
20 | return $("
").text(text).html();
21 | },
22 | tabs: function(cb){
23 | chrome.tabs.getAllInWindow(null, function(tabs){
24 | if (localStorage.pinned === "skip") {
25 | tabs = tabs.filter(function(t){ return !t.pinned; });
26 | }
27 |
28 | cb(tabs.map(function(t){ return t.url; }));
29 | sessions.load();
30 | });
31 | }
32 | };
33 |
34 |
35 | /*** data ***/
36 | var background = chrome.extension.getBackgroundPage();
37 |
38 | var state = {
39 | name: "",
40 | action: "",
41 | entered: ""
42 | };
43 |
44 | var sessions = {
45 | list: JSON.parse(localStorage.sessions),
46 | temp: localStorage.temp ? JSON.parse(localStorage.temp) : undefined,
47 |
48 | load: function(){
49 | var $temp = $("#main-saved-temp"), $list = $("#main-saved-list");
50 | $temp.add($list).empty();
51 |
52 | if (sessions.temp) {
53 | localStorage.temp = JSON.stringify(sessions.temp);
54 | $temp.html("
× Temp session: " + sessions.display(null, true) + " -
Open -
Add (
tab )
");
55 | } else {
56 | delete localStorage.temp;
57 | }
58 |
59 | localStorage.sessions = JSON.stringify(sessions.list);
60 | $.each(sessions.list, function(name){
61 | $("
").html("
" + utils.escape(name) + " × " +
62 | sessions.display(name, true) +
63 | "
Open - Add (tab ) - Replace " +
64 | "
").attr("data-name", name).appendTo($list);
65 | });
66 |
67 | $("hr", "#main-saved").last().remove();
68 |
69 | $list.children().css("margin-right", Object.keys(sessions.list).length > 10 ? 5 : 0);
70 | },
71 | display: function(name, count){
72 | var prefix = "", session = name === null ? (name = "temp session", !count && (prefix = "the "), sessions.temp) : sessions.list[name];
73 | return prefix + '
' + (count ? session.length + " tabs" : utils.escape(name)) + ' ';
74 | }
75 | };
76 |
77 |
78 | /*** actions ***/
79 | var actions = {
80 | import: [function(){
81 | var reader = new FileReader();
82 |
83 | reader.onload = function(e){
84 | try {
85 | $.each(JSON.parse(e.target.result), function(name, urls){
86 | sessions.list[name] = urls;
87 | });
88 |
89 | state.entered = "Success";
90 | } catch (e) {
91 | state.entered = "ParseError";
92 | }
93 |
94 | utils.action("import", 1);
95 | };
96 |
97 | reader.onerror = function(){
98 | state.entered = "FileError";
99 | utils.action("import", 1);
100 | };
101 |
102 | reader.readAsText($("#import-file")[0].files[0]);
103 | }, function(){
104 | var status = state.entered,
105 | success = status === "Success",
106 | message = $("#import-message").text(success ? "Success!" : "Import failed!").delay(500).slideDown();
107 |
108 | success && message.delay(1500).queue(function(next){
109 | location.search ? window.close() : utils.view("main");
110 | message.hide();
111 | next();
112 | });
113 |
114 | background.ga("send", "event", "Action", "Import", state.entered);
115 | }],
116 |
117 | export: [function(){
118 | var data = new Blob([localStorage.sessions]);
119 |
120 | $("#export-link").prop("href", (window.URL || window.webkitURL).createObjectURL(data));
121 | }, function(){
122 | $("#export-check").fadeIn().delay(2000).fadeOut();
123 |
124 | background.ga("send", "event", "Action", "Export");
125 | }],
126 |
127 | rename: [function(name){
128 | $("#rename-legend").html("Rename " + sessions.display(name));
129 | utils.view("rename");
130 | $("#rename-text").val("").focus();
131 | }, function(oname){
132 | var nname = state.entered = $("#rename-text").val().trim();
133 |
134 | if (nname) {
135 | if (sessions.list[nname]) {
136 | utils.confirm("Are you sure you want to replace " + sessions.display(nname) + " by renaming " + sessions.display(oname) + "?", 2);
137 | } else {
138 | utils.action("rename", 2);
139 | utils.view("main");
140 | }
141 | }
142 | }, function(oname){
143 | sessions.list[state.entered] = sessions.list[oname];
144 |
145 | if (state.entered !== oname) {
146 | delete sessions.list[oname];
147 | }
148 |
149 | background.ga("send", "event", "Session", "Rename");
150 | }],
151 |
152 | add: [function(name){
153 | utils.confirm("Are you sure you want to add the current window's tabs to " + sessions.display(name) + "?");
154 | }, function(name){
155 | utils.tabs(function(tabs){
156 | Array.prototype.push.apply(name === null ? sessions.temp : sessions.list[name], tabs);
157 | });
158 |
159 | background.ga("send", "event", name === null ? "Temp": "Session", "AddWin");
160 | }],
161 |
162 | tab: [function(name){
163 | utils.confirm("Are you sure you want to add the current tab to " + sessions.display(name) + "?");
164 | }, function(name){
165 | chrome.tabs.getSelected(null, function(tab){
166 | (name === null ? sessions.temp : sessions.list[name]).push(tab.url);
167 | sessions.load();
168 | });
169 |
170 | background.ga("send", "event", name === null ? "Temp": "Session", "AddTab");
171 | }],
172 |
173 | replace: [function(name){
174 | utils.confirm("Are you sure you want to replace " + sessions.display(name) + " with the current window's tabs?");
175 | }, function(name){
176 | background.ga("send", "event", "Session", sessions.list[name] ? "Replace" : "Save");
177 |
178 | utils.tabs(function(tabs){
179 | sessions.list[name] = tabs;
180 | });
181 | }, function(name){
182 | utils.confirm("Are you sure you want to replace " + sessions.display(name) + " with the session being saved?");
183 | }],
184 |
185 | remove: [function(name){
186 | utils.confirm("Are you sure you want to remove " + sessions.display(name) + "?");
187 | }, function(name){
188 | if (name === null) {
189 | delete sessions.temp;
190 | } else {
191 | delete sessions.list[name];
192 | }
193 |
194 | background.ga("send", "event", name === null ? "Temp" : "Session", "Remove");
195 | }],
196 |
197 | savetemp: [function(){
198 | utils.tabs(function(tabs){
199 | sessions.temp = tabs;
200 | });
201 |
202 | background.ga("send", "event", "Temp", "Save");
203 | }],
204 |
205 | save: [function(){
206 | var $name = $("#main-save-name"), name = state.name = $name.val().trim();
207 |
208 | if (name) {
209 | $name.val("");
210 |
211 | utils.action("replace", sessions.list[name] ? 2 : 1);
212 | }
213 | }]
214 | };
215 |
216 |
217 | /*** events ***/
218 | $("body").on("focus", "*", function(){
219 | this.blur();
220 |
221 | $("body").off("focus", "*");
222 | }).on("click keypress", "[data-view], [data-action]", function(e){
223 | if ((this.tagName === "BUTTON" && e.type === "keypress") || (this.tagName === "INPUT" && (e.type !== "keypress" || e.which !== 13))) {
224 | return;
225 | }
226 |
227 | "view" in this.dataset && utils.view(this.dataset.view);
228 | "action" in this.dataset && utils.action(this.dataset.action, this.dataset.actionindex);
229 | });
230 |
231 | $("#main-saved-list").on("click", "big, div > a:not([title])", function(){
232 | state.name = this.parentNode.dataset.name;
233 |
234 | utils.action(this.tagName === "BIG" ? "rename" : "remove");
235 | }).on("click", "span > a", function(e){
236 | var action = this.textContent.toLowerCase(),
237 | name = state.name = this.parentNode.parentNode.dataset.name;
238 |
239 | if (action === "open") {
240 | chrome.windows.getCurrent(function(win){
241 | background.openSession(win.id, sessions.list[name], e, false) !== false && window.close();
242 | });
243 | } else {
244 | utils.action(action);
245 | }
246 | });
247 |
248 | $("#main-saved-temp").on("click", "a:not([title])", function(e){
249 | var action = this.textContent.toLowerCase();
250 | state.name = null;
251 |
252 | if (action === "open") {
253 | chrome.windows.getCurrent(function(win){
254 | background.openSession(win.id, sessions.temp, e, true) !== false && window.close();
255 | });
256 | } else if (action.length === 1) {
257 | utils.action("remove");
258 | } else {
259 | utils.action(action);
260 | }
261 | });
262 |
263 | $("#import-file").change(function(){
264 | utils.action("import");
265 | });
266 |
267 |
268 | /*** init ***/
269 | sessions.load();
270 |
271 | if (localStorage.readchanges !== "true") {
272 | $("#main-changelog").show();
273 |
274 | localStorage.readchanges = true;
275 | }
276 |
277 | if (location.search) {
278 | $("#import [data-view]").click(function(){
279 | window.close();
280 |
281 | return false;
282 | });
283 |
284 | utils.view("import");
285 |
286 | background.ga("send", "pageview", "/import");
287 | } else {
288 | background.ga("send", "pageview", "/popup");
289 | }
290 |
291 | })();
292 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Session Manager",
4 | "version": "3.5.0",
5 | "description": "Simple yet powerful tab set management. Quickly and easily save, update, remove, and restore sets of tabs!",
6 | "icons": {
7 | "16": "img/16.png",
8 | "128": "img/128.png"
9 | },
10 | "browser_action": {
11 | "default_icon": {
12 | "19": "img/19-1x.png",
13 | "38": "img/19-2x.png"
14 | },
15 | "default_title": "Session Manager",
16 | "default_popup": "popup.html"
17 | },
18 | "background": {
19 | "scripts": ["js/errors.js", "js/background.js"]
20 | },
21 | "content_security_policy": "script-src 'self' https://www.google-analytics.com; object-src 'self'",
22 | "offline_enabled": true,
23 | "omnibox": {
24 | "keyword": "session"
25 | },
26 | "options_page": "options.html",
27 | "options_ui": {
28 | "chrome_style": true,
29 | "page": "options.html"
30 | },
31 | "permissions": ["tabs"]
32 | }
33 |
--------------------------------------------------------------------------------
/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Session Manager
6 |
7 |
8 |
9 |
10 |
48 |
49 |
50 | Guide
51 |
52 | Session Manager is a simple yet powerful extension that makes it quick and easy to save, update, remove, and restore sets of tabs.
53 |
54 |
55 | Create sessions for daily routines; pages you open in the morning, noon and evening.
56 | Group pages of common interest such as News, Financial and Social.
57 | Save pages discovered during a research session that you'd like to revisit later.
58 |
59 |
60 | Saving sessions
61 | To save a session, enter the name in the textbox in the "Save this window's tabs" area and press enter. A session with that name containing the current window's tabs will be created. If a session with that name already exists, you will be asked to confirm replacing it.
62 |
63 | Temp session
64 | The temporary session is a special session that, when the browser is opened, will automatically open and delete itself. Click "as temp session" next to "Save this window's tabs" to save or replace it. Except for renaming, the temp session can be opened and modified like a normal session as described below.
65 |
66 | Session list
67 |
68 | Hover over the tab count to view the url list.
69 | Click the name of the session and enter the new name to rename it. If the new name is already in use by a session, you will be asked to confirm replacing it.
70 | Click the little "×" to remove the session. You will be asked to confirm the removal.
71 | Click "Open" while optionally holding modifier keys to open the session. Key+click combo configuration is in the "Opening sessions" options.
72 | Click "Add" to add the current window's tabs to the session. You will be asked to confirm adding them.
73 | Click "tab" next to "Add" to add the current tab to the session. You will be asked to confirm adding it.
74 | Click "Replace" to replace the session with the current window's tabs. You will be asked to confirm the replacement.
75 |
76 |
77 | Omnibox
78 | Sessions can be opened by typing "session" in the omnibox and pressing the tab or space key, then entering the session name and pressing enter. Session Manager may suggest some sessions based on the text entered.
79 |
80 | Incognito
81 | "Allow in incognito" must be checked under Session Manager in chrome://extensions for the incognito features to work. Sessions can be saved and opened normally in existing incognito windows, and can be opened in new incognito windows with the combo in the "Opening sessions" options.
82 |
83 |
84 |
85 | About
86 |
87 | Guarantee
88 | Under no circumstances will I sell, monetize, or otherwise compromise Session Manager. The complete source code is publicly available on GitHub , shared under the MIT license . – Teddy Cross :)
89 |
90 | Contribute
91 | Session Manager is one of the oldest extensions in the Chrome Web Store, and needs your help to keep going! Are you an engineer or designer? Please check out the wishlist below, and get in touch . If not, you can still help out by leaving a review on the Chrome Web Store .
92 |
93 | Wishlist
94 |
95 | Branding: Name, logo, and Chrome Web Store assets.
96 | Localization: Support and translations.
97 | Back up and sync automatically.
98 | Autosaved anti-crash session.
99 | Open individual tabs.
100 | Restore pinned tabs.
101 | Session editor.
102 | List organizer.
103 |
104 |
105 |
106 |
107 | News
108 |
109 | 3.5.0 (2016-10-14)
110 |
111 | Three years later...
112 | Updated the options page.
113 | Removed error tracking, for now.
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Session Manager
6 |
7 |
8 |
9 |
10 |
11 |
Saved sessions (Import - Export )
12 |
13 |
14 |
15 |
16 |
Save this window's tabs (as temp session )
17 |
18 |
19 | Save
20 |
21 |
22 |
23 |
28 |
29 |
30 |
Import
31 | Once you've exported your sessions and copied them over, simply select the session file and you'll instantly have everything back!
32 | NOTE: Any imported session with the same name as an existing session will replace the existing session.
33 |
34 |
35 | Cancel
36 |
37 |
38 |
39 |
40 |
Export
41 | To begin, simply click the link to save your sessions to a file. Then, transfer that file to another computer via your favorite service (e.g. email, dropbox, pastebin). Once it's there, just follow the import instructions.
42 | NOTE: Chrome may not show that the file has been saved. Check your downloads folder for it. ✓
43 |
44 | Got it, download sessions.txt!
45 | Back
46 |
47 |
48 |
49 |
50 |
51 |
52 | Rename
53 | Cancel
54 |
55 |
56 |
57 |
Confirm
58 |
59 |
60 | Yes
61 | No
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------