jQuery.support.cors = true;
appdb.FindNS = function(nsname,create){
    create = create || false;
    var ns = window, i, nslen, nsitem=null;
    nsname = nsname.split(".");
    nslen = nsname.length;
    for(i=0; i<nslen; i+=1){
        nsitem = ns[nsname[i]];
        if(typeof nsitem === "undefined"){
            if(create===false){
                return null;
            }
            ns[nsname[i]] = function(){};
            nsitem = ns[nsname[i]];
        }
        ns = nsitem;
    }
    return ns;
};
appdb.DefineClass= function(name,obj,statics){
  var f = appdb.FindNS(name,true);
  f = function(){
      this._type_ = new appdb.Reflection({typename:name,base :null});
      obj.apply(this,arguments);
  }
  f.prototype.constructor = f;
  if(statics){
      for(var i in statics){
          f[i] = statics[i];
      }
  }
  return f;
};
appdb.Reflection = function(o){
    var name = o.typename || "", base = o.basetype || null;
    this.getName = function(){
        return name;
    };
    this.getBase = function(){
        return base;
    };
};
appdb.ExtendClass = function(base,name,obj,statics){
  var  basetype = (typeof base === "string")?appdb.FindNS(base, false):base;
  name = ''+name || "";
  if(basetype === null){
      alert("Could not extend object."+base+" not found");
      return null;
  }
  f = appdb.FindNS(name, true);
  var f = function(){
      base.apply(this,arguments);
      this._type_ = new appdb.Reflection({typename:name,basetype :this._type_});
      obj.apply(this,arguments);
      
  };
  f.prototype = base.prototype;
  f.prototype._super = base;
  f.prototype.constructor = f;
  statics = statics || {};
  for(var i in statics){
      f[i] = statics[i];
  }
  return f;
};
appdb.InheritView = function(target){
  if(target){
    var obj = new appdb.views.View(target), i;
    for(i in obj){
        target[i] = obj[i];
    }
  }
};
appdb.InheritTemplate = function(target,options){
  if(target){
    var obj = new appdb.Template(options), i;
    for(i in obj){
        target[i] = obj[i];
    }
  }
}
appdb.utils = {};

appdb.utils.convert = (function(){
    var _localName = ($.browser.msie )?"baseName":"localName",_text = ($.browser.msie )?"text":"textContent";
    var _removeWhitespace = function(xml){
        var node = xml.documentElement,i;
        var whitespace = /^\s+$/;
        for (i=0; i < node.childNodes.length; i++){
            var current = node.childNodes[i];
            if (current.nodeType == 3 && whitespace.test(current.nodeValue)) {
                // that is, if it's a whitespace text node
                node.removeChild(current);
                i--;
            }
        }
        return xml;
    };
    var _toObject = function(o){
        if($.isXMLDoc(o)===false){
            o = $.parseXML(o);
        }
        return _objectify(o.documentElement || o);
    };
    var _objectify = function(el){
       var e = {}, attr = [],cn = [],tmpval = null,at=null,alen = 0,clen=0,i,c,ln;
       if(el.nodeType===3){//Text Node
           return el.nodeValue;
       }
       attr = el.attributes;
       alen = attr.length;
       for(i=0; i<alen; i+=1){
            at = attr[i];
            if(at.prefix==='xmlns'){
                continue;
            }
            e[at[_localName]] = at.value;
       }
       cn = el.childNodes;
       clen = cn.length;
       for(i=0; i<clen; i+=1){
           c = cn[i];
           ln = c[_localName];
           if(c.nodeType===1){
               if(c.childNodes.length===1 && c.childNodes[0].nodeType===3){
                  if(c.attributes.length===0 || (c.attributes.length===1 && c.attributes[0].prefix=='xmlns')){
                    e[ln] = c.childNodes[0][_text];
                    continue;
                  }
               }
               if(e[ln]){
                   if((e[ln] instanceof Array)===false){
                       tmpval = e[ln];
                       e[ln] = [];
                       e[ln].push(tmpval);
                   }
                   e[ln].push(_objectify(c));
               }else{
                   e[ln] = _objectify(c);
               }
            }
           if(c.nodeType===3){//Text Content
               ln = el[_localName];
               if(el.attributes.length>0 && ((el.attributes.length===1 && el.attributes[0].prefix=='xmlns' )===false)){
                   tmpval = c[_text];
                   e["val"] = function(){return tmpval;};
               }else{
                if(e[ln]){
                    if(e[ln] instanceof Array===false){
                        tmpval = e[ln];
                        e[ln] = [];
                        e[ln].push(tmpval);
                    }
                    e[ln].push(c[_text]);
                }else{
                    e[ln] = c[_text];
                }
               }
           }           
       }
       if($.isEmptyObject(e)){
           return '';
       }
       return e;
    };
    return {
        toObject : _toObject
    }
})();

appdb.utils.base64 = (function(){
    return new function(){
        var ua = navigator.userAgent.toLowerCase(), StringMaker, keyStr;
        if (ua.indexOf(" chrome/") >= 0 || ua.indexOf(" firefox/") >= 0 || ua.indexOf(' gecko/') >= 0) {
            StringMaker = function () {
                this.str = "";
                this.length = 0;
                this.append = function (s) {
                        this.str += s;
                        this.length += s.length;
                };
                this.prepend = function (s) {
                        this.str = s + this.str;
                        this.length += s.length;
                };
                this.toString = function () {
                        return this.str;
                };
            };
        } else {
            StringMaker = function () {
                this.parts = [];
                this.length = 0;
                this.append = function (s) {
                        this.parts.push(s);
                        this.length += s.length;
                };
                this.prepend = function (s) {
                        this.parts.unshift(s);
                        this.length += s.length;
                };
                this.toString = function () {
                        return this.parts.join('');
                };
            };
        }
        keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
        this.encode = function(input) {
            var output = new StringMaker(), chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;
            while (i < input.length) {
                chr1 = input.charCodeAt(i++);
                chr2 = input.charCodeAt(i++);
                chr3 = input.charCodeAt(i++);
                enc1 = chr1 >> 2;
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                enc4 = chr3 & 63;
                if (isNaN(chr2)) {
                    enc3 = enc4 = 64;
                }else if (isNaN(chr3)) {
                    enc4 = 64;
                }
                output.append(keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4));
           }
           return output.toString();
        };
        this.decode64 = function(input) {
            var output = new StringMaker(), chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0;
            // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

            while (i < input.length) {
                enc1 = keyStr.indexOf(input.charAt(i++));
                enc2 = keyStr.indexOf(input.charAt(i++));
                enc3 = keyStr.indexOf(input.charAt(i++));
                enc4 = keyStr.indexOf(input.charAt(i++));
                chr1 = (enc1 << 2) | (enc2 >> 4);
                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                chr3 = ((enc3 & 3) << 6) | enc4;
                output.append(String.fromCharCode(chr1));
                if (enc3 != 64) {
                    output.append(String.fromCharCode(chr2));
                }
                if (enc4 != 64) {
                    output.append(String.fromCharCode(chr3));
                }
            }
            return output.toString();
        };
		this.decode = this.decode64;
};})();

appdb.utils.noFunc = function(){};

appdb.utils.identFunc = function(d){return d;};   

