/**
 * witoPreQueryProtect
 */
wito_useOwnjQuery = function() {
    /* leave function open; jQuery inlined below */

/*
 * jQuery 1.2.6 - New Wave Javascript
 *
 * Copyright (c) 2008 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
 * $Rev: 5685 $
 */
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(H(){J w=1b.4M,3m$=1b.$;J D=1b.4M=1b.$=H(a,b){I 2B D.17.5j(a,b)};J u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/,62=/^.[^:#\\[\\.]*$/,12;D.17=D.44={5j:H(d,b){d=d||S;G(d.16){7[0]=d;7.K=1;I 7}G(1j d=="23"){J c=u.2D(d);G(c&&(c[1]||!b)){G(c[1])d=D.4h([c[1]],b);N{J a=S.61(c[3]);G(a){G(a.2v!=c[3])I D().2q(d);I D(a)}d=[]}}N I D(b).2q(d)}N G(D.1D(d))I D(S)[D.17.27?"27":"43"](d);I 7.6Y(D.2d(d))},5w:"1.2.6",8G:H(){I 7.K},K:0,3p:H(a){I a==12?D.2d(7):7[a]},2I:H(b){J a=D(b);a.5n=7;I a},6Y:H(a){7.K=0;2p.44.1p.1w(7,a);I 7},P:H(a,b){I D.P(7,a,b)},5i:H(b){J a=-1;I D.2L(b&&b.5w?b[0]:b,7)},1K:H(c,a,b){J d=c;G(c.1q==56)G(a===12)I 7[0]&&D[b||"1K"](7[0],c);N{d={};d[c]=a}I 7.P(H(i){R(c 1n d)D.1K(b?7.V:7,c,D.1i(7,d[c],b,i,c))})},1g:H(b,a){G((b==\'2h\'||b==\'1Z\')&&3d(a)<0)a=12;I 7.1K(b,a,"2a")},1r:H(b){G(1j b!="49"&&b!=U)I 7.4E().3v((7[0]&&7[0].2z||S).5F(b));J a="";D.P(b||7,H(){D.P(7.3t,H(){G(7.16!=8)a+=7.16!=1?7.76:D.17.1r([7])})});I a},5z:H(b){G(7[0])D(b,7[0].2z).5y().39(7[0]).2l(H(){J a=7;1B(a.1x)a=a.1x;I a}).3v(7);I 7},8Y:H(a){I 7.P(H(){D(7).6Q().5z(a)})},8R:H(a){I 7.P(H(){D(7).5z(a)})},3v:H(){I 7.3W(19,M,Q,H(a){G(7.16==1)7.3U(a)})},6F:H(){I 7.3W(19,M,M,H(a){G(7.16==1)7.39(a,7.1x)})},6E:H(){I 7.3W(19,Q,Q,H(a){7.1d.39(a,7)})},5q:H(){I 7.3W(19,Q,M,H(a){7.1d.39(a,7.2H)})},3l:H(){I 7.5n||D([])},2q:H(b){J c=D.2l(7,H(a){I D.2q(b,a)});I 7.2I(/[^+>] [^+>]/.11(b)||b.1h("..")>-1?D.4r(c):c)},5y:H(e){J f=7.2l(H(){G(D.14.1f&&!D.4n(7)){J a=7.6o(M),5h=S.3h("1v");5h.3U(a);I D.4h([5h.4H])[0]}N I 7.6o(M)});J d=f.2q("*").5c().P(H(){G(7[E]!=12)7[E]=U});G(e===M)7.2q("*").5c().P(H(i){G(7.16==3)I;J c=D.L(7,"3w");R(J a 1n c)R(J b 1n c[a])D.W.1e(d[i],a,c[a][b],c[a][b].L)});I f},1E:H(b){I 7.2I(D.1D(b)&&D.3C(7,H(a,i){I b.1k(a,i)})||D.3g(b,7))},4Y:H(b){G(b.1q==56)G(62.11(b))I 7.2I(D.3g(b,7,M));N b=D.3g(b,7);J a=b.K&&b[b.K-1]!==12&&!b.16;I 7.1E(H(){I a?D.2L(7,b)<0:7!=b})},1e:H(a){I 7.2I(D.4r(D.2R(7.3p(),1j a==\'23\'?D(a):D.2d(a))))},3F:H(a){I!!a&&D.3g(a,7).K>0},7T:H(a){I 7.3F("."+a)},6e:H(b){G(b==12){G(7.K){J c=7[0];G(D.Y(c,"2A")){J e=c.64,63=[],15=c.15,2V=c.O=="2A-2V";G(e<0)I U;R(J i=2V?e:0,2f=2V?e+1:15.K;i<2f;i++){J d=15[i];G(d.2W){b=D.14.1f&&!d.at.2x.an?d.1r:d.2x;G(2V)I b;63.1p(b)}}I 63}N I(7[0].2x||"").1o(/\\r/g,"")}I 12}G(b.1q==4L)b+=\'\';I 7.P(H(){G(7.16!=1)I;G(b.1q==2p&&/5O|5L/.11(7.O))7.4J=(D.2L(7.2x,b)>=0||D.2L(7.34,b)>=0);N G(D.Y(7,"2A")){J a=D.2d(b);D("9R",7).P(H(){7.2W=(D.2L(7.2x,a)>=0||D.2L(7.1r,a)>=0)});G(!a.K)7.64=-1}N 7.2x=b})},2K:H(a){I a==12?(7[0]?7[0].4H:U):7.4E().3v(a)},7b:H(a){I 7.5q(a).21()},79:H(i){I 7.3s(i,i+1)},3s:H(){I 7.2I(2p.44.3s.1w(7,19))},2l:H(b){I 7.2I(D.2l(7,H(a,i){I b.1k(a,i,a)}))},5c:H(){I 7.1e(7.5n)},L:H(d,b){J a=d.1R(".");a[1]=a[1]?"."+a[1]:"";G(b===12){J c=7.5C("9z"+a[1]+"!",[a[0]]);G(c===12&&7.K)c=D.L(7[0],d);I c===12&&a[1]?7.L(a[0]):c}N I 7.1P("9u"+a[1]+"!",[a[0],b]).P(H(){D.L(7,d,b)})},3b:H(a){I 7.P(H(){D.3b(7,a)})},3W:H(g,f,h,d){J e=7.K>1,3x;I 7.P(H(){G(!3x){3x=D.4h(g,7.2z);G(h)3x.9o()}J b=7;G(f&&D.Y(7,"1T")&&D.Y(3x[0],"4F"))b=7.3H("22")[0]||7.3U(7.2z.3h("22"));J c=D([]);D.P(3x,H(){J a=e?D(7).5y(M)[0]:7;G(D.Y(a,"1m"))c=c.1e(a);N{G(a.16==1)c=c.1e(D("1m",a).21());d.1k(b,a)}});c.P(6T)})}};D.17.5j.44=D.17;H 6T(i,a){G(a.4d)D.3Y({1a:a.4d,31:Q,1O:"1m"});N D.5u(a.1r||a.6O||a.4H||"");G(a.1d)a.1d.37(a)}H 1z(){I+2B 8J}D.1l=D.17.1l=H(){J b=19[0]||{},i=1,K=19.K,4x=Q,15;G(b.1q==8I){4x=b;b=19[1]||{};i=2}G(1j b!="49"&&1j b!="H")b={};G(K==i){b=7;--i}R(;i<K;i++)G((15=19[i])!=U)R(J c 1n 15){J a=b[c],2w=15[c];G(b===2w)6M;G(4x&&2w&&1j 2w=="49"&&!2w.16)b[c]=D.1l(4x,a||(2w.K!=U?[]:{}),2w);N G(2w!==12)b[c]=2w}I b};J E="4M"+1z(),6K=0,5r={},6G=/z-?5i|8B-?8A|1y|6B|8v-?1Z/i,3P=S.3P||{};D.1l({8u:H(a){1b.$=3m$;G(a)1b.4M=w;I D},1D:H(a){I!!a&&1j a!="23"&&!a.Y&&a.1q!=2p&&/^[\\s[]?H/.11(a+"")},4n:H(a){I a.1C&&!a.1c||a.2j&&a.2z&&!a.2z.1c},5u:H(a){a=D.3k(a);G(a){J b=S.3H("6w")[0]||S.1C,1m=S.3h("1m");1m.O="1r/4t";G(D.14.1f)1m.1r=a;N 1m.3U(S.5F(a));b.39(1m,b.1x);b.37(1m)}},Y:H(b,a){I b.Y&&b.Y.2r()==a.2r()},1Y:{},L:H(c,d,b){c=c==1b?5r:c;J a=c[E];G(!a)a=c[E]=++6K;G(d&&!D.1Y[a])D.1Y[a]={};G(b!==12)D.1Y[a][d]=b;I d?D.1Y[a][d]:a},3b:H(c,b){c=c==1b?5r:c;J a=c[E];G(b){G(D.1Y[a]){2U D.1Y[a][b];b="";R(b 1n D.1Y[a])1X;G(!b)D.3b(c)}}N{1U{2U c[E]}1V(e){G(c.5l)c.5l(E)}2U D.1Y[a]}},P:H(d,a,c){J e,i=0,K=d.K;G(c){G(K==12){R(e 1n d)G(a.1w(d[e],c)===Q)1X}N R(;i<K;)G(a.1w(d[i++],c)===Q)1X}N{G(K==12){R(e 1n d)G(a.1k(d[e],e,d[e])===Q)1X}N R(J b=d[0];i<K&&a.1k(b,i,b)!==Q;b=d[++i]){}}I d},1i:H(b,a,c,i,d){G(D.1D(a))a=a.1k(b,i);I a&&a.1q==4L&&c=="2a"&&!6G.11(d)?a+"2X":a},1F:{1e:H(c,b){D.P((b||"").1R(/\\s+/),H(i,a){G(c.16==1&&!D.1F.3T(c.1F,a))c.1F+=(c.1F?" ":"")+a})},21:H(c,b){G(c.16==1)c.1F=b!=12?D.3C(c.1F.1R(/\\s+/),H(a){I!D.1F.3T(b,a)}).6s(" "):""},3T:H(b,a){I D.2L(a,(b.1F||b).6r().1R(/\\s+/))>-1}},6q:H(b,c,a){J e={};R(J d 1n c){e[d]=b.V[d];b.V[d]=c[d]}a.1k(b);R(J d 1n c)b.V[d]=e[d]},1g:H(d,e,c){G(e=="2h"||e=="1Z"){J b,3X={30:"5x",5g:"1G",18:"3I"},35=e=="2h"?["5e","6k"]:["5G","6i"];H 5b(){b=e=="2h"?d.8f:d.8c;J a=0,2C=0;D.P(35,H(){a+=3d(D.2a(d,"57"+7,M))||0;2C+=3d(D.2a(d,"2C"+7+"4b",M))||0});b-=29.83(a+2C)}G(D(d).3F(":4j"))5b();N D.6q(d,3X,5b);I 29.2f(0,b)}I D.2a(d,e,c)},2a:H(f,l,k){J e,V=f.V;H 3E(b){G(!D.14.2k)I Q;J a=3P.54(b,U);I!a||a.52("3E")==""}G(l=="1y"&&D.14.1f){e=D.1K(V,"1y");I e==""?"1":e}G(D.14.2G&&l=="18"){J d=V.50;V.50="0 7Y 7W";V.50=d}G(l.1I(/4i/i))l=y;G(!k&&V&&V[l])e=V[l];N G(3P.54){G(l.1I(/4i/i))l="4i";l=l.1o(/([A-Z])/g,"-$1").3y();J c=3P.54(f,U);G(c&&!3E(f))e=c.52(l);N{J g=[],2E=[],a=f,i=0;R(;a&&3E(a);a=a.1d)2E.6h(a);R(;i<2E.K;i++)G(3E(2E[i])){g[i]=2E[i].V.18;2E[i].V.18="3I"}e=l=="18"&&g[2E.K-1]!=U?"2F":(c&&c.52(l))||"";R(i=0;i<g.K;i++)G(g[i]!=U)2E[i].V.18=g[i]}G(l=="1y"&&e=="")e="1"}N G(f.4g){J h=l.1o(/\\-(\\w)/g,H(a,b){I b.2r()});e=f.4g[l]||f.4g[h];G(!/^\\d+(2X)?$/i.11(e)&&/^\\d/.11(e)){J j=V.1A,66=f.65.1A;f.65.1A=f.4g.1A;V.1A=e||0;e=V.aM+"2X";V.1A=j;f.65.1A=66}}I e},4h:H(l,h){J k=[];h=h||S;G(1j h.3h==\'12\')h=h.2z||h[0]&&h[0].2z||S;D.P(l,H(i,d){G(!d)I;G(d.1q==4L)d+=\'\';G(1j d=="23"){d=d.1o(/(<(\\w+)[^>]*?)\\/>/g,H(b,a,c){I c.1I(/^(aK|4f|7E|aG|4T|7A|aB|3n|az|ay|av)$/i)?b:a+"></"+c+">"});J f=D.3k(d).3y(),1v=h.3h("1v");J e=!f.1h("<au")&&[1,"<2A 7w=\'7w\'>","</2A>"]||!f.1h("<ar")&&[1,"<7v>","</7v>"]||f.1I(/^<(aq|22|am|ak|ai)/)&&[1,"<1T>","</1T>"]||!f.1h("<4F")&&[2,"<1T><22>","</22></1T>"]||(!f.1h("<af")||!f.1h("<ad"))&&[3,"<1T><22><4F>","</4F></22></1T>"]||!f.1h("<7E")&&[2,"<1T><22></22><7q>","</7q></1T>"]||D.14.1f&&[1,"1v<1v>","</1v>"]||[0,"",""];1v.4H=e[1]+d+e[2];1B(e[0]--)1v=1v.5T;G(D.14.1f){J g=!f.1h("<1T")&&f.1h("<22")<0?1v.1x&&1v.1x.3t:e[1]=="<1T>"&&f.1h("<22")<0?1v.3t:[];R(J j=g.K-1;j>=0;--j)G(D.Y(g[j],"22")&&!g[j].3t.K)g[j].1d.37(g[j]);G(/^\\s/.11(d))1v.39(h.5F(d.1I(/^\\s*/)[0]),1v.1x)}d=D.2d(1v.3t)}G(d.K===0&&(!D.Y(d,"3V")&&!D.Y(d,"2A")))I;G(d[0]==12||D.Y(d,"3V")||d.15)k.1p(d);N k=D.2R(k,d)});I k},1K:H(d,f,c){G(!d||d.16==3||d.16==8)I 12;J e=!D.4n(d),40=c!==12,1f=D.14.1f;f=e&&D.3X[f]||f;G(d.2j){J g=/5Q|4d|V/.11(f);G(f=="2W"&&D.14.2k)d.1d.64;G(f 1n d&&e&&!g){G(40){G(f=="O"&&D.Y(d,"4T")&&d.1d)7p"O a3 a1\'t 9V 9U";d[f]=c}G(D.Y(d,"3V")&&d.7i(f))I d.7i(f).76;I d[f]}G(1f&&e&&f=="V")I D.1K(d.V,"9T",c);G(40)d.9Q(f,""+c);J h=1f&&e&&g?d.4G(f,2):d.4G(f);I h===U?12:h}G(1f&&f=="1y"){G(40){d.6B=1;d.1E=(d.1E||"").1o(/7f\\([^)]*\\)/,"")+(3r(c)+\'\'=="9L"?"":"7f(1y="+c*7a+")")}I d.1E&&d.1E.1h("1y=")>=0?(3d(d.1E.1I(/1y=([^)]*)/)[1])/7a)+\'\':""}f=f.1o(/-([a-z])/9H,H(a,b){I b.2r()});G(40)d[f]=c;I d[f]},3k:H(a){I(a||"").1o(/^\\s+|\\s+$/g,"")},2d:H(b){J a=[];G(b!=U){J i=b.K;G(i==U||b.1R||b.4I||b.1k)a[0]=b;N 1B(i)a[--i]=b[i]}I a},2L:H(b,a){R(J i=0,K=a.K;i<K;i++)G(a[i]===b)I i;I-1},2R:H(a,b){J i=0,T,2S=a.K;G(D.14.1f){1B(T=b[i++])G(T.16!=8)a[2S++]=T}N 1B(T=b[i++])a[2S++]=T;I a},4r:H(a){J c=[],2o={};1U{R(J i=0,K=a.K;i<K;i++){J b=D.L(a[i]);G(!2o[b]){2o[b]=M;c.1p(a[i])}}}1V(e){c=a}I c},3C:H(c,a,d){J b=[];R(J i=0,K=c.K;i<K;i++)G(!d!=!a(c[i],i))b.1p(c[i]);I b},2l:H(d,a){J c=[];R(J i=0,K=d.K;i<K;i++){J b=a(d[i],i);G(b!=U)c[c.K]=b}I c.7d.1w([],c)}});J v=9B.9A.3y();D.14={5B:(v.1I(/.+(?:9y|9x|9w|9v)[\\/: ]([\\d.]+)/)||[])[1],2k:/75/.11(v),2G:/2G/.11(v),1f:/1f/.11(v)&&!/2G/.11(v),42:/42/.11(v)&&!/(9s|75)/.11(v)};J y=D.14.1f?"7o":"72";D.1l({71:!D.14.1f||S.70=="6Z",3X:{"R":"9n","9k":"1F","4i":y,72:y,7o:y,9h:"9f",9e:"9d",9b:"99"}});D.P({6W:H(a){I a.1d},97:H(a){I D.4S(a,"1d")},95:H(a){I D.3a(a,2,"2H")},91:H(a){I D.3a(a,2,"4l")},8Z:H(a){I D.4S(a,"2H")},8X:H(a){I D.4S(a,"4l")},8W:H(a){I D.5v(a.1d.1x,a)},8V:H(a){I D.5v(a.1x)},6Q:H(a){I D.Y(a,"8U")?a.8T||a.8S.S:D.2d(a.3t)}},H(c,d){D.17[c]=H(b){J a=D.2l(7,d);G(b&&1j b=="23")a=D.3g(b,a);I 7.2I(D.4r(a))}});D.P({6P:"3v",8Q:"6F",39:"6E",8P:"5q",8O:"7b"},H(c,b){D.17[c]=H(){J a=19;I 7.P(H(){R(J i=0,K=a.K;i<K;i++)D(a[i])[b](7)})}});D.P({8N:H(a){D.1K(7,a,"");G(7.16==1)7.5l(a)},8M:H(a){D.1F.1e(7,a)},8L:H(a){D.1F.21(7,a)},8K:H(a){D.1F[D.1F.3T(7,a)?"21":"1e"](7,a)},21:H(a){G(!a||D.1E(a,[7]).r.K){D("*",7).1e(7).P(H(){D.W.21(7);D.3b(7)});G(7.1d)7.1d.37(7)}},4E:H(){D(">*",7).21();1B(7.1x)7.37(7.1x)}},H(a,b){D.17[a]=H(){I 7.P(b,19)}});D.P(["6N","4b"],H(i,c){J b=c.3y();D.17[b]=H(a){I 7[0]==1b?D.14.2G&&S.1c["5t"+c]||D.14.2k&&1b["5s"+c]||S.70=="6Z"&&S.1C["5t"+c]||S.1c["5t"+c]:7[0]==S?29.2f(29.2f(S.1c["4y"+c],S.1C["4y"+c]),29.2f(S.1c["2i"+c],S.1C["2i"+c])):a==12?(7.K?D.1g(7[0],b):U):7.1g(b,a.1q==56?a:a+"2X")}});H 25(a,b){I a[0]&&3r(D.2a(a[0],b,M),10)||0}J C=D.14.2k&&3r(D.14.5B)<8H?"(?:[\\\\w*3m-]|\\\\\\\\.)":"(?:[\\\\w\\8F-\\8E*3m-]|\\\\\\\\.)",6L=2B 4v("^>\\\\s*("+C+"+)"),6J=2B 4v("^("+C+"+)(#)("+C+"+)"),6I=2B 4v("^([#.]?)("+C+"*)");D.1l({6H:{"":H(a,i,m){I m[2]=="*"||D.Y(a,m[2])},"#":H(a,i,m){I a.4G("2v")==m[2]},":":{8D:H(a,i,m){I i<m[3]-0},8C:H(a,i,m){I i>m[3]-0},3a:H(a,i,m){I m[3]-0==i},79:H(a,i,m){I m[3]-0==i},3o:H(a,i){I i==0},3S:H(a,i,m,r){I i==r.K-1},6D:H(a,i){I i%2==0},6C:H(a,i){I i%2},"3o-4u":H(a){I a.1d.3H("*")[0]==a},"3S-4u":H(a){I D.3a(a.1d.5T,1,"4l")==a},"8z-4u":H(a){I!D.3a(a.1d.5T,2,"4l")},6W:H(a){I a.1x},4E:H(a){I!a.1x},8y:H(a,i,m){I(a.6O||a.8x||D(a).1r()||"").1h(m[3])>=0},4j:H(a){I"1G"!=a.O&&D.1g(a,"18")!="2F"&&D.1g(a,"5g")!="1G"},1G:H(a){I"1G"==a.O||D.1g(a,"18")=="2F"||D.1g(a,"5g")=="1G"},8w:H(a){I!a.3R},3R:H(a){I a.3R},4J:H(a){I a.4J},2W:H(a){I a.2W||D.1K(a,"2W")},1r:H(a){I"1r"==a.O},5O:H(a){I"5O"==a.O},5L:H(a){I"5L"==a.O},5p:H(a){I"5p"==a.O},3Q:H(a){I"3Q"==a.O},5o:H(a){I"5o"==a.O},6A:H(a){I"6A"==a.O},6z:H(a){I"6z"==a.O},2s:H(a){I"2s"==a.O||D.Y(a,"2s")},4T:H(a){I/4T|2A|6y|2s/i.11(a.Y)},3T:H(a,i,m){I D.2q(m[3],a).K},8t:H(a){I/h\\d/i.11(a.Y)},8s:H(a){I D.3C(D.3O,H(b){I a==b.T}).K}}},6x:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,2B 4v("^([:.#]*)("+C+"+)")],3g:H(a,c,b){J d,1t=[];1B(a&&a!=d){d=a;J f=D.1E(a,c,b);a=f.t.1o(/^\\s*,\\s*/,"");1t=b?c=f.r:D.2R(1t,f.r)}I 1t},2q:H(t,o){G(1j t!="23")I[t];G(o&&o.16!=1&&o.16!=9)I[];o=o||S;J d=[o],2o=[],3S,Y;1B(t&&3S!=t){J r=[];3S=t;t=D.3k(t);J l=Q,3j=6L,m=3j.2D(t);G(m){Y=m[1].2r();R(J i=0;d[i];i++)R(J c=d[i].1x;c;c=c.2H)G(c.16==1&&(Y=="*"||c.Y.2r()==Y))r.1p(c);d=r;t=t.1o(3j,"");G(t.1h(" ")==0)6M;l=M}N{3j=/^([>+~])\\s*(\\w*)/i;G((m=3j.2D(t))!=U){r=[];J k={};Y=m[2].2r();m=m[1];R(J j=0,3i=d.K;j<3i;j++){J n=m=="~"||m=="+"?d[j].2H:d[j].1x;R(;n;n=n.2H)G(n.16==1){J g=D.L(n);G(m=="~"&&k[g])1X;G(!Y||n.Y.2r()==Y){G(m=="~")k[g]=M;r.1p(n)}G(m=="+")1X}}d=r;t=D.3k(t.1o(3j,""));l=M}}G(t&&!l){G(!t.1h(",")){G(o==d[0])d.4s();2o=D.2R(2o,d);r=d=[o];t=" "+t.6v(1,t.K)}N{J h=6J;J m=h.2D(t);G(m){m=[0,m[2],m[3],m[1]]}N{h=6I;m=h.2D(t)}m[2]=m[2].1o(/\\\\/g,"");J f=d[d.K-1];G(m[1]=="#"&&f&&f.61&&!D.4n(f)){J p=f.61(m[2]);G((D.14.1f||D.14.2G)&&p&&1j p.2v=="23"&&p.2v!=m[2])p=D(\'[@2v="\'+m[2]+\'"]\',f)[0];d=r=p&&(!m[3]||D.Y(p,m[3]))?[p]:[]}N{R(J i=0;d[i];i++){J a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];G(a=="*"&&d[i].Y.3y()=="49")a="3n";r=D.2R(r,d[i].3H(a))}G(m[1]==".")r=D.5m(r,m[2]);G(m[1]=="#"){J e=[];R(J i=0;r[i];i++)G(r[i].4G("2v")==m[2]){e=[r[i]];1X}r=e}d=r}t=t.1o(h,"")}}G(t){J b=D.1E(t,r);d=r=b.r;t=D.3k(b.t)}}G(t)d=[];G(d&&o==d[0])d.4s();2o=D.2R(2o,d);I 2o},5m:H(r,m,a){m=" "+m+" ";J c=[];R(J i=0;r[i];i++){J b=(" "+r[i].1F+" ").1h(m)>=0;G(!a&&b||a&&!b)c.1p(r[i])}I c},1E:H(t,r,h){J d;1B(t&&t!=d){d=t;J p=D.6x,m;R(J i=0;p[i];i++){m=p[i].2D(t);G(m){t=t.8r(m[0].K);m[2]=m[2].1o(/\\\\/g,"");1X}}G(!m)1X;G(m[1]==":"&&m[2]=="4Y")r=62.11(m[3])?D.1E(m[3],r,M).r:D(r).4Y(m[3]);N G(m[1]==".")r=D.5m(r,m[2],h);N G(m[1]=="["){J g=[],O=m[3];R(J i=0,3i=r.K;i<3i;i++){J a=r[i],z=a[D.3X[m[2]]||m[2]];G(z==U||/5Q|4d|2W/.11(m[2]))z=D.1K(a,m[2])||\'\';G((O==""&&!!z||O=="="&&z==m[5]||O=="!="&&z!=m[5]||O=="^="&&z&&!z.1h(m[5])||O=="$="&&z.6v(z.K-m[5].K)==m[5]||(O=="*="||O=="~=")&&z.1h(m[5])>=0)^h)g.1p(a)}r=g}N G(m[1]==":"&&m[2]=="3a-4u"){J e={},g=[],11=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2D(m[3]=="6D"&&"2n"||m[3]=="6C"&&"2n+1"||!/\\D/.11(m[3])&&"8q+"+m[3]||m[3]),3o=(11[1]+(11[2]||1))-0,d=11[3]-0;R(J i=0,3i=r.K;i<3i;i++){J j=r[i],1d=j.1d,2v=D.L(1d);G(!e[2v]){J c=1;R(J n=1d.1x;n;n=n.2H)G(n.16==1)n.4q=c++;e[2v]=M}J b=Q;G(3o==0){G(j.4q==d)b=M}N G((j.4q-d)%3o==0&&(j.4q-d)/3o>=0)b=M;G(b^h)g.1p(j)}r=g}N{J f=D.6H[m[1]];G(1j f=="49")f=f[m[2]];G(1j f=="23")f=6u("Q||H(a,i){I "+f+";}");r=D.3C(r,H(a,i){I f(a,i,m,r)},h)}}I{r:r,t:t}},4S:H(b,c){J a=[],1t=b[c];1B(1t&&1t!=S){G(1t.16==1)a.1p(1t);1t=1t[c]}I a},3a:H(a,e,c,b){e=e||1;J d=0;R(;a;a=a[c])G(a.16==1&&++d==e)1X;I a},5v:H(n,a){J r=[];R(;n;n=n.2H){G(n.16==1&&n!=a)r.1p(n)}I r}});D.W={1e:H(f,i,g,e){G(f.16==3||f.16==8)I;G(D.14.1f&&f.4I)f=1b;G(!g.24)g.24=7.24++;G(e!=12){J h=g;g=7.3M(h,H(){I h.1w(7,19)});g.L=e}J j=D.L(f,"3w")||D.L(f,"3w",{}),1H=D.L(f,"1H")||D.L(f,"1H",H(){G(1j D!="12"&&!D.W.5k)I D.W.1H.1w(19.3L.T,19)});1H.T=f;D.P(i.1R(/\\s+/),H(c,b){J a=b.1R(".");b=a[0];g.O=a[1];J d=j[b];G(!d){d=j[b]={};G(!D.W.2t[b]||D.W.2t[b].4p.1k(f)===Q){G(f.3K)f.3K(b,1H,Q);N G(f.6t)f.6t("4o"+b,1H)}}d[g.24]=g;D.W.26[b]=M});f=U},24:1,26:{},21:H(e,h,f){G(e.16==3||e.16==8)I;J i=D.L(e,"3w"),1L,5i;G(i){G(h==12||(1j h=="23"&&h.8p(0)=="."))R(J g 1n i)7.21(e,g+(h||""));N{G(h.O){f=h.2y;h=h.O}D.P(h.1R(/\\s+/),H(b,a){J c=a.1R(".");a=c[0];G(i[a]){G(f)2U i[a][f.24];N R(f 1n i[a])G(!c[1]||i[a][f].O==c[1])2U i[a][f];R(1L 1n i[a])1X;G(!1L){G(!D.W.2t[a]||D.W.2t[a].4A.1k(e)===Q){G(e.6p)e.6p(a,D.L(e,"1H"),Q);N G(e.6n)e.6n("4o"+a,D.L(e,"1H"))}1L=U;2U i[a]}}})}R(1L 1n i)1X;G(!1L){J d=D.L(e,"1H");G(d)d.T=U;D.3b(e,"3w");D.3b(e,"1H")}}},1P:H(h,c,f,g,i){c=D.2d(c);G(h.1h("!")>=0){h=h.3s(0,-1);J a=M}G(!f){G(7.26[h])D("*").1e([1b,S]).1P(h,c)}N{G(f.16==3||f.16==8)I 12;J b,1L,17=D.1D(f[h]||U),W=!c[0]||!c[0].32;G(W){c.6h({O:h,2J:f,32:H(){},3J:H(){},4C:1z()});c[0][E]=M}c[0].O=h;G(a)c[0].6m=M;J d=D.L(f,"1H");G(d)b=d.1w(f,c);G((!17||(D.Y(f,\'a\')&&h=="4V"))&&f["4o"+h]&&f["4o"+h].1w(f,c)===Q)b=Q;G(W)c.4s();G(i&&D.1D(i)){1L=i.1w(f,b==U?c:c.7d(b));G(1L!==12)b=1L}G(17&&g!==Q&&b!==Q&&!(D.Y(f,\'a\')&&h=="4V")){7.5k=M;1U{f[h]()}1V(e){}}7.5k=Q}I b},1H:H(b){J a,1L,38,5f,4m;b=19[0]=D.W.6l(b||1b.W);38=b.O.1R(".");b.O=38[0];38=38[1];5f=!38&&!b.6m;4m=(D.L(7,"3w")||{})[b.O];R(J j 1n 4m){J c=4m[j];G(5f||c.O==38){b.2y=c;b.L=c.L;1L=c.1w(7,19);G(a!==Q)a=1L;G(1L===Q){b.32();b.3J()}}}I a},6l:H(b){G(b[E]==M)I b;J d=b;b={8o:d};J c="8n 8m 8l 8k 2s 8j 47 5d 6j 5E 8i L 8h 8g 4K 2y 5a 59 8e 8b 58 6f 8a 88 4k 87 86 84 6d 2J 4C 6c O 82 81 35".1R(" ");R(J i=c.K;i;i--)b[c[i]]=d[c[i]];b[E]=M;b.32=H(){G(d.32)d.32();d.80=Q};b.3J=H(){G(d.3J)d.3J();d.7Z=M};b.4C=b.4C||1z();G(!b.2J)b.2J=b.6d||S;G(b.2J.16==3)b.2J=b.2J.1d;G(!b.4k&&b.4K)b.4k=b.4K==b.2J?b.6c:b.4K;G(b.58==U&&b.5d!=U){J a=S.1C,1c=S.1c;b.58=b.5d+(a&&a.2e||1c&&1c.2e||0)-(a.6b||0);b.6f=b.6j+(a&&a.2c||1c&&1c.2c||0)-(a.6a||0)}G(!b.35&&((b.47||b.47===0)?b.47:b.5a))b.35=b.47||b.5a;G(!b.59&&b.5E)b.59=b.5E;G(!b.35&&b.2s)b.35=(b.2s&1?1:(b.2s&2?3:(b.2s&4?2:0)));I b},3M:H(a,b){b.24=a.24=a.24||b.24||7.24++;I b},2t:{27:{4p:H(){55();I},4A:H(){I}},3D:{4p:H(){G(D.14.1f)I Q;D(7).2O("53",D.W.2t.3D.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("53",D.W.2t.3D.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3D";I D.W.1H.1w(7,19)}},3N:{4p:H(){G(D.14.1f)I Q;D(7).2O("51",D.W.2t.3N.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("51",D.W.2t.3N.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3N";I D.W.1H.1w(7,19)}}}};D.17.1l({2O:H(c,a,b){I c=="4X"?7.2V(c,a,b):7.P(H(){D.W.1e(7,c,b||a,b&&a)})},2V:H(d,b,c){J e=D.W.3M(c||b,H(a){D(7).4e(a,e);I(c||b).1w(7,19)});I 7.P(H(){D.W.1e(7,d,e,c&&b)})},4e:H(a,b){I 7.P(H(){D.W.21(7,a,b)})},1P:H(c,a,b){I 7.P(H(){D.W.1P(c,a,7,M,b)})},5C:H(c,a,b){I 7[0]&&D.W.1P(c,a,7[0],Q,b)},2m:H(b){J c=19,i=1;1B(i<c.K)D.W.3M(b,c[i++]);I 7.4V(D.W.3M(b,H(a){7.4Z=(7.4Z||0)%i;a.32();I c[7.4Z++].1w(7,19)||Q}))},7X:H(a,b){I 7.2O(\'3D\',a).2O(\'3N\',b)},27:H(a){55();G(D.2Q)a.1k(S,D);N D.3A.1p(H(){I a.1k(7,D)});I 7}});D.1l({2Q:Q,3A:[],27:H(){G(!D.2Q){D.2Q=M;G(D.3A){D.P(D.3A,H(){7.1k(S)});D.3A=U}D(S).5C("27")}}});J x=Q;H 55(){G(x)I;x=M;G(S.3K&&!D.14.2G)S.3K("69",D.27,Q);G(D.14.1f&&1b==1S)(H(){G(D.2Q)I;1U{S.1C.7V("1A")}1V(3e){3B(19.3L,0);I}D.27()})();G(D.14.2G)S.3K("69",H(){G(D.2Q)I;R(J i=0;i<S.4W.K;i++)G(S.4W[i].3R){3B(19.3L,0);I}D.27()},Q);G(D.14.2k){J a;(H(){G(D.2Q)I;G(S.3f!="68"&&S.3f!="1J"){3B(19.3L,0);I}G(a===12)a=D("V, 7A[7U=7S]").K;G(S.4W.K!=a){3B(19.3L,0);I}D.27()})()}D.W.1e(1b,"43",D.27)}D.P(("7R,7Q,43,85,4y,4X,4V,7P,"+"7O,7N,89,53,51,7M,2A,"+"5o,7L,7K,8d,3e").1R(","),H(i,b){D.17[b]=H(a){I a?7.2O(b,a):7.1P(b)}});J F=H(a,c){J b=a.4k;1B(b&&b!=c)1U{b=b.1d}1V(3e){b=c}I b==c};D(1b).2O("4X",H(){D("*").1e(S).4e()});D.17.1l({67:D.17.43,43:H(g,d,c){G(1j g!=\'23\')I 7.67(g);J e=g.1h(" ");G(e>=0){J i=g.3s(e,g.K);g=g.3s(0,e)}c=c||H(){};J f="2P";G(d)G(D.1D(d)){c=d;d=U}N{d=D.3n(d);f="6g"}J h=7;D.3Y({1a:g,O:f,1O:"2K",L:d,1J:H(a,b){G(b=="1W"||b=="7J")h.2K(i?D("<1v/>").3v(a.4U.1o(/<1m(.|\\s)*?\\/1m>/g,"")).2q(i):a.4U);h.P(c,[a.4U,b,a])}});I 7},aL:H(){I D.3n(7.7I())},7I:H(){I 7.2l(H(){I D.Y(7,"3V")?D.2d(7.aH):7}).1E(H(){I 7.34&&!7.3R&&(7.4J||/2A|6y/i.11(7.Y)||/1r|1G|3Q/i.11(7.O))}).2l(H(i,c){J b=D(7).6e();I b==U?U:b.1q==2p?D.2l(b,H(a,i){I{34:c.34,2x:a}}):{34:c.34,2x:b}}).3p()}});D.P("7H,7G,7F,7D,7C,7B".1R(","),H(i,o){D.17[o]=H(f){I 7.2O(o,f)}});J B=1z();D.1l({3p:H(d,b,a,c){G(D.1D(b)){a=b;b=U}I D.3Y({O:"2P",1a:d,L:b,1W:a,1O:c})},aE:H(b,a){I D.3p(b,U,a,"1m")},aD:H(c,b,a){I D.3p(c,b,a,"3z")},aC:H(d,b,a,c){G(D.1D(b)){a=b;b={}}I D.3Y({O:"6g",1a:d,L:b,1W:a,1O:c})},aA:H(a){D.1l(D.60,a)},60:{1a:5Z.5Q,26:M,O:"2P",2T:0,7z:"4R/x-ax-3V-aw",7x:M,31:M,L:U,5Y:U,3Q:U,4Q:{2N:"4R/2N, 1r/2N",2K:"1r/2K",1m:"1r/4t, 4R/4t",3z:"4R/3z, 1r/4t",1r:"1r/as",4w:"*/*"}},4z:{},3Y:H(s){s=D.1l(M,s,D.1l(M,{},D.60,s));J g,2Z=/=\\?(&|$)/g,1u,L,O=s.O.2r();G(s.L&&s.7x&&1j s.L!="23")s.L=D.3n(s.L);G(s.1O=="4P"){G(O=="2P"){G(!s.1a.1I(2Z))s.1a+=(s.1a.1I(/\\?/)?"&":"?")+(s.4P||"7u")+"=?"}N G(!s.L||!s.L.1I(2Z))s.L=(s.L?s.L+"&":"")+(s.4P||"7u")+"=?";s.1O="3z"}G(s.1O=="3z"&&(s.L&&s.L.1I(2Z)||s.1a.1I(2Z))){g="4P"+B++;G(s.L)s.L=(s.L+"").1o(2Z,"="+g+"$1");s.1a=s.1a.1o(2Z,"="+g+"$1");s.1O="1m";1b[g]=H(a){L=a;1W();1J();1b[g]=12;1U{2U 1b[g]}1V(e){}G(i)i.37(h)}}G(s.1O=="1m"&&s.1Y==U)s.1Y=Q;G(s.1Y===Q&&O=="2P"){J j=1z();J k=s.1a.1o(/(\\?|&)3m=.*?(&|$)/,"$ap="+j+"$2");s.1a=k+((k==s.1a)?(s.1a.1I(/\\?/)?"&":"?")+"3m="+j:"")}G(s.L&&O=="2P"){s.1a+=(s.1a.1I(/\\?/)?"&":"?")+s.L;s.L=U}G(s.26&&!D.4O++)D.W.1P("7H");J n=/^(?:\\w+:)?\\/\\/([^\\/?#]+)/;G(s.1O=="1m"&&O=="2P"&&n.11(s.1a)&&n.2D(s.1a)[1]!=5Z.al){J i=S.3H("6w")[0];J h=S.3h("1m");h.4d=s.1a;G(s.7t)h.aj=s.7t;G(!g){J l=Q;h.ah=h.ag=H(){G(!l&&(!7.3f||7.3f=="68"||7.3f=="1J")){l=M;1W();1J();i.37(h)}}}i.3U(h);I 12}J m=Q;J c=1b.7s?2B 7s("ae.ac"):2B 7r();G(s.5Y)c.6R(O,s.1a,s.31,s.5Y,s.3Q);N c.6R(O,s.1a,s.31);1U{G(s.L)c.4B("ab-aa",s.7z);G(s.5S)c.4B("a9-5R-a8",D.4z[s.1a]||"a7, a6 a5 a4 5N:5N:5N a2");c.4B("X-9Z-9Y","7r");c.4B("9W",s.1O&&s.4Q[s.1O]?s.4Q[s.1O]+", */*":s.4Q.4w)}1V(e){}G(s.7m&&s.7m(c,s)===Q){s.26&&D.4O--;c.7l();I Q}G(s.26)D.W.1P("7B",[c,s]);J d=H(a){G(!m&&c&&(c.3f==4||a=="2T")){m=M;G(f){7k(f);f=U}1u=a=="2T"&&"2T"||!D.7j(c)&&"3e"||s.5S&&D.7h(c,s.1a)&&"7J"||"1W";G(1u=="1W"){1U{L=D.6X(c,s.1O,s.9S)}1V(e){1u="5J"}}G(1u=="1W"){J b;1U{b=c.5I("7g-5R")}1V(e){}G(s.5S&&b)D.4z[s.1a]=b;G(!g)1W()}N D.5H(s,c,1u);1J();G(s.31)c=U}};G(s.31){J f=4I(d,13);G(s.2T>0)3B(H(){G(c){c.7l();G(!m)d("2T")}},s.2T)}1U{c.9P(s.L)}1V(e){D.5H(s,c,U,e)}G(!s.31)d();H 1W(){G(s.1W)s.1W(L,1u);G(s.26)D.W.1P("7C",[c,s])}H 1J(){G(s.1J)s.1J(c,1u);G(s.26)D.W.1P("7F",[c,s]);G(s.26&&!--D.4O)D.W.1P("7G")}I c},5H:H(s,a,b,e){G(s.3e)s.3e(a,b,e);G(s.26)D.W.1P("7D",[a,s,e])},4O:0,7j:H(a){1U{I!a.1u&&5Z.9O=="5p:"||(a.1u>=7e&&a.1u<9N)||a.1u==7c||a.1u==9K||D.14.2k&&a.1u==12}1V(e){}I Q},7h:H(a,c){1U{J b=a.5I("7g-5R");I a.1u==7c||b==D.4z[c]||D.14.2k&&a.1u==12}1V(e){}I Q},6X:H(a,c,b){J d=a.5I("9J-O"),2N=c=="2N"||!c&&d&&d.1h("2N")>=0,L=2N?a.9I:a.4U;G(2N&&L.1C.2j=="5J")7p"5J";G(b)L=b(L,c);G(c=="1m")D.5u(L);G(c=="3z")L=6u("("+L+")");I L},3n:H(a){J s=[];G(a.1q==2p||a.5w)D.P(a,H(){s.1p(3u(7.34)+"="+3u(7.2x))});N R(J j 1n a)G(a[j]&&a[j].1q==2p)D.P(a[j],H(){s.1p(3u(j)+"="+3u(7))});N s.1p(3u(j)+"="+3u(D.1D(a[j])?a[j]():a[j]));I s.6s("&").1o(/%20/g,"+")}});D.17.1l({1N:H(c,b){I c?7.2g({1Z:"1N",2h:"1N",1y:"1N"},c,b):7.1E(":1G").P(H(){7.V.18=7.5D||"";G(D.1g(7,"18")=="2F"){J a=D("<"+7.2j+" />").6P("1c");7.V.18=a.1g("18");G(7.V.18=="2F")7.V.18="3I";a.21()}}).3l()},1M:H(b,a){I b?7.2g({1Z:"1M",2h:"1M",1y:"1M"},b,a):7.1E(":4j").P(H(){7.5D=7.5D||D.1g(7,"18");7.V.18="2F"}).3l()},78:D.17.2m,2m:H(a,b){I D.1D(a)&&D.1D(b)?7.78.1w(7,19):a?7.2g({1Z:"2m",2h:"2m",1y:"2m"},a,b):7.P(H(){D(7)[D(7).3F(":1G")?"1N":"1M"]()})},9G:H(b,a){I 7.2g({1Z:"1N"},b,a)},9F:H(b,a){I 7.2g({1Z:"1M"},b,a)},9E:H(b,a){I 7.2g({1Z:"2m"},b,a)},9D:H(b,a){I 7.2g({1y:"1N"},b,a)},9M:H(b,a){I 7.2g({1y:"1M"},b,a)},9C:H(c,a,b){I 7.2g({1y:a},c,b)},2g:H(k,j,i,g){J h=D.77(j,i,g);I 7[h.36===Q?"P":"36"](H(){G(7.16!=1)I Q;J f=D.1l({},h),p,1G=D(7).3F(":1G"),46=7;R(p 1n k){G(k[p]=="1M"&&1G||k[p]=="1N"&&!1G)I f.1J.1k(7);G(p=="1Z"||p=="2h"){f.18=D.1g(7,"18");f.33=7.V.33}}G(f.33!=U)7.V.33="1G";f.45=D.1l({},k);D.P(k,H(c,a){J e=2B D.28(46,f,c);G(/2m|1N|1M/.11(a))e[a=="2m"?1G?"1N":"1M":a](k);N{J b=a.6r().1I(/^([+-]=)?([\\d+-.]+)(.*)$/),2b=e.1t(M)||0;G(b){J d=3d(b[2]),2M=b[3]||"2X";G(2M!="2X"){46.V[c]=(d||1)+2M;2b=((d||1)/e.1t(M))*2b;46.V[c]=2b+2M}G(b[1])d=((b[1]=="-="?-1:1)*d)+2b;e.3G(2b,d,2M)}N e.3G(2b,a,"")}});I M})},36:H(a,b){G(D.1D(a)||(a&&a.1q==2p)){b=a;a="28"}G(!a||(1j a=="23"&&!b))I A(7[0],a);I 7.P(H(){G(b.1q==2p)A(7,a,b);N{A(7,a).1p(b);G(A(7,a).K==1)b.1k(7)}})},9X:H(b,c){J a=D.3O;G(b)7.36([]);7.P(H(){R(J i=a.K-1;i>=0;i--)G(a[i].T==7){G(c)a[i](M);a.7n(i,1)}});G(!c)7.5A();I 7}});J A=H(b,c,a){G(b){c=c||"28";J q=D.L(b,c+"36");G(!q||a)q=D.L(b,c+"36",D.2d(a))}I q};D.17.5A=H(a){a=a||"28";I 7.P(H(){J q=A(7,a);q.4s();G(q.K)q[0].1k(7)})};D.1l({77:H(b,a,c){J d=b&&b.1q==a0?b:{1J:c||!c&&a||D.1D(b)&&b,2u:b,41:c&&a||a&&a.1q!=9t&&a};d.2u=(d.2u&&d.2u.1q==4L?d.2u:D.28.5K[d.2u])||D.28.5K.74;d.5M=d.1J;d.1J=H(){G(d.36!==Q)D(7).5A();G(D.1D(d.5M))d.5M.1k(7)};I d},41:{73:H(p,n,b,a){I b+a*p},5P:H(p,n,b,a){I((-29.9r(p*29.9q)/2)+0.5)*a+b}},3O:[],48:U,28:H(b,c,a){7.15=c;7.T=b;7.1i=a;G(!c.3Z)c.3Z={}}});D.28.44={4D:H(){G(7.15.2Y)7.15.2Y.1k(7.T,7.1z,7);(D.28.2Y[7.1i]||D.28.2Y.4w)(7);G(7.1i=="1Z"||7.1i=="2h")7.T.V.18="3I"},1t:H(a){G(7.T[7.1i]!=U&&7.T.V[7.1i]==U)I 7.T[7.1i];J r=3d(D.1g(7.T,7.1i,a));I r&&r>-9p?r:3d(D.2a(7.T,7.1i))||0},3G:H(c,b,d){7.5V=1z();7.2b=c;7.3l=b;7.2M=d||7.2M||"2X";7.1z=7.2b;7.2S=7.4N=0;7.4D();J e=7;H t(a){I e.2Y(a)}t.T=7.T;D.3O.1p(t);G(D.48==U){D.48=4I(H(){J a=D.3O;R(J i=0;i<a.K;i++)G(!a[i]())a.7n(i--,1);G(!a.K){7k(D.48);D.48=U}},13)}},1N:H(){7.15.3Z[7.1i]=D.1K(7.T.V,7.1i);7.15.1N=M;7.3G(0,7.1t());G(7.1i=="2h"||7.1i=="1Z")7.T.V[7.1i]="9m";D(7.T).1N()},1M:H(){7.15.3Z[7.1i]=D.1K(7.T.V,7.1i);7.15.1M=M;7.3G(7.1t(),0)},2Y:H(a){J t=1z();G(a||t>7.15.2u+7.5V){7.1z=7.3l;7.2S=7.4N=1;7.4D();7.15.45[7.1i]=M;J b=M;R(J i 1n 7.15.45)G(7.15.45[i]!==M)b=Q;G(b){G(7.15.18!=U){7.T.V.33=7.15.33;7.T.V.18=7.15.18;G(D.1g(7.T,"18")=="2F")7.T.V.18="3I"}G(7.15.1M)7.T.V.18="2F";G(7.15.1M||7.15.1N)R(J p 1n 7.15.45)D.1K(7.T.V,p,7.15.3Z[p])}G(b)7.15.1J.1k(7.T);I Q}N{J n=t-7.5V;7.4N=n/7.15.2u;7.2S=D.41[7.15.41||(D.41.5P?"5P":"73")](7.4N,n,0,1,7.15.2u);7.1z=7.2b+((7.3l-7.2b)*7.2S);7.4D()}I M}};D.1l(D.28,{5K:{9l:9j,9i:7e,74:9g},2Y:{2e:H(a){a.T.2e=a.1z},2c:H(a){a.T.2c=a.1z},1y:H(a){D.1K(a.T.V,"1y",a.1z)},4w:H(a){a.T.V[a.1i]=a.1z+a.2M}}});D.17.2i=H(){J b=0,1S=0,T=7[0],3q;G(T)ao(D.14){J d=T.1d,4a=T,1s=T.1s,1Q=T.2z,5U=2k&&3r(5B)<9c&&!/9a/i.11(v),1g=D.2a,3c=1g(T,"30")=="3c";G(T.7y){J c=T.7y();1e(c.1A+29.2f(1Q.1C.2e,1Q.1c.2e),c.1S+29.2f(1Q.1C.2c,1Q.1c.2c));1e(-1Q.1C.6b,-1Q.1C.6a)}N{1e(T.5X,T.5W);1B(1s){1e(1s.5X,1s.5W);G(42&&!/^t(98|d|h)$/i.11(1s.2j)||2k&&!5U)2C(1s);G(!3c&&1g(1s,"30")=="3c")3c=M;4a=/^1c$/i.11(1s.2j)?4a:1s;1s=1s.1s}1B(d&&d.2j&&!/^1c|2K$/i.11(d.2j)){G(!/^96|1T.*$/i.11(1g(d,"18")))1e(-d.2e,-d.2c);G(42&&1g(d,"33")!="4j")2C(d);d=d.1d}G((5U&&(3c||1g(4a,"30")=="5x"))||(42&&1g(4a,"30")!="5x"))1e(-1Q.1c.5X,-1Q.1c.5W);G(3c)1e(29.2f(1Q.1C.2e,1Q.1c.2e),29.2f(1Q.1C.2c,1Q.1c.2c))}3q={1S:1S,1A:b}}H 2C(a){1e(D.2a(a,"6V",M),D.2a(a,"6U",M))}H 1e(l,t){b+=3r(l,10)||0;1S+=3r(t,10)||0}I 3q};D.17.1l({30:H(){J a=0,1S=0,3q;G(7[0]){J b=7.1s(),2i=7.2i(),4c=/^1c|2K$/i.11(b[0].2j)?{1S:0,1A:0}:b.2i();2i.1S-=25(7,\'94\');2i.1A-=25(7,\'aF\');4c.1S+=25(b,\'6U\');4c.1A+=25(b,\'6V\');3q={1S:2i.1S-4c.1S,1A:2i.1A-4c.1A}}I 3q},1s:H(){J a=7[0].1s;1B(a&&(!/^1c|2K$/i.11(a.2j)&&D.1g(a,\'30\')==\'93\'))a=a.1s;I D(a)}});D.P([\'5e\',\'5G\'],H(i,b){J c=\'4y\'+b;D.17[c]=H(a){G(!7[0])I;I a!=12?7.P(H(){7==1b||7==S?1b.92(!i?a:D(1b).2e(),i?a:D(1b).2c()):7[c]=a}):7[0]==1b||7[0]==S?46[i?\'aI\':\'aJ\']||D.71&&S.1C[c]||S.1c[c]:7[0][c]}});D.P(["6N","4b"],H(i,b){J c=i?"5e":"5G",4f=i?"6k":"6i";D.17["5s"+b]=H(){I 7[b.3y()]()+25(7,"57"+c)+25(7,"57"+4f)};D.17["90"+b]=H(a){I 7["5s"+b]()+25(7,"2C"+c+"4b")+25(7,"2C"+4f+"4b")+(a?25(7,"6S"+c)+25(7,"6S"+4f):0)}})})();',62,669,'|||||||this|||||||||||||||||||||||||||||||||||if|function|return|var|length|data|true|else|type|each|false|for|document|elem|null|style|event||nodeName|||test|undefined||browser|options|nodeType|fn|display|arguments|url|window|body|parentNode|add|msie|css|indexOf|prop|typeof|call|extend|script|in|replace|push|constructor|text|offsetParent|cur|status|div|apply|firstChild|opacity|now|left|while|documentElement|isFunction|filter|className|hidden|handle|match|complete|attr|ret|hide|show|dataType|trigger|doc|split|top|table|try|catch|success|break|cache|height||remove|tbody|string|guid|num|global|ready|fx|Math|curCSS|start|scrollTop|makeArray|scrollLeft|max|animate|width|offset|tagName|safari|map|toggle||done|Array|find|toUpperCase|button|special|duration|id|copy|value|handler|ownerDocument|select|new|border|exec|stack|none|opera|nextSibling|pushStack|target|html|inArray|unit|xml|bind|GET|isReady|merge|pos|timeout|delete|one|selected|px|step|jsre|position|async|preventDefault|overflow|name|which|queue|removeChild|namespace|insertBefore|nth|removeData|fixed|parseFloat|error|readyState|multiFilter|createElement|rl|re|trim|end|_|param|first|get|results|parseInt|slice|childNodes|encodeURIComponent|append|events|elems|toLowerCase|json|readyList|setTimeout|grep|mouseenter|color|is|custom|getElementsByTagName|block|stopPropagation|addEventListener|callee|proxy|mouseleave|timers|defaultView|password|disabled|last|has|appendChild|form|domManip|props|ajax|orig|set|easing|mozilla|load|prototype|curAnim|self|charCode|timerId|object|offsetChild|Width|parentOffset|src|unbind|br|currentStyle|clean|float|visible|relatedTarget|previousSibling|handlers|isXMLDoc|on|setup|nodeIndex|unique|shift|javascript|child|RegExp|_default|deep|scroll|lastModified|teardown|setRequestHeader|timeStamp|update|empty|tr|getAttribute|innerHTML|setInterval|checked|fromElement|Number|jQuery|state|active|jsonp|accepts|application|dir|input|responseText|click|styleSheets|unload|not|lastToggle|outline|mouseout|getPropertyValue|mouseover|getComputedStyle|bindReady|String|padding|pageX|metaKey|keyCode|getWH|andSelf|clientX|Left|all|visibility|container|index|init|triggered|removeAttribute|classFilter|prevObject|submit|file|after|windowData|inner|client|globalEval|sibling|jquery|absolute|clone|wrapAll|dequeue|version|triggerHandler|oldblock|ctrlKey|createTextNode|Top|handleError|getResponseHeader|parsererror|speeds|checkbox|old|00|radio|swing|href|Modified|ifModified|lastChild|safari2|startTime|offsetTop|offsetLeft|username|location|ajaxSettings|getElementById|isSimple|values|selectedIndex|runtimeStyle|rsLeft|_load|loaded|DOMContentLoaded|clientTop|clientLeft|toElement|srcElement|val|pageY|POST|unshift|Bottom|clientY|Right|fix|exclusive|detachEvent|cloneNode|removeEventListener|swap|toString|join|attachEvent|eval|substr|head|parse|textarea|reset|image|zoom|odd|even|before|prepend|exclude|expr|quickClass|quickID|uuid|quickChild|continue|Height|textContent|appendTo|contents|open|margin|evalScript|borderTopWidth|borderLeftWidth|parent|httpData|setArray|CSS1Compat|compatMode|boxModel|cssFloat|linear|def|webkit|nodeValue|speed|_toggle|eq|100|replaceWith|304|concat|200|alpha|Last|httpNotModified|getAttributeNode|httpSuccess|clearInterval|abort|beforeSend|splice|styleFloat|throw|colgroup|XMLHttpRequest|ActiveXObject|scriptCharset|callback|fieldset|multiple|processData|getBoundingClientRect|contentType|link|ajaxSend|ajaxSuccess|ajaxError|col|ajaxComplete|ajaxStop|ajaxStart|serializeArray|notmodified|keypress|keydown|change|mouseup|mousedown|dblclick|focus|blur|stylesheet|hasClass|rel|doScroll|black|hover|solid|cancelBubble|returnValue|wheelDelta|view|round|shiftKey|resize|screenY|screenX|relatedNode|mousemove|prevValue|originalTarget|offsetHeight|keyup|newValue|offsetWidth|eventPhase|detail|currentTarget|cancelable|bubbles|attrName|attrChange|altKey|originalEvent|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|font|gt|lt|uFFFF|u0128|size|417|Boolean|Date|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|wrap|contentWindow|contentDocument|iframe|children|siblings|prevAll|wrapInner|nextAll|outer|prev|scrollTo|static|marginTop|next|inline|parents|able|cellSpacing|adobeair|cellspacing|522|maxLength|maxlength|readOnly|400|readonly|fast|600|class|slow|1px|htmlFor|reverse|10000|PI|cos|compatible|Function|setData|ie|ra|it|rv|getData|userAgent|navigator|fadeTo|fadeIn|slideToggle|slideUp|slideDown|ig|responseXML|content|1223|NaN|fadeOut|300|protocol|send|setAttribute|option|dataFilter|cssText|changed|be|Accept|stop|With|Requested|Object|can|GMT|property|1970|Jan|01|Thu|Since|If|Type|Content|XMLHTTP|th|Microsoft|td|onreadystatechange|onload|cap|charset|colg|host|tfoot|specified|with|1_|thead|leg|plain|attributes|opt|embed|urlencoded|www|area|hr|ajaxSetup|meta|post|getJSON|getScript|marginLeft|img|elements|pageYOffset|pageXOffset|abbr|serialize|pixelLeft'.split('|'),0,{}));
/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

    /* close wito_useOwnjQuery function; jQuery inlined above */
}

var witoQuery = function(){};
witoQuery.protectedTemp = function() {
    // if no jQuery on the page, fetch our version
    if (!window.jQuery) {
        wito_useOwnjQuery();
        witoQuery = jQuery.noConflict(true);
        // alert('no jQuery, using own');
    } else {
        if (window.jQuery().jquery.replace(/\./ig,"") == 126) {
            // INSERT check for plugins
            if (false) {
                // include missing plugins
            }
            // use version on-the-page
            witoQuery = window.jQuery;
            // alert('using on-the-page version');
        } else {
            // store their version
            var userjQuery = jQuery;
            var userDollar = null;
            if (window.$) userDollar = $;
            // load ours
            witoQuery = jQuery.noConflict(true);
            // restore theirs
            window.jQuery = userjQuery;
            if (userDollar) window.$ = userDollar;
            // alert('preserving user version, using own version');
        }
    }
}

witoQuery.protectedTemp();
/**
 *
 * AjaxUpdate class
 *
 */
witoAjaxUpdateClass = function() {
	// constructor (ajax update)
}


witoAjaxUpdateClass.prototype.init = function(wito, list, action) {
	this.wito = wito;
	this.list = list;
	this.status = this.wito.flag_statusNONE;
	// ref is position in list
	this.ref = this.wito.ref_UNSET;
	this.masterlist = this.wito.ajaxUpdateList;
	// position in masterlist
	this.masterref = this.wito.ref_UNSET;
	// create postObj for building/sending to server
	this.postObj = new Object();
	this.postObj.action = action;
	// concurrency information
	this.delayNoTimes = 0;
	this.delayLastLen = 0;
	// create container for server returned data
	this.retDataObj = null;
	// add to both lists (sets ref, masterref, postobj.update_seq)
	this.masterlist.add(this);
	if (this.list != this.masterlist)
		this.list.add(this);
	// by default, updates are async not locking
	this.locking = false;
}


witoAjaxUpdateClass.prototype.isActive = function() {
	return(!(this.status & this.wito.flag_statusDISCARDED));
}


witoAjaxUpdateClass.prototype.tag = function() {
	// include session basics
	this.postObj.url = this.wito.url;
	// if no domainID defined, put onto test domain
	if (!window.wito_domainID) wito_domainID = 1;
	this.postObj.domain_id = wito_domainID;
	// append cookie if cookie attached to sessionList
	if (this.wito.sessionList) {
		if (this.wito.sessionList.cookie) {
			this.postObj.cookie = this.wito.sessionList.cookie;
			// this.debug('sending cookie with request: '+postObj.cookie);
		}
	}
	// append cookie to request only is using cookies
	if (this.wito.cookie_useCookie) {
		upd.postObj.cookie = this.wito.cookie(this.wito.cookie_NAME);
	}
	// tag this request with time dispatched
	var d = new Date();
	var msnow = d.getTime();
	// tag this request with additional data (local time, version, hash, aggregate)
	this.postObj.version_embed = this.wito.version;
	this.postObj.time_dispatched = msnow;
	if (this.wito.hash) {
		// some requests are sent before startup/hashing complete
		this.postObj.top__hval = this.wito.hash.hval;
		this.postObj.top__hchild = this.wito.hash.hchild;
	}
}


witoAjaxUpdateClass.prototype.send = function() {
	// check local updateList for exact duplicates
	if (this.list != this.masterlist) {
		if (this.list.isExactDuplicate(this)) {
			// don't send, now or later, instead delete from lists
			this.masterlist.remove(this);
			this.list.remove(this);
			return;
		}
	}
	// find out if another update is pending on this object
	if ((!this.locking) && (this.list.parent.isLocked(this.wito.lockType_toForeignForSERVER))) {
		// buffer if locked
		this.status = this.wito.flag_statusPENDING;
	} else {
		// fire if locking or unlocked
		this.fire();
	}
}


witoAjaxUpdateClass.prototype.fire = function() {
	// fire post
	this.status = this.wito.flag_statusSENDING;
	this.tag();
	var postUrl = this.wito.protocol + this.wito.serverName + this.wito.serverReceiver + 'type=js&';
	postUrl += this.wito.__object_toURL(this.postObj);
	this.wito.attach_javascript(postUrl, this.event_callback(this), null);
}


witoAjaxUpdateClass.prototype.ajaxJson_set_data = function(ret) {
	this.retDataObj = ret;
	// this.wito.debug('retDataObj set for upd '+this.masterref);
}


witoAjaxUpdateClass.prototype.callback_get_data = function() {
	// now a local object to protect concurrent execution
	var k = this.retDataObj;
	// this.wito.debug('retDataObj retreived for upd '+this.masterref);
	// destroy object reference so we can't do multiple callbacks
	this.retDataObj = null;
	return(k);
}


witoAjaxUpdateClass.prototype.event_callback = function(context) {
	return( function() {
		context.pre_callback();
	});
}


witoAjaxUpdateClass.prototype.pre_callback = function() {
	var rdo = this.callback_get_data();
	if (!this.isActive()) {
		// ignore this callback
	}
	else if ((!rdo) || (this.masterlist.isLocked())) {
		// delay the processing of this callback by a short time
		if (this.delayNoTimes == 0) {
			this.delayLastLen = this.wito.delay_processCALLBACK + Math.floor(Math.random() * this.wito.delay_processCALLBACK);
		} else {
			this.delayLastLen *= 2;
		}
		this.delayNoTimes++;
		this.wito.debug('delayed update '+this.masterref+' by '+this.delayLastLen+'ms.');
		setTimeout(this.event_callback(this),this.delayLastLen);
	} else {
		this.callback(rdo);
	}
}


witoAjaxUpdateClass.prototype.callback = function(rdo) {
	this.masterlist.lock();
	if (rdo.errorcode) {
		// if error returned, report
		this.wito.error('Error ('+rdo.errorcode+'): '+rdo.message);
	}
	else {
		// check and action operation success flag, if defined/required
		if (rdo.saveSuccess) {
			switch(rdo.saveSuccess) {
				case this.save_SUCCESS :
					// no action required
					break;
				case this.save_PENDING :
					// wait
					break;
				case this.save_FAIL :
					// notify user
					break;
			}
		}
		// flag request as acknowledged/received back
		this.status = this.wito.flag_statusRCVDBACK;
		// remove from lists
		this.masterlist.remove(this);
		if (this.list != this.masterlist)
			this.list.remove(this);
		// process load additionals
		if (rdo.loadjs) {
			var jsbase = this.wito.page_getAssetPath();
			for (var i=0 ; i<rdo.loadjs.length ; ++i) {
				this.wito.attach_javascript(jsbase + 'js/' + rdo.loadjs[i]);
			}
		}
		// process server updates (e.g. re-ref) (should unlock object if locked)
		if (rdo[this.wito.server_side_updatedObject_NAME]) {
			// work through each of the properties and apply to the local object
			this.list.processServerChanges(rdo[this.wito.server_side_updatedObject_NAME]);
		}
		// if this was a locking update, now we can unlock
		if (this.locking) {
			this.list.parent.unlock(this.wito.lockType_toForeignForSERVER);			
			// trigger next update if any for this object (this.list not master)
			this.list.next();
		}
		// callback function if set
		if (this.postObj.callback) {
			this.postObj.callback(rdo);
		}
		// process foreign updates (if not already processed by callback)
		if (rdo[this.wito.server_side_sessionList_NAME]) {
			this.wito.sessionList.compare(rdo[this.wito.server_side_sessionList_NAME]);
			this.wito.intUpdQueue.process();
		}
		// process notifications
		if (rdo[this.wito.server_side_notList_NAME]) {
			this.wito.toolbox.notifier.recv_nots(rdo[this.wito.server_side_notList_NAME]);
		}
		// schedule next heartbeat if set (0 means cancel)
		if (rdo.timetobeat) {
			this.wito.heartbeat.schedule(rdo.timetobeat);
		} else {
			this.wito.heartbeat.cancel();
		}
	}
	this.masterlist.unlock();
}


witoAjaxUpdateClass.prototype.getInner = function() {
	var list = ['post','thread','session'];
	for(field in list) {
		if (this.postObj[list[field]]) {
			return(list[field]);
		}
	}
}


witoAjaxUpdateClass.prototype.processServerChanges = function(changes) {
	var inner = this.getInner();
	for(name in changes) {
		var pi = this.postObj[inner];
		if (pi[name]) {
			pi[name] = changes[name];
		}
		// this.wito.debug('updated '+name+'='+pi[name]+' in '+inner);
	}
}


witoAjaxUpdateClass.prototype.receiver = function(ret) {
	this.ajaxJson_set_data(ret);
}

/**
 *
 * AjaxUpdateList class
 *
 */
witoAjaxUpdateListClass = function() {
	// constructor (ajax update list)
}


witoAjaxUpdateListClass.prototype.init = function(wito, obj) {
	this.wito = wito;
	this.parent = obj;
	this.list = new Array();
	this.list.length = 0;
	this.total = 0;
	this.locked = false;
	this.seqCounter = 0;
}


witoAjaxUpdateListClass.prototype.count = function() {
	return(this.total);
}


witoAjaxUpdateListClass.prototype.lock = function() {
	this.locked = true;
}


witoAjaxUpdateListClass.prototype.unlock = function() {
	this.locked = false;
}


witoAjaxUpdateListClass.prototype.isLocked = function() {
	return(this.locked == true);
}


witoAjaxUpdateListClass.prototype.add = function(upd) {
	// attach sequence number and store this post object
	var ref = this.list.length;
	var isMaster = (this == this.wito.ajaxUpdateList);
	if (isMaster) {
		upd.masterref = ref;
		upd.postObj.update_ref = ref;
		upd.postObj.update_seq = this.nextSeq();
	} else {
		upd.ref = ref;
	}
	// record object in sequence array
	this.list[ref] = upd;
	this.total++;
	// if (isMaster) { this.wito.debug('added'+(isMaster?' [to MASTER '+upd.masterref+']':'')+': '+this.wito.__objectToString(this)); }
}


witoAjaxUpdateListClass.prototype.remove = function(upd) {
	var ref;
	var isMaster = (this == this.wito.ajaxUpdateList);
	if (isMaster) {
		ref = upd.masterref;
	} else {
		ref = upd.ref;
	}
	// flag request as 'resolved' in update queue
	this.list[ref] = null;
	// collapse list back if empty
	var collapsePoint = -1;
	// find last valid value
	for (var i=0 ; i<this.list.length ; ++i) {
		if (this.list[i] != null)
			collapsePoint = i;
	}
	this.list.length = collapsePoint+1;
	// this.debug(this.__arrayToString(this.list));
	this.total--;
	// if (isMaster) { this.wito.debug('removed'+(isMaster?' [from MASTER]':'')+': '+this.wito.__objectToString(this)); }
}


witoAjaxUpdateListClass.prototype.next = function() {
	for (var i=0 ; i<this.list.length ; ++i) {
		var upd = this.list[i];
		// skip blank entries in sparse array
		if (upd == null) continue;
		// find next pending update
		if (upd.status == this.wito.flag_statusPENDING) {
			upd.fire();
		}
		// this.wito.debug(this.wito.__objectToString(upd));
	}
}


witoAjaxUpdateListClass.prototype.nextSeq = function() {
	return(this.seqCounter++);
}


witoAjaxUpdateListClass.prototype.processServerChanges = function(changes) {
	// apply to parent
	this.parent.processServerChanges(changes);
	// apply to statusPENDING updates
	for (var i=0 ; i<this.list.length ; ++i) {
		var upd = this.list[i];
		// skip blank entries in sparse array
		if (upd == null) continue;
		// find pending updates
		if (upd.status == this.wito.flag_statusPENDING) {
			upd.processServerChanges(changes);
		}
	}
}


witoAjaxUpdateListClass.prototype.isExactDuplicate = function(dup) {
	for (var i=0 ; i<this.list.length ; ++i) {
		var upd = this.list[i];
		// skip blank entries in sparse array
		if (upd == null) continue;
		// skip self
		if (upd.masterref == dup.masterref) continue;
		// match a basic set of fast-check outer attributes
		if (upd.postObj.action == dup.postObj.action) {
			var inner = upd.getInner();
			// check that both objects have the same inner
			if (!dup.postObj[inner]) continue;
			// compare all the fields (slow)
			var res = this.isExactDuplicateCompareObject(upd.postObj[inner], dup.postObj[inner]);
			return(res);
		}
	}
	return(false);
}


witoAjaxUpdateListClass.prototype.isExactDuplicateCompareObject = function(a,b) {
	// match the refs
	if (a.ref != b.ref) return(false);
	// match the update hashes
	if (a.hupd != b.hupd) return(false);
	// field by field comparison
	for(field in a) {
		// ignore hash fields
		if (field.indexOf('hval') != -1) continue;
		if (field.indexOf('hchild') != -1) continue;
		// recurse into subobjects
		if (typeof(a[field]) == 'object') {
			var res = this.isExactDuplicateCompareObject(a[field], b[field]);
			if (!res) return(false);
		} else {
			// compare fields
			if (a[field] != b[field]) {
				// this.wito.debug(field + ' is different: '+a[field]+' as opposed to '+b[field]);
				return(false);
			}
		}
	}
	// this.wito.debug('comparing '+this.wito.__objectToString(a)+"\r\nwith\r\n\r\n"+this.wito.__objectToString(b));
	return(true);
}


witoAjaxUpdateListClass.prototype.receiver = function(retDataObj) {
	// use updateSeq to find the right update, reref-aware
	var matched = false;
	for (var i=retDataObj.update_ref ; i<this.list.length ; ++i) {
		var upd = this.list[i];
		if (upd == null) continue;
		// check that the update sequences match
		if (upd.postObj.update_seq == retDataObj.update_seq) {
			matched = true;
			upd.receiver(retDataObj);
		}
	}
	if (!matched) {
		this.wito.debug('Attempt to reconcile update (seq '+retDataObj.update_seq+') was unsuccessful.');
	}
}

/**
 * witoClass
 * - blueprint for witoGlobal
 *
 */
function witoClass() {
	// constructor is empty
	// - because it can't access 'this'
}


witoClass.prototype.init = function() {
    // don't initialise if we're in library mode
	if (!window.wito_domainID) return;
	// pre-requisites: none
	this.init_constants();
	this.init_vars();
	// [debug, optionally] delete thinker cookie
	// this.cookie(this.cookie_NAME, '', -1);
	// connect to wito server
	this.init_server();
	this.init_page();
	// pre-requisites: must have called init_server
	// branch-point: init_styles forks execution
	this.init_styles();
	this.init_ajax();
	this.init_toolbox();
	this.init_sitebox();
    // don't show toolbox until init event returns
}


// deprecated
witoClass.prototype.init_witoQuery = function() {
    return;
	var version = witoQuery().jquery;
	var vnum = parseInt(version.replace(/\./ig,""));
	// check equivalency to jquery 1.2.6
	if (vnum < 126) {
		// default to witoQuery substitute
		witoQuery = witoQueryClass;
		// this.debug('Your version of jQuery needs to be 1.2.6 or later.  Reverting to witoQuery substitute.');
	}
}


witoClass.prototype.init_vars = function() {
    // filter url (remove wito reference if attached)
	var urlnohash = location.href.replace(/(witoqref=([^\&^\#]*)\&*)+/ig,"");
    /** Regex tests (http://www.regextester.com/) (witoqref=([^\&^\#]*)\&*)+
            something?jim=9&witoqref=jack&jill=2
            something?witoqref=jack&jill=2
            something?witoqref=jack#10
            something?else
            something?witoqref=jack
            end
    **/
	// strip trailing /,&,? or # from URL
    urlnohash = urlnohash.replace(/(\#|\?|\&|\/)+$/ig,"");
    /** Regex tests (http://www.regextester.com/) (\#|\?|\&|\/)+$
            #something
            something#?
            something#fred
            something?
            something?#fred
            something?&
            something?&k=2
            something/
            something/#fred
            something/fred
            something?j=1&k=2#fred

    **/
	this.url = escape(urlnohash);
	// session vars initialised in session_init
	this.feedback_visible = true;
	this.serverName = '';
	this.page = null;
	// pre-init, don't know if we can communicate with server yet
	this.online = this.status_DONTKNOW;
	// set unknown debugging status
	this.DEBUG_LOSEC = this.ref_UNSET;
	// initialise pacemaker
	this.heartbeat = new witoHeartbeatClass();
	this.heartbeat.init(this);
	// initialise update queue
	this.intUpdQueue = new witoInterfaceUpdateQueue();
	this.intUpdQueue.init(this);
    // assume don't show toolbox
    // overriden by site (thinko), session with threads
   	this.showToolbox = false;
}


witoClass.prototype.init_constants = function() {
	// internal
	this.valid = 0xC0FFEE;
	this.version = 108003; // V.XX.YYY

	// globals
	this.scriptName = 'wito_embed';
	// use Drupal receiver
	// this.serverReceiver = '/index.php?q=wito_receiver&';
	// use fielder receiver (only partial Drupal bootstrap)
	this.serverReceiver = '/wito_receiver.php?';
	this.rcvAlias = '/sites/all/modules/wito6/receiver';
	this.threadBaseID = 'wito_threadBase';
	this.pageLinkClass = 'wito_embed_link';

	/**
	 * Constants
	 * - duplicated server side
	 */

	// constants (general)
	this.ref_UNSET = -1;

	// constants (status)
	this.status_ONLINE = 1;
	this.status_OFFLINE = 0;
	this.status_DONTKNOW = 2;

	// constants (times in ms)
	this.delay_processCALLBACK = 200;
	this.delay_discardUPDATE = 20000;
	this.delay_fadeAwayTEXT = 800;

	// constants (hashing)
	this.hash_tableCRC	     = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D"; 
	this.hash_fieldsTOP	     = null;
	this.hash_fieldsSESSION  = ['data'];
	this.hash_fieldsTHREAD   = ['data','left','top','width','height','flagdisp','minishape','colour','z'];
	this.hash_fieldsPOST	 = ['data','flagdisp'];

    // constants (url)
    this.url_refNAME         = 'witoqref';
    this.url_fieldsSEPARATOR = ',';

	// object whitelists
	this.fieldlist_objectDOCUMENT = ['referrer','compatMode'];
	this.fieldlist_objectNAVIGATOR = ['userAgent','appVersion','appName'];

	// constants (locking)
	this.lockType_toLocalForFOREIGN  = 0x0001;
	this.lockType_toForeignForLOCAL  = 0x0002;
	this.lockType_toForeignForSERVER = 0x0004;
	this.lockType_toForeign		  = this.lockType_toForeignForLOCAL | this.lockType_toForeignForSERVER;

	// constants (flag)
	this.flag_BASE = 0x00000000;

	// send flags
	this.flag_statusNONE	   = 0x00000000;
	this.flag_statusPENDING	= 0x00000001;
	this.flag_statusSENDING	= 0x00000004;
	this.flag_statusSENT	   = 0x00000008;
	this.flag_statusFAILED	 = 0x00000010;
	this.flag_statusRCVDBACK   = 0x00000020;
	this.flag_statusDISCARDED  = 0x00000040;

	// action targets
	this.flag_targetMASK	   = 0x0000F000;
	this.flag_targetSERVER	 = this.flag_BASE;
	this.flag_targetTHREAD	 = 0x00001000;
	this.flag_targetPOST	   = 0x00002000;
	this.flag_targetSESSION	= 0x00004000;

	/**
	 * action and edit (actionable) flags
	 * + shares mask with action targets
	 */
	this.flag_actionMASK			 = 0x7FFF0FFF;
	this.flag_actionNONE			 = 0x00000000;
	this.flag_actionUNCONFDEL		= 0x00000001;
	this.flag_actionEDIT			 = 0x00000002;
	this.flag_actionAPPEND		   = 0x00000004; // implemented using actionNEW on child
	this.flag_actionMOVE			 = 0x00000008;
	this.flag_actionDELETE		   = 0x00000010;
	this.flag_actionMINIMISE_RESTORE = 0x00000020;
	this.flag_actionCOLCHANGE		= 0x00000040;
	this.flag_actionCONFDEL		  = 0x00000080;
	this.flag_actionRESIZE		   = 0x00000100;
	this.flag_actionSELECT		   = 0x00000200;
	this.flag_actionHIDE			 = 0x00000400;
	this.flag_actionSHOW			 = 0x00000800;
	this.flag_actionGET			  = 0x00010000;
	this.flag_actionUPDATEALL		= this.flag_actionMASK;
	this.flag_actionNEW			  = this.flag_actionUPDATEALL;
	this.flag_actionSRVREHASH		= this.flag_actionMASK ^ 0x40000000;
	this.flag_actionNEW			  = this.flag_actionMASK ^ 0x20000000;

	/**
	 * display flags
	 * + independent domain
	 */
	this.flag_displayMASK	  = this.flag_actionMASK; // for no real reason
	this.flag_displayNONE	  = this.flag_displayMASK; // hidden
	this.flag_displayVISIBLE   = 0x00000001;
	this.flag_displayDELETED   = 0x00000010;
	this.flag_displayMINIMISED = 0x00000040;
	this.flag_displayCONFDEL   = 0x00000080;
	this.flag_displaySELECTED  = 0x00000200;
	this.flag_displayVISIFSEL  = 0x00000400;
	this.flag_displayVISIFNOT  = 0x00000800;

	/**
	 * 'session as' flags
	 */
	this.flag_USASNONE  = 0x0;
	this.flag_USASUSER  = 0x1;
	this.flag_USASGROUP = 0x2;
	this.flag_USASALL   = 0x4;
	this.flag_USASOWNER = 0x8;

    /**
     * filter values
     */
    this.filter_MAXLEN = 4 * 1024;

	// assume PHP session identification
	this.cookie_useCookie = false;

	// names
	this.cookie_NAME = 'WIThinkerOf';
	this.server_side_toolList_NAME = 'sso_tool_list';
	this.server_side_sessionList_NAME = 'sso_session_list';
	this.server_side_threadList_NAME = 'sso_thread_list';
	this.server_side_postList_NAME = 'sso_post_list';
	this.server_side_updatedObject_NAME = 'sso_updated';
    this.server_side_notList_NAME = 'sso_not_list';

	// operation success flags
	this.save_UNKNOWN = 0;
	this.save_SUCCESS = 1;
	this.save_FAIL = 2;
	this.save_PENDING = 3;
}


witoClass.prototype.init_server = function() {
	// get remote server name by scanning scripts
	var scripts = document.getElementsByTagName('script');
	for (var i=0 ; i<scripts.length ; ++i) {
		var src = scripts[i].src;
		var len = src.length;
		// find our script in the list
        if (src.indexOf(this.scriptName) != -1) {
			// see if the script is local
			if (src.substring(0,1) == '/') {
				src = window.location.toString();
			}
			// establish what protocol we're on
			this.protocol = src.substring(0,7);
			if (src.substring(0,8) == 'https://') {
				this.protocol = src.substring(0,8);
			}
			var nextslash = src.indexOf('/',this.protocol.length);
			this.serverName = src.substring(this.protocol.length, nextslash);
		}
	}
}


/**
 *
 *
 * Sheets and Scripts
 * - attach stylesheets, preload images
 *
 * 
 */
witoClass.prototype.init_styles = function() {
	this.attach_stylesheet('wito_.css');
	// pre-cache images
	var imagepath = this.page_getAssetPath() + 'images/';
	this.attach_image(imagepath + 'backadd.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'backedit.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'backdel.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'arrow_right.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'arrow_down.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'deletex.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'editpen.gif', document.body, 'image/gif', 'wito_hidden');
	this.attach_image(imagepath + 'resize.gif', document.body, 'image/gif', 'wito_hidden');
	// attach backgrounds (dynamic)
	var style_inline = (" \r\n \
/* Image references */ \r\n \
div.wito_glyphright { background-image: url('"+imagepath+"arrow_right.gif'); } \r\n \
div.wito_glyphdown { background-image: url('"+imagepath+"arrow_down.gif'); } \r\n \
div.wito_deletex { background-image: url('"+imagepath+"deletex.gif'); } \r\n \
div.wito_editpen { background-image: url('"+imagepath+"editpen.gif'); } \r\n \
div.wito_add { background-image: url('"+imagepath+"backadd.gif'); } \r\n \
div.wito_debug { background-image: url('"+imagepath+"arrow_right.gif'); } \r\n \
div.wito_resize { background-image: url('"+imagepath+"resize.gif'); } \r\n \
a.wito_link_look { background-image: url('"+imagepath+"logo_thought.gif'); } \r\n \
div.wito_toolbox_tools { background-image: url('"+imagepath+"plinth.jpg'); } \r\n \
");
	this.attach_styles(style_inline);
}


witoClass.prototype.attach_stylesheet = function(sheetname) {
	var url = this.page_getAssetPath() + 'css/' + sheetname;
	if (document.createStyleSheet) {
		document.createStyleSheet(url);
	} else {
		if (!document.getElementById('uidc'+sheetname)) {
			var type = 'link';
			if (document.createElementNS && this.page.head.tagName == 'head') {
				var newobj = this.page.head.appendChild(document.createElementNS('http://www.w3.org/1999/xhtml', type));
			} else {
				var newobj = this.page.head.appendChild(document.createElement(type));
			}
			newobj.id = 'uidc'+sheetname;
			newobj.rel = 'stylesheet';
			newobj.href = url;
			newobj.type = 'text/css';
			newobj.media = 'screen';
		}
	}
}


witoClass.prototype.attach_styles = function(styles) {
	var type = 'style';
	if (document.createStyleSheet) {
		// IE only
		var lineArray = styles.split("\r\n");
		var newobj = document.createStyleSheet();
		// add rules one at a time
		for (var i=0 ; i<lineArray.length ; ++i) {
			var posbraco = lineArray[i].indexOf('{');
			if (posbraco > 0) {
				var spec = lineArray[i].substring(0,posbraco);
				var posbracc = lineArray[i].indexOf('}');
				var rule = lineArray[i].substring(posbraco+1, posbracc);
				newobj.addRule(spec, rule);
			}
		}
	} else {
		// Firefox and Chrome
		if (document.createElementNS && this.page.head.tagName == 'head') {
			var newobj = this.page.head.appendChild(document.createElementNS('http://www.w3.org/1999/xhtml', type));
		} else {
			var newobj = this.page.head.appendChild(document.createElement(type));
		}
		if (witoQuery.browser.mozilla) {
			newobj.innerHTML = styles;
		} else {
			newobj.innerText = styles; // changed from innerHTML
		}
		newobj.type = 'text/css';
		newobj.media = 'screen';
	}
}


/**
 * attach_javascript
 * + bi-directional information flow
 */
witoClass.prototype.attach_javascript = function (url, callback, scriptname) {
	// if this particular script isn't attached yet
	if ((scriptname == null) || (!document.getElementById('uids'+scriptname))) {
		var type = 'script';
		if (document.createElementNS && this.page.head.tagName == 'head') {
			var newobj = this.page.head.appendChild(document.createElementNS('http://www.w3.org/1999/xhtml', type));
		} else {
			var newobj = this.page.head.appendChild(document.createElement(type));
		}
		if (scriptname != null) {
			newobj.id = 'uidc'+scriptname;
		}
		newobj.src = url;
		newobj.type = 'text/javascript';
		this.attach_javascript_add_listener(newobj, callback, true);
	}
}


witoClass.prototype.attach_javascript_add_listener = function(newobj, callback, destroy) {
	if (witoQuery.browser.msie) {
		witoQuery(newobj).bind( "readystatechange", null, function() {
			if(newobj.readyState == "loaded") {
				if (callback) callback(newobj);
				if (destroy) {
					witoGlobal.page.head.removeChild(newobj);
				}
			}
		} );
	} else {
		witoQuery(newobj).bind( "load", null, function() {
			if (callback) callback(newobj);
			if (destroy) {
				witoGlobal.page.head.removeChild(newobj);
			}
		} );
	}
}


/**
 * attach_image
 * - single directional flow
 * - information up to server, not back
 * - doesn't require witoQuery
 * + also useful for caching images
 *
 * optional arguments
 * [3] = class
 */
witoClass.prototype.attach_image = function (url, base, type) {
	var type = 'img';
	if (typeof(base) == 'string') {
		base = document.getElementById(base);
	}
	if (document.createElementNS) {
		var newobj = base.appendChild(document.createElementNS('http://www.w3.org/1999/xhtml', type));
	} else {
		var newobj = base.appendChild(document.createElement(type));
	}
	newobj.src = url;
	newobj.type = type;
    // initially attach images without displaying (class-only makes them flash)
    newobj.style.display = 'none';
	// optionally attach classname
	if (arguments.length > 3) {
		newobj.className = arguments[3];
	}
}


// get and set cookies
witoClass.prototype.cookie = function(name) {
	if (arguments.length == 1) {
		// get
		var parts = document.cookie.split( ';' );
		for (i=0; i<parts.length; i++)
		{
			var temp_cookie = parts[i].split('=');
			// trim left/right whitespace
			var cookie_name = temp_cookie[0].replace(/^\s+|\s+$/g, '');
			// if the extracted name matches passed check_name
			if (cookie_name == name) {
				// we need to handle case where cookie has no value but exists (no = sign, that is):
				if ( temp_cookie.length>1) {
					return(unescape(temp_cookie[1].replace(/^\s+|\s+$/g, '')));
				}
			}
		}
		return(false);
	} else {
		// set
		var value = arguments[1];
		var expires = arguments[2];
		var domain = arguments[3];
		var secure = arguments[4];
		
		var today = new Date();
		msnow = today.getTime()
		today.setTime(msnow);
		var expires_date = new Date(msnow + expires);
		
		document.cookie = name + "=" +escape(value) +
		( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
		(";path=/") + 
		( ( domain ) ? ";domain=" + domain : "" ) +
		( ( secure ) ? ";secure" : "" );
	}
}


/**
 *
 *
 * Page operations
 *
 * 
 */
witoClass.prototype.init_page = function() {
	// generic object for page
	this.page = new Object();
	// create thread container div
	witoQuery('body').append('<div id="'+this.threadBaseID+'"></div>');
	this.page.threadBase = witoQuery('#'+this.threadBaseID);
	// find wito links in page
	if (witoQuery('.'+this.pageLinkClass).is('*')) {
		witoQuery('.'+this.pageLinkClass).click(function(e) {
			witoGlobal.page_link_click();
			witoGlobal.event_stop_bubble(e);
		});
    }
	this.page.head = document.getElementsByTagName('head')[0];
}


witoClass.prototype.page_link_click = function() {
	// work out if we're in online/offline mode
	if (this.online == this.status_ONLINE) {
		var session = this.sessionList.getCurrent();
		if (session) {
			session.new_thread();
		}
	}
	if (this.online == this.OFFLINE) {
		// this.debug('offline');
	}
	if (this.online == this.DONTKNOW) {
		// this.debug('don\'t know');
	}
}


witoClass.prototype.page_getAssetPath = function() {
	var assetpath = this.protocol + this.serverName + this.rcvAlias + '/';
	return(assetpath);
}


witoClass.prototype.page_getDimensions = function() {
	var dim = new Object();
	var db = document.body;
	var dde = document.documentElement;

	if (typeof window.innerWidth != 'undefined') {
		// standards compliant browsers
		dim.viewwidth = window.innerWidth;
		dim.viewheight = window.innerHeight;
	} else if (typeof document.documentElement != 'undefined'
		&& typeof document.documentElement.clientWidth !=
		'undefined' && document.documentElement.clientWidth != 0) {
		// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
		dim.viewwidth = document.documentElement.clientWidth;
		dim.viewheight = document.documentElement.clientHeight;
	} else {
		// older versions of IE
		dim.viewwidth = document.getElementsByTagName('body')[0].clientWidth;
		dim.viewheight = document.getElementsByTagName('body')[0].clientHeight;
	}

	if( typeof( window.pageYOffset ) == 'number' ) {
		// Netscape compliant
		dim.scrollx = window.pageXOffset;
		dim.scrolly = window.pageYOffset;
	} else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
		// DOM compliant
		dim.scrollx = document.body.scrollLeft;
		dim.scrolly = document.body.scrollTop;
	} else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
		// IE6 standards compliant mode
		dim.scrollx = document.documentElement.scrollLeft;
		dim.scrolly = document.documentElement.scrollTop;
	}
	
	dim.docwidth = Math.max(db.scrollWidth, dde.scrollWidth, db.offsetWidth, dde.offsetWidth, db.clientWidth, dde.clientWidth);
	dim.docheight = Math.max(db.scrollHeight, dde.scrollHeight, db.offsetHeight, dde.offsetHeight, db.clientHeight, dde.clientHeight);

	return(dim);
}



/**
 *
 *
 * Server operations
 * - ajax posts
 *
 *
 */
witoClass.prototype.init_ajax = function() {
	this.ajaxUpdateList = new witoAjaxUpdateListClass();
	this.ajaxUpdateList.init(this, this);
	// connect with server
	this.ajax_server_init();
}


witoClass.prototype.ajax_countOutstanding = function() {
	return(this.ajaxUpdateList.count());
}


witoClass.prototype.ajax_prep = function(obj, action) {
	// create new ajax update
	var upd = new witoAjaxUpdateClass();
	// add to object and master list
	upd.init(this, obj.ajaxUpdateList, action);
	return(upd);
}


witoClass.prototype.ajax_server_init = function() {
	// post to server
	var upd = this.ajax_prep(this, this.flag_actionINIT | this.flag_targetSERVER);
	upd.postObj.callback = this.event_ajax_server_init_callback(this);
	// capture analytics data
	upd.postObj.doc = this.filterWhiteByKey(document, this.fieldlist_objectDOCUMENT);
	var nav = this.filterWhiteByKey(navigator, this.fieldlist_objectNAVIGATOR);
	this.generic_copyFromTargetted(upd.postObj.doc, nav);
	var dim = this.page_getDimensions();
	this.generic_copyFromTargetted(upd.postObj.doc, dim);
	// send init request with learned data
	upd.send();
}


witoClass.prototype.event_ajax_server_init_callback = function(context) {
	return( function(rdo) {
		context.ajax_server_init_callback(rdo);
	});
}


witoClass.prototype.ajax_server_init_callback = function(rdo){
	// called by witoAjaxUpdateClass.callback()
	if (!rdo[this.server_side_sessionList_NAME]) {
		this.error('Invalid response from receiver.');
	} else {
		// inherit debug level from server
		if (rdo.DEBUG_SECSTATE) {
			this.DEBUG_LOSEC = rdo.DEBUG_SECSTATE;
		} else {
            // otherwise assume not debugging
            this.DEBUG_LOSEC = 0;
        }
		this.session_init(rdo);
		// remove sessionList from rdo to mark as processed
		rdo[this.server_side_sessionList_NAME] = null;
	}
	if (rdo[this.server_side_toolList_NAME]) {
		// process import/recv of new tools
		this.toolbox.recv_tools(rdo[this.server_side_toolList_NAME]);
	}
    // initialise the UI either way
    this.ui_init();
}


witoClass.prototype.isLocked = function(type) {
	return(false);
}


/**
 *
 * Session
 * 
 */
witoClass.prototype.session_init = function(rdo) {
	// rdo comes from server, use as basis
	if (rdo.default_session) {
		var temp = new witoSessionListClass();
		temp.wito = this;
		temp.recv_default(rdo.default_session);
	}
	if (rdo.default_thread) {
		// temporarily instantiate a threadList so we can call recv_default (for class tidiness)
		var temp = new witoThreadListClass();
		temp.wito = this;
		temp.recv_default(rdo.default_thread);
	}
	if (rdo.default_post) {
		var temp = new witoPostListClass();
		temp.wito = this;
		temp.recv_default(rdo.default_post);
	}
	if (rdo.default_tool) {
		// temporarily instantiate a threadList so we can call recv_default (for class tidiness)
		var temp = new witoToolboxClass();
		temp.wito = this;
		temp.recv_default(rdo.default_tool);
	}
	
	// process received session list
	this.sessionList = new witoSessionListClass();
	this.sessionList.init(this, rdo[this.server_side_sessionList_NAME]);
	
	// set & use cookies if returned by server
	if (rdo.cookie) {
		this.cookie(this.cookie_NAME, rdo.cookie, 7 * 24 * 60 * 60 * 1000, false, false);
		this.cookie_useCookie = true;
	}
	if (this.cookie_useCookie) {
		this.sessionList.cookie = this.cookie(this.cookie_NAME);
		if (!this.sessionList.cookie) {
			// if unable to set cookie, just remember
			this.sessionList.cookie = rdo.cookie;
		}
	}
	
	// init top-level hash, then cascade-down to setup aggregates
	this.hash = new witoHashClass();
	this.hash.init(this, this.hash_fieldsTOP, this, this.sessionList, null);
	this.hash.hash_calculate(false); // top level hash so no need to cascade up
	this.hash.hash_aggregate(false, true, "|");
	// this.debug(this.hash.debugHashTree('|SESS|THRD|POST|'));

	// if list of sessions, show sessionbox
	var count = this.sessionList.getCount();
	if (count > 1) {
		// multiple sessions, show
		this.showToolbox = true;
	} else if (count == 1) {
        var session = this.sessionList.getCurrent();
		// single session, check for thoughts
		var tcount = session.threadList.getCount();
		if (tcount > 0) {
			this.showToolbox = true;
		}
	}
    // service live
	this.online = this.status_ONLINE;
}


/**
 *
 * Genericised functions
 * 
 */
witoClass.prototype.generic_copyFrom = function(master) {
	var keymaster = master;
	if (arguments.length > 1) keymaster = arguments[1];
	witoClass.prototype.generic_copyFrom_manual(this, master, keymaster);
}


witoClass.prototype.generic_copyFromTargetted = function(target, master) {
	var keymaster = master;
	if (arguments.length > 2) keymaster = arguments[2];
	witoClass.prototype.generic_copyFrom_manual(target, master, keymaster);
}


witoClass.prototype.generic_copyFrom_manual = function(target, master, keymaster) {
	for (key in keymaster) {
		if (master[key] != undefined) {
			target[key] = master[key];
		}
	}
}


witoClass.prototype.generic_filter = function(data) {
    var output = data;
    // limit length
    if (output.length > this.filter_MAXLEN)
        output = data.substr(0, this.filter_MAXLEN);
	// strip html
	output = output.replace(/[\r\n]+/g,' ').replace(/<[^>]*>/g,'');
    return(output);
}


witoClass.prototype.generic_compareList = function(obj, latest, name) {
	var compared = new Array();
	// compare server's session list
	for (var i = 0 ; i<latest.length ; ++i) {
		var sso = latest[i];
		if (!sso) continue;
		// this.debug(name+' list['+i+'] '+this.__objectToString(sso));
		var sref = sso.ref;
		var cso = obj.get(sref);
		// this.debug('searching for '+name+' ref '+sref+', got obj['+cso+']');
		if (!cso) {
			// skip deleted threads
			if (sso.flagdisp & this.flag_displayDELETED) continue;
			// this.debug('creating new '+name+' ref('+sref+')');
			// sso <name> doesn't exist locally (as cso), create (from ListClass)
			obj.receive(sso);
		} else {
			// server session has corresponding local session, compare
			cso.compare(sso);
		}
		compared[compared.length] = sref;
	}
}


witoClass.prototype.generic_processUpdateToQueue = function(obj, latest, name) {
	// this.debug('process update '+name+' ref('+obj.ref+')');
	// first of all check hash for this update
	var lhash;
	lhash = this.generic_validateUpdateHash(latest, obj);
	if (lhash == latest.hval) {
		// diff latest properties against stored
		for (var prop in latest) {
			// skip hashes (at this stage)
			if ((prop == 'hval') || (prop == 'hchild')) continue;
			var propType = typeof(latest[prop]);
			// can't do simple comparison of lists
			if ((propType == 'object') || (propType == 'array')) continue;
			if (latest[prop] != obj[prop]) {
				this.intUpdQueue.add(obj, prop, obj[prop], latest[prop]);
				// this.debug(prop + ' is different ('+obj[prop]+','+latest[prop]+')');
			}
		}
	} else {
		// send re-hash request (works like GET)
		obj.updateSendRehash();
		this.debug('REHASH: our hash['+lhash+' from '+obj.data+'] server hash['+latest.hval+']'+"\r\n"+'firing rehash for '+name+' ref('+obj.ref+')');
	}
}


witoClass.prototype.generic_validateUpdateHash = function(latest, obj) {
	var hash = new witoHashClass();
	hash.init(this, obj.hash.fields, latest, null, null);
	hash.hash_calculate(false);
	// this.debug('our hash['+hash.hval+'] server hash['+latest.hval+']');
	return(hash.hval);
}


witoClass.prototype.generic_get = function(ref) {
	if (ref == null) return(null);
	if (ref <= this.list.length) {
		var elem = this.list[ref];
		if (!elem) return(null);
		if (ref == elem.ref)
			return(elem);
	}
    // var name = arguments[1];
	// this.wito.warning('Attempt to access ('+name+') reference '+ref+', not found in '+name+'List.');
	return(null);
}


witoClass.prototype.generic_add = function(obj) {
	if (obj.ref == this.wito.ref_UNSET) {
		obj.ref = this.list.length;
	}
	this.list[obj.ref] = obj;
    // var name = arguments[1];
	// this.wito.warning('Added ('+name+') reference '+ref+' to '+name+'List.');
}


witoClass.prototype.generic_getNextUsedRef = function(ref) {
	if (this.count == 0) return(this.wito.ref_UNSET);
	if (ref >= this.list.length) return(this.wito.ref_UNSET);
	for (var i=ref+1 ; i < this.list.length ; i++) {
		if (this.list[i] == null) continue;
		if (this.list[i].jq != null) return(i);
	}
	// incase we get to the end of the list without finding a live (!dead) item
	return(this.wito.ref_UNSET);
}


witoClass.prototype.generic_processPreInitQueue = function() {
    var q = this.preInitQueue;
    for (var i=0 ; i<q.length ; i++) {
        // this.wito.debug('processing update '+this.wito.__objectToString(q[i]));
    	this.receiver(q[i]);
    }
}


/**
 * External receiver called by json eval
 */
witoClass.prototype.ajaxUpdateReceiver = function(retDataObj) {
	if (!retDataObj) return;
	this.ajaxUpdateList.receiver(retDataObj);
}


/**
 * Sitebox
 */
witoClass.receiverQ_site = witoClass.receiverQ_site || [];


witoClass.prototype.init_sitebox = function() {
	// initialise toolbox
	this.sitebox = new witoSiteboxClass();
	this.sitebox.init(this);
	this.sitebox.processQueue();
}


/**
 * Toolbox
 */
witoClass.receiverQ_tool = witoClass.receiverQ_tool || [];


witoClass.prototype.init_toolbox = function() {
	// initialise toolbox
	this.toolbox = new witoToolboxClass();
	this.toolbox.init(this);
	this.toolbox.processQueue();
}


/**
 *
 * Edit
 * - aggregated global editing code
 *   + edits are object managed, so easy to multitask
 * - user can only edit one field at a time
 *
 */
witoClass.prototype.edit_begin = function(edobj) {
	var session = this.sessionList.getCurrent(); if (!session) return;
	session.edit_begin(edobj);
}


witoClass.prototype.edit_commit = function(edobj) {
	var session = this.sessionList.getCurrent(); if (!session) return;
	if (!session.editing) return;
	session.editing.commit();
	session.editing = null;
}


/**
 *
 * UI functions
 * + non jQuery/witoQuery user interactions
 *
 */
witoClass.prototype.ui_init = function() {
    if (this.online == this.status_ONLINE) {
        if (this.sessionList) {
            // loop through current session threads and display
            var session = this.sessionList.getCurrent();
            if (session) session.show();
        }
        // show Feedback link
        var pageLink = witoQuery('.'+this.pageLinkClass);
        if (pageLink.is('*')) {
            // fade in page link
            if (pageLink.animate) pageLink.css('opacity', 0.0);
			var linkText = pageLink.html();
			if ((linkText == 'Feedback') || (linkText == 'F eedback')) {
				// insert spacer if applying styles (wito_embed_link)
				pageLink.html('F<span class="wito_eedback"></span>eedback');
			}
            pageLink.css('visibility', 'visible');
            if (pageLink.animate) pageLink.animate({opacity: 1.0},1000,null);
        }
        else if (!this.showToolbox) {
            // if no wito links found on page, show partial toolbox
            this.toolbox.show_nto();
        }
        // either way
        if (this.showToolbox) {
            // only display full toolbox if appropriate
            this.toolbox.show();
        }
    }
}


witoClass.prototype.drag_mouse_up_down_move = function(e) {
	var eventext = (witoQuery.browser.msie ? event : e);
	var evtarget = (witoQuery.browser.msie ? event.srcElement : e.target);
	var context = null;
	// jQuery compatible
	if (e.data) context = e.data;
	// witoQuery compatible
	if (arguments[1]) context = arguments[1];
	if (!context) return;
	
	if (eventext.type == 'mousedown') {
		if (evtarget.id == context.dragCatch) {
			context.dragging = true;
			// call .start function
			if (context.options.start) {
				context.options.start(eventext, context.options.context);
			}
		}
	} else if (eventext.type == 'mouseup') {
		if (context.dragging) {
			// call .stop function
			if (context.options.stop) {
				context.options.stop(eventext, context.options.context);
			}
			context.dragging = false;
		}
	} else if (eventext.type == 'mousemove') {
		if (context.dragging) {
			// call .drag function
			if (context.options.drag) {
				context.options.drag(eventext, context.options.context);
			}
		}
	}
}


/**
 * Event handler
 */
witoClass.prototype.event_stop_bubble = function(e) {
	if (!e) var e = window.event;
	// ie
	e.cancelBubble = true;
	e.returnValue = false;
	// ff
	if (e.preventDefault) e.preventDefault();
	if (e.stopPropagation) e.stopPropagation();
}


/**
 *
 *
 * Helper functions
 *   __function name
 * 
 *
 */

/**
 * __object_toURL
 *
 * Input
 *  object to convert into string
 *  prepend (optional)
 */
witoClass.prototype.__object_toURL = function(obj) {
	var str='';
	var prepend='';
	// prepend is an optional parameter
	if (arguments.length == 2) {
		prepend = arguments[1] + '__';
	}
	for(var prop in obj) {
		// skip internal subobjects
		if (prop == '__internal') continue;
		if (typeof(obj[prop]) == 'object') {
			// trailing &amp; comes from call down to _toURL()
			str += this.__object_toURL(obj[prop], prepend + prop);
		} else if (typeof(obj[prop]) == 'function') {
			// exclude functions
		} else {
			str += prepend + prop + '=' + escape(obj[prop]) + '&';
		}
	}
	return(str);
}


witoClass.prototype.__objectToString = function(obj) {
	var str='';
    var showFunc = false || arguments[1];
	for(var prop in obj) {
		if (obj[prop] && !showFunc) {
			if (obj[prop].toString().indexOf('{') != -1) continue;
		}
		str+=prop + " value :"+ (obj[prop] ? obj[prop] : '0')+"\n";
	}
	return(str);
}


witoClass.prototype.__propsToString = function(obj) {
	str = '';
	for(var prop in obj) {
		// add to string
		try {
			str+=prop + " ["+ (obj[prop] ? typeof(obj[prop]) : 'null')+"]\n";
		} catch (err) {
			str+=prop + " [err]\n";
		}
	}
	return(str);
}


witoClass.prototype.filterWhiteByType = function(obj) {
	var filtrate = new Object();
	var white = null;
	if (arguments.length > 1) {
		white = arguments[1];
	}
	for(var prop in obj) {
		try {
			var type = typeof(obj[prop]);
			if (type && white) {
				if (white.indexOf(type) != -1) {
					filtrate[prop] = obj[prop];
				}
			}
		} catch (err) {
			// ignore errors
		}
	}
	return(filtrate);
}


witoClass.prototype.filterWhiteByKey = function(obj, arr) {
	var filtrate = new Object();
	for (var i=0 ; i<arr.length ; ++i) {
		var key = arr[i];
		if (obj[key] != undefined) {
			filtrate[key] = obj[key];
		}
	}
	return(filtrate);
}


witoClass.prototype.__arrayToString = function(obj) {
	str='';
	for(var i=0 ; i<obj.length ; ++i) {
		var k = obj[i];
		str += '['+i+'] '+ (k ? k : 'NULL') +"\n";
	}
	return(str);
}


witoClass.prototype.pad = function(num) {
	var str = "";
	if (num <= 99) str+="0";
	if (num <= 9) str+="0";
	str+=num;
	return(str);
}


witoClass.prototype.padHex = function(num,len) {
	var k = num.toString(16);
	var pad = '';
	for (var i=k.length ; i<len ; ++i) {
		pad += '0';
	}
	return(''+pad+k);
}


witoClass.prototype.colourThreshold = function(colour, threshold) {
	var b = 0.114*(colour & 0x0000FF), g = 0.587*((colour & 0x00FF00) >> 8), r = 0.299*((colour & 0xFF0000) >> 16);
	var gr = Math.sqrt(r*r + g*g + b*b);
	// this.debug('r['+r+'] g['+g+'] b['+b+'] -> grey['+gr+']');
	return(gr < threshold);
}


witoClass.prototype.colourMathDarken = function(colour, amt, lighten) {
	var c = new Array();
	// force lighten flag to be consistent
	lighten = true;
	c[0] = (colour & 0x0000FF);
	c[1] = (colour & 0x00FF00) >> 8;
	c[2] = (colour & 0xFF0000) >> 16;
	// amt [0-1], amount to lighten where 0 = none, 1 = white
	if (lighten) {
		amt *= -1;
	}
	for (var i=0 ; i<3 ; ++i) {
		c[i] = Math.round(c[i] + (amt * 0xFF));
		if (c[i] > 0xFF) c[i] = 0xFF;
		if (c[i] < 0x00) c[i] = 0x00;
	}
	var outcol = c[0] + (c[1] << 8) + (c[2] << 16);
	// this.debug('r['+c[2]+'] g['+c[1]+'] b['+c[0]+']');
	return(outcol);
}


witoClass.prototype.debug = function(mess) {
	if (this.DEBUG_LOSEC) {
		if (window.console) {
			console.debug(mess);
		} else {
            // debug must not be invasive, cannot use alert
            // var dbdiv = '<div class="wito_debug_dbdiv">'+mess+'</div>';
            // witoQuery('body').append(dbdiv);
		}
	}
}


witoClass.prototype.debugCacheMess = function(mess) {
	if (this.DEBUG_LOSEC) {
		if (!this.debugCache) this.debugCache = new Array();
		this.debugCache[this.debugCache.length] = mess;
		if (this.debugCache.length >= 20) this.debugCacheClear();
	}
}


witoClass.prototype.debugCacheClear = function() {
	if (this.DEBUG_LOSEC) {
		var str = '';
		for (var i=0 ; i<this.debugCache.length ; ++i) {
			str += this.debugCache[i] + "\r\n";
		}
		this.debug(str);
		this.debugCache.length = 0;
		this.debugCache = null;
	}
}


witoClass.prototype.warning = function(mess) {
	// alert(mess);
}


witoClass.prototype.error = function(mess) {
	// alert(mess+' Please refresh your browser window (typically Ctrl+R or Ctrl+F5).');
}



/**
 *
 * Text editing manager
 *
 */
witoEditingClass = function() {
	// constructor (editing)
}


witoEditingClass.prototype.init = function(wito, session, edobj) {
	this.wito = wito;
	this.parent = session;
	this.obj = edobj;
}


witoEditingClass.prototype.begin = function() {
	// this.wito.debug('editing.begin called, tFfL:'+(this.obj.isLocked(this.wito.lockType_toForeignForLOCAL)?'true':'false'))
	// try to lock new object
	if (!this.obj.isLocked(this.wito.lockType_toForeignForLOCAL)) {
		this.obj.lock(this.wito.lockType_toForeignForLOCAL);
	} else {
		return(false);
	}
	// determine type
	if (this.obj.className == 'witoThreadClass') {
		// edit thread title
		this.id = 'wito_thread_paratbar-' + this.obj.ref;
	} else {
		// edit post
		this.id = 'wito_post-' + this.obj.postList.thread.ref + '-' + this.obj.ref + '_data';
	}
	// replace text with editable text field
	var src = new Object();
	src.jq = witoQuery('#'+this.id);
	src.text = src.jq.html();
	src.text_changed = false;
	// set textarea box dimensions to match replacing paragraph's
	src.text_pos_px = -1;
	src.text_height = src.jq.height();
	if (src.text_height.indexOf) if ((src.text_pos_px = src.text_height.indexOf('px'))) src.text_height = src.text_height.substr(0,src.text_pos_px);
	// set default colours
	src.colBack = 'FFFFFF';
	src.colText = '000000';
	src.text_minHeight = 0;
	// call listener if attached to correct height/colour/button text etc.
	if (this.obj.textEditListener) {
		this.obj.textEditListener(src);
	}
	var newtext = '<textarea class="wito_editbox" '+
		'type="text" '+
		'style="height:'+src.text_height+'px;'+
		(src.text_minHeight ? 'min-height:'+src.text_minHeight+'px;' : '')+
		'background-color:#'+src.colBack+';'+
		'color:#'+src.colText+';'+
		'" '+
		'wordwrap="true" '+
		'id="text_'+this.id+'" '+
		'>'+src.text+'</textarea>';
	src.jq.html(newtext);
	if (src.text_changed) {
		this.listenerTextUpdated();
	}
	// clean up
	src = null;
	// read back textarea
	this.jq = witoQuery('#text_'+this.id);
	// make dummy listener ready for first-key check
	this.dummyChecked = false;
	// check caret into edit box
	this.setCaret('text_'+this.id);
	// check keydown
	this.jq.keydown(this.event_keydown(this));
	// listen for click outside box to end edit
	witoQuery(document).click(this.event_click(this));
	return(true);
}


witoEditingClass.prototype.destroy = function() {
	if (this.dummy) {
		this.dummy.destroy();
	}
	this.dummy = null;
}


witoEditingClass.prototype.setCaret = function(target_id) {
	var target = document.getElementById(target_id);
	if (target.createTextRange) {
		var range = target.createTextRange();
		range.collapse(false);
		range.select();
	} else if (target.setSelectionRange) {
		target.focus();
		var ilen = target.value.length;
		target.setSelectionRange(ilen, ilen);
	}
}


witoEditingClass.prototype.commit = function() {
	// return edit field to read-only text
	var targetjq = witoQuery('#'+this.id);
	var newdata = this.jq.val();
	targetjq.html(newdata);
	// filter new data
	var data = this.wito.generic_filter(newdata);
	// tell the object to update itself
	// - because this could be triggered by another edit beginning
	this.obj.commitEdit(data);
	if (data != newdata) {
		// update UI element
		if (this.obj.setText) this.obj.setText(this.obj.data);
		// alert user that the text contents have been altered
		if (this.obj.setMessage) this.obj.setMessage('Text filtered for security.');
	}
	if (this.obj.className == 'witoThreadClass') {
		this.obj.applyDimensionIfHeightChange();
	}
	// release lock (although there may be a second ForSERVER)
	this.obj.unlock(this.wito.lockType_toForeignForLOCAL);
	// clean up
	this.destroy();
}


witoEditingClass.prototype.checkDummy = function() {
	this.dummyChecked = true;
	// if the [thread/post] has an autoGrow policy...
	if (this.obj.autoGrow) {
		// and that policy says grow...
		if (this.obj.autoGrow()) {
			this.dummy = new witoEditingDummyClass();
			this.dummy.init(this.wito, this, this.jq);
		}
	}
}


witoEditingClass.prototype.event_keydown = function(context) {
	return( function(e) {
		if (!e) var e = window.event;
		var key = (e.keyCode ? e.keyCode : e.which);
		if (!context.dummyChecked) context.checkDummy();
		// catch return keystrokes
		if (key == 13) {
			context.wito.edit_commit();
			context.wito.event_stop_bubble(e);
			return(false);
		}
		return(true);
	});
}


witoEditingClass.prototype.event_click = function(context) {
	return( function(e) {
		if (!e) var e = window.event;
		var evtarget = (witoQuery.browser.msie ? e.srcElement : e.target);
		if (evtarget.id == 'text_'+context.id) {
			// ignore clicks on text box
		} else {
			context.wito.edit_commit();
		}
		return(true);
	});
}


witoEditingClass.prototype.listenerTextUpdated = function() {
	if (this.obj.listenerTextUpdated)
		this.obj.listenerTextUpdated();
}


/**
 * Editing dummy container
 */
witoEditingDummyClass = function() {
	// constructor (editing)
}


witoEditingDummyClass.prototype.init = function(wito, edi, tajq) {
	// single editing mode, could list-ise like threads
	this.ref = 0;
	this.wito = wito;
	this.editing = edi;
	this.tajq = tajq;
	this.delay = 400;
	this.minHeight = this.tajq.css('min-height');
	// setup dummy
	var html = '<div class="wito_dummy" style="'+
		'font-size:'+this.tajq.css('font-size')+';'+
		'font-family:'+this.tajq.css('font-family')+';'+
		'line-height:'+this.tajq.css('line-height')+';'+
		'min-height:'+this.minHeight+';'+
		'width:'+this.tajq.width()+'px;'+
		'padding:'+this.tajq.css('padding')+';'+'" '+
		'id="wito_dummy-'+this.ref+'" '+
	'"></div>';
	this.wito.page.threadBase.append(html);
	this.dumjq = witoQuery('#wito_dummy-'+this.ref);
	// this.wito.debug(this.wito.__objectToString(this.dumjq));
	// setup callback
	var cbfunc = this.event_callback(this);
	this.callback = setInterval(cbfunc, this.delay);
}


witoEditingDummyClass.prototype.destroy = function() {
	// clear callback
	clearInterval(this.callback);
	// detach dummy
    if (this.dumjq) {
        this.dumjq.remove();
        this.dumjq = null;
    }
}


witoEditingDummyClass.prototype.beat = function() {
	// get the text (+10 letters) from the textarea and set it to dummy
	this.dumjq.html(this.tajq.val()+' word word');
	var dumjq_height = this.dumjq.height();
	var tajq_height = this.tajq.height();
	// this.wito.debug('dummy '+dumjq_height+', textarea '+tajq_height);
	if (tajq_height != dumjq_height) {
		this.tajq.height(dumjq_height);
		this.editing.listenerTextUpdated();
	}
}


witoEditingDummyClass.prototype.event_callback = function(context) {
	return( function(e) {
		context.beat();
	});
}


/** 
 * WITO Embedding javascript
 *
 *   WITO
 *	 javascript support file for embedded links
 *	 sent to page by embed.module
 *
 * jQuery 1.2.6 or later
 *
 * Globals:
 *		witoGlobal
 */

/**
 *
 * INLINE SECTION
 *
 */
var witoGlobal = function(){};

(function() {
    var loadTarget = function() {
        // quit if this function has already been called
        if (arguments.callee.done) return;
        
        // flag this function so we don't do the same thing twice
        arguments.callee.done = true;
        
        // kill the timer
        if (_timer) {
            clearInterval(_timer);
            _timer = null;
        }
        
        witoGlobal = new witoClass();
        witoGlobal.init();
    }
    /**
     * Embedding code to handle onload before binary-complete
     * - for Mozilla 
     */
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", loadTarget, false);
    }
    /**
     * - for Internet Explorer
     */
    /*@cc_on @*/
    /*@if (@_win32)
        document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
        var wito_script = document.getElementById("__ie_onload");
        wito_script.onreadystatechange = function() {
            if (this.readyState == "complete") {
                loadTarget(); // call the onload handler
            }
        };
    /*@end @*/
    /**
     * - for Safari
     */
    if (/WebKit/i.test(navigator.userAgent)) { // sniff
        var _timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) {
                loadTarget(); // call the onload handler
            }
        }, 10);
    }
    /**
     * - for other browsers
     */
    window.onload = loadTarget;
})();


/**
 *
 * Hash class
 *
 */
witoHashClass = function() {
	// constructor (hash)
}
 

witoHashClass.prototype.init = function(wito, fields, obj, childList, parent) {
	this.wito = wito;
	this.serial = '';
	this.hval = 0;
	this.hchild = -1;   // less likely than 0 which is the empty set hash
	this.fields = fields;
	this.obj = obj;				 // e.g. Thread
	this.childList = childList;	 // e.g. PostList
	this.parent = parent;		   // e.g. Session
}


witoHashClass.prototype.convertUTF8 = function(str) {
	for(var c, i = -1, l = (str = str.split("")).length, o = String.fromCharCode; ++i < l;
		str[i] = (c = str[i].charCodeAt(0)) >= 127 ? o(0xc0 | (c >>> 6)) + o(0x80 | (c & 0x3f)) : str[i]
	);
	return(str+"");
}


witoHashClass.prototype.crc32 = function(str) {
	var table = this.wito.hash_tableCRC;
	var crc = 0 ^ (-1);
	var x = 0;
	var y = 0;
	for( var i = 0, iTop = str.length; i < iTop; i++ ) {
		y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
		x = "0x" + table.substr( y * 9, 8 );
		crc = ( crc >>> 8 ) ^ x;
	}	
	return(crc ^ (-1));
}
   

witoHashClass.prototype.serialise = function() {
	var str = '';
	for(key in this.fields) {
		if (str.length > 0) str += ';';
		str += this.obj[this.fields[key]];
		//str+=this.fields[key];
	}
	// this.serial = this.convertUTF8(str);
	this.serial = str;
	return(this.serial);
}


witoHashClass.prototype.hash_calculate = function(cascadeUp) {
	this.serialise();
	this.hval = this.crc32(this.serial);
	// this.wito.debug('hval('+this.hval+') serial('+this.serial+')');
	// tell parent to re-aggregate
	if (cascadeUp && this.parent) {
		this.parent.hash.hash_aggregate(cascadeUp, false, false);
	}
	return(this.hval);
}


witoHashClass.prototype.hash_aggregate = function(cascadeUp, cascadeDown, debugLevel) {
	if (debugLevel === false) debugLevel = "";
	var debugStr = "";
	if (!this.childList) {
		this.hchild = 0;
		return('');
		return(debugLevel+"No children");
	}
	// get list of children
	var objArr = this.childList.getList();
	var newChildAgg = 0;
	// aggregate child hashes
	for (var i=0 ; i<objArr.length ; ++i) {
		// ignore deleted entries (null)
		if (!objArr[i]) continue
		// ignore flagged deleted entries (some clients won't have them at all, say after refresh)
		if (objArr[i].isDeleted()) continue;
		// cascade changes down tree
		if (cascadeDown) {
			var downStr = objArr[i].hash.hash_aggregate(cascadeUp, cascadeDown, debugLevel+'  '+this.wito.pad(i)+'| ');
			if (downStr) debugStr += "\r\n"+downStr;
		}
		var childChildAgg = objArr[i].hash.hchild;
		newChildAgg ^= childChildAgg;
		var childHash = objArr[i].hash.hval;
		newChildAgg ^= childHash;
		debugStr += "\r\n"+debugLevel + '. '+this.wito.pad(i)+'| h('+childHash+') a('+childChildAgg+')';
	}
	// if (i>0) debugStr += debugLevel + '-=-=-=-=-=-#';
	// this.wito.debug('aggregateValue('+newChildAgg+') from '+objArr.length+' sources');
	// has anything changed
	if (newChildAgg != this.hchild) {
		this.hchild = newChildAgg;
		// cascade on change (tell parent to re-aggregate)
		if (cascadeUp && this.parent) {
			this.parent.hash.hash_aggregate(cascadeUp, cascadeDown, debugLevel+"");
		}
	}
	// return used only for debugging data
	return(debugStr);
}


witoHashClass.prototype.debugHash = function(key) {
	var debugHash = (key ? key + "\r\n" : '') + 'v('+this.hval+') ch(' + this.hchild +')';
	return(debugHash);
}


witoHashClass.prototype.debugHashTree = function(key) {
	var debugHashTree = this.hash_aggregate(false, true, "|");
	debugHashTree = key + "\r\n" + debugHashTree + "\r\n\r\n" + 'Overall v('+this.hval+') ch(' + this.hchild +')';
	return(debugHashTree);
}


/**
 *
 * Heartbeat pacemaker
 *
 */
witoHeartbeatClass = function() {
	// constructor (heartbeat pacemaker)
}
 

witoHeartbeatClass.prototype.init = function(wito) {
	this.wito = wito;
	this.time = 0;
	this.nextBeat = null;
	this.suspended = false;
}


witoHeartbeatClass.prototype.event_heartbeat = function(context) {
	return( function(e) {
		context.beat();
	});
}


witoHeartbeatClass.prototype.cancel = function() {
	if (this.nextBeat) {
		// cancel current 'next' beat
		clearTimeout(this.nextBeat);
		this.nextBeat = null;
	}
}


witoHeartbeatClass.prototype.schedule = function(time) {
	// no heartbeat unless connected to server
	if (this.wito.online != this.wito.status_ONLINE) return;
	// find out if we're waiting on the server for anything else
	if (this.wito.ajax_countOutstanding()) return;
	// set min interval
	if (time < 1000) time = 1000;
	this.time = time;
	this.reschedule();
}


witoHeartbeatClass.prototype.reschedule = function() {
	// need to resume before issuing schedule/reschedule
	if (this.suspended) return;
	// only one heartbeat at a time
	this.cancel();
	// schedule beat
	this.nextBeat = setTimeout(this.event_heartbeat(this), this.time);
}


witoHeartbeatClass.prototype.beat = function() {
	var beat = true;
	// no heartbeat unless connected to server, but we once were connected
	if (this.wito.online != this.wito.status_ONLINE) beat = false;
	// find out if we're waiting on the server for anything else
	if (this.wito.ajax_countOutstanding()) beat = false;
	// get current session
	var session = this.wito.sessionList.getCurrent();
	if (session == null) beat = false;
	// beat, or schedule next beat
	if (beat) {
		// send 'none' update to server
		var upd = session.wito.ajax_prep(session, this.wito.flag_actionNONE | this.wito.flag_targetSESSION);
		upd.postObj.session = session.createPartial(this.wito.flag_actionNONE);
		upd.send();
		// this.wito.debug('heartbeat (update request) sent');
	} else {
		this.reschedule();
	}
}


witoHeartbeatClass.prototype.suspend = function() {
	if (!this.suspended) {
		this.cancel();
		this.suspended = true;
	}
}


witoHeartbeatClass.prototype.resume = function() {
	if (this.suspended) {
		if (!this.time) this.time = 1000;
		this.suspended = false;
		this.schedule(this.time);
	}
}

/**
 *
 * Hover target for informing user
 * 
 */
witoHoverTargetClass = function() {
	
}


witoHoverTargetClass.prototype.init = function(wito, parent, id) {
	this.wito = wito;
	this.parent = parent;
	this.id = 'witoHoverTarget-'+id;
	this.mess = '';
	this.jq = null;
	this.tjqlist = new Array();
    this.listenerOver = null;
}


witoHoverTargetClass.prototype.render = function() {
	var html = '';
	html += '<p class="wito_hovertarget" id="'+this.id+'">';
	html += this.mess;
	html += '</p>';
	return(html);
}


witoHoverTargetClass.prototype.attach = function(ijq, html) {
	// attach takes an argument
	if (this.jq) return(null);
	if (!ijq) return(null);
	ijq.after(html);
	this.jq = witoQuery('#'+this.id);
	return(this.jq);
}


witoHoverTargetClass.prototype.detach = function() {
	if (!this.jq) return;
	// detach second hand events
	for (var i=0 ; i<this.tjqlist.length ; ++i) {
		this.tjqlist[i].unbind();
	}
	// clear any outstanding timeouts
	if (this.timeout) {
		clearTimeout(this.timeout);
	}
	this.jq.remove();
}


witoHoverTargetClass.prototype.setMessage = function(mess) {
	if (!this.jq) return;
	this.mess = mess;
	this.jq.html(mess);
}


witoHoverTargetClass.prototype.attachOver = function(tjq, getMess) {
	tjq.bind('mouseover', null, this.event_over(this, getMess));
	tjq.bind('mouseout', null, this.event_out(this, getMess));
	tjq.bind('click', null, this.event_click(this));
	this.tjqlist[this.tjqlist.length] = tjq;
}


witoHoverTargetClass.prototype.event_over = function(context, getMess) {
	return(function() {
		// dynamic message
		if (getMess) {
			// can either attach message or message-getting-function
			var mess = getMess;
			if (typeof(getMess) == 'function') mess = getMess();
			context.over(mess);
		}
	});
}


witoHoverTargetClass.prototype.over = function(mess) {
	this.setMessage(mess);
    if (this.hook_over) this.hook_over();
	// cancel previous timeout (from last out)
	if (this.timeout) {
		clearTimeout(this.timeout);
	}
    if (witoQuery.browser.msie) {
        this.jq.css({opacity: 'show'});
    } else {
    	// fast animate in
    	this.jq.animate({opacity: 'show'},100);
    }
}


witoHoverTargetClass.prototype.event_out = function(context, mess) {
	return(function() {
		context.out(mess);
	});
}


witoHoverTargetClass.prototype.out = function(mess) {
	// ready fade out
	this.timeout = setTimeout(this.event_fadeAway(this), this.wito.delay_fadeAwayTEXT);
}


witoHoverTargetClass.prototype.event_click = function(context) {
	return(function() {
		context.click();
	});
}


witoHoverTargetClass.prototype.click = function() {
	// don't fade away because we still get over and out events
	// this.fadeAway();
}


witoHoverTargetClass.prototype.event_fadeAway = function(context) {
	return(function() {
		context.fadeAway();
	});
}


witoHoverTargetClass.prototype.fadeAway = function(context) {
    if (witoQuery.browser.msie) {
        this.jq.css({opacity: 'hide'});
    } else {
        // slow animate out
        var outspeed = 500;
        this.jq.animate({opacity: 'hide'},outspeed);
    }
	this.timeout = setTimeout(this.event_shrinkAfterFade(this), outspeed);
}


witoHoverTargetClass.prototype.event_shrinkAfterFade = function(context) {
	return(function() {
		context.shrinkAfterFade();
	});
}


witoHoverTargetClass.prototype.shrinkAfterFade = function() {
	this.setMessage('');
}


witoHoverTargetClass.prototype.attachListenerOver = function(func) {
    this.listenerOver = func;
}


/**
 *
 * InterfaceUpdateQueue class
 *
 */
witoInterfaceUpdateQueue = function() {
	// constructor (update queue)
}
 

witoInterfaceUpdateQueueElement = function() {
	// constructor (update queue element)
}


witoInterfaceUpdateQueue.prototype.init = function(wito) {
	this.wito = wito;
	this.q = new Array();
	this.anim = new Object();
}


witoInterfaceUpdateQueueElement.prototype.init = function(wito, q, obj, prop, before, after) {
	this.wito = wito;
	this.q = q;
	this.obj = obj;
	this.prop = prop;
	this.before = before;
	this.after = after;
	this.ref = this.wito.ref_UNSET;
}


witoInterfaceUpdateQueue.prototype.add = function(obj, prop, before, after) {
	// store update in array
	var elem = new witoInterfaceUpdateQueueElement();
	elem.init(this.wito, this, obj, prop, before, after);
	// add to list
	elem.ref = this.q.length;
	this.q[elem.ref] = elem;
	// this.wito.debug('adding update to queue: '+this.wito.__objectToString(elem));
}


witoInterfaceUpdateQueue.prototype.inQueue = function(name) {
	for (var i=0 ; i<this.q.length ; ++i) {
		var elem = this.q[i];
		if (elem == null) continue;
		if (elem.prop == name)
			return(elem);
	}
	return(null);
}


witoInterfaceUpdateQueue.prototype.process = function() {
	if (this.q.length == 0) return;
	// process inanimates (selected non-animated UI updates that have to be done first)
	var priorities = ['flagdisp'];
	for (var i=0 ; i<priorities.length ; ++i) {
		var elem = this.inQueue(priorities[i]);
		if (elem == null) continue;
		this.processElement(elem);
		// update UI
		elem.obj.updateUI(elem.prop, elem.before, elem.after);
		// skip this entry next time
		elem.prop = 'skip';
	}
	// update local data = object = cso
	for (var i=0 ; i<this.q.length ; ++i) {
		var elem = this.q[i];
		if (elem == null) continue;
		this.processElement(elem);
		// this.wito.debug('updated '+elem.prop+' from '+elem.before+' to '+elem.obj[elem.prop]);
		// rehash element accordingly and cascade up
		if (elem.obj.hash) elem.obj.hash.hash_calculate(true);
	}
	// hunt for double-ups (note: UI only, update already done)
	var doubleUps = [['top','left'],['width','height']];
	for (var i=0 ; i<doubleUps.length ; ++i) {
		var elemT = this.inQueue(doubleUps[i][0]);
		var elemL = this.inQueue(doubleUps[i][1]);
		if (elemT && elemL) {
			if (elemT.obj == elemL.obj) {
				// convert T to TL
				elemT.prop += elemL.prop
				// skip L
				elemL.prop = 'skip';
			}
		}
	}
	// show queue
	// this.wito.debug(this.debugQueue());
	// process remaining UI updates
	for (var i=0 ; i<this.q.length ; ++i) {
		var elem = this.q[i];
		if (elem == null) continue;
		// update UI
		elem.obj.updateUI(elem.prop, elem.before, elem.after);
	}
	// unlock objects
	for (var i=0 ; i<this.q.length ; ++i) {
		var elem = this.q[i];
		if (elem == null) continue;
		if (elem.obj.unlock(this.wito.lockType_toLocalForFOREIGN)) {
			// if it's actually being unlocked, show 'finished updating with foreign'
			elem.obj.updateUI('endUpdate');
		}
	}
	// scrub queue
	this.q.length = 0;
}


witoInterfaceUpdateQueue.prototype.processElement = function(elem) {
	// lock object
	if (elem.obj.lock(this.wito.lockType_toLocalForFOREIGN)) {
		// if it's the first time this object is being locked, show 'updating with foreign'
		elem.obj.updateUI('beginUpdate');
	}
	// update property
	elem.obj[elem.prop] = elem.after;
	// update derived variables based on property
	this.processDerived(elem.obj, elem.prop);
}


witoInterfaceUpdateQueue.prototype.processDerived = function(obj, prop) {
	switch (prop) {
		case 'z' :
			if (obj.threadList) {
				obj.threadList.checkMaxZ(obj[prop]);
			}
			break;
	}
}


witoInterfaceUpdateQueue.prototype.debugQueue = function() {
	var str = "";
	for (var i=0 ; i<this.q.length ; ++i) {
		var elem = this.q[i];
		if (elem == null) continue;
		str += '['+i+'] '+elem.prop+' from '+elem.before+' to '+elem.after + "\r\n";
	}
	return(str);
}

/**
 *
 * Notifier
 *
 */
witoNotifierClass = function() {
	// constructor (toolbox)
}


witoNotifierClass.prototype.init = function(wito, toolbox, hovertarget) {
	this.wito = wito;
	this.toolbox = toolbox;
	this.hovertarget = hovertarget;
}


witoNotifierClass.prototype.recv_nots = function(nots) {
	this.wito.debug('got nots: '+this.wito.__objectToString(nots));
}

/**
 *
 * Session class
 *
 */
witoSessionClass = function() {
	// constructor (session)
}


witoSessionClass.prototype.init = function(wito, sessionList) {
	this.wito = wito;
	this.sessionList = sessionList;
	this.threadList = new witoThreadListClass();
	this.threadList.init(this.wito, this);
	this.hash = new witoHashClass();
	this.hash.init(wito, this.wito.hash_fieldsSESSION, this, this.threadList, this.wito);
	this.ajaxUpdateList = new witoAjaxUpdateListClass();
	this.ajaxUpdateList.init(this.wito, this);
}


witoSessionClass.prototype.clone = function() { 
	// this object does not contain any objects, so use the lightweight copy code
	var temp = new witoSessionClass();
	temp.copyFrom(this);
	return temp; 
}


witoSessionClass.prototype.copyFrom = witoClass.prototype.generic_copyFrom;


// implements UpdateableInterface
witoSessionClass.prototype.compare = function(latest) {
	// ignore if thread is locked to foreign updates (discard, wait for another)
	if (this.isLocked(this.wito.lockType_toForeign))
		return;
	// compare hash to see if we need to update
	if (this.hash.hval != latest.hval) {
		this.update(latest);
	}
	// if children updated
	if (this.hash.hchild != latest.hchild) {
		// see if sublist defined in latest, else send update request
		if (this.threadList && latest[this.wito.server_side_threadList_NAME]) {
			this.threadList.compare(latest[this.wito.server_side_threadList_NAME]);
		} else {
			this.updateSendRequest();
		}
	}
}


witoSessionClass.prototype.isLocked = function(type) {
	// sessions are async/refs are user-specific, therefore no client-side locking
	return(false);
}


witoSessionClass.prototype.update = function(latest) {
	// decide if this is a populated update, or a thin update which needs populating
	if (!this.incomplete(latest)) {
		this.wito.generic_processUpdateToQueue(this, latest, 'session');
	} else {
		this.updateSendRequest();
	}
}


witoSessionClass.prototype.updateSendRequest = function() {
	// this.wito.debug('send update session ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionGET | this.wito.flag_targetSESSION);
	upd.postObj.session = this.createPartial(this.wito.flag_actionGET);
	upd.send();
}


witoSessionClass.prototype.updateSendRehash = function() {
	// this.wito.debug('send rehash session ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionSRVREHASH | this.wito.flag_targetSESSION);
	upd.postObj.session = this.createPartial(this.wito.flag_actionSRVREHASH);
	upd.send();
}


witoSessionClass.prototype.incomplete = function(obj) {
	if (!obj) obj = this;
	// return(obj.url == undefined); // every session must be on a page, therefore url
	// return(!obj.flagedit);
	return(obj.data == undefined);
}


// implements UpdateableVisualInterface
witoSessionClass.prototype.updateUI = function(prop, before, after) {
	switch(prop) {
		case 'data' :
			var update = after;
			if (this.wito.toolbox) {
				if (this.wito.toolbox.isVisible()) {
					// can't assume that a visible toolbox means an instantiated sessionSelect
					if (this.wito.toolbox.sessionSelect) {
						update = this.wito.toolbox.sessionSelect.makeDisplayText(this.ref, after, this.threadList.getCount());
					}
				}
			}
			witoQuery('#' + 'wito_sess_opt-' + this.ref).html(update);
			break;
		default :
			// this.wito.debug(prop+' has changed ('+before+','+after+')');
			break;
	}
}


witoSessionClass.prototype.show = function(postToServer) {
	this.threadList.show();
	/**
	 * haven't decided about this yet
	 * 
	if (postToServer) {
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionSHOW | this.wito.flag_targetSESSION);
		upd.postObj.session = this.createPartial(this.wito.flag_actionSHOW);
		upd.send();
	}
	 */
}


witoSessionClass.prototype.hide = function(postToServer) {
	this.threadList.hide();
	/**
	 * haven't decided about this yet
	 * 
	if (postToServer) {
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionHIDE | this.wito.flag_targetSESSION);
		upd.postObj.session = this.createPartial(this.wito.flag_actionHIDE);
		upd.send();
	}
	 */
}


witoSessionClass.prototype.setCurrent = function(postToServer) {
	this.sessionList.setCurrent(this.ref);
	if (postToServer) {
		// pass session up to server
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionSELECT | this.wito.flag_targetSESSION);
		upd.postObj.session = this.createPartial(this.wito.flag_actionSELECT);
		upd.send();
	}
}


witoSessionClass.prototype.createPartial = function(action) {
	// rehash before sending to server, [run-time] cascade aggregates
	this.hash.hash_calculate(true);			 // cascade up (hval)
	this.hash.hash_aggregate(true, true, "|");  // cascade up and down (hchild)
	// send sub-object to server
	var pso = new Object;
	pso.ref = this.ref;
	pso.hval = this.hash.hval;
	pso.hchild = this.hash.hchild;
	pso.hupd = 0;
	if (action & this.wito.flag_actionSELECT) {
		pso.flagdisp = this.flagdisp;
		pso.hupd ^= this.flagdisp;
	}
	if (action & this.wito.flag_actionEDIT) {
		pso.flagedit = this.flagedit;
		pso.hupd ^= this.flagedit;
	}
	return(pso);
}


witoSessionClass.prototype.isSelected = function() {
	return(this.flagdisp & this.wito.flag_displaySELECTED);
}


witoSessionClass.prototype.isVisible = function() {
	return(this.flagdisp & this.wito.flag_displayVISIBLE);
}


witoSessionClass.prototype.isDeleted = function() {
	return(this.flagdisp & this.wito.flag_displayDELETED);
}


witoSessionClass.prototype.edit_begin = function(edobj) {
	if (this.editing != null) {
		// if we were previously editing this object
		if (this.editing.obj == edobj) {
			// just commit and return
			this.editing.commit();
			// note duplication because of return
			this.editing = null;
			return;
		} else {
			// otherwise commit and flow into edit
			this.editing.commit();
			this.editing = null;
		}
	}
	// create new object
	this.editing = new witoEditingClass();
	this.editing.init(this.wito, this, edobj);
	if (!this.editing.begin()) {
		// but cancel if we fail to begin the edit (e.g. can't get lock)
		this.editing = null;
	}
}


witoSessionClass.prototype.event_new_session_callback = function(context) {
	return( function(rdo) {
		context.new_session_callback(rdo);
	});
}


witoSessionClass.prototype.new_session_callback = function(rdo){
	var old_session = this.wito.sessionList.getCurrent();
	this.wito.toolbox.sessionSelect.renderAttachOption(this);
	this.wito.toolbox.sessionSelect.forceTo(this.ref);
	if (old_session) old_session.hide();
	this.wito.sessionList.show();
	this.setCurrent(true); // new session then sends 'select' request
	if (this.wito.feedback_visible) {
		this.show();
	}
	// adding a session, there must now be at least two
	this.wito.toolbox.sessionSelect.show();
}


witoSessionClass.prototype.new_thread = function() {
	if (this.threadList) {
		// create a new thread
		var thread = this.threadList.new_thread();
		// if (this.DEBUG_LOSEC) thread.data = 'fupm ref:'+thread.ref;
		thread.renderAttachShow();
		thread.edit();
		// show feedback if hidden
		if (!this.sessionList.isVisible()) this.sessionList.feedback_toggle();
		// show toolbox if this is the first thread
		var tcount = this.threadList.getCount();
		showToolbox = false;
		if (tcount > 0) showToolbox = true;
		if (showToolbox) {
			this.wito.toolbox.show();
		}
	} else {
		this.wito.warning('Session thread list has yet to be initialised.');
	}
}


/**
 * witoSessionList
 *   list of sessions
 *  
 * implements
 *   ListInterface
 */
witoSessionListClass = function() {
	// constructor (sessionList)
}


witoSessionListClass.prototype.init = function(wito, rdo) {
	this.list = new Array();
	this.wito = wito;
	this.parent = null;
	// initialise vars
	this.current = 0;
	this.flagdisp = this.wito.flag_displayVISIBLE;
	this.editing = null;		   // all sessions created with editing
	// add passed sessions to list
	this.recv_sessions(rdo);
	// setup selected (and pass up)
	var sess = this.deriveCurrent();
	sess.setCurrent();
	this.current = sess.ref;
	// attach session list to toolbox
	this.linkToolbox(this.wito.toolbox);
}


witoSessionListClass.prototype.clone = function() {
	// this object does not contain any objects, so use the lightweight copy code
	var temp = new witoSessionListClass();
	for (key in this) { 
		temp[key] = this[key]; 
	} 
	return temp;
}


witoSessionListClass.prototype.get_default = function() {
	if (this.wito.default_session) return(this.wito.default_session);
	var session = new witoSessionClass();
	// session ref is initially unassigned
	session.ref = this.wito.ref_UNSET;
	// default display (show if selected) and edit (read only) settings
	session.data = 'no title';
	session.flagdisp = this.wito.flag_displayVISIBLE | this.wito.flag_displayVISIFSEL; // new sessions are visible by default
	session.flagedit = this.wito.flag_actionNONE;
	// setup constants
	session.addOffsetX = 0;
	session.addOffsetY = 0;
	session.addOffsetXinc = 15;
	session.addOffsetYinc = 30;
	session.addOffsetXmod = 105;
	session.addOffsetYmod = 210;
	// cache default
	this.wito.default_session = session;
	return(this.wito.default_session);
}


witoSessionListClass.prototype.recv_default = function(server_session) {
	var session = this.get_default();
	// overwrite with defaults from server
	session.copyFrom(server_session);
	// set as default (redundant)
	this.wito.default_session = session;
}


witoSessionListClass.prototype.new_session = function(template) {
	// var template is local (argument)
	if (!template) template = this.get_default();
	// copy template to create new object
	var session = template.clone();
	session.init(this.wito, this);
	session.ref = this.wito.ref_UNSET;
	// add to list (overwrites ref)
	this.add(session);
	// pass session up to server
	var upd = this.wito.ajax_prep(session, this.wito.flag_actionNEW | this.wito.flag_targetSESSION);
	upd.postObj.session = session.createPartial(this.wito.flag_actionNEW);
	upd.postObj.callback = session.event_new_session_callback(session);
	upd.send();
	return(session);
}


witoSessionListClass.prototype.recv_session = function(recvd) {
	var template = this.get_default();
	// copy template to create new object
	var session = template.clone();
	session.init(this.wito, this);
	session.ref = this.wito.ref_UNSET; // copyFrom will set with recvd.ref
	// only copy in the fields already defined (from default)
	session.copyFrom(recvd, session);
	if (recvd[this.wito.server_side_threadList_NAME]) {
		var tlist = recvd[this.wito.server_side_threadList_NAME];
		for (var i=0 ; i<tlist.length ; ++i) {
			var t = tlist[i];
			session.threadList.recv_thread(t);
		}
	}
	this.add(session);
	// if session was added incomplete, send request to server to update
	if (session.incomplete(recvd)) {
		session.updateSendRequest();
	}
	return(session);
}


witoSessionListClass.prototype.recv_sessions = function(rdo_sessOOM) {
	// rdo_sessOOM = return data object - sessions (one or more)
	if (typeof(rdo_sessOOM.length) == 'undefined') {
		this.recv_session(rdo_sessOOM);
	}
	else {
		for (var i = 0 ; i<rdo_sessOOM.length ; ++i) {
			this.recv_session(rdo_sessOOM[i]);
		}
	}
}


// implement ListInterface
witoSessionListClass.prototype.compare = function(latest) {
	this.wito.generic_compareList(this, latest, 'session');
}


witoSessionListClass.prototype.add = function(sess) {
	// rehash before adding to list, [init-time] delay cascading
	sess.hash.hash_calculate(false);
	if (sess.ref == this.wito.ref_UNSET) {
		// assign sess identifier (if not recvd from server)
		sess.ref = this.list.length;
	}
	// append to sessionList
	this.list[sess.ref] = sess;
}


witoSessionListClass.prototype.get = witoClass.prototype.generic_get;


witoSessionListClass.prototype.getList = function() {
	return(this.list);
}


witoSessionListClass.prototype.receive = function(latest) {
	return(this.recv_session(latest));
}


witoSessionListClass.prototype.deriveCurrent = function() {
	// work through all sessions and test flags to find current
	for (i=0 ; i<this.list.length ; ++i) {
		var session = this.list[i];
		if (!session) continue;
		// debugString += 'session '+i+' flagdisp '+session.flagdisp+'\r\n';
		if (session.isSelected()) {
			// this.wito.debug('selecting session ref '+session.ref);
			return(this.get(session.ref));
		}
	}
	// if not found
	return(this.getLast());
}


/**
 * Session list class keeps track of current session
 * - although wito also caches (wito.session) so could use that
 */
witoSessionListClass.prototype.getCurrent = function() {
	var ref = this.current;
	if (ref > (this.list.length - 1)) return(null);
	return(this.get(ref));
}


witoSessionListClass.prototype.setCurrent = function(ref) {
	if (ref > (this.list.length - 1)) return(null);
	this.current = ref;
	var session = this.get(ref);
	// check count of current session
	if (session.threadList.count == 0) {
		this.wito.heartbeat.suspend();
	}
	if (session.threadList.count > 0) {
		this.wito.heartbeat.resume();
	}
	return(session);
}


witoSessionListClass.prototype.getNext = function() {
	return(this.getDelta(1));
}


witoSessionListClass.prototype.getPrevious = function() {
	return(this.getDelta(-1));
}


witoSessionListClass.prototype.getDelta = function(delta) {
	var session = null;
	var ref = this.current;
	// sparse list safe version
	for (var i=0 ; (i<this.list.length) && !session ; ++i) {
		ref += delta;
		if (ref > (this.list.length - 1)) ref = 0;
		if (ref < 0) ref = this.list.length - 1;
		session = this.get(ref);
		if (session) break;
	}
	// this.wito.debug(session.ref);
	return(session);
}


witoSessionListClass.prototype.getLast = function() {
	var ref = this.list.length - 1;
	// this.wito.debug(this.wito.__objectToString(this.get(ref)));
	return(this.get(ref));
}


witoSessionListClass.prototype.getCount = function() {
	return(this.list.length);
}


witoSessionListClass.prototype.linkToolbox = function(toolbox) {
	this.toolbox = toolbox;
	for (i=0 ; i<this.list.length ; ++i) {
		var session = this.list[i];
		if (!session) continue;
		toolbox.addSelectOption(session);
	}
}


witoSessionListClass.prototype.isVisible = function() {
	return(this.flagdisp & this.wito.flag_displayVISIBLE);
}


witoSessionListClass.prototype.show = function() {
	this.flagdisp |= this.wito.flag_displayVISIBLE;
	if (this.visibilityListener) this.visibilityListener(true);
}


witoSessionListClass.prototype.hide = function() {
	this.flagdisp &= (this.wito.flag_displayVISIBLE ^ this.wito.flag_displayMASK);
	if (this.visibilityListener) this.visibilityListener(false);
}


witoSessionListClass.prototype.feedback_toggle = function() {
	var session = this.getCurrent();
	if (this.isVisible()) {
		if (session) session.hide();
		if (this.visibilityListener) this.visibilityListener(1);
		// tool.setState(1);
		this.hide();
	} else {
		if (session) session.show();
		if (this.visibilityListener) this.visibilityListener(0);
		// tool.setState(0);
		this.show();
	}
}


/**
 *
 * Toolbox::SessionSelect
 *
 */
witoSessionSelectClass = function() {
	// constructor (sessionSelect)
}


witoSessionSelectClass.prototype.init = function(wito, toolbox) {
	this.wito = wito;
	this.toolbox = toolbox;
	this.optionSeq = 0;
	this.toolbox.jq.append(this.render());
	this.jq = witoQuery('#wito_sessionSelect');
	// attach change listeners
	this.jq.bind('change', null, this.event_change(this));
	if (this.toolbox.hovertarget) this.toolbox.hovertarget.attachOver(this.jq, 'Select session');
	var prev = witoQuery('#wito_sessionSelect_prev');
	prev.bind('click', null, this.event_clickDelta(this, -1));
	if (this.toolbox.hovertarget) this.toolbox.hovertarget.attachOver(prev, 'View previous session');
	var next = witoQuery('#wito_sessionSelect_next');
	next.bind('click', null, this.event_clickDelta(this, 1));
	if (this.toolbox.hovertarget) this.toolbox.hovertarget.attachOver(next, 'View next session');
}


witoSessionSelectClass.prototype.render = function() {
	var html = '';
	html += '<div class="wito_toolbox_plinth wito_toolbox_sessionSelect" style="display:none;" id="wito_sessionSelect_outer">'
	html += '<p class="wito_toolbox_button"><a class="pointer" href="#" id="wito_sessionSelect_prev">&laquo;</a></p>';
	html += '<p class="wito_toolbox_elem">';
	html += '<select name="wito_sessionSelect" id="wito_sessionSelect">';
	html += '</select>';
	html += '</p>';
	html += '<p class="wito_toolbox_button"><a class="pointer" href="#" id="wito_sessionSelect_next">&raquo;</a></p>';
	html += '<div class="wito_clear"></div>';
	html += '</div>';
	return(html);
}


witoSessionSelectClass.prototype.event_change = function(context) {
	return( function(e) {
		context.change(e);
	});
}


witoSessionSelectClass.prototype.change = function(e) {
	var new_session = this.wito.sessionList.get(this.jq.val());
	var old_session = this.wito.sessionList.getCurrent();
// this.wito.debug(this.wito.__objectToString(this.jq));
	// out with the old, in with the new
	if (new_session.ref != old_session.ref) {
		old_session.hide();
		this.wito.sessionList.show();
		if (this.wito.feedback_visible) {
			new_session.show();
		}
		// change current session
		new_session.setCurrent(true);
	}
}


witoSessionSelectClass.prototype.event_clickDelta = function(context, delta) {
	return( function(e) {
		context.clickDelta(delta);
		context.wito.event_stop_bubble(e);
	});
}


witoSessionSelectClass.prototype.clickDelta = function(delta) {
	var new_session = this.wito.sessionList.getDelta(delta);
	var old_session = this.wito.sessionList.getCurrent();
	old_session.hide();
	this.wito.sessionList.show();
	this.forceTo(new_session.ref);
	if (this.wito.feedback_visible) {
		new_session.show();
	}
	new_session.setCurrent(true);
}


witoSessionSelectClass.prototype.renderAttachOption = function(session) {
	var html = '';
	var owner = session.flagedit & this.wito.flag_USASUSER;
	html += '<option ';
	html += 'value="'+session.ref+'" ';
	html += 'name="wito_sess_opt-'+session.ref+'" ';
	html += 'class="'+(owner ? 'wito_sess_iam' : '')+'" ';
	var old_session = this.wito.sessionList.getCurrent();
	if (old_session) {
		if (old_session.ref == session.ref) {
			html += 'selected="selected" ';
		}
	}
	html += 'id="wito_sess_opt-'+session.ref+'" ';
	html += '>';
	html += this.makeDisplayText(session.ref, session.data, session.threadList.getCount());
	html += '</option>';
	this.jq.append(html);
	this.optionSeq++;
}


witoSessionSelectClass.prototype.makeDisplayText = function(ref, data, count) {
	var text = ( data == "" ? 'untitled' : data)+' ('+count+')';
	return(text);
}


witoSessionSelectClass.prototype.getCount = function() {
	return(this.optionSeq);
}


witoSessionSelectClass.prototype.forceTo = function(ref) {
	this.jq.val(ref);
}


witoSessionSelectClass.prototype.show = function() {
	var outer = witoQuery('#wito_sessionSelect_outer');
	outer.show();
}


witoSessionSelectClass.prototype.hide = function() {
	var outer = witoQuery('#wito_sessionSelect_outer');
	outer.hide();
}


/**
 *
 * Site
 *
 */
witoSiteClass = function() {
	// constructor (toolbox)
}


witoSiteClass.prototype.init = function(wito) {
	this.wito = wito;
	this.ref = this.wito.ref_UNSET;
}


witoSiteClass.prototype.clone = function() { 
	var temp = new witoSiteClass();
	temp.copyFrom(this);
	return temp; 
}


witoSiteClass.prototype.copyFrom = function(master) {
	var keymaster = master;
	if (arguments.length > 2) keymaster = arguments[1];
	for (key in keymaster) {
		if (master[key] != undefined) {
			this[key] = master[key];
		}
	}
}


// stub, overwritten
witoSiteClass.prototype.setup = null;


/**
 *
 * Sitebox
 *
 */
witoSiteboxClass = function() {
	// constructor (sitebox)
}


witoSiteboxClass.prototype.init = function(wito) {
	this.wito = wito;
	this.list = new Array();
    this.preInitQueue = witoClass.receiverQ_site;
}


witoSiteboxClass.prototype.receiver = function(obj) {
	this.recv_site(obj);
}


witoSiteboxClass.prototype.add = witoClass.prototype.generic_add;


witoSiteboxClass.prototype.get = witoClass.prototype.generic_get;


witoSiteboxClass.prototype.get_default = function() {
	if (this.wito.default_site) return(this.wito.default_site);
	var site = new witoSiteClass();
	// default values here should be overwritten by server values
	// ref is initially unassigned
	site.ref = this.wito.ref_UNSET;
	// cache default
	this.wito.default_site = site;
	return(this.wito.default_site);
}


witoSiteboxClass.prototype.recv_site = function(recvd) {
	var site;
	var siteIsNew = true;
	if (recvd.ref != undefined) {
		// see if this site exists already
		site = this.get(recvd.ref);
		if (site) {
			siteIsNew = false;
		}
	}
	if (siteIsNew) {
		var template = this.get_default();
		// copy template to create new object
		site = template.clone();
		site.init(this.wito, this);
		// copyFrom will overwrite with recvd.ref
		site.ref = this.wito.ref_UNSET;
    }
    // overwrite locals with this one
    site.copyFrom(recvd, site);
    // this.wito.debug(this.wito.__objectToString(site, true));
    // site setup allows dynamic sites to hook in (after init event)
    if (site.setup) site.setup();
    if (siteIsNew) {
		this.add(site);
	}
	return(site);
}


witoSiteboxClass.prototype.recv_sites = function(server_sites) {
	for (var i=0 ; i<server_sites.length ; ++i) {
		this.recv_site(server_sites[i]);
		// recv_site (add) also renders if visible
	}
}


witoSiteboxClass.prototype.getNextUsedRef = witoClass.prototype.generic_getNextUsedRef;


witoSiteboxClass.prototype.processQueue = witoClass.prototype.generic_processPreInitQueue;


/**
 * Blueprint for thread
 * - wito -> session -> threadList -> thread
 * 
 * Blueprint for post
 * - wito -> session -> threadList -> thread -> postList -> post
 * 
 */
function witoThreadClass() {
	// constructor (thread)
}

function witoPostClass() {
	// constructor (post)
}


witoThreadClass.prototype.init = function(wito, threadList) {
	this.wito = wito;
	this.className = "witoThreadClass";
	this.threadList = threadList;
	this.postList = new witoPostListClass()
	this.postList.init(this.wito, this);
	// alias for shared functions
	this.parentList = this.threadList;
	this.hash = new witoHashClass();
	this.hash.init(wito, this.wito.hash_fieldsTHREAD, this, this.postList, this.threadList.parent);
	this.ajaxUpdateList = new witoAjaxUpdateListClass();
	this.ajaxUpdateList.init(this.wito, this);
	this.upd = null;
	this.lockedToLocalForForeign = false;
	this.lockedToForeignForLocal = false;
	this.lockedToForeignForServer= false;
}


witoPostClass.prototype.init = function(wito, postList) {
	this.wito = wito;
	this.postList = postList;
	// alias for shared functions
	this.parentList = this.postList;
	this.className = "witoPostClass";
	this.hash = new witoHashClass();
	this.hash.init(wito, this.wito.hash_fieldsPOST, this, null, this.postList.parent);
	// posts have no children, i.e. no one below to pass up aggregates/zeros
	this.hash.hchild = 0;
	this.ajaxUpdateList = new witoAjaxUpdateListClass();
	this.ajaxUpdateList.init(this.wito, this);
	this.upd = null;
	this.lockedToLocalForForeign = false;
	this.lockedToForeignForLocal = false;
	this.lockedToForeignForServer= false;
}


witoThreadClass.prototype.clone = function() { 
	// clone object properties
	var temp = new witoThreadClass(); 
	temp.copyFrom(this);
	// clone sub-objects
	if (this.postList)
		temp.postList = this.postList.clone();
	return temp; 
}


witoPostClass.prototype.clone = function() { 
	// this object does not contain any objects, so use the lightweight copy code
	var temp = new witoPostClass();
	temp.copyFrom(this);
	return temp; 
}


/**
 * copyFrom
 * - copies data from master object into this object
 * + optionally specify keymaster, incase copying from hostile object
 */
witoThreadClass.prototype.copyFrom = witoClass.prototype.generic_copyFrom;


witoPostClass.prototype.copyFrom = witoClass.prototype.generic_copyFrom;


// implements UpdateableInterface
witoThreadClass.prototype.compare = function(latest) {
	// ignore if thread is locked to foreign updates (discard, wait for another)
	if (this.isLocked(this.wito.lockType_toForeign))
		return;
	// compare hash to see if we need to update
	if (this.hash.hval != latest.hval) {
		this.update(latest);
	}
	// if children updated
	if (this.hash.hchild != latest.hchild) {
		// see if sublist defined in latest, else send update request
		if (this.postList && latest[this.wito.server_side_postList_NAME]) {
			this.postList.compare(latest[this.wito.server_side_postList_NAME]);
		} else {
			this.updateSendRequest();
		}
	}
}


witoPostClass.prototype.compare = function(latest) {
	// ignore if thread is locked to foreign updates (discard, wait for another)
	if (this.isLocked(this.wito.lockType_toForeign))
		return;
	// compare hash to see if we need to update
	if (this.hash.hval != latest.hval) {
		this.update(latest);
	}
	// no children to update
}


witoThreadClass.prototype.update = function(latest) {
	// decide if this is a populated update, or a thin update which needs populating
	if (!this.incomplete(latest)) {
		// this.wito.debug('rest of thread update received '+this.wito.__objectToString(latest));
		this.wito.generic_processUpdateToQueue(this, latest, 'thread');
	} else {
		this.updateSendRequest();
	}
}


witoPostClass.prototype.update = function(latest) {
	if (!this.incomplete(latest)) {
		this.wito.generic_processUpdateToQueue(this, latest, 'post');
	} else {
		this.updateSendRequest();
	}
}


witoThreadClass.prototype.updateSendRequest = function() {
	// this.wito.debug('send update thread ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionGET | this.wito.flag_targetTHREAD);
	upd.postObj.thread = this.createPartial(this.wito.flag_actionGET);
	upd.send();
}


witoPostClass.prototype.updateSendRequest = function() {
	// this.wito.debug('send update post ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionGET | this.wito.flag_targetPOST);
	upd.postObj.post = this.createPartial(this.wito.flag_actionGET);
	upd.send();
}


witoThreadClass.prototype.updateSendRehash = function() {
	// this.wito.debug('send rehash thread ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionSRVREHASH | this.wito.flag_targetTHREAD);
	upd.postObj.thread = this.createPartial(this.wito.flag_actionSRVREHASH);
	upd.send();
}


witoPostClass.prototype.updateSendRehash = function() {
	// this.wito.debug('send rehash post ref('+this.ref+')');
	var upd = this.wito.ajax_prep(this, this.wito.flag_actionSRVREHASH | this.wito.flag_targetPOST);
	upd.postObj.post = this.createPartial(this.wito.flag_actionSRVREHASH);
	upd.send();
}


witoThreadClass.prototype.incomplete = function(obj) {
	if (!obj) obj = this;
	return(!obj.flagedit);
	// return(obj.data == undefined);
}


witoPostClass.prototype.incomplete = function(obj) {
	if (!obj) obj = this;
	return(!obj.flagedit);
	// return(obj.data == undefined);
}


witoThreadClass.prototype.isLocked = function(type) {
	var is = false;
	if (type & this.wito.lockType_toLocalForFOREIGN) {
		is |= this.lockedToLocalForForeign;
	}
	if (type & this.wito.lockType_toForeignForLOCAL) {
		is |= this.lockedToForeignForLocal;
	}
	if (type & this.wito.lockType_toForeignForSERVER) {
		is |= this.lockedToForeignForServer;
	}
	return(is);
}


witoPostClass.prototype.isLocked = witoThreadClass.prototype.isLocked;


witoThreadClass.prototype.lock = function(type) {
	var changed = false; // changed if either (any) is different from before
	if (type & this.wito.lockType_toLocalForFOREIGN) {
		changed |= (this.lockedToLocalForForeign == false);
		this.lockedToLocalForForeign = true;
	}
	if (type & this.wito.lockType_toForeignForLOCAL) {
		changed |= (this.lockedToForeignForLocal == false);
		this.lockedToForeignForLocal = true;
	}
	if (type & this.wito.lockType_toForeignForSERVER) {
		changed |= (this.lockedToForeignForServer == false);
		this.lockedToForeignForServer = true;
	}
	return(changed);
}


witoPostClass.prototype.lock = witoThreadClass.prototype.lock;


witoThreadClass.prototype.unlock = function(type) {
	var changed = false; // changed if either is different from before
	if (type & this.wito.lockType_toLocalForFOREIGN) {
		changed |= (this.lockedToLocalForForeign == true);
		this.lockedToLocalForForeign = false;
	}
	if (type & this.wito.lockType_toForeignForLOCAL) {
		changed |= (this.lockedToForeignForLocal == true);
		this.lockedToForeignForLocal = false;
	}
	if (type & this.wito.lockType_toForeignForSERVER) {
		changed |= (this.lockedToForeignForServer == true);
		this.lockedToForeignForServer = false;
	}
	return(changed);
}


witoPostClass.prototype.unlock = witoThreadClass.prototype.unlock;


// implements UpdateableVisualInterface
witoThreadClass.prototype.updateUI = function(prop, before, after) {
	// handle deletes up front
	if ((prop == 'flagdisp') &&
		(after == this.wito.flag_displayDELETED) &&
		(before != this.wito.flag_displayDELETED)) {
		this.deletex(false);
	}

	// for everything else, only make UI change if object is now visible
	if (!this.isVisible()) return;
	if (!this.jq) {
		// create UI element to update
		this.renderAttachShow();
	} else {
		// ...or update existing UI element
		// this.wito.debug(prop+' now '+after+"px");
		switch(prop) {
			case 'top' :
			case 'left' :
			case 'topleft' :
				this.updateUI('fadeOut');
				this.jq.animate({top: this.top+"px", left: this.left+"px"});
				this.updateUI('fadeIn');
				break;
			case 'width' :
			case 'height' :
			case 'widthheight' :
				// width/height updated (this[prop] = after)
				this.applyDimensionChangeUIonly(true, false);
				// foreign updates may have changed titlebar height, so test/update
				this.applyDimensionIfHeightChange();
				break;
			case 'z' :
				this.jq.css('z-index', after);
				break;
			case 'colour' :
				this.colchange(after, false);
				break;
			case 'data' :
				witoQuery('#wito_thread_paratbar-' + this.ref).html(after);
				// text changes in titlebar may have changed height
				this.applyDimensionIfHeightChange();
				break;
			case 'flagdisp' :
				// find changed bits by XOR
				var bitdiff = before ^ after;
				// this.wito.debug(prop+' has changed ('+before+','+after+'), bitdiff '+bitdiff);
				// if bit is set, use action to change but don't update the server
				if (bitdiff & this.wito.flag_displayMINIMISED) {
					this.minimise_restore(after & this.wito.flag_displayMINIMISED, false);
				}
				if (bitdiff & this.wito.flag_displayCONFDEL) {
					this.confdel_unconfdel(after & this.wito.flag_displayCONFDEL, false);
				}
				break;
			case 'fadeOut' :
				this.jq.animate({opacity: 0.5},500);
				break;
			case 'fadeIn' :
				this.jq.animate({opacity: 1.0},500);
				break;
			case 'skip' :
			default :
				// other changes don't necessarily have a visual component
				// this.wito.debug(prop+' has changed ('+before+','+after+')');
				break;
		}
	}
}


witoPostClass.prototype.updateUI = function(prop, before, after) {
	// handle deletes up front
	if ((prop == 'flagdisp') &&
		(after == this.wito.flag_displayDELETED) &&
		(before != this.wito.flag_displayDELETED)) {
		this.deletex(false);
	}

	if (!this.isVisible()) return;
	if (!this.jq) {
		// create UI element to update
		this.renderAttachShow();
	} else {
		// ...or update existing UI element
		switch(prop) {
			case 'data' :
				witoQuery('#' + 'wito_post-' + this.postList.thread.ref + '-' + this.ref + '_data').html(after);
				break;
			case 'skip' :
			default :
				// this.wito.debug(prop+' has changed ('+before+','+after+')');
				break;
		}
	}
}


/**
 * move the new thread so sequential adds don't overlap
 */
witoThreadClass.prototype.offsetPosition = function() {
	this.left += this.threadList.session.addOffsetX;
	this.top += this.threadList.session.addOffsetY;
	this.threadList.session.addOffsetX = (this.threadList.session.addOffsetX + this.threadList.session.addOffsetXinc) % this.threadList.session.addOffsetXmod;
	this.threadList.session.addOffsetY = (this.threadList.session.addOffsetY + this.threadList.session.addOffsetYinc) % this.threadList.session.addOffsetYmod;
}


witoThreadClass.prototype.renderCalc = function(minimised) {
	var dx = 0, dy = this.height;
	// look for two optional arguments
	if (arguments.length == 3) {
		dx = arguments[1];
		dy = arguments[2];
		// fix up dy in this conditional (was previously in 'shadowHeightRight =' assignment)
		dy = dy - this.heightAdd;
	}
	// calculate margins depending on background state
	this.marginLeft = this.marginLeftExp;
	this.marginTop = this.marginTopExp;
	if (minimised) {
		this.marginLeft = this.marginLeftMini;
		this.marginTop = this.marginTopMini;
	}
	// additional width = margin left (if any) + shadow right + border width
	this.widthAdd = this.marginLeft + this.widthShadow + 2;
	// additional height = margin top (if any) + titlebar + statusbar + shadow bottom
	this.heightAdd = this.marginTop + this.heightTitlebar + this.heightStatusbar + this.heightShadow;
	this.shadowHeightRight = (minimised ? this.heightTitlebar : dy+this.heightTitlebar+this.heightStatusbar-this.shadowOffset+7);
}


/**
 * render the thread as html
 */
witoThreadClass.prototype.render = function() {
	var draggable = true;
	// states
	var minimised = this.isMinimised();
	var confdel = this.isConfdel();
	var visible = this.isVisible();
	// available buttons/options/functions
	var appendable = this.isAppendable();
	var minimiseable = appendable;
	var deleteable = appendable;
	var editable = appendable;
	var resizeable = appendable;
	var colourable = appendable;
	var connectable = appendable;
	var imagepath = this.wito.page_getAssetPath() + 'images/';
	// colour maths stored in thread
	var html = '';
	// don't show invisible threads
	if (!visible && !confdel) return('');
	// calculate derived dimensional vars
	this.renderCalc(minimised);
	this.colComputeVariants();
	// output html
	html += '<div class="wito_thread'+
				(confdel ? '_archived' : '')+
				(minimised ? ' wito_thread_minimised' : '')+
				'" '+
				'style="top:'+(this.top-this.marginTop)+'px;left:'+(this.left-this.marginLeft)+'px;width:'+(this.width+this.widthAdd)+'px;'+
				'height:'+(minimised ? this.heightAdd : this.height+this.heightAdd)+'px;'+
				'z-index:'+this.z+';' +
				'color:#'+this.colourText+';'+
				'" '+
				'id="wito_thread-'+this.ref+'"'+
			'>';
	html += '<img class="wito_yellow'+
				(draggable ? 'arrowptr' : 'arrownot')+'" '+
				'style="'+
					'display: '+(minimised ? 'block' : 'none')+'; '+'" '+
				'src="'+imagepath+'circle_55.png" '+
				'id="wito_thread_'+(draggable ? 'arrowptr' : 'arrownot')+'-'+this.ref+'" '+
			'/>';
	// render titlebar (slightly lighter)
	html += '<div class="wito_'+(draggable ? 'titlebar' : 'titlenot')+' wito_out" '+
				'style="width:'+this.width+'px;min-height:'+this.heightTitlebar+';'+
				'background-color:#'+this.colourLighten+';'+
				'border-color:#'+this.colourDarken+';'+
				'margin-top:'+this.marginTop+'px;margin-left:'+this.marginLeft+'px;" '+
				'id="wito_thread_'+(draggable ? 'titlebar' : 'titlenot')+'-'+this.ref+'" '+
			'>';
	if (minimiseable) {
		html += '<div class="wito_titlebar_button wito_titlebar_button_left wito_glyphright '+(minimised ? '' : 'wito_glyphdown')+ '" '+
					'id="wito_thread_arrowglyph-'+this.ref+'"'+
				'>';
		html += '<a href="#" id="wito_thread_minimise_restore_hook-'+this.ref+'">';
		html += '<img src="'+imagepath+'arrow_spacer.gif" border="0" '+
				'alt="" '+
				'/>';
		html += '</a></div><!-- #wito_thread_arrowglyph-'+this.ref+' -->';
	}
	if (deleteable) {
		html += '<div class="wito_titlebar_button wito_titlebar_button_right wito_deletex" '+
					'id="wito_thread_confdel-'+this.ref+'"'+
				'>';
		html += '<a href="#" id="wito_thread_confdel_hook-'+this.ref+'">';
		html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" />';
		html += '</a></div><!-- wito_thread_confdel-'+this.ref+' -->';
	}
	if (editable) {
		html += '<div class="wito_titlebar_button wito_titlebar_button_right wito_editpen" '+
					'id="wito_thread_editpen-'+this.ref+'"'+
				'>';
		html += '<a href="#" id="wito_thread_edit_hook-'+this.ref+'">';
		html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" id="wito_thread_editpen_img-'+this.ref+'" />';
		html += '</a></div><!-- wito_thread_editpen-'+this.ref+' -->';
	}
	html += '<p class="wito_titlebar_text" '+
				'id="wito_thread_'+(draggable ? "paratbar" : "paratnot")+'-'+this.ref+'" '+
			'>'+(this.data ? this.data : '&nbsp;')+'</p>';
	html += '</div><!-- #wito_thread_titlebar-'+this.ref+' -->';
	// render posts
	html += '<div class="wito_thread_posts'+(minimised ? ' wito_minimised' : '')+'" '+
				'style="width:'+this.width+'px;height:'+this.height+'px;'+
				'background-color:#'+this.colourBack+';'+
				'border-color:#'+this.colourDarken+';'+
				'margin-left:'+this.marginLeft+'px;'+'" '+
				'id="wito_thread_posts-'+this.ref+'"'+
			'>';
	// button seperator
	html += '<div class="wito_clear" id="wito_thread_button_sep-'+this.ref+'"></div>';
	// restore & confirm button (only visible in archived threads)
	if (confdel) {
		html += '<div class="wito_post">';
		html += '<p class="wito_button wito_archived_button wito_button_restore" '+
					'id="wito_thread_restore-'+this.ref+'"'+
				'>';
		html += '<a href="#" '+
					'class="wito_archived_button wito_button_restore" '+
					'id="wito_thread_restore_hook-'+this.ref+'">restore</a>';
		html += '</p><!-- #wito_thread_restore-'+this.ref+'-->';
		html += '<p class="wito_button wito_archived_button wito_button_confdel" '+
					'id="wito_thread_delete-'+this.ref+'"'+
				'>';
		html += '<a href="#" '+
					'class="wito_archived_button wito_button_confdel" '+
					'id="wito_thread_delete_hook-'+this.ref+'">delete</a>';
		html += '</p><!-- #wito_thread_delete-'+this.ref+'-->';
		html += '<p class="wito_data" '+
					'id="wito_thread_confdel_text-'+this.ref+'"'+
				'>';
		html += 'Are you sure you want to delete this thread, and all the posts it contains?  Click <em>Restore</em> to undo.';
		html += '</p><!-- #wito_thread_confdel_text-'+this.ref+'-->';
		html += '</div>';
	}
	// testing out removal of this para
	//   doesn't seem to be anything, but I'm cautious to remove it
	// html += '<p style="clear: both;"></p>';
	html += '</div><!-- #wito_thread_posts-'+this.ref+' -->';
	// thread status bar
	html += '<div class="wito_thread_status'+(minimised ? ' wito_minimised' : '')+' wito_out" '+
				'style="width:'+this.width+'px;height:'+this.heightStatusbar+'px;'+
				'background-color:#'+this.colourBack+';'+
				'border-color:#'+this.colourDarken+';'+
				'margin-left:'+this.marginLeft+'px;'+'" '+
				'id="wito_thread_status-'+this.ref+'" '+
			'>';
	if (!confdel) {
		// add/append link
		if (appendable) {
			html += '<div class="wito_statusbar_button wito_add" id="wito_thread_add-'+this.ref+'"'+'>';
			html += '<a href="#" id="wito_thread_add_hook-'+this.ref+'">';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" id="wito_thread_add_img-'+this.ref+'" />';
			html += '</a></div>';
		}
		if (colourable && false) {
			html += '<div class="wito_statusbar_button wito_linkto" '+
						'id="wito_thread_linkto-'+this.ref+'" '+
					'>';
			html += '<a href="#" id="wito_thread_linkto_hook-'+this.ref+'">';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" id="wito_thread_linkto_img-'+this.ref+'" />';
			html += '</a></div><!-- #wito_thread_linkto-'+this.ref+' -->';
		}
		if (connectable) {
			nextCol = this.colNext(this.colour);
			html += '<div class="wito_statusbar_button wito_colchange" '+
						'style="background-color:#'+this.wito.padHex(nextCol,6)+';'+'"'+
						'id="wito_thread_colchange-'+this.ref+'" '+
					'>';
			html += '<a href="#" id="wito_thread_colchange_hook-'+this.ref+'">';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" id="wito_thread_colchange_img-'+this.ref+'" />';
			html += '</a></div><!-- #wito_thread_colchange-'+this.ref+' -->';
		}
		if (resizeable) {
			html += '<div class="wito_statusbar_button wito_resize" id="wito_resize-'+this.ref+'"'+'>';
			html += '<a href="#" id="wito_thread_resize_hook-'+this.ref+'">';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="" border="0" id="wito_resize_img-'+this.ref+'" />';
			html += '</a></div>';
		}
		if (this.wito.DEBUG_LOSEC) {
			html += '<div class="wito_statusbar_button wito_debug" '+
						'id="wito_thread_debug-'+this.ref+'" '+
					'>';
			html += '<a href="#" id="wito_thread_debug_hook-'+this.ref+'">';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="Link to another" border="0" id="wito_thread_debug_img-'+this.ref+'" />';
			html += '</a></div><!-- #wito_debug_linkto-'+this.ref+' -->';
		}
	}
	html += '<div id="wito_thread_statusbar_sep-'+this.ref+'"></div>';
	html += '</div><!-- #wito_thread_status-'+this.ref+' -->';
	// shadows
	html += '<div class="wito_shadow wito_shadow_right" '+
			'style="height:'+this.shadowHeightRight+'px;top:-'+(this.shadowHeightRight-5)+'px;" '+
			'id="wito_shadow_right-'+this.ref+'" '+
			'></div>';
	html += '<div class="wito_shadow wito_shadow_bottom" '+
			'style="width:'+(minimised ? this.width - this.shadowOffset : this.width-10)+'px;top:'+(minimised ? 0 : 0)+'px;" '+
			'id="wito_shadow_bottom-'+this.ref+'" '+
			'>&nbsp;</div>';
	html += '</div><!-- #wito_thread-'+this.ref+' -->';
	return(html);
}


/**
 * render the post as html
 */
witoPostClass.prototype.render = function() {
	var editable = this.isEditable();
	var deleteable = editable;
	var visible = this.isVisible();
	var imagepath = this.wito.page_getAssetPath() + 'images/';
	var html = '';
	if (visible) {
		html += '<div class="wito_post wito_out" '+
					'id="wito_post-'+this.postList.thread.ref+'-'+this.ref+'"'+
				'>';
        /**
         *
         * working on the idea of two sets of edit/delete buttons
         *
		if (deleteable) {
			html += '<div class="wito_button wito_button_right wito_deletex" '+
						'id="wito_post_pre_delete-'+this.postList.thread.ref+'-'+this.ref+'"'+
					'>';
			html += '<a href="#" '+
						'class="wito_button wito_delete"'+
						'id="wito_post_pre_delete_hook-'+this.postList.thread.ref+'-'+this.ref+'" '+
					'>';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="delete" border="0" />';
			html += '</a></div><!-- wito_thread_pre_confdel-'+this.ref+' -->';
		}
		 *
		 *
         */
		html += '<p class="wito_data" '+
					'id="wito_post-'+this.postList.thread.ref+'-'+this.ref+'_data"'+
				'>'+this.data+'</p>';
		if (deleteable) {
			html += '<div class="wito_button wito_button_right wito_deletex" '+
						'id="wito_post_delete-'+this.postList.thread.ref+'-'+this.ref+'"'+
					'>';
			html += '<a href="#" '+
						'class="wito_button wito_delete"'+
						'id="wito_post_delete_hook-'+this.postList.thread.ref+'-'+this.ref+'" '+
					'>';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="delete" border="0" />';
			html += '</a></div><!-- wito_thread_confdel-'+this.ref+' -->';
		}
		if (editable) {
			html += '<div class="wito_button wito_button_right wito_editpen" '+
						'id="wito_post_editpen-'+this.postList.thread.ref+'-'+this.ref+'"'+
					'>';
			html += '<a href="#" '+
						'class="wito_button wito_edit"'+
						'id="wito_post_edit_hook-'+this.postList.thread.ref+'-'+this.ref+'" '+
					'>';
			html += '<img src="'+imagepath+'arrow_spacer.gif" alt="edit post" border="0" />';
			html += '</a></div><!-- wito_thread_editpen-'+this.ref+' -->';
		}
		html += '</div><!-- #wito_post-'+this.postList.thread.ref+'-'+this.ref+' -->';
	}
	return(html);
}


/**
 * attach thread html to page
 */
witoThreadClass.prototype.attach = function(html) {
	var tpart;
	// protect against repeat calls
	if (this.jq) return;
	// append to end of thread base div
	this.wito.page.threadBase.append(html);
	this.jq = witoQuery('#wito_thread-'+this.ref);
	// read back variable heights and reset outer container height
	this.applyDimensionIfHeightChange();
	// attach status bar hovertarget
	this.hovertarget = new witoHoverTargetClass();
	this.hovertarget.init(this.wito, this, 'thread-'+this.ref);
	tpart = this.hovertarget.attach(witoQuery('#wito_thread_statusbar_sep-'+this.ref), this.hovertarget.render());
/**
 *
 * START HERE
 *   this doesn't work in IE
 *
 */
	this.event_drag_statusbar_hover_function = this.event_dragStart(this, tpart[0].id);
	tpart.bind('mousedown', null, this.event_drag_statusbar_hover_function);
	// if thread is visible, attach event handlers
	if (this.isVisible()) {
		if (this.isConfdel()) {
			// attach confirm delete thread events
			this.event_delete_function = this.event_delete(this);
			witoQuery('#wito_thread_delete_hook-'+this.ref).bind('click', null, this.event_delete_function);
			this.event_unconfdel_function = this.event_unconfdel(this);
			witoQuery('#wito_thread_restore_hook-'+this.ref).bind('click', null, this.event_unconfdel_function);
			// reuse titlebar buttons for delete restore (in this context)
			this.event_edit_function = this.event_unconfdel(this);
			witoQuery('#wito_thread_edit_hook-'+this.ref).bind('click', null, this.event_unconfdel_function);
			// confdel hook is used to confirm the delete (in this context)
			this.event_confdel_function = this.event_delete(this);
			witoQuery('#wito_thread_confdel_hook-'+this.ref).bind('click', null, this.event_delete_function);
		} else {
			// setup postBase for this newly attached thread
			this.postBase = witoQuery('#wito_thread_button_sep-'+this.ref)
			// attach normal thread events
			this.event_iconvis_show_function = this.event_iconvis(this, true);
			tpart = witoQuery('#wito_thread_titlebar-'+this.ref);
			tpart.bind('mouseover', null, this.event_iconvis_show_function);
			this.event_iconvis_hide_function = this.event_iconvis(this, false);
			tpart.bind('mouseout', null, this.event_iconvis_hide_function);
			tpart = witoQuery('#wito_thread_status-'+this.ref);
			this.event_drag_statusbar_function = this.event_dragStart(this, 'wito_thread_status-'+this.ref);
			tpart.bind('mousedown', null, this.event_drag_statusbar_function);
			tpart.bind('mouseover', null, this.event_iconvis_show_function);
			tpart.bind('mouseout', null, this.event_iconvis_hide_function);
			this.event_edit_function = this.event_edit(this);
			tpart = witoQuery('#wito_thread_edit_hook-'+this.ref);
			tpart.bind('click', null, this.event_edit_function);
			this.hovertarget.attachOver(tpart, "Edit this title");
			this.event_confdel_function = this.event_confdel(this);
			tpart = witoQuery('#wito_thread_confdel_hook-'+this.ref);
			tpart.bind('click', null, this.event_confdel_function);
			this.hovertarget.attachOver(tpart, "Delete this feedback");
			this.event_minimise_restore_function = this.event_minimise_restore(this);
			tpart = witoQuery('#wito_thread_minimise_restore_hook-'+this.ref);
			tpart.bind('click', null, this.event_minimise_restore_function);
			this.hovertarget.attachOver(tpart, "Collapse this feedback");
			this.event_add_function = this.event_add(this)
			tpart = witoQuery('#wito_thread_add_hook-'+this.ref);
			tpart.bind('click', null, this.event_add_function);
			this.hovertarget.attachOver(tpart, "Add more detail");
			this.event_colchange_function = this.event_colchange(this)
			tpart = witoQuery('#wito_thread_colchange_hook-'+this.ref);
			tpart.bind('click', null, this.event_colchange_function);
			this.hovertarget.attachOver(tpart, "Change the colour");
			this.event_debug_function = this.event_debug(this)
			witoQuery('#wito_thread_debug_hook-'+this.ref).bind('click', null, this.event_debug_function);
			// extra careful on the mousedown event handlers (see also _status-)
			this.event_drag_paratbar_function = this.event_dragStart(this, 'wito_thread_paratbar-'+this.ref);
			witoQuery('#wito_thread_paratbar-'+this.ref).bind('mousedown', null, this.event_drag_paratbar_function);
			this.event_drag_titlebar_function = this.event_dragStart(this, 'wito_thread_titlebar-'+this.ref);
			witoQuery('#wito_thread_titlebar-'+this.ref).bind('mousedown', null, this.event_drag_titlebar_function);
			this.event_drag_arrow_function = this.event_dragStart(this, 'wito_thread_arrowptr-'+this.ref);
			witoQuery('#wito_thread_arrowptr-'+this.ref).bind('mousedown', null, this.event_drag_arrow_function);
			this.event_drag_posts_function = this.event_dragStart(this, 'wito_thread_posts-'+this.ref, 'wito_post-'+this.ref);
			tpart = witoQuery('#wito_thread_posts-'+this.ref);
			tpart.bind('mousedown', null, this.event_drag_posts_function);
			tpart.bind('mouseover', null, this.event_iconvis_show_function);
			tpart.bind('mouseout', null, this.event_iconvis_hide_function);
			this.event_resize_drag_function = this.event_resizeStart(this, 'wito_resize_img-'+this.ref);
			tpart = witoQuery('#wito_thread_resize_hook-'+this.ref);
			tpart.bind('mousedown', null, this.event_resize_drag_function);
			this.hovertarget.attachOver(tpart, "Resize this container");
			this.event_resize_click_function = this.event_ignore(this);
			witoQuery('#wito_thread_resize_hook-'+this.ref).bind('click', null, this.event_resize_click_function);
		}
	}
}


/**
 * attach post html to thread
 */
witoPostClass.prototype.attach = function(html) {
	// protect against repeat calls
	if (this.jq) return;
	if (this.isVisible()) {
		this.attachInOrder(html);
		this.jq = witoQuery('#wito_post-'+this.postList.thread.ref+'-'+this.ref);
		// add events to this post
		this.event_edit_function = this.event_edit(this);
		this.event_delete_function = this.event_delete(this);
		witoQuery('#wito_post_edit_hook-'+this.postList.thread.ref+'-'+this.ref).bind('click', null, this.event_edit_function);
		witoQuery('#wito_post_delete_hook-'+this.postList.thread.ref+'-'+this.ref).bind('click', null, this.event_delete_function);
		this.event_iconvis_show_function = this.event_iconvis(this, true);
		this.jq.bind('mouseover', null, this.event_iconvis_show_function);
		this.event_iconvis_hide_function = this.event_iconvis(this, false);
		this.jq.bind('mouseout', null, this.event_iconvis_hide_function);
	}
}


witoPostClass.prototype.attachInOrder = function(html) {
	var nextRef = this.postList.getNextUsedRef(this.ref);
	if (nextRef == this.wito.ref_UNSET) {
		// insert post at tail
		this.postList.thread.postBase.before(html);
	} else {
		// insert post before next
		witoQuery('#wito_post-'+this.postList.thread.ref+'-'+nextRef).before(html);
	}
}


/**
 * detach the thread by unhooking all events and removing html
 */
witoThreadClass.prototype.detach = function() {
	if (!this.jq) return;
	if (this.postList.list.length > 0) {
		for (var i=0 ; i<this.postList.list.length ; ++i) {
			var post = this.postList.list[i];
			if (post) {
				post.detach();
			}
		}
	}
	// detach normal thread events
	if (this.event_edit_function)
		witoQuery('#wito_thread_edit_hook-'+this.ref).unbind('click', this.event_edit_function);
	if (this.event_confdel_function)
		witoQuery('#wito_thread_confdel_hook-'+this.ref).unbind('click', this.event_confdel_function);
	if (this.event_minimise_restore_function)
		witoQuery('#wito_thread_minimise_restore_hook-'+this.ref).unbind('click', this.event_minimise_restore_function);
	if (this.event_add_function)
		witoQuery('#wito_thread_add_hook-'+this.ref).unbind('click', this.event_add_function);
	if (this.event_drag_paratbar_function)
		witoQuery('#wito_thread_paratbar-'+this.ref).unbind('mousedown', this.event_drag_paratbar_function);
	if (this.event_drag_statusbar_function)
		witoQuery('#wito_thread_status-'+this.ref).unbind('mousedown', this.event_drag_statusbar_function);
	if (this.event_drag_arrow_function)
		witoQuery('#wito_thread_arrowptr-'+this.ref).unbind('mousedown', this.event_drag_arrow_function);
	if (this.event_drag_posts_function)
		witoQuery('#wito_thread_posts-'+this.ref).unbind('mousedown', this.event_drag_posts_function);
	if (this.event_resize_drag_function)
		witoQuery('#wito_thread_resize_hook-'+this.ref).unbind('mousedown', null, this.event_resize_drag_function);
	// detach confdel thread events
	if (this.event_delete_function)
		witoQuery('#wito_thread_delete_hook-'+this.ref).unbind('click', this.event_delete_function);
	if (this.event_unconfdel_function)
		witoQuery('#wito_thread_restore_hook-'+this.ref).unbind('click', this.event_unconfdel_function);
	// detach hovertarget (and associated direct and secondhand events)
	if (this.hovertarget) this.hovertarget.detach();
	// delete html from page
	this.jq.remove();
	this.jq = null;
}


/**
 * attach post html to thread
 */
witoPostClass.prototype.detach = function(html) {
	if (!this.jq) return;
	// detach events from this post
	witoQuery('#wito_post_edit_hook-'+this.postList.thread.ref+'-'+this.ref).unbind('click', this.event_edit_function);
	witoQuery('#wito_post_delete_hook-'+this.postList.thread.ref+'-'+this.ref).unbind('click', this.event_delete_function);
	this.jq.unbind('mouseover', this.event_iconvis_show_function);
	this.jq.unbind('mouseout', this.event_iconvis_hide_function);
	this.jq.remove();
	this.jq = null;
}


witoThreadClass.prototype.renderAttachShow = function() {
	// protect against multiple calls
	if (this.jq) return;
	if (this.attach) {
		this.attach(this.render());
		// if thread has posts, attach posts
		if (this.postList.list.length > 0) {
			if (this.isVisible() && !this.isConfdel()) {
				for (var i=0 ; i<this.postList.list.length ; ++i) {
					var post = this.postList.list[i];
					if (post) {
						post.renderAttachShow();
					}
				}
			}
		}
		this.show();
	}
}


witoPostClass.prototype.renderAttachShow = function() {
	// protect against multiple calls
	if (this.jq) return;
	if (this.attach) {
		this.attach(this.render());
		this.show();
	}
}


/**
 * display the thread by making it visible
 */
witoThreadClass.prototype.show = function() {
	if (!this.jq) return;
	this.jq.show();
}


witoPostClass.prototype.show = function() {
	// post visibility/show controlled by thread vis/show
	// may extend in order to scroll pane to this post
}


/**
 * hide the thread by making it display none
 */
witoThreadClass.prototype.hide = function() {
	if (!this.jq) return;
	this.jq.hide();
}


witoPostClass.prototype.hide = function() {
	if (!this.jq) return;
	this.jq.hide();
}


witoThreadClass.prototype.setText = function(mess) {
	var id = 'wito_thread_paratbar-' + this.ref;
	witoQuery('#'+id).html(mess);
}


witoPostClass.prototype.setText = function(mess) {
	var id = 'wito_post-' + this.postList.thread.ref + '-' + this.ref + '_data';
	witoQuery('#'+id).html(mess);
}


witoThreadClass.prototype.setMessage = function(mess) {
	
}


witoPostClass.prototype.setMessage = function(mess) {
	
}


/**
 * begin editing this thread
 * - change title to editable textfield, set cursor etc.
 */
witoThreadClass.prototype.edit = function() {
	this.wito.edit_begin(this);
}


/**
 * test if a thread is visible
 */
witoThreadClass.prototype.isVisible = function() {
	return(this.flagdisp & this.wito.flag_displayVISIBLE);
}


/**
 * test if a post is visible
 * - really testing whether we should attach events or not
 */
witoPostClass.prototype.isVisible = function() {
	// post visibility limited by thread
	return((this.flagdisp & this.wito.flag_displayVISIBLE) && this.postList.thread.isVisible());
}


witoThreadClass.prototype.isConfdel = function() {
 // test if a thread is confirm-delete mode
	return(this.flagdisp & this.wito.flag_displayCONFDEL);
}


witoThreadClass.prototype.isMinimised = function() {
	return(this.flagdisp & this.wito.flag_displayMINIMISED);
}


witoThreadClass.prototype.isAppendable = function() {
	return(this.flagedit & this.wito.flag_actionAPPEND);
}


witoThreadClass.prototype.isEditable = function() {
	return(this.flagedit & this.wito.flag_actionEDIT);
}


witoPostClass.prototype.isEditable = function() {
	return(this.flagedit & this.wito.flag_actionEDIT);
}


witoThreadClass.prototype.isDeleted = function() {
	return(this.flagdisp & this.wito.flag_displayDELETED);
}


witoPostClass.prototype.isDeleted = function() {
	return(this.flagdisp & this.wito.flag_displayDELETED);
}


witoThreadClass.prototype.event_dragStart = function(context, matchid) {
	var matchwild = matchid;
	// if wildcard (3rd) argument given, try and match to that also
	if (arguments.length == 3) {
		matchwild = arguments[2];
	}
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		var evtarget = (witoQuery.browser.msie ? event.srcElement : e.target);
		var evcompare = evtarget.id.substr(0,matchwild.length);
		// context.wito.debug('drag start: matching click('+evtarget.id+') to either ('+matchid+') or ('+matchwild+')');
		if ((evtarget.id == matchid) ||
			(evcompare == matchwild)) {
			// calculate scrollbar bounding box
			var withinScrollbar = false;
			// client X/Y is the mouse coord
			var minX = context.left+context.marginLeft;
			var minY = context.top+context.marginTop;
			var maxX = minX + context.width;
			var maxY = minY + context.heightTitlebar + context.height;
			var scrollWidth = 16;
			// don't need to trap against minX/Y because listener attached to inner div
			withinScollbar = (e.clientX > (maxX - scrollWidth));

			var s;
			s  = 'min '+minX+' '+minY+'\r\n';
			s += 'max '+maxX+' '+maxY+'\r\n';
			s += 'e '+e.clientX+' '+e.clientY+'\r\n';
			s += 'within='+(withinScollbar ? 'yes' : 'no')+'\r\n';
			//this.wito.debug(s);

			if (!withinScollbar) {
				// commit previous edit 
				context.wito.edit_commit();
				// try to lock object
				if (!context.isLocked(context.wito.lockType_toForeignForLOCAL)) {
					context.lock(context.wito.lockType_toForeignForLOCAL);
				} else {
					return;
				}
				context.dragStart(e, false);
				context.wito.event_stop_bubble(e);
				// attach document listener for mousemove & mouseup
				context.event_dragging_function = context.event_dragging(context);
				context.event_dragStop_function = context.event_dragStop(context);
				witoQuery(document).bind('mousemove', null, context.event_dragging_function);
				witoQuery(document).bind('mouseup', null, context.event_dragStop_function);
			} else {
				// ignore clicks in scrollbar
			}
		}
	});
}


witoThreadClass.prototype.event_resizeStart = function(context, matchid) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		var evtarget = (witoQuery.browser.msie ? event.srcElement : e.target);
		if (evtarget.id == matchid) {
			// commit previous edit 
			context.wito.edit_commit();
			// try to lock object
			if (!context.isLocked(context.wito.lockType_toForeignForLOCAL)) {
				context.lock(context.wito.lockType_toForeignForLOCAL);
			} else {
				return;
			}
			context.dragStart(e, true);
			context.wito.event_stop_bubble(e);
			// attach document listener for mousemove & mouseup
			context.event_dragging_function = context.event_dragging(context);
			context.event_dragStop_function = context.event_dragStop(context);
			witoQuery(document).bind('mousemove', null, context.event_dragging_function);
			witoQuery(document).bind('mouseup', null, context.event_dragStop_function);
		}
	});
}


