var Utility={};(function(){if(typeof console=="undefined"){console={}}if(typeof console.error!="function"){console.error=function(){}}Utility.trim=function(a){return a.replace(/^\s+|\s+$/g,"")};Utility.memo=function(b,a){a=a||{};return function(c){if(c&&a[c]){return a[c]}a[c]=b(c);return a[c]}};Utility.camelCase=Utility.memo(function(a){return a.replace(/\-(\w)/g,function(b,c){return c.toUpperCase()})});Utility.attr=(function(){var f={},a=Utility.trim,e=("accessKey,action,checked,className,cols,colSpan,dir,disabled,href,id,maxLength,method,name,readOnly,rows,rowSpan,selected,selectedIndex,selection,src,style,tabIndex,target,title,type,value").split(",");for(var b=0,c=e.length;b<c;b++){f[e[b].toLowerCase()]=e[b]}f["class"]="className";function d(m,g){g=g.split(";");var k,h;for(var j=0,l=g.length;j<l;j++){k=g[j].split(":");if(k.length==2){h=Utility.camelCase(a(k[0].toLowerCase()));if(h=="float"){h="cssFloat"}m.setStyle(h,a(k[1]))}}}return function(i,g,h){var k=g;g=f[g.toLowerCase()];if(!g){console.error("The attribute "+k+" is not currently supported in FBJS!");return}var j=(typeof h!="undefined")?"set":"get";j+=g.charAt(0).toUpperCase()+g.substr(1);if(h||h===""||h===0){if(j=="setStyle"){d(i,h)}else{i[j](h)}return i}return i[j]()}})();Utility.makeMap=function(d){var e={},b=d.split(",");for(var c=0,a=b.length;c<a;c++){e[b[c]]=true}return e};Utility.each=function(f,a,b){if(!f||!f.length){return[]}var e,c=0,d=f.length;if(b){if(d){for(;c<d;c++){a.apply(f[c],b)}}else{for(e in f){if(f.hasOwnProperty(e)){a.apply(f[e],b)}}}}else{if(d){for(;c<d;c++){a.call(f[c])}}else{for(e in f){if(f.hasOwnProperty(e)){a.call(f[e])}}}}return f};Utility.unique=function(f){if(!f||!f.length){return[]}var d=[],b={},c;var a=function(h){return h};if(f[0].__instance||f[0].__instance===0){a=function(h){return h.__instance}}for(var e=0,g=f.length;e<g;e++){c=a(f[e]);if(!b[c]){b[c]=true;d.push(f[e])}}return d};Utility.indexOf=function(e,d){var b=function(f){return(e===f)};if(e.equals){b=function(f){return e.equals(f)}}if(e.__instance||e.__instance===0){b=function(f){return f.__instance&&(e.__instance===f.__instance)}}for(var c=0,a=d.length;c<a;c++){if(b(d[c])){return c}}return -1};Utility.inArray=function(b,a){return Utility.indexOf(b,a)};Utility.json=(function(){var e="(?:-?\\b(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b)";var g='(?:[^\\0-\\x08\\x0a-\\x1f"\\\\]|\\\\(?:["/\\\\bfnrt]|u[0-9A-Fa-f]{4}))';var b='(?:"'+g+'*")';var a=new RegExp("(?:false|true|null|[\\{\\}\\[\\]]|"+e+"|"+b+")","g");var d=new RegExp("\\\\(?:([^u])|u(.{4}))","g");var c={'"':'"',"/":"/","\\":"\\",b:"\b",f:"\f",n:"\n",r:"\r",t:"\t"};function f(h,i,j){return i?c[i]:String.fromCharCode(parseInt(j,16))}return function(q,l){var k=q.match(a);var t;var r=k[0];if("{"===r){t={}}else{if("["===r){t=[]}else{console.error("unsupported initial json token: "+r)}}var p;var m=[t];for(var j=1,h=k.length;j<h;++j){r=k[j];var s;switch(r.charCodeAt(0)){case 34:r=r.substring(1,r.length-1);if(r.indexOf("\\")!==-1){r=r.replace(d,f)}s=m[0];if(!p){if(s instanceof Array){p=s.length}else{p=r||"";break}}s[p]=r;p=0;break;case 91:s=m[0];m.unshift(s[p||s.length]=[]);p=0;break;case 93:m.shift();break;case 102:s=m[0];s[p||s.length]=false;p=0;break;case 110:s=m[0];s[p||s.length]=null;p=0;break;case 116:s=m[0];s[p||s.length]=true;p=0;break;case 123:s=m[0];m.unshift(s[p||s.length]={});p=0;break;case 125:m.shift();break;default:s=m[0];s[p||s.length]=+(r);p=0;break}}if(m.length){console.error("Could not fully process json object")}if(l){var o=function(z,y){var A=z[y];if(A&&typeof A==="object"){var n=null;for(var w in A){if(A.hasOwnProperty(w)){var u=o(A,w);if(u!==0){A[w]=u}else{if(!n){n=[]}n.push(w)}}}if(n){for(var x=n.length;--x>=0;){delete A[n[x]]}}}return l.call(z,y,A)};t=o({"":t},"")}return t}})();Utility.html=(function(){var q=/^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,k=/^<\/(\w+)[^>]*>/,p=/(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,o=/<\/(table)>/,m=Utility.makeMap,e=Utility.each;var l=m("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed");var j=m("address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul");var f=m("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var");var d=m("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr");var b=m("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected");var c=m("script,style");var a,i,h=[];h.last=function(){return this[this.length-1]};h.reset=function(){this.length=0};function t(y,A){var B=h.length-1,z=B;if(!A){B=0}else{for(;B>=0;B--){if(h[B]==A){break}}}if(B>=0){for(;z>=B;z--){if(a.end){a.end(h[z])}}h.length=B}}function u(y,B,C,z){if(j[B]){while(h.last()&&f[h.last()]){t("",h.last())}}if(d[B]&&h.last()==B){t("",B)}z=l[B]||!!z;if(!z){h.push(B)}if(a.start){var A=[];C.replace(p,function(E,D){var F=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:b[D]?D:"";A.push({name:D,value:F,escaped:F.replace(/(^|[^\\])"/g,'$1\\"')})});if(a.start){a.start(B,A,z)}}}function s(y,z){z=z.replace(/<!\[CDATA\[(.*?)\]\]>/g,"$1").replace(/<!--(.*?)-->/g,"$1");if(a.chars){a.chars(z)}return""}var n=(function(){var C={},E=["nbsp","iexcl","cent","pound","curren","yen","brvbar","sect","uml","copy","ordf","laquo","not","shy","reg","macr","deg","plusmn","sup2","sup3","acute","micro","para","middot","cedil","sup1","ordm","raquo","frac14","frac12","frac34","iquest","Agrave","Aacute","Acirc","Atilde","Auml","Aring","AElig","Ccedil","Egrave","Eacute","Ecirc","Euml","Igrave","Iacute","Icirc","Iuml","ETH","Ntilde","Ograve","Oacute","Ocirc","Otilde","Ouml","times","Oslash","Ugrave","Uacute","Ucirc","Uuml","Yacute","THORN","szlig","agrave","aacute","acirc","atilde","auml","aring","aelig","ccedil","egrave","eacute","ecirc","euml","igrave","iacute","icirc","iuml","eth","ntilde","ograve","oacute","ocirc","otilde","ouml","divide","oslash","ugrave","uacute","ucirc","uuml","yacute","thorn","yuml"],D,z,A;for(D=0,z=E.length;D<z;D++){C[E[D]]=String.fromCharCode(160+D)}E=["quot","apos","amp","lt","gt","forall","part","exists","empty","nabla","isin","notin","ni","prod","sum","minus","lowast","radic","prop","infin","ang","and","or","cap","cup","int","there4","sim","cong","asymp","ne","equiv","le","ge","sub","sup","nsub","sube","supe","oplus","otimes","perp","sdot","Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega","alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigmaf","sigma","tau","upsilon","phi","chi","psi","omega","thetasym","upsih","piv","OElig","oelig","Scaron","scaron","Yuml","fnof","circ","tilde","ensp","emsp","thinsp","zwnj","zwj","lrm","rlm","ndash","mdash","lsquo","rsquo","sbquo","ldquo","rdquo","bdquo","dagger","Dagger","bull","hellip","permil","prime","Prime","lsaquo","rsaquo","oline","euro","trade","larr","uarr","rarr","darr","harr","crarr","lceil","rceil","lfloor","rfloor","loz","spades","clubs","hearts","diams"];A=[34,39,38,60,62,8704,8706,8707,8709,8711,8712,8713,8715,8719,8721,8722,8727,8730,8733,8734,8736,8743,8744,8745,8746,8747,8756,8764,8773,8776,8800,8801,8804,8805,8834,8835,8836,8838,8839,8853,8855,8869,8901,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,977,978,982,338,339,352,353,376,402,710,732,8194,8195,8201,8204,8205,8206,8207,8211,8212,8216,8217,8218,8220,8221,8222,8224,8225,8226,8230,8240,8242,8243,8249,8250,8254,8364,8482,8592,8593,8594,8595,8596,8629,8968,8969,8970,8971,9674,9824,9827,9829,9830];for(D=0,z=E.length;D<z;D++){C[E[D]]=String.fromCharCode(A[D])}var y=/&(#?)(\w+);/,B,F,G;return function(H){F="";while((B=y.exec(H))!==null){if(B[2]){if(B[1]){H=H.replace("&#"+B[2]+";",String.fromCharCode(B[2]))}else{if(C[B[2]]){H=H.replace("&"+B[2]+";",C[B[2]])}else{G=H.indexOf("&"+B[2]+";")+B[2].length+2;F+=H.substr(0,G);H=H.substr(G)}}}}return F+H}})();function x(C){var A,E,D=C;var z=false;h.reset();while(C){E=true;if(!h.last()||!c[h.last()]){if(C.indexOf("<!--")===0){A=C.indexOf("-->");if(A>=0){if(a.comment){a.comment(C.substring(4,A))}C=C.substring(A+3);E=z=false}}else{if(C.indexOf("</")===0){i=C.match(k);if(i){C=C.substring(i[0].length);i[0].replace(k,t);E=z=false}}else{if(C.indexOf("<")===0){i=C.match(q);if(i){if(z&&i[1]!=="tbody"){C=C.replace(o,"</tbody></table>");C="<tbody>"+C;i=C.match(q)}C=C.substring(i[0].length);i[0].replace(q,u);E=false;z=i[1].toLowerCase()=="table"}}}}if(E){A=C.indexOf("<");var B,y=/^<!--/;while(A>=0){B=C.substring(A);i=B.match(q);if(i){break}i=B.match(k);if(i){break}i=B.match(y);if(i){break}A=C.indexOf("<",A+1)}var F=A<0?C:C.substring(0,A);if(Utility.trim(F)){F=n(F);a.chars(F)}C=A<0?"":C.substring(A)}}else{C=C.replace(new RegExp("(.*)</"+h.last()+"[^>]*>"),s);t("",h.last())}if(C==D){throw"Parse Error: "+C}D=C}t()}var w,v,r,g;a={start:function(A,z,y){var B=document.createElement(A);e(z,function(){Utility.attr(B,this.name,this.value)},[B]);if(r&&r.appendChild){r.appendChild(B)}if(!y){w.push(B);r=B}},end:function(y){w.length-=1;r=w[w.length-1]},chars:function(z){var y=document.createElement("span");y.setClassName("textNode");y.setTextValue(z);r.appendChild(y)},comment:function(y){}};return function(y,z){w=[];y="<div>"+y+"</div>";v=document.createElement("div");r=v;x(y);g=v.getChildNodes()[0].getChildNodes();if(!z){return g}z.setTextValue("");e(g,function(){z.appendChild(this)},[z]);return z}})()})();var FBjqRY=function(a,b){return new FBjqRY.prototype.init(a,b)};(function(){var d=Utility.trim;var e=Utility.unique;var k=Utility.each;function l(i){if(typeof(i)=="string"){i=d(i).toLowerCase();switch(i){case"fast":i=200;break;case"slow":i=600;break;default:i=400;break}}return i?i:400}function g(i){if(console&&console.log){if(i){console.log(i)}else{console.log("The method you are trying to use is not yet supported by FBjqRY or FBJS")}}}var h=(function(){var r=/^#(\w+)/,s=/^\.([\w\-]+)/,o=/^([A-Za-z_]{1}\w*)/,u=/^\[(\w+)(!|\^|\$|\*)?=?"?'?([^\]]+)?'?"?\]/,q=/^:(\w+)\("?'?([^\)]+)'?"?\)/,v=/^:(\w+)/;function n(w,A,x,D){var z=[];if(!w||!w.length){return[]}for(var y=0,B=w.length;y<B;y++){var C=A.apply(w[y],x);if(C){z.push(w[y])}if(D){z=z.concat(n(w[y].getChildNodes(),A,x,D))}}return z}function i(w,z,x,y){if(w.length===0){w=[document.getElementById(z)]}else{w=n(w,function(){return this.getId()==z},[z],true)}return w}function t(x,w,y,z){if(x.length===0){x=[document.getRootElement()]}x=n(x,function(){return this.hasClassName(w)},[w],z);return x}function m(x,w,A,C){if(x.length===0){x=document.getRootElement().getElementsByTagName(w)}else{var y=[];for(var z=0,B=x.length;z<B;z++){y=y.concat(x[z].getElementsByTagName(w))}x=y}return x}function p(y,w,A,x,z,C){var B=null;switch(A){case"!":B=function(E,D){return E!=D};break;case"^":B=function(E,D){return E.indexOf(D)===0};break;case"$":B=function(E,D){return E.indexOf(D)+D.length==E.length};break;case"*":B=function(E,D){return E.indexOf(D)>=0};break;default:if(x===true){B=function(E,D){return !!E}}else{B=function(E,D){return E==D}}break}y=n(y,function(){return B(FBjqRY(this).attr(w),x)},[w,x],C);return y}return function(x,K,y){if(typeof(K)!="string"){if(K.length||K.length===0){return K}return[K]}if(y&&!y.getElementById){return[]}var C,A,F,J=K.split(","),w=[],I=x;for(var B=0,z=J.length;B<z;B++){K=d(J[B]);F="";C=true;while(K&&K!=F){if(F){if(!x.length){break}C=(K.charAt(0)==" ");K=d(K)}F=K;A=r.exec(K);if(A){x=i(x,A[1],K,C);K=K.substr(K.indexOf(A[1])+A[1].length);continue}A=s.exec(K);if(A){x=t(x,A[1],K,C);K=K.substr(K.indexOf(A[1])+A[1].length);continue}A=o.exec(K);if(A){x=m(x,A[1],K,C);K=K.substr(K.indexOf(A[1])+A[1].length);continue}A=u.exec(K);if(A){A[3]=A[3]||true;x=p(x,A[1],A[2],A[3],K,C);K=K.substr(K.indexOf("]")+1);continue}A=q.exec(K);if(!A){A=v.exec(K)}if(A){var D=A[0];var G=A[1];var H=A.length>2?A[2]:null;var E=H?parseInt(H,10):null;switch(G){case"first":x=[x[0]];break;case"last":x=[x[x.length-1]];break;case"eq":x=[x[E]];break;case"lt":x=x.splice(0,E);break;case"gt":x=x.splice(E+1,(x.length-E));break;case"even":x=FBjqRY.grep(x,function(L,M){return(M%2===0)});break;case"odd":x=FBjqRY.grep(x,function(L,M){return(M%2==1)});break;case"contains":x=null;g("We cannot read from nodes, so we cannot support the :contains pseudo selector!");break;case"visible":x=n(x,function(){var L=FBjqRY(this);return(L.attr("visibility")!="hidden"&&L.attr("display")!="none")});break;case"hidden":x=n(x,function(){var L=FBjqRY(this);return(L.attr("visibility")=="hidden"||L.attr("display")=="none")});break}K=K.substr(D.length);continue}}if(K){x=[]}else{w=w.concat(x);x=I}}return e(w)}})();var b=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,j=/^.[^:#\[\.]*$/,c;FBjqRY.fn=FBjqRY.prototype={init:function(i,n){this.nodes=[];if(!i){return}var o=n||document;if(i.html&&i.css&&i.attr){this.nodes=i.get();this.nodes=this.nodes.length?this.nodes:[this.nodes];this.length=this.nodes.length;return this}if(i.getNodeType||i[0]&&i[0].getNodeType){this.nodes=(i.length)?i:[i];this.length=this.nodes.length;return this}var m=b.exec(i);if(m&&(m[1]||!n)){if(m[1]){this.nodes=Utility.html(m[1])}else{this.nodes=[document.getElementById(m[3])]}this.length=this.nodes.length}else{this.nodes=h(this.nodes,i,o)}if(typeof i=="function"){i()}this.length=this.nodes.length;return this},version:"0.1.0",size:function(){return this.nodes.length},each:function(m,i){if(FBjqRY.isFunction(m)){i=m;m=this.nodes;k(m,i);return this}return k(m,i)},get:function(){if(arguments.length<=1){if(!this.nodes.length){return null}var o=arguments[0]?arguments[0]:null;if(o===null&&this.nodes.length==1){return this.nodes[0]}return(o||o===0)?this.nodes[o]:this.nodes}else{var m,n,i;m=arguments[0];n=arguments[1];i=arguments[2]?arguments[2]:null;this.post(m,n,i)}},eq:function(i){this.nodes=[this.nodes[i]];return this},index:function(n){for(var m=this.nodes.length-1;m>=0;m--){if(n.__instance==this.nodes[m].__instance){break}}return m},attr:function(m,i){if(typeof i!="undefined"){k(this.nodes,function(){Utility.attr(this,m,i)});return this}return Utility.attr(this.nodes[0],m)},addClass:function(i){k(this.nodes,function(){this.addClassName(i)});return this},removeClass:function(i){k(this.nodes,function(){this.removeClassName(i)});return this},toggleClass:function(i){k(this.nodes,function(){var m=FBjqRY(this);if(m.hasClass(i)){m.removeClass(i)}else{m.addClass(i)}});return this},html:function(i){if(typeof i!="undefined"){k(this.nodes,function(){Utility.html(i,this)});return this}return g("There is no html getter in FBJS")},fbml:function(i){if(typeof i!="undefined"){k(this.nodes,function(){this.setInnerFBML(i)});return this}return g("There is no fbml getter in FBJS")},text:function(i){if(typeof i!="undefined"){k(this.nodes,function(){this.setTextValue(i)});return this}return g("There is no text getter in FBJS")},val:function(i){if(typeof i!="undefined"){k(this.nodes,function(){this.setValue(i)});return this}return this.nodes[0].getValue()},dimensions:function(){var i=this.nodes[0];return{top:i.getAbsoluteTop(),left:i.getAbsoluteLeft(),width:i.getOffsetWidth(),height:i.getOffsetHeight(),right:i.getAbsoluteLeft()+i.getOffsetWidth(),bottom:i.getAbsoluteTop()+i.getOffsetHeight(),clientWidth:i.getClientWidth(),clientHeight:i.getClientHeight(),scrollTop:i.getScrollTop(),scrollLeft:i.getScrollLeft()}},css:function(i,m){if(typeof i=="string"&&typeof m!="undefined"){if(i=="float"){i="cssFloat"}k(this.nodes,function(){this.setStyle(i,m)});return this}if(typeof i=="object"){if(i["float"]&&!i.cssFloat){i.cssFloat=i["float"]}k(this.nodes,function(){this.setStyle(i)})}return this.nodes[0].getStyle(i)},offset:function(){var i=this.nodes[0];return{top:i.getAbsoluteTop(),left:i.getAbsoluteLeft()}},height:function(i){if(typeof i=="undefined"){return this.nodes[0].getOffsetHeight()}return this.css("height",i)},width:function(i){if(typeof i=="undefined"){return this.nodes[0].getOffsetWidth()}return this.css("width",i)},append:function(i){i=FBjqRY(i).get();i=i.length?i:[i];k(this.nodes,function(){var m=this;k(i,function(){m.appendChild(this)})});return this},appendTo:function(i){return FBjqRY(i).append(this)},prepend:function(i){i=FBjqRY(i).get();i=i.length?i:[i];k(this.nodes,function(){var m=this;k(i,function(){m.insertBefore(this)})});return this},prependTo:function(i){return FBjqRY(i).prepend(this)},after:function(i){i=FBjqRY(i).get();i=i.length?i:[i];k(this.nodes,function(){var m=this;k(i,function(){m.getParentNode().insertBefore(this,m.getNextSibling())})});return this},before:function(i){},insertAfter:function(i){},insertBefore:function(i){},wrap:function(i){},wrapAll:function(i){},wrapInner:function(i){},replaceWith:function(i){},replaceAll:function(i){},empty:function(){},remove:function(i){if(!i){k(this.nodes,function(){this.getParentNode().removeChild(this)})}else{k(this.nodes,function(){if(FBjqRY(this).is(i)){this.getParentNode().removeChild(this)}})}return this},clone:function(m){var i=[];k(this.nodes,function(){i.push(this.cloneNode())});return FBjqRY(i)},hasClass:function(i){var m=false;k(this.nodes,function(){m=m||this.hasClassName(i)});return m},filter:function(o){var m=[];if(typeof(o)=="string"){o=function(i){return i.is(o)}}for(var n=0,p=this.nodes.length;n<p;n++){if(o(FBjqRY(this.nodes[n]))){m.push(this.nodes[n])}}this.nodes=m;return this},is:function(i){return(this.find(i).length>0)},not:function(m){if(m.get){m=[m]}if(m[0]&&m[0].get){var n=this;k(m,function(){var o=this.get();n.filter(function(p){p=p.get();return(o&&o.__instance)&&(p&&p.__instance)&&(o.__instance!=p.__instance)})})}else{var i=this.find(m);this.not(i)}return this},slice:function(n,i){var m;m=i?this.nodes.slice(n,i):this.nodes.slice(n);return FBjqRY(m)},add:function(m){var i=FBjqRY(m);this.nodes=this.nodes.concat(i.get());this.nodes=FBjqRY.unique(this.nodes);return this},children:function(s){var r,o,m,q,n=[],p=[];if(s){n=FBjqRY(this.nodes).find(s).get()}else{for(r=0,q=this.nodes.length;r<q;r++){n=n.concat(this.nodes[r].getChildNodes())}}return FBjqRY(e(n))},contents:function(){function p(t){var q=t.getChildNodes();for(var r=0,s=q.length;r<s;r++){q=q.concat(p(q[r]))}return q}var n,m=this.nodes,o=m.length;for(n=0;n<o;n++){m=m.concat(p(m[n]))}return FBjqRY(e(m))},find:function(i){return FBjqRY(h(this.nodes,i))},next:function(p){var q=[],o=this.nodes.length;for(var m=0;m<o;m++){var n=this.nodes[m].getNextSibling();if(!p||n.is(p)){q.push(n)}}return FBjqRY(FBjqRY.unique(q))},nextAll:function(p){var q=[],o=this.nodes.length;for(var m=0;m<o;m++){var n=this.nodes[m].getNextSibling();while(n){if(!p||n.is(p)){q.push(n)}n=n.getNextSibling()}}return FBjqRY(FBjqRY.unique(q))},parent:function(q){var m=[],p=this.nodes.length,o;for(var n=0;n<p;n++){o=this.nodes[n].getParentNode();if(!q||FBjqRY(o).is(q)){m.push(o)}}return FBjqRY(FBjqRY.unique(m))},parents:function(r){var m=[],q=this.nodes.length,p,o=null;for(var n=0;n<q;n++){p=this.nodes[n].getParentNode();while(p){if(!r||FBjqRY(p).is(r)){m.push(p)}p=p.getParentNode()}}return FBjqRY(FBjqRY.unique(m))},prev:function(p){var q=[],o=this.nodes.length;for(var m=0;m<o;m++){var n=this.nodes[m].getPreviousSibling();if(!p||n.is(p)){q.push(n)}}return FBjqRY(FBjqRY.unique(q))},prevAll:function(p){var q=[],o=this.nodes.length;for(var m=0;m<o;m++){var n=this.nodes[m].getPreviousSibling();while(n){if(!p||n.is(p)){q.push(n)}n=n.getPreviousSibling()}}return FBjqRY(FBjqRY.unique(q))},siblings:function(i){return this.prevAll(i).concat(this.nextAll(i))},andSelf:function(){},end:function(){},ready:function(i){i()},bind:function(m,i){var n=this;k(this.nodes,function(){this.addEventListener(m,function(o){return i.apply(this,[o])});return n},[m,i]);return this},one:function(m,i){var n=this;k(this.nodes,function(){this.addEventListener(m,function(o){var p=i.apply(this,[o]);this.purgeEventListeners(m);return p});return n},[m,i])},trigger:function(i,m){k(this.nodes,function(){this[i]()})},triggerHandler:function(i,m){},unbind:function(i,m){k(this.nodes,function(){this.purgeEventListeners(i)},[i]);return this},hover:function(m,i){this.mouseover(m);this.mouseout(i)},toggle:function(){var i=arguments;var m=arguments.length;k(this.nodes,function(){var n=0;FBjqRY(this).click(function(){i[n].apply(this);n=(n+1)%m})});return this},show:function(m,i){if(FBjqRY.isFunction(m)&&!i){i=m;m=null}if(!m){this.stop();k(this.nodes,function(){this.setStyle("display","block").setStyle("opacity","1.0");if(this.getStyle("height")){this.setStyle("height","auto")}if(this.getStyle("width")){this.setStyle("width","auto")}});if(i){i()}return this}return this.animate({height:"auto",width:"auto",opacity:"1.0"},m,null,i,1)},hide:function(m,i){if(FBjqRY.isFunction(m)&&!i){i=m;m=null}if(!m){this.stop();k(this.nodes,function(){this.setStyle("display","none").setStyle("opacity","0.0");if(this.getStyle("height")){this.setStyle("height","0px")}if(this.getStyle("width")){this.setStyle("width","0px")}});if(i){i()}return this}return this.animate({height:"0px",width:"0px",opacity:"0.0"},m,null,i,2)},slideDown:function(m,i){return this.animate({height:"auto"},m,null,i,1)},slideUp:function(m,i){return this.animate({height:"0px"},m,null,i,2)},slideToggle:function(m,i){},fadeIn:function(m,i){k(this.nodes,function(){var n=FBjqRY(this);if(n.css("display")=="none"||n.css("visibility")=="hidden"){n.css("opacity","0.0").css("display","block").css("visibility","visible")}});return this.fadeTo(m,1,i)},fadeOut:function(n,i){var m=this.nodes;return this.fadeTo(n,0,function(){k(m,function(){FBjqRY(this).css("display","none")})})},fadeTo:function(n,m,i){return this.animate({opacity:m},n,null,i)},animate:function(r,q,s,m,o){q=l(q);var p=(o==2);var n=(o==1);var i=function(v){var u=Animation(v).duration(q);for(var t in r){if(r.hasOwnProperty(t)){u=u.to(t,r[t])}}if(s){u=u.ease(s)}if(p){u=u.blind().hide()}if(n){u=u.blind().show()}return u};this.stop();k(this.nodes,function(){i(this).go()});if(m){setTimeout(m,q)}return this},stop:function(){k(this.nodes,function(){Animation(this).stop()})},queue:function(i){},dequeue:function(){},serialize:function(){return this.serializeArray().join("&")},serializeArray:function(){var m=this.serializeHash();var i=[];for(var n in m){if(m.hasOwnProperty(n)){i.push(n+"="+escape(m[n]))}}return i},serializeHash:function(){return this.nodes[0].serialize()}};var a=("blur,change,click,dblclick,error,focus,keydown,keypress,keyup,load,mousedown,mousemove,mouseout,mouseover,mouseup,resize,scroll,select,submit,unload").split(",");for(var f=a.length-1;f>=0;f--){(function(){var i=a[f];FBjqRY.fn[i]=function(m){return m?this.bind(i,m):this.trigger(i)}})()}FBjqRY.fn.init.prototype=FBjqRY.fn;FBjqRY.extend=FBjqRY.fn.extend=function(){var r=arguments[0]||{},p=1,q=arguments.length,m=false,o;if(typeof(r)=="boolean"){m=r;r=arguments[1]||{};p=2}if(typeof(r)!="object"&&typeof(r)!="function"){r={}}if(q==p){r=this;--p}for(;p<q;p++){if((o=arguments[p])){for(var n in o){var s=r[n],t=o[n];if(r===t){continue}if(m&&t&&typeof(t)=="object"&&!t.getNodeType){r[n]=FBjqRY.extend(m,s||(t.length?[]:{}),t)}else{if(t!==c){r[n]=t}}}}}return r};FBjqRY.extend({ajax:function(i){},genericAJAX:function(m,p,i,n,q){q=q||3;if(!i&&FBjqRY.isFunction(p)){i=p;p=null}var o=new Ajax();o.responseType=n;o.ondone=i;o.onerror=function(){console.error("AJAX error occurred! Retrying...");if(q>0){FBjqRY.genericAJAX(m,p,i,n,q-1)}};o.post(m,p)},getJSON:function(m,n,i){this.genericAJAX(m,n,i,Ajax.JSON)},getScript:function(m,i){g("We can't pull in scripts dynamically using FBJS")},post:function(m,n,i){this.genericAJAX(m,n,i,Ajax.FBML)},ajaxSetup:function(i){},isFunction:function(i){return !!i&&typeof i!="string"&&!i.nodeName&&/^[\s[]?function/.test(i+"")},trim:d,each:k,grep:function(o,n,m){var p=[];for(var q=o.length-1;q>=0;q--){if(!m!=!n(o[q],q)){p.push(o[q])}}return p},makeArray:function(o){var m=[];if(o!==null){var n=o.length;if(n===null||o.split||o.setInterval||o.call){m[0]=o}else{while(n){m[--n]=o[n]}}}return m},map:function(m,r){if(FBjqRY.isFunction(m)){r=m;m=this.nodes}var n=[];for(var o=0,p=m.length;o<p;o++){var q=r(m[o],o);if(q!==null){n[n.length]=q}}return n.concat.apply([],n)},indexOf:function(p,m){var o=function(q,i){return q===i};if(p.equals){o=function(q,i){return q.equals(i)}}for(var n=m.length-1;n>=0;n--){if(o(p,m[n])){break}}return n},inArray:function(m,i){return this.indexOf(m,i)},unique:function(i){return e(i)}})})();var jQuery=FBjqRY,$=FBjqRY;
/*!
 * Ext JS Library 3.0.0
 * Copyright(c) 2006-2009 Ext JS, LLC
 * licensing@extjs.com
 * http://www.extjs.com/license
 */

//alert('fdf');
/**
 * @class Ext
 * Ext core utilities and functions.
 * @singleton
 */ 

Ext = {
    /**
     * The version of the framework
     * @type String
     */
    version : '3.0'
};

var X = $x = Ext;

X.DEBUG_DIV = "PeanutLabsDiv";
/**
 * Copies all the properties of config to obj.
 * @param {Object} obj The receiver of the properties
 * @param {Object} config The source of the properties
 * @param {Object} defaults A different object that will also be applied for default values
 * @return {Object} returns obj
 * @member Ext apply
 */
Ext.apply = function(o, c, defaults){
    // no "this" reference for friendly out of scope calls
    if(defaults){
        Ext.apply(o, defaults);
    }
    if(o && c && typeof c == 'object'){
        for(var p in c){
            o[p] = c[p];
        } 
    }
    return o;
};


(function(){
    var idSeed = 0,
        toString = Date.prototype.toString,
        //assume it's not null and not an array
        isIterable = function(v){
            //check for array or arguments
            if(Ext.isArray(v) || v.callee){
                return true;
            } 
            //check for node list type
            if(/NodeList|HTMLCollection/.test(toString.call(v))){
                return true;
            }
            //NodeList has an item and length property
            //IXMLDOMNodeList has nextNode method, needs to be checked first.
            return ((v.nextNode || v.item) && Ext.isNumber(v.length));
        },
        ua = X.USER_AGENT,
        check = function(r){
            return r.test(ua);
        },
        DOC = document,
        isStrict = DOC.compatMode == "CSS1Compat",
        isOpera = check(/opera/),
        isChrome = check(/chrome/),
        isWebKit = check(/webkit/),
        isSafari = !isChrome && check(/safari/),
        isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
        isSafari3 = isSafari && check(/version\/3/), 
        isSafari4 = isSafari && check(/version\/4/),
        isIE = !isOpera && check(/msie/),
        isIE7 = isIE && check(/msie 7/),
        isIE8 = isIE && check(/msie 8/),
        isIE6 = isIE && !isIE7 && !isIE8,
        isGecko = !isWebKit && check(/gecko/),
        isGecko2 = isGecko && check(/rv:1\.8/),
        isGecko3 = isGecko && check(/rv:1\.9/),
        isBorderBox = isIE && !isStrict,
        isWindows = check(/windows|win32/),
        isMac = check(/macintosh|mac os x/),
        isAir = check(/adobeair/),
        isLinux = check(/linux/),
        isSecure =false;  // /^https/i.test(window.location.protocol);


    Ext.apply(Ext, {
        /**
         * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
         * the IE insecure content warning (defaults to javascript:false).
         * @type String
         */
        SSL_SECURE_URL : 'javascript:false',
        /**
         * True if the browser is in strict (standards-compliant) mode, as opposed to quirks mode
         * @type Boolean
         */
        isStrict : isStrict,
        /**
         * True if the page is running over SSL
         * @type Boolean
         */
        isSecure : isSecure,
        /**
         * True when the document is fully initialized and ready for action
         * @type Boolean
         */
        isReady : false,

        /**
         * True if the {@link Ext.Fx} Class is available
         * @type Boolean
         * @property enableFx
         */

        /**
         * True to automatically uncache orphaned Ext.Elements periodically (defaults to true)
         * @type Boolean
         */
        enableGarbageCollector : true,

        /**
         * True to automatically purge event listeners after uncaching an element (defaults to false).
         * Note: this only happens if {@link #enableGarbageCollector} is true.
         * @type Boolean
         */
        enableListenerCollection : false,

        /**
         * Indicates whether to use native browser parsing for JSON methods.
         * This option is ignored if the browser does not support native JSON methods.
         * <b>Note: Native JSON methods will not work with objects that have functions.
         * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
         * @type Boolean
         */
        USE_NATIVE_JSON : false,

        /**
         * Copies all the properties of config to obj if they don't already exist.
         * @param {Object} obj The receiver of the properties
         * @param {Object} config The source of the properties
         * @return {Object} returns obj
         */
        applyIf : function(o, c){
            if(o){
                for(var p in c){
                    if(Ext.isEmpty(o[p])){
                        o[p] = c[p];
                    }
                }
            }
            return o;
        },

        /**
         * Generates unique ids. If the element already has an id, it is unchanged
         * @param {Mixed} el (optional) The element to generate an id for
         * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
         * @return {String} The generated Id.
         */
        id : function(el, prefix){
            return (el = Ext.getDom(el) || {}).id = el.id || (prefix || "ext-gen") + (++idSeed);
        },

        /**
         * Extends one class with another class and optionally overrides members with the passed literal. This class
         * also adds the function "override()" to the class that can be used to override
         * members on an instance.
         * * <p>
         * This function also supports a 2-argument call in which the subclass's constructor is
         * not passed as an argument. In this form, the parameters are as follows:</p><p>
         * <div class="mdetail-params"><ul>
         * <li><code>superclass</code>
         * <div class="sub-desc">The class being extended</div></li>
         * <li><code>overrides</code>
         * <div class="sub-desc">A literal with members which are copied into the subclass's
         * prototype, and are therefore shared among all instances of the new class.<p>
         * This may contain a special member named <tt><b>constructor</b></tt>. This is used
         * to define the constructor of the new class, and is returned. If this property is
         * <i>not</i> specified, a constructor is generated and returned which just calls the
         * superclass's constructor passing on its parameters.</p></div></li>
         * </ul></div></p><p>
         * For example, to create a subclass of the Ext GridPanel:
         * <pre><code>
MyGridPanel = Ext.extend(Ext.grid.GridPanel, {
    constructor: function(config) {
        // Your preprocessing here
        MyGridPanel.superclass.constructor.apply(this, arguments);
        // Your postprocessing here
    },

    yourMethod: function() {
        // etc.
    }
});
</code></pre>
         * </p>
         * @param {Function} subclass The class inheriting the functionality
         * @param {Function} superclass The class being extended
         * @param {Object} overrides (optional) A literal with members which are copied into the subclass's
         * prototype, and are therefore shared between all instances of the new class.
         * @return {Function} The subclass constructor.
         * @method extend
         */
        extend : jQuery.extend,

        /**
         * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
         * Usage:<pre><code>
Ext.override(MyClass, {
    newMethod1: function(){
        // etc.
    },
    newMethod2: function(foo){
        // etc.
    }
});
</code></pre>
         * @param {Object} origclass The class to override
         * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
         * containing one or more methods.
         * @method override
         */
        override : function(origclass, overrides){
            if(overrides){
                var p = origclass.prototype;
                Ext.apply(p, overrides);
                if(Ext.isIE && overrides.toString != origclass.toString){
                    p.toString = overrides.toString;
                }
            }
        },


        /**
         * Takes an object and converts it to an encoded URL. e.g. Ext.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
         * @param {Object} o
         * @param {String} pre (optional) A prefix to add to the url encoded string
         * @return {String}
         */
        urlEncode: function(o, pre){
            var undef, buf = [], key;

            for(key in o){
                undef = !Ext.isDefined(o[key]);
                Ext.each(undef ? key : o[key], function(val, i){
                    buf.push("&", key, "=", (val != key || !undef) ? val : "");
                });
            }
            if(!pre){
                buf.shift();
                pre = "";
            }
            return pre + buf.join('');
        },

        /**
         * Takes an encoded URL and and converts it to an object. Example: <pre><code>
Ext.urlDecode("foo=1&bar=2"); // returns {foo: "1", bar: "2"}
Ext.urlDecode("foo=1&bar=2&bar=3&bar=4", false); // returns {foo: "1", bar: ["2", "3", "4"]}
</code></pre>
         * @param {String} string
         * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
         * @return {Object} A literal with members
         */
        urlDecode : function(string, overwrite){
            var obj = {},
                pairs = string.split('&'),
                d = decodeURIComponent,
                name,
                value;
            Ext.each(pairs, function(pair) {
                pair = pair.split('=');
                name = d(pair[0]);
                value = d(pair[1]);
                obj[name] = overwrite || !obj[name] ? value :
                            [].concat(obj[name]).concat(value);
            });
            return obj;
        },

        /**
         * Appends content to the query string of a URL, which handles logic for whether to place
         * a question mark or ampersand.
         * @param {String} url The url to append to.
         * @@param {String} s The content to append to the url.
         * @return (String) The appended string
         */
        urlAppend : function(url, s){
            if(!Ext.isEmpty(s)){
                return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
            }
            return url;
        },

        /**
         * Converts any iterable (numeric indices and a length property) into a true array
         * Don't use this on strings. IE doesn't support "abc"[0] which this implementation depends on.
         * For strings, use this instead: "abc".match(/./g) => [a,b,c];
         * @param {Iterable} the iterable object to be turned into a true Array.
         * @return (Array) array
         */
        toArray : function(){
            return isIE ?
                function(a, i, j, res){
                    res = [];
                    Ext.each(a, function(v) {
                        res.push(v);
                    });
                    return res.slice(i || 0, j || res.length);
                } :
                function(a, i, j){
                    return Array.prototype.slice.call(a, i || 0, j || a.length);
                }
        }(),

        /**
         * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
         * passed array is not really an array, your function is called once with it.
         * The supplied function is called with (Object item, Number index, Array allItems).
         * @param {Array/NodeList/Mixed} array
         * @param {Function} fn
         * @param {Object} scope
         */
        each: function(array, fn, scope){
            if(Ext.isEmpty(array, true)){
                return;
            }
            if(!isIterable(array) || Ext.isPrimitive(array)){
                array = [array];
            }
            for(var i = 0, len = array.length; i < len; i++){
                if(fn.call(scope || array[i], array[i], i, array) === false){
                    return i;
                };
            }
        },

        /**
         * Iterates either the elements in an array, or each of the properties in an object.
         * <b>Note</b>: If you are only iterating arrays, it is better to call {@link #each}.
         * @param {Object/Array} object The object or array to be iterated
         * @param {Function} fn The function to be called for each iteration.
         * The iteration will stop if the supplied function returns false, or
         * all array elements / object properties have been covered. The signature
         * varies depending on the type of object being interated:
         * <div class="mdetail-params"><ul>
         * <li>Arrays : <tt>(Object item, Number index, Array allItems)</tt>
         * <div class="sub-desc">
         * When iterating an array, the supplied function is called with each item.</div></li>
         * <li>Objects : <tt>(String key, Object value)</tt>
         * <div class="sub-desc">
         * When iterating an object, the supplied function is called with each key-value pair in
         * the object.</div></li>
         * </ul></div>
         * @param {Object} scope The scope to call the supplied function with, defaults to
         * the specified <tt>object</tt>
         */
        iterate : function(obj, fn, scope){
            if(isIterable(obj)){
                Ext.each(obj, fn, scope);
                return;
            }else if(Ext.isObject(obj)){
                for(var prop in obj){
                    if(obj.hasOwnProperty(prop)){
                        if(fn.call(scope || obj, prop, obj[prop]) === false){
                            return;
                        };
                    }
                }
            }
        },

      
        /**
         * <p>Returns true if the passed value is empty.</p>
         * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
         * <li>null</li>
         * <li>undefined</li>
         * <li>an empty array</li>
         * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
         * </ul></div>
         * @param {Mixed} value The value to test
         * @param {Boolean} allowBlank (optional) true to allow empty strings (defaults to false)
         * @return {Boolean}
         */
        isEmpty : function(v, allowBlank){ 
            return v === null || v === undefined || ((Ext.isArray(v) && !v.length)) || (!allowBlank ? v === '' : false);
        },
        e:Ext.isEmpty,
        /**
         * Returns true if the passed object is a JavaScript array, otherwise false.
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isArray : function(v){
            return toString.apply(v) === '[object Array]';
        },

        /**
         * Returns true if the passed object is a JavaScript Object, otherwise false.
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isObject : function(v){
            return v && typeof v == "object";
        },

        /**
         * Returns true if the passed object is a JavaScript 'primitive', a string, number or boolean.
         * @param {Mixed} value The value to test
         * @return {Boolean}
         */
        isPrimitive : function(v){
            return Ext.isString(v) || Ext.isNumber(v) || Ext.isBoolean(v);
        },

        /**
         * Returns true if the passed object is a JavaScript Function, otherwise false.
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isFunction : function(v){
            return toString.apply(v) === '[object Function]';
        },

        /**
         * Returns true if the passed object is a number. Returns false for non-finite numbers.
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isNumber: function(v){
            return typeof v === 'number' && isFinite(v);
        },

        /**
         * Returns true if the passed object is a string.
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isString: function(v){
            return typeof v === 'string';
        },

        /**
         * Returns true if the passed object is a boolean.
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isBoolean: function(v){
            return typeof v === 'boolean';
        },

        /**
         * Returns true if the passed object is not undefined.
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isDefined: function(v){
            return typeof v !== 'undefined';
        },

        /**
         * True if the detected browser is Opera.
         * @type Boolean
         */
        isOpera : isOpera,
        /**
         * True if the detected browser uses WebKit.
         * @type Boolean
         */
        isWebKit: isWebKit,
        /**
         * True if the detected browser is Chrome.
         * @type Boolean
         */
        isChrome : isChrome,
        /**
         * True if the detected browser is Safari.
         * @type Boolean
         */
        isSafari : isSafari,
        /**
         * True if the detected browser is Safari 3.x.
         * @type Boolean
         */
        isSafari3 : isSafari3,
        /**
         * True if the detected browser is Safari 4.x.
         * @type Boolean
         */
        isSafari4 : isSafari4,
        /**
         * True if the detected browser is Safari 2.x.
         * @type Boolean
         */
        isSafari2 : isSafari2,
        /**
         * True if the detected browser is Internet Explorer.
         * @type Boolean
         */
        isIE : isIE,
        /**
         * True if the detected browser is Internet Explorer 6.x.
         * @type Boolean
         */
        isIE6 : isIE6,
        /**
         * True if the detected browser is Internet Explorer 7.x.
         * @type Boolean
         */
        isIE7 : isIE7,
        /**
         * True if the detected browser is Internet Explorer 8.x.
         * @type Boolean
         */
        isIE8 : isIE8,
        /**
         * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
         * @type Boolean
         */
        isGecko : isGecko,
        /**
         * True if the detected browser uses a pre-Gecko 1.9 layout engine (e.g. Firefox 2.x).
         * @type Boolean
         */
        isGecko2 : isGecko2,
        /**
         * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
         * @type Boolean
         */
        isGecko3 : isGecko3,
        /**
         * True if the detected browser is Internet Explorer running in non-strict mode.
         * @type Boolean
         */
        isBorderBox : isBorderBox,
        /**
         * True if the detected platform is Linux.
         * @type Boolean
         */
        isLinux : isLinux,
        /**
         * True if the detected platform is Windows.
         * @type Boolean
         */
        isWindows : isWindows,
        /**
         * True if the detected platform is Mac OS.
         * @type Boolean
         */
        isMac : isMac,
        /**
         * True if the detected platform is Adobe Air.
         * @type Boolean
         */
        isAir : isAir
    });

    /**
     * Creates namespaces to be used for scoping variables and classes so that they are not global.
     * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
     * <pre><code>
Ext.namespace('Company', 'Company.data');
Ext.namespace('Company.data'); // equivalent and preferable to above syntax
Company.Widget = function() { ... }
Company.data.CustomStore = function(config) { ... }
</code></pre>
     * @param {String} namespace1
     * @param {String} namespace2
     * @param {String} etc
     * @method namespace
     */
   // Ext.ns = Ext.namespace;
})();

//Ext.ns("Ext", "Ext.util", "Ext.lib", "Ext.data");



function Core(params, succFunc,  errFunc, options){ 

	Core.prototype.initCore = function(scope, params, succFunc, errFunc, options){
		var tis = scope;
		tis.success = succFunc;
		tis.error = errFunc;
		tis.options = options;
		tis.options2 = {};
		
		tis.params = params;
		//options2 = {};
		//if(!params) params = {};
		
		//if(!is(params.coreName)) params.coreName = this.getCoreName();
		
		tis.options2.dataType = 'json';
		tis.options2.success = tis.onSucc;//succFunc;
		tis.options2.succFunc = succFunc;
		tis.options2.error = errFunc == false?null:tis.onError;//.onError;
		tis.options2.timeout = 30*1000;
		tis.options2.method = 'GET';
		tis.options2.url = X.rootServer + 'core.php?';
		tis.options2.data = params;
		
		X.apply(tis.options2, tis.options);
	}
	Core.prototype.setOption = function(scope, optionKey, optionVal){
		scope.options2[optionKey] = optionVal;
	}
	Core.prototype.setParam = function(scope, optionKey, optionVal){
		scope.options2.data[optionKey] = optionVal;
	}
	this.initCore(this, params, succFunc,  errFunc, options);
	
	Core.prototype.send = function(scope){
		var op = scope.options2;
		var ajax = new Ajax();
		ajax.responseType = Ajax.JSON;
		ajax.ondone = op.success;
		op.url = X.urlEncode(op.data, op.url);
		//X.d(op.url);
		if(op.method == 'GET'){
			ajax.post(op.url,{});
		}else{
			ajax.post(op.url, op.data);
		}
	}
	
	//this.send(this);
	
}

CmdCore.prototype = new Core();        
CmdCore.prototype.constructor=CmdCore;   
function CmdCore(params, succFunc,  errFunc, options){ 
	
	
	Core.prototype.initCmdCore = function(scope, params, succFunc,  errFunc, options){
		params.coreName = 'CmdCore';
		if(!params.writer) 
			params.writer = 'JSONCmdWriter';	
			
		scope.initCore(scope, params, succFunc,  errFunc, options);
	}
	this.initCmdCore(this, params, succFunc,  errFunc, options);
	//X.de(Core.prototype);
	//Core(this, params, succFunc,  errFunc, options);
	
}
X.extend(CmdCore, Core);

ReportCore.prototype = new Core();        
ReportCore.prototype.constructor=ReportCore;
function ReportCore(){
	ReportCore.prototype.initReportCore = function(scope, params, succFunc,  errFunc, options){
		params.coreName = 'ReportCore';
		params.writer = 'JSONReportWriter';	
	}
	this.initReportCore(this, params, succFunc,  errFunc, options);
	//Core(params, succFunc,  errFunc, options);
	
}
X.extend(ReportCore, Core);


EditCore.prototype = new Core();
EditCore.prototype.constructor=EditCore;
function EditCore(params, succFunc,  errFunc, options){
	
	EditCore.CMD_LOAD = "LOAD";
	EditCore.CMD_UPDATE = "UPDATE";
	EditCore.CMD_CREATE = "CREATE";
	EditCore.prototype.initEditCore = function(scope, params, succFunc,  errFunc, options){
		var dparams = {};
		dparams.coreName = 'EditCore';
		dparams.writer = 'JSONEditWriter';
		dparams.noRedirect = '1';
		X.apply(dparams, params);
	}
	this.initEditCore(this, params, succFunc,  errFunc, options);
	//Core.prototype.constructor.call(this, dparams, succFunc,  errFunc, options);
	
}
X.extend(EditCore, Core);

X.apply(X, {
	error: function(response){
		X.d("error occured!"+response);
	},
	f: function (id){ return document.getElementById(id); },
	e: X.isEmpty,
	ee:function(o){
		if(X.isObject(o)) {
			for(var i in o){
				if(!X.e(i)) return false;
			}
			return this.e(o);
		}
	},
	ex: function(o){ return !this.e(o); },
	d: function(msg) { new Dialog(Dialog.DIALOG_POP ).showMessage('Debug', msg); }, //debug message
	de:function(e){ 
		var s=''; 
		//$j.each(e,function(a, b){ s +=a+'='+b+',\n'; });
		
		X.iterate(e,function(a, b){ s +=a+'='+b+',\n'; });
		this.d(s); 
	},
	toggleDisplay: function(target, on){ //toggle a display on/off
		
		if(X.e(target)) return;
		if(on){
			target.setStyle('display', 'inline');
		}else{
			target.setStyle('display', 'none');
		}
	},
	bind: function(targetId, event, data){
		/**
		 * targetId: id of element to which event must be attached
		 * event: name of event 
		 * data: {obj:x, fn:y} where x is the object whose function to call on activation. y = name of function to call
		 */
		var target = X.f(targetId);
		target.bind(event, data, X.activateBound);
	},
	switchUI: function (from, to){
		var f = X.f(from);
		var t = X.f(to);
		//X.d(t.html());
		this.toggleDisplay(f, false);
		this.toggleDisplay(t, true);
	},
	tmpGlobalVars:{},
	storeTmpGlobalVars:function (vars){
		var id = X.Serial.nextSerial();
		X.tmpGlobalVars[id] = vars;
		return id;
	},
	getTmpGlobalVars: function(id){
		//unset the var before returning;
		var ret = X.tmpGlobalVars[id];
		X.tmpGlobalVars[id] =null;
		return ret;
	}, 
	processCoreResult: function(json){ //TODO make sure the report response is valid and NOT empty b4 processing it
		if(X.e(json.root)){
			X.error("Invalid response");
		}
		if(json.root.error){
			X.error(json.root.error);
		}
		var echo = json.root.echo;
		var tmpVarId = echo.tmpVarId;
		var obj = X.getTmpGlobalVars(tmpVarId);
		obj[echo.callback](obj, json);
	},
	initCoreRequest: function(core, senderObj, callback){ 
		if(X.e(callback)){
			callback = 'processResult';
		}
		var tmpVarId = X.storeTmpGlobalVars(senderObj);
		core.setParam(core, 'echo_tmpVarId' , tmpVarId);
		core.setParam(core, 'echo_callback' , callback);
		core.setOption(core, 'success', X.processCoreResult);
		
		core.send(core);
	},
	FIELD_PH_PRE :'${',
	FIELD_PH_SUFF : '}',
	getFieldPlaceHolder:function(field){
		//X.d(field + '='+X.FIELD_PH_PRE); 
		return X.FIELD_PH_PRE + field + X.FIELD_PH_SUFF;
	},
	getFieldPlaceHolder2:function(field){
		return '$[' + field + ']';
	},
	getFieldPlaceHolderEnc:function(field){
		return '#{' + field + '}';
	},
	injectObjectInContainer: function(containerId, obj){ 
		
		var fh = X.f(containerId); //X.de(fh);
		var html = fh.html(), ohtml = html;
		//X.d(containerId);
		//X.d('before - ' + html);
		html = this.injectObjectData(html, obj);
		html = this.injectObjectData(html, obj, true);
		
		fh.html(html);
		//X.d('after - ' + fh.html());
		return (html != ohtml);
	},
	inj:X.injectObjectInContainer,
	injectObjectData: function(body, obj, phType){ 
		var tis = X;
		var body2;
		//X.d(body);
		X.iterate(obj, function(field, val){
			var ph = phType? tis.getFieldPlaceHolder2(field) : tis.getFieldPlaceHolder(field);
			var i = 0;
			var phe = tis.getFieldPlaceHolderEnc(field);
			while((++i) < 10){
				body2 = body.replace(ph, val);
				body2 = body2.replace(phe, escape(val));
				 //X.d(ph+ ' - -' +val);
				if( body == body2) break;
				
				//X.d(body);
				body = body2
				//i++;
			}
		});
		//X.d(body);
		return body;
	},
	checkResponseOK: function(response){
		return response.status == 'OK' || response.data.status == 'OK';
	},
	/** Given a piece of string, shorten it to the specified number of words and optionaly put a dot dot dot at the end...******/
	shortenText:function(text, wordLimit, suffix){
		var tis = this;
		var b;
		var split = text.split(" ");
		var n=0, wc=0, reduced='', prev='';
		var sr= /\s/i;
		//sr.compile();
		
		if(X.e(suffix)){ suffix = '...'; };
		//X.de(text);
		if(X.e(text) || typeof text != 'string'){
			return '';
		}
		for (var i=0; i<text.length; i++){ 
			
			b =text.charAt(i);
			//X.d(b);
			if(typeof b =='function') continue; 
			//X.d(b);
			//X.d("prev:"+prev+", curr:"+b+", red:"+reduced);
			if(sr.test(prev) && !sr.test(b)){
				wc++;
				if(wc >= wordLimit){
					return reduced.trim() + suffix;
				}
			}
			reduced += b;
			prev = b;
			
			
		}
		return reduced;
		
	}
});

X.apply(X, {inj:X.injectObjectInContainer});

X.Serial = {id:1};
X.apply(X.Serial, {
	nextSerial: function(){ return this.id++; }
	
});

/**
 * {fields:
 	{
	 {id:'field-id', title:'', vtype:'', controlClass:'name-of-the-control-class' //if empty, assumed to be there 
	 listeners: {event1:function1, event2, function2... }}, 
 *   {...another field}
 *   control, value are being used by the framework
 	},
 	validtionSetting: { }
 	
 */
X.Form = function(elements,  params, config){ //
	X.Form.prototype.initForm = function(scope, elements,  params, config){
		scope.elements = elements;
		scope.idfiedElements = scope.idelt = scope.idfyElements(scope);
		scope.config = scope.fc = config;
		scope.params = params;
		scope.recordId = config.recordId;
		scope.isUpdate = !X.e(scope.recordId);
		scope.formData = null;
		
		scope.idsep = X.ex(config.idsep)? config.idsep : '-';		
	}
	this.initForm(this, elements,  params, config);
	//this.standbyIcon;
	//if(params.standbyIcon){this.standbyIcon=params.standbyIcon}
	//X.de(this.elements);
}
X.Form.prototype = {
	idfyElements : function(scope){
		var ret = {};
		var tis = scope;
		X.iterate(scope.elements, function(i, obj){
			obj.control = tis.getControl(scope, obj, tis);
			//eval (' new X.'+obj.controlClass+'(obj, tis);')
			ret[obj.id] = obj;
		});
		//X.de(ret);
		return ret;
	},
	getControl: function(scope, obj, parent){
		switch(obj.controlClass){
			case 'X.CheckboxControl':
				return new X.CheckboxControl(obj, parent);
			break;
			case 'X.TextControl':
				return new X.TextControl(obj, parent);
			break;
			case 'X.RadioControl':
				return new X.TextControl(obj, parent);
			break;
			case 'X.SelectControl':
				return new X.TextControl(obj, parent);
			break;
		}
        },
	getElementVal:function(scope, id){
		//X.de(this.idfiedElements[id].control);
		return scope.idfiedElements[id].control.getValue(scope);
	},
	fid: function(scope, id){ 
		return X.f(scope.fidStr(id));
		
	},
	fidStr: function(scope, id){ 
		return 'fid'+scope.idsep+id;
		
	},
	fshellStr: function(scope, id){ 
		return 'fid'+scope.idsep+id+scope.idsep+'shell';
		
	},
	fnameStr: function(scope, id){ 
		return 'fn'+scope.idsep+id;
		
	},
	fElement: function(scope, obj){ 
		var type,id;
		id = obj.id;
		if(X.e(obj.type)){
			type = 'id';
			id = scope.fidStr(scope, id);
		}else{
			type = obj.type;
			id = scope.fnameStr(scope, id);
		}
		return (type=='id')? X.f(id): jQuery('['+type+'='+id+']');
	},
	fname: function(scope, id){ 
		var r = jQuery('[name='+scope.fnameStr(scope, id)+']');
		
		return r;
	},
	ferr: function(scope, id){ 
		return X.f('err'+scope.idsep+id+''); 
	},
	toggleDisplay: X.toggleDisplay,
	toggleErrorDisplay:function(scope, id, on){
		var fe = scope.ferr(scope, id);
		//	X.d(fe)
		scope.toggleDisplay(scope, fe, on);
	},

	STATIC_processSelectReport: function(json){ //TODO make sure the report response is valid b4 processing it
		//call X.validateReportResult, and check whether it's empty...
		var echo = json.root.echo, data = json.root.data.row;
		var str = '<select id="'+echo.id+'">';
		var key, val, obj, selected;
		
		X.each(data, function (i, obj){
			val = obj[echo.valueField];
			if(echo.selectedId == val){
				selected = 'selected';
			}else {
				selected = '';
			}
			str += '<option value="'+val+'" '+selected+'>'+obj[echo.displayField]+'</option>';
		});
		str +='</select>';
		X.f(echo.shellId).html(str);
	},
	initSelectReport: function(scope, id, displayField, valueField, params, selectedId){
		var core = new ReportCore(params, scope.STATIC_processSelectReport )
		params.echo_id = scope.fidStr(scope, id);
		//X.d(params.echo_id);
		params.echo_displayField =displayField;
		params.echo_valueField =valueField;
		params.echo_selectedId =selectedId;
		params.echo_shellId =scope.fshellStr(scope, id);
		core.send(core);
	},
	registerSubmitButton: function(scope, id, onSubmit){ 
		X.bind(id, 'click', {obj:scope, fn:'submit'}); 
		scope.onSubmit = onSubmit;
		
	},
	collectFormData: function(scope){
		var post={}, obj;
		X.each(scope.elements, function(a, b){
			post[b.id] = b.value;
		});
		return post;
	},
	validate: function (scope){ 
		var obj, vtype, ferr, errored, fid, hasError, val;
		for(var i=0; i<scope.elements.length; i++){ 
			errored=false;
			obj = scope.elements[i]; //X.de(obj);
			ferr = scope.ferr(scope, obj.id);
			
			//simply setting value before validating...
			obj.value = obj.control.getValue(scope);
			
			if(obj.vtype !=0 && !obj.control.validate(scope)  ){
				
				errored = true;
			}
		
			if(!errored){
				scope.toggleErrorDisplay(scope, obj.id, false);
			}else{
				//X.d(obj.id+'-');
				scope.toggleErrorDisplay(scope, obj.id, true);
			}
			hasError = hasError | errored;
		} 
		//X.d(!hasError);
		return !hasError;
	},
	
	submit: function(scope){  //X.d('dufdf')
		if(!scope.validate(scope)){ //X.d('invalid!');
				return false;
			}
		
		var data  = scope.collectFormData();
		var rid = X.ex(scope.recordId)? scope.recordId : '';
		var defaultparams = {cmd:scope.isUpdate? 'UPDATE':'CREATE', id:rid, idx:rid};
		var defaultOptions = {method:'POST'};
		Ext.apply(data, defaultparams);
		Ext.apply(data, scope.params);
		//X.de(data);
		var cor = new EditCore(data, scope.onSubmit, scope.onSubmit, defaultOptions);
		//cor.send();
		X.initCoreRequest(cor, scope, 'submitDone');
		//X.init
	},
	toggleForm: function(scope, id, on){
		var f = ('form-'+id);
		var s = ('submit-'+id);
		if(on)
			X.switchUI(f, s);
		else X.switchUI(s, f);
	},
	loadFormData:function(scope){
		var tp = X.apply({}, scope.params);
		tp.cmd = 'LOAD';
		tp.method = 'GET';
		//tp.id = this.recordId;
		
		X.initCoreRequest(new EditCore(tp), scope, 'processFormData');
		
	},
	submitDone: function(scope, data){ //X.d('fuck');

		scope.onSubmit(scope, data);
	},
	processFormData: function(scope, json){

		scope.formData  = json.root.data;
		var ie ;
		for (var i in scope.formData){
			obj = scope.formData[i];
			ie = scope.idfiedElements[obj.name];

			
			if(!X.e(ie)){
				
				ie.control.postDisplay(scope, obj);
				//this.setValue(ie, obj);
				ie.control.setValue(scope, obj);
			}
		}
	},
	checkResponseOK:X.checkResponseOK
	
};


X.FormControl = function(element, form){ //
	X.FormControl.prototype.initFormControl = function(scope, element, form){
		scope.element = element;
		scope.form = form;
	}
	this.initFormControl(this,element, form );
	//this.registerListeners(element.listeners);
}
X.FormControl.prototype = {
    
	setValue:function(scope, valObj){
		scope.getDomElement().setValue(scope, valObj.value);
	},
	fnameStr:function(scope){ //X.de(this.form);
		return scope.form.fnameStr(scope, scope.element.id);
	},
	getDomElement: function(scope){ 
		return scope.form.fElement(scope, scope.element);
	},
	getValue:function(scope){
		return scope.getDomElement(scope).getValue(scope);
	},
	validate:function(scope){
		val = scope.element.value = scope.getValue(scope);
		//X.d(this.element.id + ' - '+val);
		return !(X.e(val)) ;
		
	},
	getCheckedValue:function(scope, name, allowMulti){
		var fls = jQuery('[name='+name+']');
		var multi = [];
		for(var i=0; i<fls.length; i++){
			if(fls[i].getChecked(scope)){
				if(allowMulti){
					multi.push(fls[i].getValue(scope));			
				}else
					return fls[i].getValue(scope);
			}
		}
		return multi.lenght>0? multi : false;
    },
	/**
	 * Draw addition stuff that you need to draw after data comes from the server...
	 */
	postDisplay: function(scope, dataObj){
		
	}
}

X.RadioControl = function(element, form){ 
	X.RadioControl.prototype.initRadioControl = function(scope,element, form ){
		
		scope.initFormControl(scope, element, form);
	}
	this.initRadioControl(this, element, form);
}
X.RadioControl.prototype = new X.FormControl();        
X.RadioControl.prototype.constructor=X.RadioControl;  

X.extend(X.RadioControl, X.FormControl);
X.apply(X.RadioControl.prototype, {
	setValue:function(scope, valObj){
	 	jQuery('[name='+scope.fnameStr()+'][value='+valObj.value+']').click();
	},
	getValue:function(scope){
		//var fls = jQuery('[name='+this.fnameStr()+']');
		return scope.getCheckedValue(scope.fnameStr(), false);
		/*for(var i=0; i<fls.length; i++){
			if(fls[i].getChecked()){
				return fls[i].getValue();
			}
		}
		return jQuery('[name='+this.fnameStr()+']:checked').val();
		*/
	}
});

 
X.CheckboxControl = function(element, form){ 
	//X.FormControl.prototype.constructor.call(this, element, form);
	
	
	X.CheckboxControl.prototype.initRadioControl = function(scope,element, form ){
		
		scope.initCheckboxControl(scope, element, form);
	}
	this.initCheckboxControl(this, element, form);
}
X.CheckboxControl.prototype = new X.FormControl();        
X.CheckboxControl.prototype.constructor=X.CheckboxControl;

X.extend(X.CheckboxControl, X.FormControl);
X.apply(X.CheckboxControl.prototype, {
	sepPrefix:function(){return '[';},
	sepPostfix:function(){return ']';},
	setValue:function(valObj){
		jQuery('[name='+scope.fnameStr(scope)+'][value='+valObj.value+']').click();
	},
	getValue:function(scope){
		//alert('not yet implemented!');
		//var vs = '';
		//X.d('checkbox[name='+this.fnameStr()+']:checked');
		//var fl = jQuery('[name='+this.fnameStr()+']:checked').val(); 
		//X.d(fl);
		var fl =scope.getCheckedValue(scope.fnameStr(scope), true);
		return X.ex(fl)? fl.join() : '';
		
	}
});
 

 
X.TextControl = function(element, form){ 
	
	X.TextControl.prototype.initTextControl = function(scope,element, form ){
		
		scope.initCheckboxControl(scope, element, form);
	}
	this.initTextControl(this, element, form);	
}
X.TextControl.prototype = new X.FormControl();        
X.TextControl.prototype.constructor=X.TextControl;
X.extend(X.TextControl, X.FormControl);


X.SelectControl = function(element, form){ 
	
	X.SelectControl.prototype.initSelectControl = function(scope,element, form ){
		
		scope.initSelectControl(scope, element, form);
	}
	this.initSelectControl(this, element, form);	
}
X.SelectControl.prototype = new X.FormControl();        
X.SelectControl.prototype.constructor=X.SelectControl; 

X.extend(X.SelectControl, X.FormControl);
X.apply(X.SelectControl.prototype, {
	validate:function(scope){
		val = scope.element.value = scope.getValue(scope);
		//X.d("val="+val+"-");
		return !(val ==0 || X.e(val)) ;
		
	},
	postDisplay: function(scope, dataObj){
		var str='', dao = dataObj, val, display;
		var id = dao.name;
		var selectedList = {};
		if(!X.e(dao.selectedOptions)){
			X.each(dao.selectedOptions, function (i, obj){
				//X.d('here');
				selectedList[obj.data] = obj.data;
			});
		}
		var oldClass = scope.form.fElement(scope, obj).getClassName();
		//var oldStyle = this.form.fElement(obj).attr("style");
		str = '<select  class="'+oldClass+'" mode="1" id="'+scope.form.fidStr(obj.name)+'">';
		X.each(dao.options, function (i, obj){
			val = obj.data;
			display = obj.label;
			if(selectedList[val] == val){
				selected = 'selected';
			}else {
				selected = '';
			}
			str += '<option value="'+val+'" '+selected+'>'+display+'</option>';
		}); 
		var shellId = scope.form.fshellStr(scope, id);
		//X.d(shellId+ ' - '+str);
		X.f(shellId).setInnerXHTML(str);
		//var fid = this.form.fidStr(id);
		//var z = dhtmlXComboFromSelect(fid);
		//z.enableFilteringMode(true);
		//X.d(str);
		//this.getDomElement().html(str);
	}
});

/**
 * General Reporting how-to:
 * 
 * -reportParams are the variables to be passed over to the server when requesting the report.
 * -reportConfig: specific to the type of report, to be used by the actual Report class to figure out how to show the report
 * 
 * pagination how-to:
 * enabledPagination=1
 * pageSize=x // indicates page size for pagination
 * pageListContainers: [list-of-pagination container ids for inject pagination]
 * reportName: name of the report object as a string 
 * displayDone: name of a function to be called after data is 
 * noResult: function to call if result set is empty
 * 
 */
X.Report = function(reportParams, reportConfig){
	var cd = {header:'',
	 				footer :'', lineCount:0, lineBreak:'<br>', 
	 				enablePagination:true, limitSize:10, 
	 				pageListSize:10, reportName:"report", 
	 				noResult:'doNoResult', noResultString:'<div class="text">No data available</div>',
					preProcessor:null //eg: should be function(row)
			};
	 X.apply(cd, reportConfig);
	 //X.de(cd);
	this.reportConfig =cd;
	this.reportParams = reportParams;
	this.data = null;
	this.dataComplete = null;
	this.limitInfo ;
	this.FIELD_PH_PRE = X.FIELD_PH_PRE; '${';
	this.FIELD_PH_SUFF = X.FIELD_PH_SUFF; //'}';
	this.standbyIcon;
	if(reportParams.standbyIcon){this.standbyIcon=reportParams.standbyIcon}
	
	this.paginationData =null;
	//X.d('created!');
};

X.Report.prototype =   {
	
	responseHasData: function (response){
		return X.ex(response.root.data);
	},
	activateReport: function(){ //X.d('dfd'); return;
		this.activatePage(0);
	},	
	initReport: function (){
		var core = new ReportCore(this.reportParams);
		X.initCoreRequest(core, this, 'processResult');
	},
	processResult:function(json){
		//X.de(json.root.data);
		//X.de(json.root.data);
		if(this.standbyIcon && uiUtilities){
			uiUtilities.hideStandbyIcon(this.standbyIcon?this.standbyIcon:true);
		}	
		
		if(!this.responseHasData(json)){
			var nr = this.reportConfig.noResult; 
			if(X.ex(this[nr])){
				this[nr]();
			}
			return;
		}
		this.dataComplete = json;
		this.limitInfo = json.root.limit;
		this.data = json.root.data.row;
		//X.de(this.data);
		if(X.e(this.paginationData)){
			this.paginationInfo = this.paginationData  = this.generatePaginationData();
			//X.de(this.paginationData);
		}
		this.doDisplay();
		this.printPaginationDisplay();
		
		var dd = this.reportConfig.displayDone;
		if(X.ex(dd)){ 
			dd();
		}
	},
	preProcess:function(row){
		var ppl = reportConfig.preProcessor;
		if(X.e(ppl)) return;
		ppl(row);
	},
	doDisplay:function(){},
	doNoResult:function(){},
	getReportData:function(){
		return this.data;
	},
	getFieldPlaceHolder:X.getFieldPlaceHolder,
	injectObjectInContainer: X.injectObjectInContainer,
	injectObjectData: X.injectObjectData,
	/**
	 * @param - query - object containing field-value pairs of what to match
	 * @param - single - whether to return the first object ONLY
	 * @return - list matching objects in the data set
	 */
	searchReportData: function(query, single){
		var data = this.getReportData(), obj, qo, resultList=[], broken=false;
		if(X.e(single)) single = false;
		for(var i=0; i<data.length; i++){
			obj= data[i];
			broken=  false;
			for(var k in query){
				if(query[k] != obj[k]  ){
					//NOT found!
					broken=true;
					break;
					
				}
				
			}
			if(broken){
				continue;
			}
			if(single){
				return obj;
			}
			resultList.push(obj);
		}
		return resultList;
	},
	/**
	 * Figure out how to toggle a description from a trim version to a full version
	 * the record is expected to have the following field. 
	 * suppose descPrefix == description
	 * description_trim should contain a trimmed version of the text
	 * description should contain a full version of the text
	 */
	toggleTrim: function(containerId, recordId, descPrefix, show){
		
	},
	/** BEGIN Pagination code **/ 
	/**
	 * @param page - the page you want returned
	 * given a page that exists, return it's pagination info, containing it's page number + limitStart number
	 * NOTE: if page doesnt exist, the default behavior is to return an object with both properties = 0
	 */
	getPaginationInfo:function(page){
		var pi = X.e(this.paginationData)? null : this.paginationData[page];
		if(X.e(page) || X.e(pi)) return {page:0, limitStart:0};
		
		return pi;
	},
	activatePage: function(page){ 
		var rp = this.reportParams, rc= this.reportConfig, pi = this.getPaginationInfo(page);
		this.currPaginationInfo = pi;
		this.reportParams.enablePagination = rc.enablePagination;
		this.reportParams.limitSize = rc.limitSize;
		this.reportParams.limitStart = pi.limitStart;
		//X.de(pi);
		this.initReport();
		//X.d(page);
		//if(page <= 2)
			//setTimeout('report.activatePage('+(page+1)+');', 1000*3);
	},	
	paginationEnabled: function(){
		return this.reportConfig.enablePagination ; 
	},
	generatePaginationData: function(){
		
		var total = this.limitInfo.resultSetSize;
		if(!this.paginationEnabled || !(total>0)){ return {}; }
		
		var result = [];
		var pageSize = this.reportConfig.limitSize;
		
		for(var i=0, n=0; n<total; n+=pageSize, i++){
			
			result[i] = {page:i, limitStart:n};
		}
		return result;
	},
	getPaginationLink: function(page, display, reportName, selected){
		if(page == display){
			display += 1;
		}
		if(!selected){
			return '<a style="text-decoration:underline" href="javascript:'+reportName+'.activatePage('+page+');">'+display+'</a>&nbsp;';
		}else{
			return ''+display+'&nbsp;';
		}
	},
	generatePaginationDisplay: function(reportName){
		var listSize=this.reportConfig.pageListSize;
		var currPage = this.currPaginationInfo.page, listCount = this.paginationData.length;
		var html='', leftLimit=currPage-Math.floor(listSize/2);
		
		if(leftLimit<0) leftLimit =0;
		var rightLimit = leftLimit + listSize
		if(rightLimit>listCount) rightLimit = listCount-1;
		
		if(currPage > 0){
			html += this.getPaginationLink(currPage-1, '&larr; Previous', reportName, false);
		}
		//X.d(leftLimit+' - '+rightLimit);
		for(var i=leftLimit; i<rightLimit && i<listCount; i++){
			html += this.getPaginationLink(i, i, reportName, currPage == i);
		}
		if(currPage < listCount-1){
			html += this.getPaginationLink(currPage+1, 'Next &rarr;', reportName, false);
		}
		return html;
	},
	printPaginationDisplay:function(){
		var pc = this.reportConfig.pageListContainers;
		var rn = this.reportConfig.reportName;
		if(X.e(pc)) return;
		var html = this.generatePaginationDisplay(rn);
		for(var i=0; i<pc.length; i++){
			X.f(pc[i]).setInnerXHTML(html);
		}

	}
	/** END Pagination code **/
};

/**
 * ListReport how-to:
 * 1. pass the following parameters to reportConfig:
 * 	-containerId: where to display the report when ready
 *  -header: header of report
 *  -lineCount: if you want to punctuate result items with some string, lineCount indicates how many items before 
 *  	punctuating
 *  -lineBreak: what string to punctuate with
 *  
 */
X.ListReport = function (reportParams, reportConfig){
	X.Report.prototype.constructor.call(this, reportParams, reportConfig); 
}
jQuery.extend(X.ListReport, X.Report);
X.apply(X.ListReport.prototype, {
	doNoResult:function(){ 
		//var containerId =
		//X.de(this);
		var conf = this.reportConfig; //X.de(conf);
		var container = X.f(conf.containerId);
		var html = conf.noResultString;
		//X.d(html);  
		container.setInnerXHTML(html);
		//X.d(container.attr("id")+' - '+ container.html());
	},
	prepareData:function(data){ //modify data before displaying it...if necessary
		
	},
	doDisplay:function(){ 
		//var containerId =
		var conf = this.reportConfig;
		var container = X.f(conf.containerId);
		//X.d(conf.containerId);
		var html = conf.header; 
		var dataObj; 
		var lc = this.reportConfig.lineCount, lb = this.reportConfig.lineBreak;
		var ln;
		for(var i =0; i<this.data.length; i++){
			ln = i+1;
			dataObj = this.data[i];
			this.prepareData(dataObj);
			html += this.injectObjectData(conf.body, dataObj);
			
			if(lc>0 && ln>0 && ((ln % lc)==0) && !X.e(lb)){ //if line break and line count both exist
				html += lb;
			}
		}
		html += conf.footer;
		container.setInnerXHTML(html);
		//X.d(container.attr("id")+' - '+ container.html());
	}
});



/**
 * params - params to send it for the request
 * config - config for the Cmd, currently supports:
 * 	-delayRequest: if not passed, Cmd request will be send auto on init!
 *  -ready: name of function to call when the data is available  
 */
X.Cmd = function (params, config){
	this.params = params;
	this.config = config;
	this.data = null;
	if(!this.config.delayRequest){
		this.initRequest(this);
	}
	//this.standbyIcon;
	//if(params.standbyIcon){this.standbyIcon=params.standbyIcon}
}
//X.extend(X.GridReport, X.Report);
X.apply(X.Cmd.prototype, {
	initRequest: function(scope){ 
		var core = new CmdCore(scope.params);
		X.initCoreRequest(core, scope);
	},
	processResult: function(scope, json){
		scope.data = json;
		if(!X.e(scope.config.ready)){
			(scope.config.ready)(scope.data.root.data);
		}
	},
	get:function(scope, key){
		return scope.data[key];
	}
});
// JavaScript Document
var dealInfo = new DealInfo();
var dealBuy = new DealBuy();

var U = new Utilities({pageId:"page",pageWidth:760});


init();


function Utilities(params){
	this.pageId = params.pageId;
	this.pageWidth = params.pageWidth;
	
	Utilities.prototype.x = function(target,xhtml){
		X.f(target).setInnerXHTML(xhtml);
	}
	
	Utilities.prototype.f = function(target,fbml){
		X.f(target).setInnerFBML(fbml);
	}
	
	Utilities.prototype.pg = function(xhtml){
		this.x(this.pageId, xhtml);
	}
	
	Utilities.prototype.i = function(target,content){
		this.x(target, content);
	}
	
	Utilities.prototype.ipg = function(pageURL,params){
		if(params){
			pageURL=pageURL+"?"
		}
		for(var i in params){
			thisValue = params[i];
			pageURL+=i+"="+params[i];
			
		}
		this.x(this.pageId, "<iframe id='"+this.pageId+"_iframe' src='"+staticURL+pageURL+"' frameborder='0' width='"+this.pageWidth+"' ></iframe>");
		X.f(this.pageId+"_iframe").setStyle("width",600);
	}
	
	Utilities.prototype.urls = function(params){
		urlString = "";
		var thisValue = '';
		for(var i in params){
			thisValue = this.exh(params[i]);
			urlString+=i+"="+thisValue+"&amp;";
		}
		return urlString;
	}
	
	Utilities.prototype.exh = function(str){
		str = str.replace(" ", "&nbsp;")
		str = str.replace(".", "&middot;");
		return str;
	}
	
	Utilities.prototype.ac = function(target,func,data){
		var obj = X.f(target);
		var params = {};
		params.data = data;
		params.source = obj;
		obj.addEventListener('click', function(e){
			params.event = e;
			func(params);
			}, false);
	}
	
	Utilities.prototype.s = function(target,style,value){
		X.f(target).setStyle(style,value);
	}
}

function init(){
	X.rootServer=staticURL;
}
function DealInfo(){
	
	this.pageHTML = "";/*"<div>" +
						"<div class='dealtitle'>"+
						"<h1>" +
								"<span>Today's Deal:</span> ${title}" +
							"</h1>" +
						"</div>" +
						"<div class='dealsplash'>" +
							"<div class='dealsplash1'>" +
								"<div class='dealfacts'>" +
									"<div class='dealfact1'>" +
										"<div class='dealcost'>${currency}${deal_price}</div>" +
										"<a id='buyBtn' href='"+appURL+"index.php?p=buyDeal&amp;appURL=%{appURL}' ><div class='dealbuybutton'>Buy</div></a>" +
										"<div class='dealvalues'>" +
											"<dl>" +
												"<dt>Value</dt>" +
												"<dd>${currency}${deal_value}</dd>" +
											"</dl>" +
											"<dl>" +
												"<dt>Discount</dt>" +
												"<dd>${discount_perc}</dd>" +
											"</dl>" +
											"<dl>" +
												"<dt>You Save</dt>" +
												"<dd>${currency}${deal_savings}</dd>" +
											" </dl>" +
										"</div>" +
									"</div>" +
									"<div class='dealfact2'>" +
										"<dl>" +
											"<dt>Time Left To Buy</dt>" +
											"<dd>2 hours 10 minutes</dd>" +
										"</dl>" +
									"</div>" +
									"<div class='dealfact3'>" +
										"<h3>1,456 bought</h3>" +
										"<dl>" +
											"<dt>The deal is on!</dt>" +
											"<dd>Tipped at 7:57AM with ${min_sales} bought</dd>" +
										" </dl>" +
									"</div>" +
								"</div>" +
							"</div>" +
							"<div class='dealsplash2'>" +
									"<img src='%{staticURL}${med_img}' class='dealpic' />" +
								"<div class='dealsummaries'>" +
									"<div class='dealfineprint'>" +
										"<h3>The Fine Print</h3>" +
										"${fine_print}" +
									"</div>" +
									"<div class='dealhighlights'>" +
										"<h3>Highlights</h3>" +
										"${highlights}" +
									"</div>" +
								"</div>" +
							"</div>" +
						"</div>" +
						"<div class='dealdetail'>" +
							"<div class='dealdetail1'>" +
								"${description}" +
							"</div>" +
							"<div class='dealdetail2'>" +
								"<h3>The Company</h3>" +
								"<ul>" +
									"<li>${company}</li>" +
									"<li>${address}</li>" +
									"<li><a href='${website}' target='_blank'>${website}</a></li>" +
									"<li><a href='http://maps.google.com/maps?q=${address}' target='_blank'>Map it!</a></li>" +
								"</ul>" +
							"</div>" +
						"</div>"+
					"</div>";
	*/
	
	DealInfo.prototype.getTodays = function(){
		var p = {
				coreClass:"DealOfTheDayCmd", 
				module:"offer.cd"
				};
		todaysDealCmd = new X.Cmd(p, {ready:this.showPage});
	};
	
	DealInfo.prototype.showPage = function(r){
		//U.pg(X.injectObjectData(dealInfo.pageHTML.replace('%{params}',U.urls(r)),r));
		//dealInfo.pageHTML = dealInfo.pageHTML.replace('%{appURL}',U.exh(appURL));
		//dealInfo.pageHTML = dealInfo.pageHTML.replace('%{staticURL}',U.exh(staticURL));
		U.pg(X.injectObjectData(dealInfo.pageHTML,r));
		//U.ac('buyBtn', dealBuy.showPage);
		X.de(r);
	};
}
function DealBuy(){
	DealBuy.prototype.showPage = function(){
		//U.ipg("buy.php",{userId:"saad123-69-221a44d681"});
		//window.location = appURL+"buyDeal?title=dadsadsa";
	};
}

var dealTimer = new DealTimer();
var dealState = new DealState();
var getDealSateIntervalID;
var deal = {
};
var fbui = new FBUI();
var splashPage = new SplashPage();
var dealPage = new DealPage();
var buyDealStatusPage = new BuyDealStatusPage();
var loadDefaults = {
	module:'offer.cd'
}
var PAGE_VAR = "p";

if(staticURL){
	//document.setLocation(staticURL);//this is FB specific code
}
function dealInit(dealInfo){
	
	setDeal(dealInfo);
	dealState.setState();

}

function setDeal(dealInfo){
	
	deal = X.apply(deal,dealInfo);
	
}

function DealState(){
	
	this.pbWidth = 162;
	this.min_sales = 0;
	this.max_sales = 0;
	this.sales = 0;
	this.actualProgress = 0;
	this.progress = 0;
	
	
	DealState.prototype.setState = function(){
		if((deal.active && deal.active!='0' && deal.active!=0)){
			/*
			if((parseInt(deal.sales)>=parseInt(deal.min_sales))){
				if((parseInt(deal.sales)>=parseInt(deal.max_sales))){
					//dealState.addSoldOut();
					dealTimer.clearCountDown();
				}else{
					//dealTimer.start();
					//dealState.addDealIsOn();
					dealTimer.start();
					
				}
			}else{
				//dealTimer.start();
				//dealState.addProgressBar();
				dealTimer.start();
			}
			*/
			
			if(getDealSateIntervalID){clearInterval(getDealSateIntervalID);}
			
			if(parseInt(deal.sales)<parseInt(deal.max_sales)){
				dealTimer.start();
				getDealSateIntervalID = setInterval(function(){dealState.loadState();}, 45000);
			}else{
				dealTimer.clearCountDown();
			}
		}else{
			dealTimer.clearCountDown();
		}
		
	};
	
	DealState.prototype.loadState = function(){
		var p = {
			coreClass:"CampaignSalesCmd",
			campaign_id:deal.campaign_id
			};
		p = X.apply(loadDefaults,p);
		campaignSalesCmd = new X.Cmd(p, {ready:dealState.updateState});
	};
	
	DealState.prototype.updateState = function(res){
		deal = X.apply(deal,res);
		dealState.updateSales();
		
		/*
		if(!deal.dealIsOn){
			if((deal.sales>=deal.min_sales)){
				dealState.setState();
			}else{
				dealState.updateProgressBar();
			}
		}else{
			if((deal.sales>=deal.max_sales)){
				dealState.setState();
			}
		}*/
		
		if(!deal.active){
			dealTimer.clearCountDown();
		}
		if(deal.sales >= deal.max_sales){
			this.addSoldOut();
			dealTimer.clearCountDown();
		}else if(!deal.active){
			this.addNotAvailable();
			dealTimer.clearCountDown();
		}
		
	};
	
	DealState.prototype.updateSales = function(){
		U.i("dealSales","<div class='heading b'><div class='inline' >"+deal.sales+" Bought</div></div>");
	};
	
	DealState.prototype.addSoldOut = function(){
		deal.tip_date = 123123231;
		var tipDate = new Date(parseInt(deal.tip_date));
		var soldOutHTML = 	"<div>" +
								"<div class='soldout'><h4><b></b></h4></div>" +
								"<div class='subtitle'><h5>Sold out at "+tipDate.getHours()+":"+tipDate.getMinutes()+" with "+deal.max_sales+" bought</h5></div>"+
							"</div>";
		//U.i("dealState",soldOutHTML);
		
		U.i("dealAction","<div class='heading m i mr2'>Sold<br>Out!</div>");
		
	};
	
	DealState.prototype.addNotAvailable = function(){
		U.i("dealAction","<div class='heading m i mr2'>No<br/>Longer<br/>Available!</div>");
	};
	
	DealState.prototype.addDealIsOn = function(){
		deal.dealIsOn = true;
		deal.tip_date = 123123231;
		var tipDate = new Date(parseInt(deal.tip_date));
		//X.d(tipDate.toString())
		//X.d(deal.tip_date)
		
		var dealIsOnHTML = 	"<div>" +
								"<div class='checkMark'><h4><b>The deal is ON</b></h4></div>" +
								"<div class='subtitle'><h5>Tipped at "+tipDate.getHours()+":"+tipDate.getMinutes()+" with "+deal.min_sales+" bought</h5></div>" +
							"</div>";
		U.i("dealState",dealIsOnHTML);
	};
	
	DealState.prototype.addProgressBar = function(){
		
		deal.dealIsOn = false;
		
		this.min_sales = parseInt(deal.min_sales);
		var pubWidthHalf =Math.floor(this.pbWidth/2);
		U.i("dealState","<div class='saleProgressBarContainer'>" +
												"<div id='progressbarwrapper' class='progressbarwrapper'>" +
													"<div id='sale-progressbar' class='cl_progressbar'>" +
														"<div id='saleprogressbarfill' class='cl_progressbarfill' style='width:"+(pubWidthHalf)+"px'></div>" +
													"</div>" +
													"<div id='saleprogressbarpercentage' class='cl_progressbarpercentage'>50%</div>" +
												"</div>" +
												"<div class='subtitle' style='width:220px;'><h5><b><div id='salesneeded' class='inline'>"+dealState.salesNeeded()+"</div> more needed to get the deal</b></h5></div>" +
										"</div>");
			
		this.updateProgressBar();
			
	};
	
	DealState.prototype.salesNeeded = function(){
		var salesNeeded;
		if(deal.min_sales>deal.sales){
			salesNeeded = parseInt(deal.min_sales) - parseInt(deal.sales);
		}else{
			salesNeeded = 0;
		}
		return salesNeeded;
	}
	
	DealState.prototype.updateProgressBar = function(){
		if(deal.dealIsOn){
			return;
		}
		deal.actualProgress = (parseInt(deal.sales)/parseInt(deal.min_sales))*100;
		deal.progress = Math.floor(deal.actualProgress);
		var pubWidthHalf = this.pbWidth*(deal.actualProgress/100);
		U.i("sale-progressbar","<div id='saleprogressbarfill' class='cl_progressbarfill' style='width:"+Math.floor(pubWidthHalf)+"px'></div>");
		U.i("saleprogressbarpercentage","<div>"+deal.progress+'%'+"</div>");
		U.i("salesneeded","<div class='inline'>"+dealState.salesNeeded()+"</div>");
	};
	
	DealState.prototype.subscribeEmail = function(o){
		X.de(o);
		//var isValidEmail = validateForm.validateEmail(o);
		
		/*
		var p = {
			module:"email",
			coreName: "CmdCore",
			witer: "JSONCmdWriter",
			coreClass:"CaptureEmailCmd",
			email: "test@test2.com",
			user_id: "173"
			};
		emailSubscribeCmd = new X.Cmd(p, {ready:dealState.emailSubscribeResponse});
		*/
	};
	
	DealState.prototype.emailSubscribeResponse = function(response){
		emSub = response;
		var emStatus = emSub.status;
		if (emStatus == "OK") {
		
			X.d("Thank you your email has been added");
		}
		else {
			//something else
		}	
	};
	
	
}

function DealTimer(){
	var currentTimeStamp = 0;
	var timeRemaining = 0;
	
	//timer start
	var miliSec = 0;   // set the seconds
	var sec=1;   // set the minutes
	var time = 100;
	var currentTitle = "";
	var currentBody = "bb";
	var startHours = 0;
	var startMinutes = 0;
	var startSeconds = 0;
	var startMilliseconds = 0;
	var SD;
	var now;
	var startedAt;
	
	DealTimer.prototype.close_ts = 1;
	DealTimer.prototype.now_ts = 1;

	DealTimer.prototype.start = function() {
		
	this.close_ts = deal.close_ts;
	this.now_ts = deal.now_ts;
	
	if(!deal.active || deal.active=='0' || deal.active==0 || (!this.close_ts || !this.now_ts) || this.now_ts>this.close_ts){
		//U.i("timerContainer","<div>This deal has ended.</div>");
		this.clearCountDown();
		//
		return;
	}
		
	if(false){
		//X.d('timer error');
		this.clearCountDown();
	}
	sec = (parseInt(this.close_ts)/100)-(parseInt(this.now_ts)/100);
	
	if(!sec || sec<0){
		//X.d('timer sec incorrect')
	}
	
	
	if(!now || !startedAt){
		now = new Date();
		now.setTime(Math.abs(parseInt(deal.close_ts)-parseInt(deal.now_ts)));
		startedAt = new Date();
	}
	
	var current = new Date();
	
	var nowStamp = (parseInt(deal.close_ts))-(current.getTime()-startedAt.getTime())
	
	if(nowStamp<=0){
		this.clearCountDown();
		//
		return;
	}
	
	var fullHourTs = nowStamp-deal.now_ts;
	
	var fullHours = Math.floor(((fullHourTs/1000)/60)/60);
	
	fullHourTs -= (fullHours*1000*60*60);
	
	var fullMins =  Math.floor((fullHourTs/1000)/60);
	
	fullHourTs -= (fullMins*1000*60);
	
	var fullSecs =  Math.floor(fullHourTs/1000);
	
	fullHourTs -= (fullSecs*1000);
	
	fullMiliSecs = fullHourTs;
	
	
	if(fullHours<0 || fullMins<0 || fullSecs<0){
		this.clearCountDown();
		//
		return;
	}
	
	now.setTime(nowStamp);
	
	//U.i('dealSales','<div>'+now.toDateString()+'</div>');
	
	//X.d(deal.now_ts+"   ---   "+deal.close_ts)
	
	
	//U.i("timerHours","<div class='inline'>"+" ---- "+Math.abs(deadline.getHours()-now.getHours())+"</div>");
	/*
	var hours = now.getHours();
	if(hours<startHours){
		var thisHourIncrement = hours+(24-startHours);
	}else{
		var thisHourIncrement = hours-startHours;
	}
	thisHourIncrement=24-thisHourIncrement;
	
	sec-=(thisHourIncrement*(60*60*1000));
	
	
	var minutes = now.getMinutes();
	if(minutes<startMinutes){
		var thisMinuteIncrement = minutes+(60-startMinutes);
	}else{
		var thisMinuteIncrement = minutes-startMinutes;
	}
	thisMinuteIncrement=60-thisMinuteIncrement;
	
	sec-=(thisMinuteIncrement*(60*1000));
	
	var seconds = now.getSeconds();
	if(seconds<startSeconds){
		var thisSecondIncrement = seconds+(60-startSeconds);
	}else{
		var thisSecondIncrement = seconds-startSeconds;
	}
	thisSecondIncrement=60-thisSecondIncrement;
	
	
	var milliseconds = now.getMilliseconds();
	if(milliseconds<startMilliseconds){
		var thisMillisecondIncrement = milliseconds+(1000-startMilliseconds);
	}else{
		var thisMillisecondIncrement = milliseconds-startMilliseconds;
	}
	thisMillisecondIncrement=1000-thisMillisecondIncrement;
	  
	time = "<div>" +
				"<div class='subtitle'>Time Remaining:</div>" +
				"<span>"+thisHourIncrement+" hr "+thisMinuteIncrement+" mins "+thisSecondIncrement+"."+thisMillisecondIncrement.toString().substring(0,2)+" sec</span>" +
			"</div>";
	*/  
	//alert(time);
	clearTimeout(SD); 
	
	SD = setTimeout(function(){dealTimer.start();}, 300);
	  
		U.i("timerHours","<div class='inline'>"+fullHours+" Hours</div>");
		U.i("timerMinutes","<div class='inline'>"+fullMins+" Minutes</div>");
		U.i("timerSeconds","<div class='inline'>"+fullSecs+"."+fullMiliSecs.toString().substring(0,1)+" Seconds</div>");
	}

	DealTimer.prototype.clearCountDown = function(){
		var currentBody = "";
		U.i("timerHours","<div class='inline'>0 Hours</div>");
		U.i("timerMinutes","<div class='inline'>0 Minutes</div>");
		U.i("timerSeconds","<div class='inline'>0 Seconds</div>");
		//U.i("timerContainer",currentBody);
		
		clearTimeout(SD);
		
		if(parseInt(deal.sales)>=parseInt(deal.max_sales)){
			dealState.addSoldOut();
		}else{
			dealState.addNotAvailable();
		}
	}
}

function FBUI(){
	FBUI.prototype.show_photo_of_day_dialog = function()
	{
	var dialog = new Dialog();
		dialog.showMessage('Photo Of Day', 'aaa', 'Continue');
		dialog.onconfirm = function()
		{
			var attachment = {'name':'Photo of the day','href':'LINK_HERE',
				'caption': '','description': 'DESCRIPTION_HERE',
				'media': [{'type':'image','src':'MEDIA_SOURCE_HERE','href':'LINK_HERE'}]};
			var action_links = [{"text": "View Photo", "href": "LINK_HERE"}];
			var target_id = null;
			var user_message_prompt = null;
			var callback = o.callback;
			var auto_publish = true;
			var actor_id = null;
			Facebook.streamPublish('',  attachment,  action_links, target_id, user_message_prompt,  callback,  auto_publish,  actor_id);
		}
	}
	
	FBUI.prototype.askPublishStream = function(o){
		var attachment = {'name':o.title,
							'href':o.targetURL,
							'caption': '',
							'description': o.description,
							'media': [{'type':'image','src':o.img,'href':o.imgURL}]};
		var action_links = [{"text": "View More Deals!", "href": o.actionURL}];
		var target_id = null;
		var user_message_prompt = null;
		var callback = o.callback;
		var auto_publish = true;
		var actor_id = null;
		Facebook.streamPublish('',  attachment,  action_links, target_id, user_message_prompt,  callback,  auto_publish,  actor_id);
	}
	
	FBUI.prototype.showPermissionDialog = function(o){
		if(!o.permission){
			o.permission = "offline_access";
		}
		
		Facebook.showPermissionDialog(o.permission, function(perms) {
			   if (!perms) {
					if(o.onPermissionDenied){
						o.onPermissionDenied();
					}
			   } else {
					if(o.onPermissionGranted){
						o.onPermissionGranted();
					}
			   }
		 });
	}
	
	FBUI.prototype.userFriendsLoop = function(o) {
	}
}

function SplashPage(){
	this.userAnsweredYes = true;
	
	SplashPage.prototype.selectYes = function(){
		fbui.askPublishStream({
							  img:deal.small_img,
							  title:(deal.title?("I like this deal: "+deal.title):"I like this deal"),
							  description:(deal.deal_summary?deal.deal_summary:""),
							  targetURL:(appURL+"?traffic_source_id=10"),
							  imgURL:(appURL+"?traffic_source_id=11"),
							  actionURL:(appURL+"?traffic_source_id=12"),
							  callback:splashPage.goToDealPage
							  });
		
	}
	
	SplashPage.prototype.selectNo = function(){
		fbui.askPublishStream({
							  img:(deal.small_img?deal.small_img:logoCondense),
							  title:(deal.title?("I like this deal: "+deal.title):"I like this deal"),
							  description:(deal.deal_summary?deal.deal_summary:""),
							  targetURL:(appURL+"?traffic_source_id=20"),
							  imgURL:(appURL+"?traffic_source_id=21"),
							  actionURL:(appURL+"?traffic_source_id=22"),
							  callback:splashPage.goToInvitePage
							  });
		
	}
		
	SplashPage.prototype.goToDealPage = function(){
		document.setLocation(appURL+"?"+PAGE_VAR+"=deal"+(deal.campaign_id?("&campagin_id="+deal.campaign_id):"")+(cityId?("&c="+cityId):""));
	}
	
	SplashPage.prototype.goToInvitePage = function(){
		document.setLocation(appURL+"?"+PAGE_VAR+"=invite"+(deal.campaign_id?("&campagin_id="+deal.campaign_id):"")+(cityId?("&c="+cityId):""));
	}
	
	SplashPage.prototype.test = function(){
		Facebook.requireSession(splashPage.test2,splashPage.test2,true);
	}
	
	SplashPage.prototype.test2 = function(){
		X.d('v');
	}
}

function DealPage(){
	
	DealPage.prototype.targetURL = null;
	
	DealPage.prototype.loadPopup = function(){
		fbui.askPublishStream({
							  img:deal.small_img,
							  title:(deal.title?("I like this deal: "+deal.title):"I like this deal"),
							  description:(deal.deal_summary?deal.deal_summary:""),
							  targetURL:(appURL+"?traffic_source_id=10"),
							  imgURL:(appURL+"?traffic_source_id=11"),
							  actionURL:(appURL+"?traffic_source_id=12"),
							  callback:dealPage.donePublishStreamForAutoPopup
							  });
	}
	
	DealPage.prototype.donePublishStreamForAutoPopup = function(post_id, exception,data) {
		if (post_id) {
			//post the fb_stream_id to cd_fb_feed
			//<?=CHERRY_FB_URL?>core.php?module=facebook&coreName=CmdCore&writer=JSONCmdWriter&coreClass=FacebookCmd&fbid=<?=$fb_user?>&ids=<?=$invited_fbid_string?>&channel=stream
		}
	}
	
	DealPage.prototype.selectBuy = function(targetURL){
		
		dealPage.targetURL = targetURL;
		fbui.showPermissionDialog({
								  permission:"publish_stream",
								  onPermissionGranted:dealPage.donePublishStreamForBuy,
								  onPermissionDenied:dealPage.donePublishStreamForBuy
								  });
		
	}


	DealPage.prototype.donePublishStreamForBuy = function(post_id, exception,data){
		fbui.showPermissionDialog({
								  permission:"offline_access",
								  onPermissionGranted:dealPage.goToBuyDealPage,
								  onPermissionDenied:dealPage.goToBuyDealPage
								  });
	}
	
	DealPage.prototype.goToBuyDealPage = function(){
		if(dealPage.targetURL){
			document.setLocation(dealPage.targetURL);
		}else{
			document.setLocation(appURL+"?"+PAGE_VAR+"=buyDeal");
		}
	}
	
	DealPage.prototype.skipToBuyDealPage = function(targetURL){
		dealPage.targetURL = targetURL;
		if(dealPage.targetURL){
			document.setLocation(dealPage.targetURL);
		}else{
			document.setLocation(appURL+"?"+PAGE_VAR+"=buyDeal");
		}
	}
	
	//////
	
	DealPage.prototype.selectShare = function(){
		
/*	var api_key = '02adb065ed547542932f15499a801e09'; 
    var channel_path = '../xd_receiver.htm'; 
	FB_RequireFeatures(["CanvasUtil","Api","Integration"], function(){ 
	FB.Facebook.init(api_key, channel_path); 
	var api = FB.Facebook.apiClient; 
	api.requireLogin(function(exception){ 
	Debug.dump("Current session is " + api.get_session()); 
	api.users_getInfo ([api.get_session().uid],["locale"],function(result, exception){
	Debug.dump("Current session after polling the fb database is " + api.get_session()); 
	});
	}); 
	}); 	*/
		
		fbui.showPermissionDialog({
								  permission:"publish_stream",
								  onPermissionGranted:dealPage.doneLoopTroughFriends,
								  onPermissionDenied:dealPage.doneLoopTroughFriends
								  });
		
	}
	
	DealPage.prototype.doneLoopTroughFriends = function() {
		/*fbui.userFriendsLoop({
							 accessLevel:"allow"
							});*/
		dealPage.donePublishStreamForShare();					
	}

	DealPage.prototype.donePublishStreamForShare = function(post_id, exception,data){
		fbui.showPermissionDialog({
								  permission:"offline_access",
								  //onPermissionGranted:dealPage.goToBuyDealPage,
								  //onPermissionDenied:dealPage.goToBuyDealPage
								  onPermissionGranted:dealPage.goToInvitePage,
								  onPermissionDenied:dealPage.goToInvitePage
								  });
	}

	DealPage.prototype.goToBuyDealPage = function(){
		if(dealPage.targetURL){
			document.setLocation(dealPage.targetURL);
		}else{
			document.setLocation(appURL+"?"+PAGE_VAR+"=buyDeal"+(deal.campaign_id?("&campagin_id="+deal.campaign_id):"")+"&"+qryString);
		}
	}
	DealPage.prototype.goToInvitePage = function(){
		document.setLocation(appURL+"?"+PAGE_VAR+"=invite");
	}
}

function BuyDealStatusPage(){
	BuyDealStatusPage.prototype.selectShare = function(){
		fbui.askPublishStream({
							  img:(deal.small_img?deal.small_img:logoCondense),
							  title:"I just got a great deal on Cherry Deals!",
							  description:(deal.deal_summary?deal.deal_summary:""),
							  targetURL:(appURL+"?traffic_source_id=40"),
							  imgURL:(appURL+"?traffic_source_id=41"),
							  actionURL:(appURL+"?traffic_source_id=42")
							  });
		
	}
}

function ValidateForm() {
	ValidateForm.prototype.validateEmail = function(o) {
		var formParams = {
			formname: o.formname,
			emailFieldId: o.emailid,
			emailTextValue: o.emailtext
		};
	}
}