appdb.utils.rest  = function(options){
   var _options =  {
       action : 'GET',
       endpoint : '',
	   authorization : {
		   type : appdb.utils.rest.authorization.types.none,
		   mode : appdb.utils.rest.authorization.modes.never
	   },
           iscrossdomain : true
   };
   var _setupCallbacks = function(c){
        var res = {
            async:true,
            success : appdb.utils.noFunc,
            error : appdb.utils.noFunc
        };
        if(typeof c === 'undefined'){
            res.async = false;
        }else if($.isFunction(c)){
            res.success = c;
            res.error = c;
        }else if($.isPlainObject(c)){
            if(c.success){
                res.success = c.success;
            }
            if(c.error){
                res.error = c.error;
            }
        }
        return res;
   };
   var _setupData = function(p){
        var res = {query : {}, data : {}};
        res.query = ((p)?(p.query||p):{});
        res.data = ((p)?(p.data||{}):{});
        return res;
   };
   var _makeDataString = function(p){
        var res = "";
        for(var i in p){
            res += i + "=" +p[i] + "&";
        }
        return res.substring(0,res.length-1);
   };
   var _parseParams = function(p){
       var addr = _options.endpoint, unused = {}, i =0;
       //Check for unused data in url
       for(i in p){
		   if(i==="userid" || i==="passwd"){
			   continue;
		   }
            if(addr.indexOf("{"+i+"}")===-1){
                unused[i] = encodeURIComponent(p[i]);
            }
       }
       //Replace used data in url
       for(i in p){
           while(addr.indexOf("{"+i+"}")>-1){
                addr = addr.replace("{"+i+"}",encodeURIComponent(p[i]));
           }
       }
       //If url template has * then create query string
       //with the unused data and append to url
       if(addr.indexOf("{*}")!==-1){
           i = _makeDataString(unused);
           addr = addr.replace("{*}",i);
       }
	   return addr;
   };
   var _create = function(p,clbcks){
       return new function(){
           var ajx = {};
           var params = {};
           var res = null;
           var _init = function(){
                var c = _setupCallbacks(clbcks), d = _setupData(p);
                params = d;
                ajx.url = _parseParams(d.query);
                ajx.type = _options.action;
				ajx.dataType = "xml";//($.browser.msie) ? "text/plain" : "xml";
                if(ajx.type !== "GET" && ajx.type !== "DELETE"){
                    ajx.data = _makeDataString(d.data);
                }
                ajx.async = c.async;
                ajx.success = function(d,s,o){
                    res = appdb.utils.convert.toObject(d);
                    if(ajx.__timestart__){
                        res["__time_elapsed__"] = new Date().getTime() - ajx.__timestart__;
                        delete ajx.__timestart__;
                    }
                    c.success(res);
                };
                ajx.error = function(jqXHR, textStatus, errorThrown){
                    res = {status:textStatus,description:errorThrown};
                    if(ajx.__timestart__){
                        delete ajx.__timestart__;
                    }
                    c.error(res);
                };
                ajx.withCredentials = true;
           };
           var _reparse = function(p,a){
               var res = a;
                if(p.data){
                    p.data = $.extend(params.data,p.data);
                    res.data = _makeDataString(p.data);
                }
                if(p.query){
                    p.query = $.extend(params.query,p.query);
                    res.url = _parseParams(p.query);
                }
                return res;
           };
           var _call = function(p){
               var a = ajx;
                res = null;
                if(typeof p !== "undefined"){
                    a = _reparse(p,ajx);
                }
                a.__timestart__ = new Date().getTime();
				if(_options.authorization.mode.canUseAuthorization()){
					ajx = _options.authorization.type.setCredentials(ajx);
				}
                if($.browser.msie && emulateIE8==false && _options.iscrossdomain===true){
                    var xhr = new XDomainRequest();
                    xhr.onload = function() {
                        a.success(xhr.responseText);
                    };
                    xhr.onerror = function(){
                        a.error(xhr,"Error","An error occured on cross domain request");
                    };
                    xhr.open(a.type,a.url);
                    res=xhr.send();
                }else{
                    res = $.ajax(a);
                    res = (a.async)?null:appdb.utils.convert.toObject(res.responseXML);
                }
                return res;
           };
           var _getQuery = function(){
                return p.query;
           };
           var _getData = function(){
                return p.data;
           };
           _init();
           return {
               call:_call,
               getQuery : _getQuery,
               getData : _getData
            };
       };
   };
   var _init = function(o){
       _options =$.extend(_options,o);
   };
   _init(options);
   return {
       create : _create
   }
};

appdb.utils.rest.authorization = {
	types : {
		none : {
			setCredentials : function(o){
				return o;
			}
		},
		query : {
			setCredentials : function(o){
				var u = o.url;
                                if(u.indexOf("userid="+userID+"&passwd="+$.cookie("cookpass"))>=0){
                                    return o;
                                }
				//append credentials
				if(u.indexOf("?")<0){
					u+="?";
				}else{
					u+="&";
				}
				u += "userid="+userID+"&passwd="+$.cookie("cookpass");
				if(u.substr(0,5)==="http:"){
					u = "https" + u.substr(4,u.length);
				}
				o.url = u;
				return o;
			}
		}
	},
	modes : {
		never : {
			canUseAuthorization : function(o){
				return false;
			}
		},
		always : {
			canUseAuthorization : function(o){
				return true;
			}
		},
		authonly : {
			canUseAuthorization : function(o){
				return (userID!==null && $.cookie && $.cookie("cookpass")!==null);
			}
		}
	}
};

appdb.utils.LocalDataStore = function(options){
     var _options =  {
       localData : []
   };
   var _setupCallbacks = function(c){
        var res = {
            async:true,
            success : appdb.utils.noFunc,
            error : appdb.utils.noFunc
        };
        if(typeof c === 'undefined'){
            res.async = false;
        }else if($.isFunction(c)){
            res.success = c;
            res.error = c;
        }else if($.isPlainObject(c)){
            if(c.success){
                res.success = c.success;
            }
            if(c.error){
                res.error = c.error;
            }
        }
        return res;
   };
   var _setupData = function(p){
        var res = {query : {}, data : {}};
        res.query = ((p)?(p.query||p):{});
        res.data = ((p)?(p.data||{}):{});
        return res;
   };
   var _makeDataString = function(p){
        var res = "";
        for(var i in p){
            res += i + "=" +p[i] + "&";
        }
        return res.substring(0,res.length-1);
   };
   var _parseParams = function(p){
       var addr = _options.endpoint, unused = {}, i =0;
       if(typeof addr === "undefined"){
           return "";
       }
       //Check for unused data in url
       for(i in p){
            if(addr.indexOf("{"+i+"}")===-1){
                unused[i] = p[i];
            }
       }
       //Replace used data in url
       for(i in p){
           while(addr.indexOf("{"+i+"}")>-1){
                addr = addr.replace("{"+i+"}",p[i]);
           }
       }
       //If url template has * then create query string
       //with the unused data and append to url
       if(addr.indexOf("{*}")!==-1){
           i = _makeDataString(unused);
           addr = addr.replace("{*}",i);
       }
       return addr;
   };
   var _create = function(p,clbcks){
       return new function(){
           var ajx = {};
           var params = {};
           var res = null;
           var _init = function(){
                var c = _setupCallbacks(clbcks), d = _setupData(p);
                params = d;
                ajx.url = _parseParams(d.query);
                ajx.type = _options.action;
                if(ajx.type !== "GET" && ajx.type !== "DELETE"){
                    ajx.data = _makeDataString(d.data);
                }
                ajx.async = c.async;
                ajx.success = function(d,s,o){
                    res = appdb.utils.convert.toObject(d);
                    if(ajx.__timestart__){
                        res["__time_elapsed__"] = new Date().getTime() - ajx.__timestart__;
                        delete ajx.__timestart__;
                    }
                    c.success(res);
                };
                ajx.error = function(jqXHR, textStatus, errorThrown){
                    res = {status:textStatus,description:errorThrown};
                    if(ajx.__timestart__){
                        res["__time_elapsed__"] = new Date().getTime() - ajx.__timestart__;
                        delete ajx.__timestart__;
                    }
                    c.error(res);
                };
                ajx.crossDomain = true;
                ajx.xhrFields= {withCredentials: true};
                ajx.xhr = function(){
                    var xhr = new XMLHttpRequest();
                    if ("withCredentials" in xhr){
                        return xhr;
                    } else if (typeof XDomainRequest != "undefined"){
                        xhr = new XDomainRequest();
                        xhr.onload = function() {
                          ajx.success(xhr.responseText);
                        };
                        xhr.onerror = function(){
                            ajx.error(xhr,"Error","An error occured on cross domain request");
                        };
                        return xhr;
                    }
                    return xhr;
                };
           };
           var _reparse = function(p,a){
               var res = a;
                if(p.data){
                    p.data = $.extend(params.data,p.data);
                    res.data = _makeDataString(p.data);
                }
                if(p.query){
                    p.query = $.extend(params.query,p.query);
                    res.url = _parseParams(p.query);
                }
                return res;
           };
           var _call = function(p){
               var a = ajx;
                res = null;
                if(typeof p !== "undefined"){
                    a = _reparse(p,ajx);
                }
                a.__timestart__ = new Date().getTime();
                res = _options.localData;//$.ajax(a);
                if(a.async){
                    a.success(res);
                }
                return res;
           };
           var _getQuery = function(){
                return p.query;
           };
           var _getData = function(){
                return p.data;
           };
           _init();
           return {
               call:_call,
               getQuery : _getQuery,
               getData : _getData
            };
       };
   };
   var _init = function(o){
       _options =$.extend(_options,o);
   };
   _init(options);
   return {
       create : _create
   }
};