witoThreadClass.prototype.event_ignore = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.wito.event_stop_bubble(e);
	});
}


witoThreadClass.prototype.dragStart = function(e, resize) {
	// this.wito.debug(this.wito.__objectToString(e.target));
	// bring thread to front
	this.threadList.bringToFront(this);
	// create drag in progress (dip) container
	this.dip = new Object();
	this.dip.resize = resize;
	// record initial div coords
	if (this.dip.resize) {
		this.dip.minWidth = this.widthMin;
		this.dip.minHeight = this.heightAdd; // threads bound by titlebar + statusbar height
		this.dip.startX = parseInt(this.jq.css('width'));
		this.dip.startY = parseInt(this.jq.css('height'));
	} else {
		this.dip.startX = parseInt(this.jq.css('left'));
		this.dip.startY = parseInt(this.jq.css('top'));
	}
    if (e) {
        // record initial mouse coords
        this.dip.offsetX = e.clientX;
        this.dip.offsetY = e.clientY;
    } else {
        this.dip.offsetX = 0;
        this.dip.offsetY = 0;
    }
	// make dragging object semi-transparent
	this.jq.animate({opacity: 0.5},100);
}


witoThreadClass.prototype.event_dragging = function(context) {
	return( function(e) {
		context.dragging(e);
		context.wito.event_stop_bubble(e);
	});
}