appdb.utils.ObserverMediator = function(p){
    var events = {}, _batch = [], _storeEvents = false, _parent = p || null;this.getRaw = function(){return events;};
    this.subscribe = function(o){
        o.caller = o.caller || _parent;
        events = events || {};
        events[o.event] = events[o.event] || [];
        events[o.event].push({callback:o.callback,caller : o.caller});
        return p;
    };
    this.unsubscribe = function(o){
        var i,e = events[o.event] || [],len = e.length;
        o.caller = o.caller || _parent;
        for(i=0; i<len; i+=1){
            if(e[i].caller){
                if(e[i].caller===o.caller){
                    events[o.event].splice(i,1);
                    break;
                }
            }
        }
        return p;
    };
    this.unsubscribeAll = function(clr){
        var i, e = events ;
        clr = clr || _parent;
        for(i in e){
           this.unsubscribe({event: i,caller : clr});
        }
        return p;
    };
    this.publish = function(o){
        if(_storeEvents){
            _batch[_batch.lengh] = o;
        }
        var i , clbcks = ((o.event && events[o.event])?events[o.event]:[]), args = o.value,len = clbcks.length,caller;
        if(clbcks){
           for(i=0; i<len; i+=1){
               caller = clbcks[i].caller || _parent;
               clbcks[i].callback.apply(caller,[args]);
           }
        }
    };
    this.clearAll = function(){
        events = {};
        return p;
    };
    this.suspend = function(storeEvents){
        _storeEvents = storeEvents || false;
    };
    this.resume = function(publishEvents){
        publishEvents = publishEvents || false;
        if(publishEvents===false){
            _batch = [];
        }
        for(var i =0; i<_batch.length; i+=1){
            _publish(_batch[i]);
        }
    };
};

appdb.utils.Pager = function(opts){
    opts = opts || {};
    var _mediator = new appdb.utils.ObserverMediator();
    var _data = null;
    var o = {
        length : (1+(1*optQueryLen)) || 10,
        offset : 0,
        count : -1,
        model : opts.model,
        lengthProperty : 'pagelength',
        offsetProperty : 'pageoffset',
        countProperty : 'count'
    };
    this.next = function(){
        var pn = this.pageNumber();
        if(pn<this.pageCount()-1){
            this.current(pn+1);
        }
    };
    this.hasNext = function(){
        var pn = this.pageNumber();
        if(pn<this.pageCount()-1){
            return true;
        }
        return false;
    };
    this.previous = function(){
         var pn = this.pageNumber();
        if(pn>0){
            this.current(pn-1);
        }
    };
    this.current = function(n){
        var pn = 0;
        if(typeof n !== "undefined"){
            _gotoPage(n);
            return this;
        }
        pn = this.pageNumber();
        if(pn<1){
            _gotoPage(0);
            return this;
        }else {
            _gotoPage(this.pageNumber());
            return this;
        }
        //return _data;
    };
    this.count = function(n){
        return opts.count;
    };
    this.length = function(n){
        if(n){
            opts.length = n;
            return this;
        }
        return opts.length;
    };
    this.offset = function(n){
        if(n){
            opts.offset = n;
            return this;
        }
        return opts.offset;
    };
    this.getCurrentPagingState = function(){
       return {length : o.length,offset:o.offset,count:o.count,pagenumber : this.pageNumber(),pagecount : this.pageCount(),hasnext: this.hasNext};
    };
    this.pageNumber = function(){
        if(o.count==0){
            return 0;
        }
        return Math.floor(o.offset/(o.length));
    };
    this.pageCount = function(){
        return Math.ceil((o.count)/(o.length));
    };
    var _onSelect = function(d){
        _data = d;
        if(typeof _data.error === "string"){
            _mediator.publish({event : 'error' , value : _data});
            return;
        }
        o.length = 1*(d[o.lengthProperty]);
        o.offset = 1*d[o.offsetProperty];
        o.count = 1*d[o.countProperty];

        var ev = {
            pager : {
                length : 0+o.length,
                offset : 0+o.offset,
                count : 0+o.count,
                pageNumber : 0+this.pageNumber(),
                pageCount : 0+this.pageCount(),
                hasNext : this.hasNext()
            },
            data : null
        };
        ev.elapsed = _data.__time_elapsed__ || -1;
        if(o.modelProperty){
		   var props = [];
		   if(o.modelProperty.indexOf(".")>-1){
			   props = o.modelProperty.split(".");
		   }else{
			   props = [o.modelProperty];
		   }
		   var datares = _data[props[0]];
		   for(var i=1; i<props.length; i+=1){
			 if($.isArray(datares)===true){
				 for(var j=0; j<datares.length; j+=1){
					datares[j]= datares[j][props[i]];
				 }
			 }else{
				 datares = datares[props[i]];
			 }
		   }
		   ev.data = datares;

           //ev.data= _data[o.modelProperty];
           if(typeof ev.data === "undefined"){
               ev.data = [];
           }
        }else{
            ev.data = _data;
        }
        _mediator.publish({event : 'pageload', value : ev});
    };
    var _onError = function(d){
        _mediator.publish({event : 'error' , value : d});
    }
    var _gotoPage = function(n){
        _calcPageOffset(n);
        o.model.get(_buildPageQuery(o.length,o.offset));
    };
    var _calcPageOffset = function(n){
        n = parseInt(n);
      o.offset=(n*(o.length));
    };
    var _buildPageQuery = function(len,ofs){
        var res = {};
        res[o.lengthProperty] = len;
        res[o.offsetProperty] = ofs;
        return res;
    };
    this.subscribe = function(e){
        _mediator.subscribe(e);
        return this;
    };
    this.unsubscribe = function(e){
       _mediator.unsubscribe(e);
       return this;
    };
    this.unsubscribeAll = function(e){
        _mediator.unsubscribeAll(e);
        return this;
    };
    this.destroy = function(){
        o.model.unsubscribeAll(this)
        _mediator.clearAll();
    };
    var _init = function(){
       o = $.extend(o,opts);
    };
    _init();
    o.model.subscribe({event : 'select',callback: _onSelect,caller : this}).subscribe({event : 'error',callback:_onError,caller : this});
};

appdb.utils.animateList = function(){
    if ( $.browser.msie === false ) {
        if ($("#viewtype")[0] !== undefined) {
            if ($("#viewtype")[0].value == "app" ) list = dojo.query("#appmainlist li");
            if ($("#viewtype")[0].value == "ppl" ) list = dojo.query("#pplmainlist li");
            if ($("#viewtype")[0].value == "vo" ) list = dojo.query("#vomainlist li");
            if ($("#viewtype")[0].value == "ngi" ) list = dojo.query("#ngimainlist li");
        }
        if ( list != null ) {
            var props = {
                i: {width:96, height:96, top:-16, left:-102},
                o: {width:64, height:64, top:0, left:-80}
            };
            list.forEach(function(n){
                var img = dojo.query("img", n)[0], a;
                dojo.connect(n, "onmouseenter", function(e){
                        a && a.stop();
                        a = dojo.anim(img, props.i, 175)
                });
                dojo.connect(n, "onmouseleave", function(e){
                        a && a.stop();
                        a = dojo.anim(img, props.o, 175, null, null, 75)
                });
            });
        }
    }
};
/*
 * Change the ISO Date format YYYY-MM-DD to DD-m-YYYY
 */
appdb.utils.FormatISODate = function(dt){
	if(typeof dt !== "string"){
		return dt;
	}
	var d = dt.split("-"), months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"], time='';
	if(d.length<3){
		return dt;
	}
	if(d[2].indexOf(" ")>-1){
		var tmp = d[2].split(" ");
		d[2] = tmp[0];
		time = tmp[1];
	}
	if(d[1][0]==="0"){
		d[1] = d[1].slice(1,2);
	}
	var res = d[2] + "-" + months[parseInt(d[1])-1] + "-" + d[0] + ((time!='')?" "+time:"");
	return res;
};

appdb.utils.ToggleFaq = function(anchor){
	if(typeof anchor === "number"){
		ajaxLoad("/help/faq","main","toggleFAQ($('#faq"+anchor+"'));");
	}else{
		ajaxLoad("/help/faq","main");
	}
}
/*
 * Executes a function when loading is finished. Loading is determined by a provided function.
 * parameters:
 * f : function to execute once loading is complete. If no function given, exits.
 * ext : object with extended parameters.
 * ext.caller : the object that made the call. It is passed in the provided function as 'this'. Default: null
 * ext.args : array of arguments for the executed method. Default: empty array
 * ext.checker : function to check whether the loading is complete. Return true on load, false otherwise. DEfault : no checking
 * ext.time : time interval to run checker. Default: 1000ms
 * ext.id : Unique id for the type of request. If given it will cancel any following requests with the same id until it completes
 * ext.count : Maximum time of checks before exiting. Default : 20
 */