witoThreadClass.prototype.dragging = function(e) {
	var dx = this.dip.startX + e.clientX - this.dip.offsetX;
	var dy = this.dip.startY + e.clientY - this.dip.offsetY;
	// update css properties based on drag distance
	if (this.dip.resize) {
		if ((dx < this.dip.minWidth) || (dy < this.dip.minHeight)) return;
		this.heightTitlebar = witoQuery('#wito_thread_titlebar-'+this.ref).height();
		this.applyDimensionChange(dx, dy, true);
		this.dip.minHeight = this.heightAdd;
	} else {
		this.jq.css('left', '' + dx + 'px');
		this.jq.css('top', '' + dy + 'px');
	}
}


witoThreadClass.prototype.event_dragStop = function(context) {
	return( function(e) {
		context.dragStop(e);
		context.wito.event_stop_bubble(e);
		// release events
		witoQuery(document).unbind('mousemove', context.event_dragging_function);
		witoQuery(document).unbind('mouseup', context.event_dragStop_function);
	});
}


witoThreadClass.prototype.dragStop = function(e) {
	var flag = null;
	// record final position
	if (this.dip.resize) {
		this.width = parseInt(this.jq.css('width')) - this.widthAdd;
		this.height = parseInt(this.jq.css('height')) - this.heightAdd;
		this.heightTitlebar = witoQuery('#wito_thread_titlebar-'+this.ref).height();
		this.applyDimensionChangeUIonly(true, false);
		flag = this.wito.flag_actionRESIZE;
	} else {
		this.top = parseInt(this.jq.css('top')) + this.marginTop;
		this.left = parseInt(this.jq.css('left')) + this.marginLeft;
		flag = this.wito.flag_actionMOVE;
	}
	// send a post to record the position/size
	var upd = this.wito.ajax_prep(this, flag | this.wito.flag_targetTHREAD);
	// create partial thread object for update
	upd.postObj.thread = this.createPartial(flag);
	upd.send();
	// collect redundant dip object
	this.dip = null;
	// make the div opaque again
	this.jq.animate({opacity: 1.0},100);
	// release the lock
	this.unlock(this.wito.lockType_toForeignForLOCAL);
}


witoThreadClass.prototype.applyDimensionChange = function(dx, dy, snap) {
	this.renderCalc(this.isMinimised(), dx, dy);
	witoQuery('#wito_thread_titlebar-'+this.ref).css('width', ''+(dx-this.widthAdd)+'px');
	witoQuery('#wito_thread_posts-'+this.ref).css('width', ''+(dx-this.widthAdd)+'px');
	witoQuery('#wito_thread_posts-'+this.ref).css('height', ''+(dy-this.heightAdd)+'px');
	witoQuery('#wito_thread_status-'+this.ref).css('width', ''+(dx-this.widthAdd)+'px');
	witoQuery('#wito_shadow_bottom-'+this.ref).css('width', ''+(dx-this.widthAdd-this.shadowOffset)+'px');
	witoQuery('#wito_shadow_right-'+this.ref).css('height', ''+this.shadowHeightRight+'px');
	witoQuery('#wito_shadow_right-'+this.ref).css('top', ''+(0-this.shadowHeightRight+5)+'px');
	if (snap) {
		this.jq.css('width',dx+"px");
		this.jq.css('height',dy+"px");
	} else {
		this.jq.animate({width: dx+"px", height: dy+"px"});
	}
}


witoThreadClass.prototype.applyDimensionChangeUIonly = function(snap, withtop) {
	var minimised = this.isMinimised()
	this.renderCalc(minimised);
	var tbar_jq = witoQuery('#wito_thread_titlebar-'+this.ref);
	var post_jq = witoQuery('#wito_thread_posts-'+this.ref);
	var stat_jq = witoQuery('#wito_thread_status-'+this.ref);
	tbar_jq.css('width', ''+(this.width)+'px');
	post_jq.css('width', ''+(this.width)+'px');
	post_jq.css('height', ''+(this.height)+'px');
	stat_jq.css('width', ''+(this.width)+'px');
	tbar_jq.css('marginTop',this.marginTop+'px');
	tbar_jq.css('marginLeft',this.marginLeft+'px');
	post_jq.css('marginLeft',this.marginLeft+'px');
	stat_jq.css('marginLeft',this.marginLeft+'px');
	witoQuery('#wito_shadow_bottom-'+this.ref).css('width', ''+(this.width-this.shadowOffset)+'px');
	var shdr_jq = witoQuery('#wito_shadow_right-'+this.ref);
	shdr_jq.css('height', ''+this.shadowHeightRight+'px');
	shdr_jq.css('top', ''+(0-this.shadowHeightRight+5)+'px');
	var heightActual = (minimised ? this.heightAdd : this.height+this.heightAdd);
	if (snap) {
		// adjust outer container
		if (withtop) {
			this.jq.css('top', this.top-this.marginTop+'px');
			this.jq.css('left', this.left-this.marginLeft+'px');
		}
		this.jq.css('width',this.width+this.widthAdd+"px");
		this.jq.css('height',heightActual+"px");
	} else {
		this.jq.animate({
			width: this.width+this.widthAdd+"px",
			height: this.height+this.heightAdd+"px"
		});
	}
}