appdb.utils.ExecuteOnLoad = function(f,ext){
	var o = ext || {};
	if($.isFunction(f) == false){
		return;
	}
	if(typeof o.caller !== "object"){
		o.caller = null;
	}
	if(typeof o.args !== "undefined"){
		if($.isArray(o.args) == false){
			o.args = [o.args];
		}
	}else{
		o.args = [];
	}
	if(typeof o.time === "string"){
		o.time = parseInt(o.time);
	}
	if(typeof o.time !== "number"){
		o.time = 1000;
	}
	if(typeof o.count === "string"){
		o.count = parseInt(o.count);
	}
	if(typeof o.count !== "number"){
		o.count = 20;
	}
	if($.isFunction(o.checker) == false ){
		o.checker = function(){return true;};
	}
	if(typeof o.id !== "undefined"){ //check if another request of the same type is running
		appdb.utils.ExecuteOnLoad.States =  appdb.utils.ExecuteOnLoad.States || {};
		if(appdb.utils.ExecuteOnLoad.States[o.id]){
			return;
		}
		appdb.utils.ExecuteOnLoad.States[o.id] = true;
	}
	var exec_callback = function(){};
	exec_callback = (function(caller,obj){
		return function(){
			if(obj.checker.apply(obj.caller)){//if content is loaded execute callback function
				setTimeout(function(){caller.apply(obj.caller,obj.args);},1);
				if(obj.id && appdb.utils.ExecuteOnLoad.States[obj.id]){ // if id is given, clear running flag for others to make requests.
					appdb.utils.ExecuteOnLoad.States[obj.id] = false;
					delete appdb.utils.ExecuteOnLoad.States[obj.id];
				}
			}else{
				if(obj.count===0){//if exceeded time of tries exit;
					return;
				}
				obj.count-=1;
				setTimeout(exec_callback,obj.time);
			}
		};
	})(f,o);
	setTimeout(exec_callback,o.time);//initial call
};
/*
 * Groups an object list according to value of the given property 'p'
 * for each object contained in the given list 'a'. If an object don't have
 * the property, it won't be included in return object.
 */
appdb.utils.GroupObjectList= function(a,p){
	if(typeof p !== "string"){
		return null;
	}
	if($.isArray(a)===false){
		return null;
	}
	var i, len = a.length,res = {};
	for(i=0; i<len; i+=1){
		if(a[i] && typeof a[i][p] === "string"){
			res[a[i][p]] = res[a[i][p]] || [];
			res[a[i][p]][res[a[i][p]].length] = a[i];
		}
	}
	return res;
};

/*
 *Creates and returns an array handler of unique objects.
 *Options object schema:
 *data : [Array] Optional. An array of objects.Defaults to an empty array.
 *property : [String] Optional. The property which identifies the uniqness of
 *					  each object in the array. Defaults to 'id'.
 */
appdb.utils.UniqueDataList = function(o){
	this._constructor = function(){
		o = o || {};
		var items = (o.data || []), p = (o.property || "id");
		var _add = function(e){
				if(_indexOf(e)<0){
					items[items.length] = e;
				}
		},
		_remove = function(e){
			var index = _indexOf(e);
			if(index>-1){
				items.splice(index,1);
			}
		},
		_indexOf = function(e){
			for(var i =0; i<items.length; i+=1){
				if(items[i][p] == e[p]){
					return i;
				}
			}
			return -1;
		},
		_get = function(){
			return items;
		};
		_clear  = function(){
			items = [];
		};
		return {
			add : _add,
			remove : _remove,
			get : _get,
			clear : _clear,
			has : function(e){return (_indexOf(e)>-1)?true:false;}
		};
	};
	return this._constructor();
};
/*
 *Appdb priveleges wrapper object. It provides a set of function to check
 *if a user has permissions. The options object is the 'action' object provided
 *by the server json response.5
 */
appdb.utils.Privileges = function(o){
	this._privs = [];
	this._constructor = function(){
		o = o || {};
		if($.isArray(o)){
			this._privs = o;
		}
		if(o.action){
			if($.isArray(o.action)){
				this._privs = o.action;
			}
		}
	};
	this.getPrivilegeById = function(id){
		if((typeof id === "string" || typeof id ==="number")==false) return false;
		if($.isArray(this._privs)==false) return false;
		var i, p = this._privs, len = p.length;
		for(i=0; i<len; i+=1){
			if(p[i].id==id){
				return true;
			}
		}
		return false;
	};
	this.canGrantPrivilege = function(){return this.getPrivilegeById(1);};
	this.canRevokePrivilege = function(){return this.getPrivilegeById(2);};
	this.canInsertApplication = function(){return this.getPrivilegeById(3);};
	this.canDeleteApplication = function(){return this.getPrivilegeById(4);};
	this.canChangeApplicationName = function(){return this.getPrivilegeById(5);};
	this.canChangeApplicationDescription = function(){return this.getPrivilegeById(6);};
	this.canChangeApplicationAbstract = function(){return this.getPrivilegeById(7);};
	this.canChangeApplicationLogo = function(){return this.getPrivilegeById(8);};
	this.canChangeApplicationStatus = function(){return this.getPrivilegeById(9);};
	this.canChangeApplicationDiscipline = function(){return this.getPrivilegeById(10);};
	this.canChangeApplicationSubdiscipline = function(){return this.getPrivilegeById(11);};
	this.canChangeApplicationCountry = function(){return this.getPrivilegeById(12);};
	this.canChangeApplicationVO = function(){return this.getPrivilegeById(13);};
	this.canChangeApplicationURLs = function(){return this.getPrivilegeById(14);};
	this.canChangeApplicationDocuments = function(){return this.getPrivilegeById(15);};
	this.canAssociatePersonToApplication = function(){return this.getPrivilegeById(16);};
	this.canDisassociatePersonFromApplication = function(){return this.getPrivilegeById(17);};
	this.canChangePersonPositionType = function(){return this.getPrivilegeById(18);};
	this.canMarkToolAsRESPECTed = function(){return this.getPrivilegeById(19);};
	this.canChangeApplicationMiddleware = function(){return this.getPrivilegeById(20);};
	this.canEditUserProfile = function(){return this.getPrivilegeById(21);};
	this.canBulkReadSensitiveData = function(){return this.getPrivilegeById(22);};
	this.canGrantOwnership = function(){return this.getPrivilegeById(23);};
	this.canChangeApplicationsTags = function(){return this.getPrivilegeById(24);};
	this._constructor();
};
/*
 *Sorts a list of objects based on a given property.
 *If no property name is given it returns the list as is.
 *If no list or argument object is given it returns an empty array.
 *Parameters of argument object are:
 *list [array]: the array to be sorted. If object is given it returns an array contianing only that object.
 *property [string] : The name of the property of the list to be sorted by.
 *orderAsc [boolean] : Default is true. If false it sorts the list in a desceding fashion.
 */
appdb.utils.SortObjectList = function(o){
 var opt = o || {}, func = null, list = [], getter;
 if(typeof o.list === "undefined") {
  return [];
 }
 if(typeof o.orderAsc === "string"){
  o.orderAsc = (o.orderAsc.toLowerCase()==="true")?true:false;
 }else if(typeof o.orderAsc !== "boolean"){
  o.orderAsc = true;
 }

 if($.isArray(o.list) == false){
  o.list = [o.list];
 }
 if(typeof o.property !== "string"){
  return o.list;
 }
 list = list.concat(o.list);

 if(o.orderAsc === true){
  func = function(a,b){
   var na = getter(a).toLowerCase(), nb = getter(b).toLowerCase();
   if ( na < nb ) return -1;
   if ( na > nb ) return 1;
   return 0;
  };
 }else{
  func = function(a,b){
   var na = getter(a).toLowerCase(), nb = getter(b).toLowerCase();
   if ( na < nb ) return 1;
   if ( na > nb ) return -1;
   return 0;
  };
 }
 getter = function(obj){
  if($.isFunction(obj[o.property]) === true){
   return obj[o.property]();
  }
  return obj[o.property];
 };
 return list.sort(func);
};

/*
 * Used by appdb.utils.DataWatcher as an item to watch for changes
 */