witoThreadClass.prototype.applyDimensionIfHeightChange = function() {
	var heightTitlebarBefore = this.heightTitlebar;
	this.heightTitlebar = witoQuery('#wito_thread_titlebar-'+this.ref).height();
	// this.wito.debug('height debugging: ref '+ this.ref + ', height '+this.heightTitlebar + ', before '+heightTitlebarBefore);
	if ((this.heightTitlebar) && (this.heightTitlebar != heightTitlebarBefore)) {
		// apply change to UI
		this.applyDimensionChangeUIonly(true, false);
	}
	// this.wito.debug(heightTitlebarBefore+' -> '+this.heightTitlebar+"\r\n"+this.height+' + '+this.heightAdd);
}


/**
 * create a partial copy of this object
 * - for sending updates to the server
 */
witoThreadClass.prototype.createPartial = function(action) {
	// rehash before sending to server, [run-time] cascade aggregates
	this.hash.hash_calculate(true);			 // cascade up (hval)
	this.hash.hash_aggregate(true, true, "|");  // cascade up and down (hchild)
	// this.wito.debug(this.wito.hash.debugHashTree('|SESS|THRD|POST|'));
	// post sub object (thread)
	var pso = new Object;
	// reference by session [ref] -> thread [ref]
	pso.session = new Object;
	pso.session.ref = this.threadList.session.ref;
	pso.session.hval = this.threadList.session.hash.hval;
	pso.session.hchild = this.threadList.session.hash.hchild;
	pso.ref = this.ref;
	pso.hupd = 0;
	if (action & this.wito.flag_actionGET) {
		// send no attributes
	}
	if (action & this.wito.flag_actionMOVE) {
		pso.top = this.top;
		pso.left = this.left;
		pso.z = this.z;
		pso.hupd ^= this.top + this.left + this.z;
	}
	if (action & this.wito.flag_actionRESIZE) {
		pso.width = this.width;
		pso.height = this.height;
		pso.z = this.z;
		pso.hupd ^= this.width + this.height + this.z;
	}
	if (action & this.wito.flag_actionEDIT) {
		pso.data = this.data;
		pso.colour = this.colour;
		pso.width = this.width;
		pso.height = this.height;
		pso.minishape = this.minishape;
		pso.hupd ^= this.colour + this.width + this.height;
	}
	if ((action & this.wito.flag_actionCONFDEL) ||
		(action & this.wito.flag_actionUNCONFDEL)) {
		pso.height = this.height;
		pso.flagdisp = this.flagdisp;
		pso.hupd ^= this.height + this.flagdisp;
	}
	if ((action & this.wito.flag_actionMINIMISE_RESTORE) ||
		(action & this.wito.flag_actionDELETE)) {
		pso.flagdisp = this.flagdisp;
		pso.hupd ^= this.flagdisp;
	}
	if (action & this.wito.flag_actionCOLCHANGE) {
		pso.colour = this.colour;
		pso.hupd ^= this.colour;
	}
	// don't send edit flags (append, edit, move)
	return(pso);
}


/**
 * create a partial copy of this object
 * - for sending updates to the server
 */
witoPostClass.prototype.createPartial = function(action) {
	// rehash before sending to server, [run-time] cascade aggregates
	this.hash.hash_calculate(true);			 // cascade up (hval)
	// this.wito.debug(this.hash.debugHash('post'));
	// this.wito.debug(this.postList.thread.hash.debugHash('thread'));
	// this.wito.debug(this.postList.thread.threadList.session.hash.debugHash('session'));
	// post sub object (thread)
	var pso = new Object;
	// reference by session [ref] -> thread [ref] -> post [ref]
	pso.session = new Object;
	pso.session.ref = this.postList.thread.threadList.session.ref;
	pso.session.hval = this.postList.thread.threadList.session.hash.hval;
	pso.session.hchild = this.postList.thread.threadList.session.hash.hchild;
	pso.thread = new Object;
	pso.thread.ref = this.postList.thread.ref;
	pso.thread.hval = this.postList.thread.hash.hval;
	pso.thread.hchild = this.postList.thread.hash.hchild;
	pso.ref = this.ref;
	pso.hupd = 0;
	if (action & this.wito.flag_actionEDIT) {
		pso.data = this.data;
	}
	if ((action & this.wito.flag_actionMINIMISE_RESTORE) ||
		(action & this.wito.flag_actionDELETE)) {
		pso.flagdisp = this.flagdisp;
		pso.hupd ^= this.flagdisp;
	}
	return(pso);
}