appdb.utils.DataWatcherItem = function(o){
	this.container = $("body");
	this.selector = undefined;
	this.state = [];
	this.currentState = [];
	this.type = "";
	this.name = "";
	this.connections = {dojo:[],jquery:[]};
	this.eventHandler = {onChange:function(){}, onReset:function(){}};
	/*
	 *Reloads the current state from the html input elements.
	 *Used by 'hasChanges' function.
	 */
	this.updateCurrentState = function(){
		if($.isFunction(this.selector)){
		 return;
		}
		var els = [], res = [];
		els = $(this.selector);
		var i, len = els.length;
		for(i=0; i<len; i+=1){
			if(dijit.byNode(els[i])){
				res[res.length] = dijit.byNode(els[i]).attr("value");
			}else{
				res[res.length] = $(els[i]).val();
			}
		}
		this.currentState = res;
	};
	/*
	 *Checks if the given value is the same in the initial state.
	 *Used by 'isStateChanged' function.
	 */
	this.inState = function(v){
		var i,st = this.state, len = st.length;
		for(i=0; i < len; i+=1) {
			if(st[i] == v) {
				return true;
			}
		}
		return false;
	};
	/*
	 *Checks for differences between the initial and the current state.
	 *Used by 'hasChanges' function.
	 */
	this.isStateChanged = function(){
		var i, st = this.currentState, len = st.length;
		if(len!==this.state.length){
			return true;
		}
		for(i=0; i<len; i+=1){
			if(this.inState(st[i])==false){
				return true;
			}
		}
		return false;
	};
	/*
	 *Checks if the watched element has changed its initial state.
	 *This function is also used by the 'hasChanges' function of the
	 *parent DataWatcher object.
	 */
	this.hasChanges = function(){
		this.updateCurrentState();
		return this.isStateChanged();
	};
	/*
	 *Stop the item from receiving events.
	 */
	this.stop = function(){
		this.unbindConnections();
		this.eventhandler = {onChange:function(){}, onReset:function(){}};
	};
	/*
	 *Unbinds 'onChange' events from dojo or html input elements,
	 *only if an html selector is given in the constructor options
	 */
	this.unbindConnections = function(){
	 var i;
	 for(i=0; i<this.connections.dojo.length; i+=1){
	  dojo.disconnect(this.connections.dojo[i].element);
	 }
	 this.connections.dojo = [];
	 for(i=0; i<this.connections.jquery.length; i+=1){
	  $(this.connections.jquery[i].element).unbind(this.connections.jquery[i].event,(this.connections.jquery[i].isHandler)?this.onListChangeDelegate:this.onChangeDelegate);
	 }
	 this.connections.jquery = [];
	};

	/*This function is called uppon onChange event occurs from an input html element.
	 *It won't be used at all if the selector is a function.
	*/
	this.onChangeDelegate = (function(_this){
	 return function(){
	  if(_this.hasChanges()){
	   _this.eventHandler.onChange({oldstate : _this.state, newstate: _this.currentState, extras : {type : _this.type, name : _this.name}});
	  }else{
	   _this.eventHandler.onReset({type : _this.type, name : _this.name});
	  }
	 };
	})(this);

	/*
	 * Binds the 'onChange' event of the html input elements or in case
	 * the 'selector' option is a function overrides the 'hasChanges' function
	 * with the 'selector' function.
	 */
	this.init = function(ev){
	 this.eventHandler = ev || {onChange : function(){}, onReset : function(){}};
	 
	 if($.isFunction(this.selector)){
	  this.hasChanges = this.selector;
	 }else{
	  var i, tst = $(this.selector);
	  if(tst.length>0){
		for(i=0; i<tst.length; i+=1){
		 if(dijit.byNode(tst[i])){
		   this.connections.dojo[this.connections.dojo.length] = {event : "onChange", element : dojo.connect(dijit.byNode(tst[i]),"onChange",this.onChangeDelegate)};
		 }else{
		  this.connections.jquery[this.connections.jquery.length] = {event : "change", element : tst[i]};
		  $(tst[i]).bind("change",this.onChangeDelegate);
		 }
		}
	  }
	 }
	};
	this.getExtras = function(){
	 return {type : this.type, name : this.name};
	};
	this._constructor = function(){
		if(typeof o.container === "string"){
			this.container = $(o.container);
		}else if (typeof o.container === "object"){
			this.container = o.container;
		}
		
		if(typeof o.selector !== "undefined"){
		 this.selector = o.selector;
		}
		
		if(typeof o.name === "string"){
		 this.name = o.name;
		}

		if(typeof o.type === "string"){
		 this.type = o.type;
		}
		
		this.updateCurrentState();
		this.state = this.currentState;

		return {
			start : (function(_this){return function(){_this.start();};})(this),
			stop : (function(_this){return function(){_this.stop();};})(this),
			hasChanges : (function(_this){return  function(){return _this.hasChanges();};})(this),
			getExtras :(function(_this){return  function(){return _this.getExtras();};})(this),
			getName : (function(_this){return  function(){return _this.name;};})(this),
			getType : (function(_this){return  function(){return _this.type;};})(this),
			init : (function(_this){return  function(ev){_this.init(ev);};})(this)
		};
	};
	return this._constructor();
};
/*
 *Holds the initial state of a collection of input elements and watches
 *for changes in their values. To check if changes occured it provides
 *the function 'hasChanges'. It options object schema is given bellow:
 *items : list of items to be watched
 *	selector : [String] The html einput element selector.
 *			   [Function] A function that returns 'true' if an element
 *						  has changes in its initial value.
 *	handlers : [Object] Used if the watched element behaves as a list and
 *						provides the selectors for the elements responsible for
 *						insertion or deletion of the items of the list.
 *			add	  : [String] The selector of the html element used for
 *							 inserting a new element to be watched.
 *			remove: [String] The selector of the html element used for
 *							 inserting a new element to be watched.
 *	type  : [String] The type of the element. Used for identification of item.
 *	name  : [String] The display name of the type of the element.
 */
appdb.utils.DataWatcher = function(o){
	this.items = [];
	this.canCheckType = function(){return true;};
	this.onReset = function(o){
	 //console.log("Reseted: " + o.name);
	};
	this.onChange = function(o){
		/*var msg  = "Change : " + o.extras.name + "\n";
		for(var i=0; i<o.oldstate.length; i+=1){
			msg += "\t" + o.oldstate[i]+" => " + o.newstate[i] + "\n";
		}
		console.log(msg);*/
	};
	this.initWatchers = function(){
		var i, w = this.items, len = w.length;
		for(i=0; i<len; i+=1){
			w[i].init({onChange:this.onChange, onReset:this.onReset});
		}
	};
	this.stopWatchers = function(){
		var i, w = this.items, len = w.length;
		for(i=0; i<len; i+=1){
		  w[i].stop();
		}
	};
	this.addWatchItem = function(item){
		if(item instanceof appdb.utils.DataWatcherItem ){
			this.items[this.items.length] = item;
		}else if(typeof item === "object"){
			this.items[this.items.length] = new appdb.utils.DataWatcherItem(item);
		}
	};
	this.start = function(){
		this.stop()
		this.initWatchers();
	};
	this.stop = function(){
		this.stopWatchers();
	};
	this.hasChanges = function(){
		var i, items = this.items, len = items.length;
		for(i=0; i<len; i+=1){
		  if(this.canCheckType(items[i].getType())){
		   if(items[i].hasChanges()){
			return true;
		   }
		  }
		}
		return false;
	};
	this.getChangedItemNames = function(){
	 var i, items = this.items, len = items.length, res = [];
	 for(i=0; i<len; i+=1){
	  if(this.canCheckType(items[i].getType())){
		 if(items[i].hasChanges() ){
		  var extras = items[i].getExtras();
		  var n = extras.name || extras.type;
		  if(n){
		   res[res.length] = n;
		  }
		 }
	  }
	 }
	 return res;
	}
	this.rebuild = function(witems){
		witems = witems || [];
		witems = ($.isArray(witems)?witems:[witems]);
		this.stopWatchers();
		this.items = [];
		for(var i=0; i<witems.length; i+=1){
			this.addWatchItem(witems[i]);
		}
	}
	this.clear = function(){
		this.stopWatchers();
		this.items = [];
	};
	this._constructor = function(){
		o = o || {};
		o.items = o.items || [];
		o.items = ($.isArray(o.items)?o.items:[o.items]);
		if($.isFunction(o.canCheckType)){
		 this.canCheckType = o.canCheckType;
		}
		this.rebuild(o.items);
		return {
			rebuild : (function(_this,watchitems){return function(){_this.rebuild(watchitems);};})(this,o.items),
			start : (function(_this){return function(){_this.start();};})(this),
			stop : (function(_this){return function(){_this.stop();};})(this),
			hasChanges : (function(_this){return  function(){return _this.hasChanges();};})(this),
			getChangedItemNames : (function(_this){return  function(){return _this.getChangedItemNames();};})(this),
			clear : (function(_this){return  function(){_this.clear();};})(this)
		};
	};
	return this._constructor();
};