witoThreadClass.prototype.makeRoomInPostArea = function(minHeight, updateUI,  updateServer) {
	if (this.height < minHeight) {
		var flag = this.wito.flag_actionRESIZE;
		this.height = minHeight;
		if (updateUI) {
			// resize thread to show post area
			this.applyDimensionChangeUIonly(false, false);
		}
		if (updateServer) {
			// send a post to record the position/size
			var upd = this.wito.ajax_prep(this, flag | this.wito.flag_targetTHREAD);
			upd.postObj.thread = this.createPartial(flag);
			upd.send();
		}
	}
}


/**
 * minimise or restore this thread
 * - EvHF
 */
witoThreadClass.prototype.event_minimise_restore = function (context) {
	return(function(e) {
		if (context.lockedToLocalForForeign) return;
		context.minimise_restore(!context.isMinimised(), true);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * minimise or restore this thread
 */
witoThreadClass.prototype.minimise_restore = function(minimise, sendToServer) {
	var temp_jq = null;
	if (minimise) {
		// minimising
		witoQuery('#wito_thread_arrowptr-'+this.ref).show();
		witoQuery('#wito_thread_posts-'+this.ref).hide();
		witoQuery('#wito_thread_arrowglyph-'+this.ref).removeClass('wito_glyphdown');
		witoQuery('#wito_thread_status-'+this.ref).hide();
		this.jq.addClass('wito_thread_minimised');
		// logical OR the flag (force set)
		this.flagdisp |= this.wito.flag_displayMINIMISED;
	} else {
		// expanding
		witoQuery('#wito_thread_posts-'+this.ref).show();
		witoQuery('#wito_thread_arrowptr-'+this.ref).hide();
		witoQuery('#wito_thread_arrowglyph-'+this.ref).addClass('wito_glyphdown');
		witoQuery('#wito_thread_status-'+this.ref).show();
		this.jq.removeClass('wito_thread_minimised');
		// logical AND the inverse flag (force clear)
		this.flagdisp &= (this.wito.flag_displayMASK ^ this.wito.flag_displayMINIMISED);
	}
	// read titlebar height as it may have been affected by add/removal of wito_thread_minimised
	this.heightTitlebar = witoQuery('#wito_thread_titlebar-'+this.ref).height();
	this.applyDimensionChangeUIonly(true, true);
	// send request to server to remember
	if (sendToServer) {
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionMINIMISE_RESTORE | this.wito.flag_targetTHREAD);
		upd.postObj.thread = this.createPartial(this.wito.flag_actionMINIMISE_RESTORE);
		upd.send();	
	}
}


/**
 * confirm delete thread
 * - thread event handler factory
 *   - returns event handler function
 */
witoThreadClass.prototype.event_confdel = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.confdel_unconfdel(true, true);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * restore a near-deleted thread
 * - EvHF
 */
witoThreadClass.prototype.event_unconfdel = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.confdel_unconfdel(false, true);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * outline a thread to confirm delete
 */
witoThreadClass.prototype.confdel_unconfdel = function(confdel, sendToServer) {
	this.hide();
	this.detach();
	var action = this.wito.flag_actionNONE;
	if (confdel) {
		// flag thread as not conventionally displayable (goes to confirm-delete state)
		this.flagdisp |= this.wito.flag_displayCONFDEL;
		// force confirm-delete mode threads to appear in full, not minimised
		this.flagdisp &= (this.wito.flag_displayMASK ^ this.wito.flag_displayMINIMISED);		
		// and must be a minimum height (and must be set on the server to avoid update wierdness)
		this.makeRoomInPostArea(this.heightMinConfdel, false, false);
		action = this.wito.flag_actionCONFDEL;
	} else {
		// flag thread as normal (displayable)
		this.flagdisp &= (this.wito.flag_displayMASK ^ this.wito.flag_displayCONFDEL);		
		action = this.wito.flag_actionUNCONFDEL;
	}
	// re-attach 'confdel' view
	this.renderAttachShow();
	if (sendToServer) {
		// send request to server to archive
		var upd = this.wito.ajax_prep(this, action | this.wito.flag_targetTHREAD);
		upd.postObj.thread = this.createPartial(action);
		upd.send();	
	}
}


/**
 * delete post
 * - post event handler factory
 *   - returns event handler function
 */
witoPostClass.prototype.event_delete = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.deletex(true);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * delete post
 */
witoPostClass.prototype.deletex = function(sendToServer) {
	this.hide();
	this.detach();
	// flag post as not displayable
	this.flagdisp = this.wito.flag_displayDELETED;
	if (sendToServer) {
		// send request to server to archive
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionDELETE | this.wito.flag_targetPOST);
		upd.postObj.post = this.createPartial(this.wito.flag_actionDELETE);
		upd.send();	
	}
}


/**
 * actually delete a thread
 * - EvHF
 */
witoThreadClass.prototype.event_delete = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.deletex(true);
		context.wito.event_stop_bubble(e);
	});
}


witoThreadClass.prototype.deletex = function(sendToServer) {
	this.hide();
	this.detach();
	// flag thread as not displayable
	this.flagdisp = this.wito.flag_displayDELETED;
	// tell threadList this is being deleted
	this.threadList.remove(this);
	if (sendToServer) {
		// send request to server to archive
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionDELETE | this.wito.flag_targetTHREAD);
		upd.postObj.thread = this.createPartial(this.wito.flag_actionDELETE);
		upd.send();
	}
}


/**
 * edit thread title
 * - thread EvHF (event handler factory)
 *   - returns event handler function
 */
witoThreadClass.prototype.event_edit = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.wito.edit_begin(context);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * following an edit_end, update the thread
 */
witoThreadClass.prototype.commitEdit = function(data) {
	this.data = data;
	var upd = this.upd;
	if (this.upd) {
		upd.postObj.thread = this.createPartial(this.wito.flag_actionNEW);
	} else {
		// send thread edit to server, unless we've got one waiting
		upd = this.wito.ajax_prep(this, this.wito.flag_actionEDIT | this.wito.flag_targetTHREAD);
		upd.postObj.thread = this.createPartial(this.wito.flag_actionEDIT);
	}
	upd.send();
	// clear the half-built update
	this.upd = null;
}


/**
 * edit post
 * - EvHF
 */
witoPostClass.prototype.event_edit = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		context.wito.edit_begin(context);
		context.wito.event_stop_bubble(e);
	});
}


/**
 * following an edit_end, update the post
 */
witoPostClass.prototype.commitEdit = function(data) {
	this.data = data;
	var upd = this.upd;
	if (this.upd) {
		upd.postObj.post = this.createPartial(this.wito.flag_actionNEW);
	} else {
		// send post edit to server, unless we've got one waiting
		upd = this.wito.ajax_prep(this, this.wito.flag_actionEDIT | this.wito.flag_targetPOST);
		upd.postObj.post = this.createPartial(this.wito.flag_actionEDIT);
	}
	upd.send();
	this.upd = null;
}


/**
 * update icon visibility (typically on hover)
 */
witoThreadClass.prototype.event_iconvis = function(context, vis) {
	return( function(e) {
		// context.wito.debug(context.ref+': '+vis);
		if (vis) {
			witoQuery('#wito_thread_titlebar-'+context.ref).addClass('wito_over');
			witoQuery('#wito_thread_titlebar-'+context.ref).removeClass('wito_out');
			witoQuery('#wito_thread_status-'+context.ref).addClass('wito_over');
			witoQuery('#wito_thread_status-'+context.ref).removeClass('wito_out');
		} else {
			witoQuery('#wito_thread_titlebar-'+context.ref).removeClass('wito_over');
			witoQuery('#wito_thread_titlebar-'+context.ref).addClass('wito_out');
			witoQuery('#wito_thread_status-'+context.ref).removeClass('wito_over');
			witoQuery('#wito_thread_status-'+context.ref).addClass('wito_out');
		}
	});
}


witoPostClass.prototype.event_iconvis = function(context, vis) {
	return( function(e) {
		// context.wito.debug(context.ref+': '+vis);
		if (vis) {
			context.jq.addClass('wito_over');
			context.jq.removeClass('wito_out');
		} else {
			context.jq.removeClass('wito_over');
			context.jq.addClass('wito_out');
		}
	});
}


/**
 * add post to thread
 * - EvHF
 */
witoThreadClass.prototype.event_add = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		// create a new post
		var post = context.postList.new_post(null, true);
		if (post.attach) {
			post.attach(post.render());
			post.show();
			// edit after showing
			context.wito.edit_begin(post);
			context.makeRoomInPostArea(context.heightMinPost, true, true);
		}
		context.wito.event_stop_bubble(e);
		// this.wito.debug('add post to thread '+this.ref);
	});
}


witoThreadClass.prototype.event_colchange = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		/**
		 *
		var debugstr =
			'colour['+context.colour+','+context.wito.padHex(context.colour,6)+'] '+
			'add['+context.colourAdd+','+context.wito.padHex(context.colourAdd,6)+'] '+
			'equals['+(context.colour + context.colourAdd)+','+context.wito.padHex((context.colour + context.colourAdd),6)+'] '+
			'modded['+context.colNext(context.colour)+','+context.wito.padHex(context.colNext(context.colour),6)+']';
		context.wito.debugCacheMess(debugstr);
		 */
		context.wito.edit_commit();
		context.colchange(context.colNext(context.colour), true);
		context.wito.event_stop_bubble(e);
	});
}


witoThreadClass.prototype.colchange = function(newColour, sendToServer) {
	this.colour = newColour;
	this.colComputeVariants();
    var tpart;
	if (this.isMinimised()) {
		tpart = witoQuery('#wito_thread_titlenot-'+this.ref);
	} else {
		tpart = witoQuery('#wito_thread_titlebar-'+this.ref);
	}
	tpart.css('backgroundColor', '#'+this.colourLighten);
	tpart.css('borderColor', '#'+this.colourDarken);
	// dark backgrounds need white text
	this.jq.css('color','#'+this.colourText);
	tpart = witoQuery('#wito_thread_posts-'+this.ref)
	tpart.css('backgroundColor', '#'+this.colourBack);
	tpart.css('borderColor', '#'+this.colourDarken);
	tpart = witoQuery('#wito_thread_status-'+this.ref)
	tpart.css('backgroundColor', '#'+this.colourBack);
	tpart.css('borderColor', '#'+this.colourDarken);
	// update next colour icon
	var nextCol = this.colNext(this.colour);
	witoQuery('#wito_thread_colchange-'+this.ref).css('backgroundColor', '#'+(this.wito.padHex(nextCol,6)));
	// set the default thread so that all future creations come up this colour
	this.wito.default_thread.colour = this.colour;
	// send if firing
	if (sendToServer) {
		// send request to server to archive
		var upd = this.wito.ajax_prep(this, this.wito.flag_actionCOLCHANGE | this.wito.flag_targetTHREAD);
		upd.postObj.thread = this.createPartial(this.wito.flag_actionCOLCHANGE);
		upd.send();
	}
}


witoThreadClass.prototype.colNext = function(col) {
	// col += this.colourAdd;
	// if (col > this.colourTop) col = 0x000000;
	col -= this.colourSub;
	if (col <= 0) col = this.colourBase;
	return(col);
}


witoThreadClass.prototype.colComputeVariants = function() {
	var lightText = this.wito.colourThreshold(this.colour, this.backgroundColourThreshold);
	this.colourBack = this.wito.padHex(this.colour,6);
	this.colourLighten = this.wito.padHex(this.wito.colourMathDarken(this.colour, 0.02,lightText),6);
	this.colourDarken = this.wito.padHex(this.wito.colourMathDarken(this.colour, 0.06,lightText),6);
	this.colourText = this.wito.padHex((lightText?'FFFFFF':'000000'),6);
}


witoThreadClass.prototype.event_debug = function(context) {
	return( function(e) {
		if (context.lockedToLocalForForeign) return;
		// create a new post
		var post = context.postList.new_post(null, false);
		// fill post with debugging information for this thread
		var data = context.wito.__objectToString(context);
		post.data = data.replace(/\n/g,'<br />').replace(/ value :/g,': ');
		if (post.attach) {
			post.attach(post.render());
			post.show();
			context.makeRoomInPostArea(context.heightMinPost, true, true);
		}
		context.wito.event_stop_bubble(e);
		// this.wito.debug('add post to thread '+this.ref);
	});
}


witoThreadClass.prototype.textEditListener = function(src) {
	// if src.text is object default (e.g. Insert comment here), scrub
	if (src.text == this.wito.default_thread.data) {
		src.text = '';
		src.text_changed = true;
		src.text_height = this.heightMinEmptyTitleTextarea;
		src.text_minHeight = src.text_height;
	}
	// set colours to match thread
	src.colBack = this.colourLighten;
	src.colText = this.colourText;
}


witoPostClass.prototype.textEditListener = function(src) {
	// blank out default text on edit
	if (src.text == this.wito.default_post.data) {
		src.text = '';
	}
	// set colours to post parent (thread) background
	src.colBack = this.postList.thread.colourBack;
	src.colText = this.postList.thread.colourText;
}


witoThreadClass.prototype.listenerTextUpdated = function() {
	// modify thread accordingly
	this.heightTitlebar = witoQuery('#wito_thread_titlebar-'+this.ref).height();
	this.applyDimensionChangeUIonly(true, false);
}


witoPostClass.prototype.listenerTextUpdated = function() {
}


witoThreadClass.prototype.autoGrow = function() {
	return(true);
}


witoPostClass.prototype.autoGrow = function() {
	return(true);
}


witoThreadClass.prototype.processServerChanges = function(changes) {
	if (changes.length > 0) {
		this.detach();
		// this.wito.debug('psc: '+this.wito.__objectToString(changes));
		for(name in changes) {
			if (name == 'ref') {
				var oldref = this.ref;
				this.ref = changes[name];
				this.parentList.reref(this, oldref);
			} else {
				if (this[name]) {
					this[name] = changes[name];
					// use same functions as foreign update for consistency
					this.wito.intUpdQueue.processDerived(this, this[name]);
					// this.wito.debug('updated thread/post '+name+' = '+this[name]);
				}
			}
		}
		// handle update of UI implicitly by rebuilding
		this.renderAttachShow();
	}
}


witoPostClass.prototype.processServerChanges = witoThreadClass.prototype.processServerChanges;

/**
 * witoThreadList
 *   wito -> session -> threadList
 *  
 * implements
 *   ListInterface
 */
witoThreadListClass = function() {
	// constructor (threadList)
}

/**
 * witoPostList
 *   wito -> session -> threadList -> thread -> postList
 *  
 * implements
 *   ListInterface
 */
witoPostListClass = function() {
	// constructor (postList)
}

// no threadList clone

witoPostListClass.prototype.clone = function() {
	// this object does not contain any objects, so use the lightweight copy code
	var temp = new witoPostListClass();
	for (key in this) { 
		temp[key] = this[key]; 
	} 
	return temp;
}


witoThreadListClass.prototype.init = function(wito, session) {
	this.list = new Array();
	this.wito = wito;
	this.session = session;
	this.parent = this.session;
	this.maxz = 0;
	this.count = 0;
}


witoPostListClass.prototype.init = function(wito, thread) {
	this.list = new Array();
	this.wito = wito;
	this.thread = thread;
	this.parent = this.thread;
	this.count = 0;
}


/**
 * get_default thread
 *   default attribute inheritance
 *	 local: static values defined here
 */
witoThreadListClass.prototype.get_default = function() {
	if (this.wito.default_thread) return(this.wito.default_thread);
	// thread.init not called until clone produces real thread
	var thread = new witoThreadClass();
	// default values heres should be overwritten by server values
	thread.left = 200;
	thread.top = 200;
	thread.width = 200;
	thread.height = 200;
	thread.data = 'Enter your comment here';
	thread.flagdisp = this.wito.flag_displayVISIBLE;
	thread.flagedit = this.wito.flag_actionEDIT | this.wito.flag_actionAPPEND;
	thread.colour = 0xFFFF33; // yellow
	// start at lowest z
	thread.z = 1;
	// [derived] simple colour Maths
	thread.colourAdd = 0x204080;
	thread.colourTop = 0xFFFFFF;
	thread.colourSub = thread.colourAdd;
	thread.colourBase = thread.colour;
	// constants
	thread.widthShadow = 5;
	thread.heightShadow = 5;
	thread.shadowOffset = 6;
	thread.heightTitlebar = 20; // assume single line only, must read back
	thread.heightStatusbar = 18;
	thread.heightMinPost = 96; // below which we expand the thread height on new_post
	thread.heightMinConfdel = 96; // below which we expand the thread height to show confirmation message
	thread.heightMinEmptyTitleTextarea = 75;
	thread.widthTitlebarIcon = 21;
	thread.widthTitlebarIcons = 2 + (3 * thread.widthTitlebarIcon); // 63 for three icons (>,e,x), 46 for two (>,x)
	thread.widthMin = 160;
	// expanded-state settings
	thread.marginTopExp = 0;
	thread.marginLeftExp = 0;
	// minimised-state settings
	thread.minishape = 'arrow';
	thread.marginTopMini = 20;
	thread.marginLeftMini = 26;
	// colour thresholds
	thread.backgroundColourThreshold = 0x66;
	// place holders
	thread.postList = null; // initialised on thread.init()
	thread.postBase = null; // initialised on thread.attach()
	// thread ref is initially unassigned
	thread.ref = this.wito.ref_UNSET;
	// cache default
	this.wito.default_thread = thread;
	return(this.wito.default_thread);
}


witoPostListClass.prototype.get_default = function() {
	if (this.wito.default_post) return(this.wito.default_post);
	var post = new witoPostClass();
	// post.init not called until clone produces real post
	post.data = 'Enter your comment here';
	post.flagdisp = this.wito.flag_displayVISIBLE;
	post.flagedit = this.wito.flag_actionEDIT;
	// post ref is initially unassigned
	post.ref = this.wito.ref_UNSET;
	// cache default
	this.wito.default_post = post;
	return(this.wito.default_post);
}


witoThreadListClass.prototype.recv_default = function(server_thread) {
	var thread = this.get_default();
	// overwrite with defaults from server
	thread.copyFrom(server_thread);
	// set as default (redundant)
	this.wito.default_thread = thread;
}


witoPostListClass.prototype.recv_default = function(server_post) {
	var post = this.get_default();
	// overwrite with defaults from server
	post.copyFrom(server_post);
	// set as default (redundant)
	this.wito.default_post = post;
}


witoThreadListClass.prototype.new_thread = function(template) {
	// var template is local (argument)
	if (!template) template = this.get_default();
	// copy template to create new object
	var thread = template.clone();
	thread.init(this.wito, this);
	thread.offsetPosition();
	// delay thread create, but lock until created on server
	thread.lock(this.wito.lockType_toForeignForSERVER);
	// add to list
	this.add(thread);
	// raise thread to top
	this.bringToFront(thread);
	// prep but don't send to server
	thread.upd = this.wito.ajax_prep(thread, this.wito.flag_actionNEW | this.wito.flag_targetTHREAD);
	thread.upd.locking = true;
	return(thread);
}


witoPostListClass.prototype.new_post = function(template, updateServer) {
	if (!template) template = this.get_default();
	// copy template to create new object
	var post = template.clone();
	post.init(this.wito, this);
	this.add(post);
	if (updateServer) {
		// prep but don't send to server
		post.upd = this.wito.ajax_prep(post, this.wito.flag_actionNEW | this.wito.flag_targetPOST);
		post.upd.locking = true;
	}
	return(post);
}


witoThreadListClass.prototype.recv_thread = function(recvd) {
	var template = this.get_default();
	// copy template to create new object
	var thread = template.clone();
	thread.init(this.wito, this);
	// only copy in the fields already defined (from default)
	thread.copyFrom(recvd, thread);
	if (recvd[this.wito.server_side_postList_NAME]) {
		var plist = recvd[this.wito.server_side_postList_NAME];
		for (var i=0 ; i<plist.length ; ++i) {
			var p = plist[i];
			thread.postList.recv_post(p);
		}
	}
	this.add(thread);
	// this.wito.debug('part thread received '+this.wito.__objectToString(recvd));
	// this.wito.debug('corresponding thread currently '+this.wito.__objectToString(thread));
	// if thread was added incomplete, send request to server to update
	if (thread.incomplete(recvd)) {
		thread.updateSendRequest();
	}
	return(thread);
}


witoPostListClass.prototype.recv_post = function(recvd) {
	var template = this.get_default();
	// copy template to create new object
	post = template.clone();
	post.init(this.wito, this);
	// only copy in the fields already defined (from default)
	post.copyFrom(recvd, post);
	this.add(post);
	// if post was added incomplete, send request to server to update
	if (post.incomplete(recvd)) {
		post.updateSendRequest();
	}
	return(post);
}


// implement ListInterface
witoThreadListClass.prototype.compare = function(latest) {
	this.wito.generic_compareList(this, latest, 'thread');
}


witoPostListClass.prototype.compare = function(latest) {
	this.wito.generic_compareList(this, latest, 'post');
}


witoThreadListClass.prototype.add = function(thread) {
	// rehash before adding to list, [init-time] delay cascading
	thread.hash.hash_calculate(false);
	if (thread.ref != this.wito.ref_UNSET) {
		// use ref in thread
	} else {
		// assign thread identifier (ref, not db id)
		thread.ref = this.list.length;
	}
	// append to threadList
	this.list[thread.ref] = thread;
	// update threadList derived vars
	this.checkMaxZ(thread.z);
	this.count++;
	// if count now non-zero, resume heartbeats
	if (this.count > 0) {
		this.wito.heartbeat.resume();
	}
	// update UI component
	this.session.updateUI('data',this.session.data,this.session.data);
}


witoPostListClass.prototype.add = function(post) {
	// rehash before adding to list, [init-time] delay cascading
	post.hash.hash_calculate(false);
	if (post.ref != this.wito.ref_UNSET) {
		// use ref in post
	} else {
		// assign post identifier (ref, not db id)
		post.ref = this.list.length;
	}
	// append to threadList
	this.list[post.ref] = post;
	this.count++;
}


witoThreadListClass.prototype.remove = function(thread) {
	// nullify reference
	this.list[thread.ref] = null;
	// update count
	this.count--;
	// if count now zero, suspend heartbeats
	if (this.count == 0) {
		this.wito.heartbeat.suspend();
	}
	// update UI component
	this.session.updateUI('data',this.session.data,this.session.data);
}


witoThreadListClass.prototype.reref = function(obj, oldref) {
	// nullify old reference
	this.list[oldref] = null;
	// update new slot, may overwrite
	this.list[obj.ref] = obj;
}


witoPostListClass.prototype.reref = witoThreadListClass.prototype.reref;


witoThreadListClass.prototype.get = witoClass.prototype.generic_get;


witoPostListClass.prototype.get = witoClass.prototype.generic_get;


witoThreadListClass.prototype.getList = function() {
	return(this.list);
}


witoPostListClass.prototype.getList = witoThreadListClass.prototype.getList;


witoThreadListClass.prototype.getNextUsedRef = witoClass.prototype.generic_getNextUsedRef;


witoPostListClass.prototype.getNextUsedRef = witoClass.prototype.generic_getNextUsedRef;


witoThreadListClass.prototype.receive = function(latest) {
	return(this.recv_thread(latest));
}


witoPostListClass.prototype.receive = function(latest) {
	return(this.recv_post(latest));
}


witoThreadListClass.prototype.getCount = function() {
	return(this.count);
}


witoThreadListClass.prototype.show = function() {
	for (i=0 ; i<this.list.length ; ++i) {
		var thread = this.list[i];
		if (thread) {
			thread.renderAttachShow();
		}
	}
}


witoThreadListClass.prototype.hide = function() {
	for (i=0 ; i<this.list.length ; ++i) {
		var thread = this.list[i];
		if (thread) {
			thread.hide();
			thread.detach();
		}
	}
}


witoThreadListClass.prototype.checkMaxZ = function(z) {
	if (z > this.maxz) this.maxz = z;
}


witoThreadListClass.prototype.bringToFront = function(thread) {
	this.maxz++;
	thread.z = this.maxz;
	// if thread is visible, update
	if (thread.jq) {
		thread.jq.css('z-index', thread.z);
	}
}


// link to go back to my account
witoToolBackToAccountClass = function() {
	this.ref = 3;
	this.stateArray = [{'img': 'toolbox/ic_backaccount.png', 'imgwidth': 33, 'imgheight':32, 'text' : 'Back to my account'}];
}


witoToolBackToAccountClass.prototype.click = function() {
	// link back to my account
	window.location('/user');
}


// execute attach to tool [ref defined]
if (window.witoGlobal) {
	witoClass.receiverQ_tool.push(
		new witoToolBackToAccountClass()
	);
}

/**
 *
 * Tool/button
 *
 */
witoToolClass = function() {
	// constructor (toolbox)
}


witoToolClass.prototype.init = function(wito, toolbox) {
	this.wito = wito;
	this.ref = this.wito.ref_UNSET;
	this.toolbox = toolbox;
	this.rendered = false;
	this.attached = false;
	this.stateArray = new Array();
	this.stateRef = 0;
	this.state = null;
	this.jq = null;
}


witoToolClass.prototype.clone = function() { 
	var temp = new witoToolClass();
	temp.copyFrom(this);
	return temp; 
}


witoToolClass.prototype.copyFrom = function(master) {
	var keymaster = master;
	if (arguments.length > 2) keymaster = arguments[1];
	for (key in keymaster) {
		if (master[key] != undefined) {
			this[key] = master[key];
		}
	}
	if (this.stateArray) {
		if (this.stateArray.length > 0) {
			this.state = this.stateArray[0];
		}
	}
}


witoToolClass.prototype.addState = function(img, text) {
	if (!this.stateArray) this.stateArray = new Array();
	var obj = new Object();
	obj.img = img;
	obj.text = text;
	this.stateArray[this.stateArray.length] = obj;
}


witoToolClass.prototype.getState = function(ref) {
	if (!this.stateArray) return(null);
	if (ref > this.stateArray.length) return(null);
	var state = this.stateArray[ref];
	return(state);
}


witoToolClass.prototype.getCurrentState = function() {
	return(this.state);
}


witoToolClass.prototype.event_getOverMess = function(context) {
	return( function() {
		return(context.getOverMess());
	});
}


witoToolClass.prototype.getOverMess = function() {
	if (!this.state) return('');
	var mess = this.state.over ? this.state.over : this.state.text;
	return(mess);
}


witoToolClass.prototype.setState = function(ref) {
	var state = this.getState(ref);
	if (state) {
		var newhtml = '';
		if (state.img) {
			newhtml += this.renderImg(state);
		} else {
			newhtml += state.text;
		}
		this.jq.html(newhtml);
		this.stateRef = ref;
		this.state = state;
	}
}


witoToolClass.prototype.isVisible = function() {
	return(this.visible);
}


witoToolClass.prototype.render = function() {
	var html = '';
	if (!this.isVisible()) return(null);
	if (this.rendered) return(null);
	var state = this.getState(0);
	if (state) {
		html += '<p class="wito_toolbox_button" id="wito_tool_p-'+this.ref+'"><a id="wito_tool-'+this.ref+'" href="#">';
		if (state.img) {
			html += this.renderImg(state);
		} else {
			html += '<span class="wito_toolbox_button_text">'+state.text+'</span>';
		}
		html += '</a></p>';
		this.rendered = true;
	}
	return(html);
}


witoToolClass.prototype.renderImg = function(context) {
	var imagepath = this.wito.page_getAssetPath() + 'images/';
	var html = '<img src="'+imagepath+context.img+'" alt="'+context.text+'" ';
    if (context.imgwidth) html += 'width="'+context.imgwidth+'" ';
    if (context.imgheight) html += 'height="'+context.imgheight+'" ';
    html += 'border="0" />';
	return(html);
}


witoToolClass.prototype.attach = function(html) {
	if (!html) return;
	if (!this.rendered) return;
	if (!this.attached) {
        // allow tool to dynamically hook in
        if (this.setup) this.setup();
		var nextRef = this.toolbox.getNextUsedRef(this.ref);
		if (nextRef == this.wito.ref_UNSET) {
			// attach before base
			this.toolbox.toolBase.before(html);
		} else {
			 // attach before
			witoQuery('#wito_tool_p-'+nextRef).before(html);
		}
		this.jq = witoQuery('#wito_tool-'+this.ref);
        this.attachListeners();
		this.attached = true;
	}
}


witoToolClass.prototype.attachListeners = function() {
	// listeners are local and redirected
    if (this.click)	this.jq.bind('click', null, this.event_click(this));
	if (this.over) this.jq.bind('mouseover', null, this.event_over(this));
	// over message could be state dependent
	if (this.toolbox.hovertarget) this.toolbox.hovertarget.attachOver(this.jq, this.event_getOverMess(this));
}


witoToolClass.prototype.event_click = function(context) {
	return( function(e) {
		if (context.click) context.click();
		context.wito.event_stop_bubble(e);
	});
}


witoToolClass.prototype.event_over = function(context) {
	return( function(e) {
		if (context.over) context.over();
		context.wito.event_stop_bubble(e);
	});
}


// stub, overwritten
witoToolClass.prototype.setup = null;


// stub, overwritten
witoToolClass.prototype.click = null;


// stub, overwritten
witoToolClass.prototype.over = null;


witoToolNewSessionClass = function() {
	this.ref = 2;
	this.stateArray = [{'img': 'toolbox/ics_newsess.png', 'imgwidth': 20, 'imgheight':16, 'text' : 'New session'}];
}

witoToolNewSessionClass.prototype.click = function() {
	this.wito.sessionList.new_session();
}

// execute attach to tool [ref defined]
if (window.witoGlobal) {
	witoClass.receiverQ_tool.push(
		new witoToolNewSessionClass()
	);
}
// new thread
witoToolNewThreadClass = function() {
	this.ref = 0;
	this.stateArray = [{'img': 'toolbox/ic_newthread.png', 'imgwidth': 33, 'imgheight':32, 'text': 'New feedback', 'over': 'Leave some feedback'}];
}


witoToolNewThreadClass.prototype.over = function() {
    // this.wito.debug(this.wito.__objectToString(this));
    if (this.toolbox) this.toolbox.show();
}


witoToolNewThreadClass.prototype.click = function() {
	// 'this' will be the click firing tool (witoToolClass)
	var session = this.wito.sessionList.getCurrent();
	if (session) {
		session.new_thread();
	}
}


// execute attach to tool [ref defined]
if (window.witoGlobal) {
	witoClass.receiverQ_tool.push(
		new witoToolNewThreadClass()
	);
}

// show-hide
witoToolShowhideClass = function() {
	this.ref = 1;
	this.stateArray = [{'img': 'toolbox/ic_feedhide.png', 'imgwidth': 40, 'imgheight':32, 'text': 'Hide feedback', 'over': 'Hide feedback for now'}, {'img': 'toolbox/ic_feedshow.png', 'text': 'Show feedback', 'over': 'Show hidden feedback'}];
}


witoToolShowhideClass.prototype.setup = function() {
	// 'this' will be the tool (witoToolClass) being setup
	var context = this;
	this.wito.sessionList.visibilityListener = function(vis) {
		context.setState(vis ? 0 : 1); // button text: 0 'hide', 1 'show'
	};
}


witoToolShowhideClass.prototype.click = function() {
	// 'this' will be the click firing tool (witoToolClass)
	this.wito.sessionList.feedback_toggle();
}


// execute attach to tool [ref defined]
if (window.witoGlobal) {
	witoClass.receiverQ_tool.push(
		new witoToolShowhideClass()
	);
}
/**
 *
 * Toolbox
 *
 */
witoToolboxClass = function() {
	// constructor (toolbox)
}


witoToolboxClass.prototype.init = function(wito) {
	this.wito = wito;
	this.toolBase = null;
	this.sessionSelect = null;
	this.visible = 0;
	this.list = new Array();
    this.preInitQueue = witoClass.receiverQ_tool;
    this.attached = false;
	// create hidden toolbox
	this.attach(this.render());
	// create a hovertarget
	this.hovertarget = new witoHoverTargetClass();
	this.hovertarget.init(this.wito, this, 'toolbox');
	this.hovertarget.attach(this.toolBase, this.hovertarget.render());
	// create a notification manager
	this.notifier = new witoNotifierClass();
	this.notifier.init(this.wito, this, this.hovertarget);
	// attach whatever tools are available
	this.renderAttachTools();
}


witoToolboxClass.prototype.receiver = function(obj) {
	this.recv_tool(obj);
}


witoToolboxClass.prototype.get = witoClass.prototype.generic_get;


witoToolboxClass.prototype.add = witoClass.prototype.generic_add;


witoToolboxClass.prototype.getNextUsedRef = witoClass.prototype.generic_getNextUsedRef;


witoToolboxClass.prototype.get_default = function() {
	if (this.wito.default_tool) return(this.wito.default_tool);
	var tool = new witoToolClass();
	// default values here should be overwritten by server values
	tool.visible = 0;
	// ref is initially unassigned
	tool.ref = this.wito.ref_UNSET;
	// cache default
	this.wito.default_tool = tool;
	return(this.wito.default_tool);
}


witoToolboxClass.prototype.recv_default = function(server_tool) {
	tool = this.get_default();
	// overwrite with defaults from server
	tool.copyFrom(server_tool);
	// set as default (redundant)
	this.wito.default_tool = tool;
}


witoToolboxClass.prototype.recv_tool = function(recvd) {
	var tool;
	var toolIsNew = true;
	if (recvd.ref != undefined) {
		// see if this tool exists already
		tool = this.get(recvd.ref);
		if (tool) {
			toolIsNew = false;
		}
	}
	if (toolIsNew) {
		var template = this.get_default();
		// copy template to create new object
		tool = template.clone();
		tool.init(this.wito, this);
		// copyFrom will overwrite with recvd.ref
		tool.ref = this.wito.ref_UNSET;
    }
    // overwrite locals with this one
    tool.copyFrom(recvd, tool);
    // note: tool setup called on attach
	if (toolIsNew) {
        this.add(tool);
	}
	// render and attach if toolbox is visible
	if (this.jq) {
		tool.attach(tool.render());
	}
	return(tool);
}


witoToolboxClass.prototype.recv_tools = function(server_tools) {
	for (var i=0 ; i<server_tools.length ; ++i) {
		this.recv_tool(server_tools[i]);
		// recv_tool (add) also renders if visible
	}
}


witoToolboxClass.prototype.render = function() {
	var imagepath = this.wito.page_getAssetPath() + 'images/';
	var html = '';
	html += '<div class="wito_toolbox" style="display:none;" id="wito_toolbox">';
	html += '<div class="wito_toolbox_plinth wito_toolbox_tools">';
	html += '<p id="wito_toolbox_toolbase"></p>';
	html += '<div class="wito_clear"></div>';
	html += '&nbsp;';
	html += '</div><!-- wito_toolbox_tools -->';
	html += '</div><!-- wito_toolbox -->';
	return(html);
}


witoToolboxClass.prototype.attach = function(html) {
	// protect against repeat calls
	if (this.jq) return;
	// append to end of thread base div
	if (this.wito.page.threadBase) {
		this.wito.page.threadBase.append(html);
		this.jq = witoQuery('#wito_toolbox');
		// identify toolBase for later tool additions
		this.toolBase = witoQuery('#wito_toolbox_toolbase');
	}
    // toolbox is effective 'live'
    this.attached = true;
}


witoToolboxClass.prototype.renderAttachTools = function() {
	if (this.jq) return;
	if (this.toolBase) {
		// attach tools
		for (var i=0 ; i<this.list.length ; ++i) {
			var tool = this.list[i];
			if (tool == null) continue;
			tool.attach(tool.render);
		}
	}
}


witoToolboxClass.prototype.addSelectOption = function(session) {
	// build sessionSelect object
	if (!this.sessionSelect) {
		this.sessionSelect = new witoSessionSelectClass();
		this.sessionSelect.init(this.wito, this);
	}
	// attach (hidden)
	this.sessionSelect.renderAttachOption(session);
	// show if multiple sessions
	if (this.sessionSelect.getCount() >= 2) {
		this.sessionSelect.show();
	}
}


witoToolboxClass.prototype.show_nto = function() {
	if (this.isVisible()) return;
	this.jq.animate({width: "42px", height: "38px", opacity: "show"},1000,null);
	this.visible = 1;
}


witoToolboxClass.prototype.show = function() {
    if (!this.jq) return;
    switch (this.isVisible()) {
        case 0:
            // show full from nothing
        	this.jq.animate({height: "show", opacity: "show"},1000,null);
            this.visible = 2;
            break;
        case 1:
            // expand out to show full, but cannot do during previous animation
            this.jq.css({width: '', height: '', overflow: ''});
            if (parseInt(this.jq.css('width')) > 43) {
                // this.wito.debug('yes'+parseInt(this.jq.css('width')));
                this.visible = 2;
            }
            break;
        case 2:
            // already fully open
            return;
    }
}


witoToolboxClass.prototype.isVisible = function() {
	return(this.visible);
}


witoToolboxClass.prototype.processQueue = witoClass.prototype.generic_processPreInitQueue;