appdb.utils.DataWatcher.Registry = (function(){
 return new function(){
  this.watchers = {};
  this.set = function(name,watcheroptions){
   if(this.get(name)){
	return;
   }
   this.watchers[name] = {options : watcheroptions, instance : undefined};
  };
  this.unset = function(name){
   var w = this.get(name);
   if(w){
	if(w.instance){
	 this.deactivate(name);
	}
	delete this.watchers[name];
   }
  };
  this.get = function(name){
   if(name && typeof name === "string"){
	 return this.watchers[name];
   }
   return undefined;
  };
  this.activate = function(name){
   var w = this.get(name);
   if(w){
	var a = this.getActiveName();
	if(a){
	 this.deactivate(a);
	}
	if(typeof w.instance === "undefined"){
	 w.instance = new appdb.utils.DataWatcher(w.options);
	}
	 w.instance.start();
	return true;
   }
   return false;
  };
  this.deactivate = function(name){
   var w = this.get(name);
   if(w && w.instance){
	w.instance.stop();
	w.instance.clear();
	w.instance = null;
	delete w.instance;
   }
  };
  this.getActive = function(){
   var name = this.getActiveName();
   if(name){
	return this.get(name);
   }
   return undefined;
  };
  this.getActiveName = function(){
   for(var i in this.watchers){
	if(this.watchers.hasOwnProperty(i)){
	 if(this.watchers[i].instance){
	  return i;
	 }
	}
   }
   return undefined;
  };
  this.checkActiveWatcher = function(){
   var w = this.getActive();
   if(w && w.instance){
	return w.instance.hasChanges();
   }
   return false;
  };
  this.checkActiveWatcherAsync = function(o){
   o = o || {};
   var opt = $.extend({
	notify : true,
	onCancel : function(){},
	onClose : function(){}
   },o);
   if(typeof this.getActiveName() === "undefined"){
	opt.onClose();
	return false;
   }
   var res = this.checkActiveWatcher();
   if(res === false){
	this.deactivate(this.getActiveName());
	opt.onClose();
	return false;
   }
   if(opt.notify){
	var changeditems = this.getActive().instance.getChangedItemNames();
	changeditems = (changeditems.length>0)?changeditems:undefined;
	appdb.utils.DataWatcher.Notification.show({data : changeditems, onClose : opt.onClose,onCancel:opt.onCancel});
   }
   return true;
  };
 };
})();

appdb.utils.DataWatcher.Notification = (function(){
 return new function(){
  this._dialog = null;
  this.show = function(o){
   this.close();
   o = o || {};
   var opt = $.extend({onClose: function(){}, onCancel : function(){}},o);
   var data = opt.data;
   
   var con = "<div class='unsaved'><div class='title'>You are about to close the editing form while there are unsaved changes";
   if($.isArray(data)){
	con += " regarding the items listed bellow:<div><ul>";
	for(var i=0; i<data.length; i+=1){
	 con += "<li>" + data[i] + "</li>";
	}
	con += "</ul></div>"
   }else{
	con += ".";
   }

   con += "<div class='option'>Click <b>Cancel</b> to return to the editing form.</div>";
   con += "<div class='option'>Click <b>Close</b> to close the editing form and discard the changes.</div>"
   con += "<div class='actions'><span class='close'></span><span class='cancel'></span></div>";
   con += "</div>";
   con = $(con);
   
   new dijit.form.Button({
	label : "Close",
	onClick : function(){
	 setTimeout(function(){
	  appdb.utils.DataWatcher.Notification.close();
	  appdb.utils.DataWatcher.Registry.deactivate(appdb.utils.DataWatcher.Registry.getActiveName());
	  opt.onClose();
	 },1);
	}
   },$(con).find("div.actions > span.close:first")[0]);

   new dijit.form.Button({
	label : "Cancel",
	onClick : function(){
	 setTimeout(function(){
	  appdb.utils.DataWatcher.Notification.close();
	  opt.onCancel();
	 },1);
	}
   },$(con).find("div.actions > span.cancel:first")[0]);

   this._dialog = new dijit.Dialog({
			title: "Unsaved changes",
			style : "width:470px",
			content: $(con)[0]
		});
   this._dialog.show();
  };
  this.close = function(){
   if(this._dialog && this._dialog !== null){
	this._dialog.hide();
	this._dialog.destroyRecursive(false);
	this._dialog = null;
   }
  };
 };
})();

appdb.utils.UrlQueryJson = function(queryString){
  if (queryString.charAt(0) == '?') queryString = queryString.substring(1);
  if (queryString.length > 0){
    queryString = queryString.replace(/\+/g, ' ');
    var queryComponents = queryString.split(/[&;]/g);
    for (var index = 0; index < queryComponents.length; index ++){
      var keyValuePair = queryComponents[index].split('=');
      var key = decodeURIComponent(keyValuePair[0]);
      var value = keyValuePair.length > 1?decodeURIComponent(keyValuePair[1]):'';
      this[key] = value;
   }
  }
 };
/*
 *Helper function to parse the hash value of url.
 *Used by the appdb.utils.Navigator object.
*/
appdb.utils.UrlHashParse = function(hash){
 
 //Check if hash is given.Defaults to current url's hash value else returns []
 hash = hash || window.location.hash;
  if(!hash || hash.length < 3){
	 return [];
  }else if(hash[0] === "#"){
	hash = hash.slice(1,hash.length);
  }
  
  //Check validity of hash value
  var isValidHash = (hash.length>2 && hash[0] === "!" && hash[1] === "/");
  if(!isValidHash ) {
   return [];
  }else{
   hash = hash.slice(2,hash.length);
   hash = hash.split("/");
   if(hash.length === 0){
	return [];
   }
  }

  //Start processing hash value
  var res = [], i , len = hash.length, queryindex = hash[len-1].indexOf("?"), query;
  //Get query string if any
  if(queryindex>-1){
   var qlen = (hash[len-1].length-queryindex)-1;
   query = hash[len-1].slice(queryindex);
   hash[len-1] = hash[len-1].slice(0,queryindex);
  }
  for(i=0; i<len; i+=1){
   if(hash[i]){
	if(isNaN(hash[i])){
	 res[res.length] = {type:"item", value:hash[i]};
	}else{
	 res[res.length] = {type:"value", value:hash[i]}
	}
   }
  }
  if(query){
   res[res.length] = {type:"query", value:new appdb.utils.UrlQueryJson(query)};
  }
  return res;
};

/*
 *Helper function to cancel the event from which a function was invoked.
 *Takes as a parameter the callee (Arguments.callee) object of a function.
 *Used by hash url navigation mechanism to cancel a hash change if needed.
 */
appdb.utils.CancelEventTrigger = function(c){
 var limit = 100, call = null,ev ;
 while(c.caller && limit!=0){
  call=c.caller;
  c = c.caller;
  limit-=1;
 }
 if(call){
  if(call.arguments.length==1){
   ev = call.arguments[0];
  }
 }
 ev = ev || window.event;
 if(ev){
   if (ev.preventDefault) {
   ev.preventDefault();
  } else {
   ev.returnValue = false;
  }
 }
 return ev;	
};

/*
 * Navigation mechanism based the url hash value.
 * It enables the browser history feature.
 */
appdb.Navigator = (function(){
 return new function(){
  this.hashDelegateImpl = function(){};
  this.setHashImpl = function(){};
  this.handleHashImpl = function(){};

  this.hashDelegate = (function(_this){
   return function(event){
	_this.hashDelegateImpl(event);
   };
  })(this);

  this.handleHash = (function(_this){
   return function(f,argv){
	_this.handleHashImpl(f,argv);
   };
  })(this);

  this.setHash = (function(_this){
   return function(h,checkLink){
	_this.setHashImpl(h,checkLink);
   };
  })(this);

  this.onWindowLoadDelegate = (function(_this){
   return function(event){
   if(window.location.hash === ""){
	showHome();
   }else{
	_this.hashDelegate(event);
   }
   };
  })(this);

  this.init = function(){
   this.setInternalMode(false);
   $(window).hashchange(this.hashDelegate);
   $(window).load(this.onWindowLoadDelegate);
   $("a[href='#']").live("click",function(){return false;});
   this.init = true;
  };
  this.sanitizeHash = function(){
   var hash = window.location.hash;
   if(hash){
	if(hash.length>0 && hash[0]==="#"){
	 hash = hash.substr(1);
	}
	if(hash.length>0 && hash[0]==="!"){
	 hash = hash.substr(1);
	}
	if(hash.substr(0,2)=="p="){
	 hash = hash.substr(2);
	}
	return $.trim(hash);
   }
   return "";
  }
  this.setTitle = function(f,argv){
   f = f || appdb.Navigator.Registry["Home"];
   var title = "";
   if(typeof f === "string"){
	title = f;
   }else if($.isFunction(f.title)){
	title = f.title.apply(null,argv);
   }else if(typeof f.title === "string"){
	title = (f.datatype +":"+f.type+" => " + appdb.config.permalinkraw);
   }
   document.title = title;
  };
  this.executePermalink = function(p){
   var _escape = function(v){
	 if(v){
	  return v.replace(/[\x00-\x1F]/g,"");
	 }
	 return v;
	};
	var item;
	if ( p != "" ) {
	 if ( p == "home" ){
	   appdb.views.Main.showHome();
	 }else if ( p == "reports" ) {
	  if ( ( userID) && ( ((userRole == 5) || (userRole = 7)) /*&& (userRoleVerified)*/ ) ) {
	   if ($("#reportslink")[0] !== undefined) {
		$("#reportslink").trigger("click");
	   } else {
		appdb.views.Main.showHome();
	   }
	  } else {
		appdb.views.Main.showHome();
	  }
	 } else if ( p == "brokenlinks" ) {
	   if ( ( userID) && ( ((userRole == 5) || (userRole == 7)) /*&& (userRoleVerified)*/ ) ) {
		if ($("#reportsbrokenlink")[0] !== undefined) $("#reportsbrokenlink").trigger("click"); else appdb.views.Main.showHome();
	   } else {
		   appdb.views.Main.showHome();
	   }
	 } else if ( p.substr(0,6) == "about:" ) {
		 dijit.byId("helppane").toggle();
		 item = _escape(p.substr(6));
		 if ($("#help"+item+"link")[0] !== undefined) $("#help"+item+"link").trigger("click"); else appdb.views.Main.showHome();
	 } else if ( p.substr(0,5) == "apps:" ) {
		 item = _escape(p.substr(5));
		 if ($("#apps"+item+"link")[0] !== undefined) $("#apps"+item+"link").trigger("click"); else appdb.views.Main.showHome();
	 } else if ( p.substr(0,7) == "people:" ) {
		 item=_escape(p.substr(7));
		 if ($("#ppl"+item+"link")[0] !== undefined) $("#ppl"+item+"link").trigger("click"); else appdb.views.Main.showHome();
	 } else {
		 var pp = appdb.utils.base64.decode(p);
		 pp = pp.replace(/[\x00-\x1F]/g,"");
		 if(pp[0]==="{"){
		   var req = JSON.parse(pp.replace(/[\x00-\x1F]/g,""));
		   if(req===null){
			   return;
		   }
		   var j = "";
		   var u = req.url;
		   var query = req.query; //get the query object
		   query = _escape(JSON.stringify(query));
		   var ext = req.ext; //the extended properties of the component to be called
		   ext = JSON.stringify(ext);
		   switch(u){
			   case "/apps":
				   j = appdb.views.Main.showApplications;
				   break;
			   case "/people":
				   j = appdb.views.Main.showPeople;
				   break;
			   case "/vos":
				   j = appdb.views.Main.showVOs;
				   break;
			   case "/person":
				   j = appdb.views.Main.showPerson;
				   break;
			   case "/vo":
				   j = appdb.views.Main.showVO;
				   break;
			   default:
				   return;
				   break;
		   }
		   j($.parseJSON(query || "{}"), $.parseJSON(ext || "{}"));
		 } else {
		  p = pp;
		   if( p == "home") {
			 appdb.views.Main.showHome();
		   } else if ( p.substr(0,10) == '/apps?flt=' ) {
			 appdb.views.Main.showApplications($.trim(p.substr(0,6)));
		   } else if ( p.substr(0,12) == '/people?flt=' ) {
			 appdb.views.Main.showPeople($.trim(p.substr(0,8)));
		   } else if ( p.substr(0,13) == '/apps/details' ) {
			 showAppDetails2(p);
			 if (detailsStyle == 1) appdb.views.Main.showHome();
		   } else if ( p.substr(0,15) == '/people/details' ) {
			 showPplDetails2(p);
			 if (detailsStyle == 1) appdb.views.Main.showHome();
		   } else if ( p.substr(0,11) == '/vo/details' ) {
			 showVODetails2(_escape(p));
			 if (detailsStyle == 1) appdb.views.Main.showHome();
		   } else if ( p.substr(0,12) == '/ngi/details' ) {
			 showNGIDetails2(_escape(p));
			 if (detailsStyle == 1) appdb.views.Main.showHome();
		   } else if (p == "brokenlinks"){
			 appdb.views.Main.showLinkStatuses();
		   } else if (p == "/news/report") {
			 appdb.views.Main.showActivityReport();alert(appdb.views.Main.showActivityReport.$);
		   } else if(p==="/help/announcements"){
			  $("#helpannouncelink").click();
		   }	else if( p.substr(0,6) === "/help/" || p.substr(0,9) === "appstats/" || p.substr(0,9) === "pplstats/" || p.substr(0,10)==="/changelog" || p == "brokenlinks") {
			 ajaxLoad(p,'main');
		   }
		   return;
		 }
	 }
	}else {
	  appdb.views.Main.showHome();
	}
  };

  this.setInternalMode = function(act){
   if(act === true){
	this.hashDelegateImpl = this.inactiveHashDelegate;
	this.handleHashImpl= this.inactiveHandleHash;
	this.setHashImpl = this.setHashInternal;
   }else{
	this.hashDelegateImpl = this.activeHashDelegate;
	this.handleHashImpl = this.activeHandleHash;
	this.setHashImpl = this.setHashExternal;
   }
  };
  this.setRawPermalink = function(p){
   var index = -1;
   if(p.substr(0,4)==="http"){
	index = p.indexOf("#!p=");
	if(index>-1){
	 p = p.substr(index);
	}
   }
   index = p.indexOf("p=");
   if(index>-1){
	p = p.substr(index+2);
   }else {
	index = p.indexOf("#");
	if(index>-1){
	 p = p.substr(index);
	}
   }
   if(typeof appdb.config!=="undefined"){
	appdb.config.permalinkraw = p;
   }
  };
  this.setPermalink = function(p){
   if(p.substr(0,4)==="http"){
	if(p.substr(0, 5)==="https"){
	  p = "http"+p.slice(5,p.length);
	}
   }else{
	p = appdb.config.endpoint.base+"?p="+p;
   }
   if(typeof appdb.config!=="undefined"){
	appdb.config.permalink = p;
   }
  };
  this.createPermalink = function(d,datatype){
   datatype = datatype || "apps";
   var u,s,p;
   if(typeof d === "undefined" || d===null){
	   d = {flt:''};
   }else if(typeof d === "string"){
	  if(d === ""){
	   u = appdb.config.endpoint.base+"#";
	  }else{
	   s = d.replace(/[\x00-\x1F]/g,"");
	   p = appdb.utils.base64.encode(s);
	   u = appdb.config.endpoint.base+"?p="+p;
	  }
   }else{
	  s = {url : "/"+datatype, query: d.query,ext:d.ext};
	  s = JSON.stringify(s);
	  s = s.replace(/[\x00-\x1F]/g,"");
	  p = appdb.utils.base64.encode(s);
	  u = appdb.config.endpoint.base+"?p="+p;
   }
   return u;
  };
  this.internalCall = function(f,d){
   if(this.init === true){
	var permalink = appdb.Navigator.createPermalink(d,f.datatype);
	this.setInternalMode(true);
	this.setPermalink(permalink);
	this.setRawPermalink(permalink);
	this.setHash(permalink,false);
	this.setTitle(f,[d.query,d.ext]);
	this.setInternalMode(false);
   }
  };
  
  this.activeHashDelegate = function(event){
	event= window.event || event;
	var hash = this.sanitizeHash();
	if(hash===""){
	 appdb.views.Main.showHome();
	 return true;
	}else if(hash==appdb.config.permalinkraw){
	 appdb.utils.CancelEventTrigger(arguments.callee);
	 return false;
	}else {
	   appdb.Navigator.executePermalink(hash,true);
	}
	return true;
  };
  this.inactiveHashDelegate = function(){
   this.setInternalMode(false);
  };
  this.setHashInternal = function(h){
   appdb.Navigator.setPermalink(h);
   appdb.Navigator.setRawPermalink(h);
   this.setHashExternal(h,false);
   this.setInternalMode(false);
  };
  this.setHashExternal = function(h,checkLink){
   if(!h){
	return;
   }   
   if(h.substr(0,4)=="http"){
	h = h.slice(appdb.config.endpoint.base.length);
   }
   if(h && h[0]=="?"){
	h = h.substr(1);
   }
   if(h.substr(0,1)=="#"){
	h = h.substr(1);
   }
   if(h.substr(0,2)=="p="){
	h = "!" + h;
   }
   if(checkLink){
	if("!p="+appdb.config.permalinkraw!==h && appdb.config.permalinkraw!=h){
	 return;
	}
   }
   window.location.hash = h;
  };
  
  this.inactiveHandleHash = function(f,argv){
   this.setInternalMode(false);
  };
  this.activeHandleHash = function(f,argv){
	var perm = "";
	if(f.datatype){
	  switch(f.type){
	   case "list":
		perm = this.createPermalink((f.permalink)?f.permalink.apply(null,argv):{query:argv[0],ext:argv[1]},f.datatype);
		break;
	   case "item":
		perm = this.createPermalink((f.permalink)?f.permalink.apply(null,argv):argv[0],f.datatype);
		break;
	   case "static":
		perm = this.createPermalink((f.permalink)?f.permalink.apply(null,argv):argv[0],f.datatype);
		break;
	   default:
		perm = this.createPermalink((f.permalink)?f.permalink.apply(null,argv):argv[0]);
		break;
	  }
	  this.setPermalink(perm);
	  this.setRawPermalink(perm);
	  if(appdb.config.permalinkraw==="#"){
	   this.setHash(appdb.config.permalinkraw,false);
	  }else{
	   this.setHash("!p="+appdb.config.permalinkraw,false);
	  }
	  this.setTitle(f,argv);
	}
  };
  this.setInternalMode(true);
 };
})();
appdb.Navigator.Helpers = (function(){
 return new function(){
  this.ApplicationTitle = function(d,prefix){
   var res = prefix || "Applications & Tools", page = 0, flt = "", o = d.query, e = d.ext;
   flt = (e && e.baseQuery)?e.baseQuery.flt:o.flt;
   flt = $.trim(flt);
   flt = flt.replace(/\"/g,"");
   if(flt!="" && flt[0]=="+"){
	flt = flt.substr(1);
   }
   if(typeof prefix === "undefined"){
	if(flt=="tool:false"){
	 res = "Applications list"
	}else if(flt=="tool:true"){
	 res = "Tools list";
	}else if(flt.substr(0,17)=="=middleware.name:"){
	 res = "Applications " + ((e && e.mainTitle)?"using " + e.mainTitle:"per middleware");
	}else if(flt.substr(0,12)=="=country.id:"){
	 res = "Applications " + ((e && e.mainTitle)?"in " + e.mainTitle:"per country");
	}else if(flt.substr(0,15)==='=discipline.id:'){
	 res = "Applications " + ((e && e.mainTitle)?"under " + e.mainTitle:"per discipline");
	}else if(flt.substr(0,18)=="=subdiscipline.id:"){
	 res = "Applications " + ((e && e.mainTitle)?"using " + e.mainTitle:"per subdiscipline");
	}else if(flt.substr(0,4)=="=vo:"){
	 res = "Applications " + ((e && e.mainTitle)?"with VO " + e.mainTitle:"per VO");
	}
   }
   if(e && e.userQuery && e.userQuery.flt && e.userQuery.flt!=""){
	var uq = e.userQuery.flt;
	uq = (uq.length>25)?uq.substr(0,22)+"...":uq;
	res = res + " search \"" + uq + "\"";
   }
   if(o.pageoffset && o.pagelength){
	page = Math.round(parseInt(o.pageoffset)/parseInt(o.pagelength)) + 1;
	res = res + " page " + page;
   }
   return res;
  };
  this.PeopleTitle = function(d){
   var o = d.query || {},e= d.ext || {};
   var res = (o && e && o.flt)?e.mainTitle:"People list";
   flt = (e && e.baseQuery)?e.baseQuery.flt:o.flt;
   flt = $.trim(flt);
   flt = flt.replace(/\"/g,"");
   if(flt!="" && flt[0]=="+"){
	flt = flt.substr(1);
   }
   if(flt!=""){
	if(flt.substr(0,12)==="=country.id:"){
	 res = "People in " + e.mainTitle;
	}else if(flt.substr(0,9)==="=role.id:"){
	 res = e.mainTitle;
	}
   }
   if(e && e.userQuery && e.userQuery.flt && e.userQuery.flt!=""){
	var uq = e.userQuery.flt;
	uq = (uq.length>25)?uq.substr(0,22)+"...":uq;
	res = res + " search \"" + uq + "\"";
   }
   if(o.pageoffset && o.pagelength){
	page = Math.round(parseInt(o.pageoffset)/parseInt(o.pagelength)) + 1;
	res = res + " page " + page;
   }
   return res;
  }
 };
})();

appdb.Navigator.Registry = {
	 "Home" :  {datatype : "home", type:"static", title : function(){
	   return "EGI Application Database";}, permalink:function(){return "";}},
	 "People" :  {datatype : "people" , type : "list",
	  title : function(o,e){
	   return appdb.Navigator.Helpers.PeopleTitle({query : o, ext:e});
	 }},
	 "Person" : (function(id){
	  if(id){
	   return {datatype : "people", type : "item", permalink : function(o,e){return "/people/details?id=" + o.id;},title : function(o,e){
		 return e.mainTitle + " profile";
	   }};
	  }
	  return {datatype : "person", type : "item", permalink : function(o){return "/people/details?id=" + o.id;},title : function(o,e){
		return e.mainTitle + " profile";
	  }};
	 })(userID),
	"Everything" :  {datatype : "apps" , type : "list"},
	"Applications" :  {datatype : "apps" , type : "list" ,
	 title : function(o,e){
	  return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});
	}},
	"RelatedApps" :  {datatype : "apps" , type : "list", title : function(o,e) {return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Related Applications");}},
	"Moderated" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Moderated Applications");}},
	"Deleted" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Deleted Applications");}},
	"Bookmarks" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Bookmarked Applications");}},
	"Editable" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Editable Applications");}},
	"Owned" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Owned Applications");}},
	"Associated" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e},"Associated Applications");}},
	"Application" :  {datatype : "app" , type : "item", permalink : function(o){return "/apps/details?id=" + o.id;}, title : function(o,e){
	  if(o.id=="0"){
	   return "Register New Application";
	  }
	  if(o["name"]){
	   return "Application " + o.name;
	  }else{
	   return "Application id:" + o.id;
	  }
	 }
	},
	"Ngis" :  {datatype : "ngis" , type : "list"},
	"Ngi" :  {datatype : "ngi" , type : "item"},
	"VOs" :  {datatype : "vos" , type : "list", permalink : function(o,e){
	  return (o)?{query:o,ext:e}:'{"url":"/vos"}';
	}, title : function(o,e){
	 var res = (e && e.mainTitle!="Virtual Organizations")?"VOs " + e.mainTitle:"Virtual Organizations";
	 if(o.name!==""){
	  var n = o.name;
	  n = (n.length>25)?n.substr(0,22)+"...":n;
	  res = res + " search \"" + n + "\"";
	 }
	 if(o.pageoffset && o.pagelength){
	  page = Math.round(parseInt(o.pageoffset)/parseInt(o.pagelength)) + 1;
	  res = res + " page " + page;
	 }
	 return res;
	}},
	"VO" :  {datatype : "vo" , type : "item", permalink : function(o){return "/vo/details?id="+o;}, title : function(o,e){
	  return (o)?"VO " + o:"VO Item";
	}},
	"Discipline" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});}},
	"Subdiscipline" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});}},
	"ApplicationCountry" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});}},
	"ApplicationMiddleware" :  {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});}},
	"ApplicationVO" : {datatype : "apps" , type : "list", title : function(o,e){return appdb.Navigator.Helpers.ApplicationTitle({query:o,ext:e});}},

	"ajaxLoad" :  {datatype:"mixed", type : "ajax" , title : function(o,e){
	  if(e=="main"){
	   switch(o){
		case "/help/usage":
		 return "EGI AppDB Usage"
		case "/help/announcements":
		 return "EGI AppDB Announcements"
		case "/help/faq":
		 return "EGI AppDB Faq";
		case "/help/credits":
		 return "EGI AppDB Credits";
		case "/changelog":
		 return "EGI AppDB Changelog";
		case "/changelog/features":
		 return "EGI AppDB features";
		case "appstats/perdomain":
		case "appstats/perdomain?ct=Pie":
		case "appstats/perdomain?ct=Bars":
		 return "Application statistics per discipline" + ((o.length>18)?" " + o.substr(18+4):"");
		case "appstats/persubdomain":
		case "appstats/persubdomain?ct=Pie":
		case "appstats/persubdomain?ct=Bars":
		 return "Application statistics per subdiscipline" + ((o.length>21)?" " + o.substr(21+4):"");
		case "appstats/percountry":
		case "appstats/percountry?ct=Pie":
		case "appstats/percountry?ct=Bars":
		 return "Application statistics per country" + ((o.length>19)?" " + o.substr(19+4):"");
		case "appstats/pervo":
		case "appstats/pervo?ct=Pie":
		case "appstats/pervo?ct=Bars":
		 return "Application statistics per virtual organization" + ((o.length>14)?" " + o.substr(14+4):"");
		case "pplstats/percountry":
		case "pplstats/percountry?ct=Pie":
		case "pplstats/percountry?ct=Bars":
		 return "People statistics per country" + ((o.length>19)?" " + o.substr(19+4):"");
		case "pplstats/perposition":
		case "pplstats/perposition?ct=Pie":
		case "pplstats/perposition?ct=Bars":
		 return "People statistics per position" + ((o.length>20)?" " + o.substr(20+4):"");
		case "/news/report"://activity report
		 return "AppDB activity report"
		default :
		 return "Appdb";
	   }
	  }
	  return "mixed";
	}},
	"LinkStatuses" :  {datatype : "brokenlinks",type : "item", permalink : function(o){return "brokenlinks";},title : function(){return "Broken Link Statuses";}},
	"ActivityReport" :  {datatype : "activityreport", type : "item" ,permalink : function(){return "/news/report";},title : function(){return "Activity Report";}}
};
