// ac.js
// Loading...

// ajax.js

var ac_ajax_debug = true;

function ac_ajax_request_object() {
    var hreq;

    try {
        hreq = new XMLHttpRequest();
    } catch (e) {
        try {
            hreq = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (__e) {
            hreq = null;
        }
    }

    if (hreq !== null) {
//      try {
//          hreq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
//      } catch (e) {}
    }

    return hreq;
}

function ac_ajax_init() {
}

function ac_ajax_call_url(url, post, cb) {
    var hreq = ac_ajax_request_object();

    if (hreq !== null) {
        hreq.onreadystatechange = function() {
            try {
                ac_ajax_handle(hreq, cb);
            } catch (e) {}
        };
	    var method = ( post === null ? 'GET' : 'POST' );
	    var postType = typeof(post);
	    if ( post !== null ) {
		    if ( postType == 'array' || postType == 'object' ) {
		    	var postArr = new Array();
		        for ( var i in post ) {
				    var postType = typeof(post[i]);
				    if ( postType == 'array' || postType == 'object' ) {
				        for ( var j in post[i] ) {
				    		if ( typeof(post[i][j]) != 'function' ) {
			            		postArr.push(i + '[' + ( j == 'undefined' ? '' : j ) + ']=' + encodeURIComponent(post[i][j]));
				    		}
				        }
				    } else if ( postType != 'function' ) {
		            	postArr.push(i + '=' + encodeURIComponent(post[i]));
				    }
			    }
			    post = postArr.join('&');
		    }
	    }
        hreq.open(method, url, true);
        if ( post !== null ) {
        	hreq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			//hreq.setRequestHeader("Content-length", post.length);		// IE doesn't like these
			//hreq.setRequestHeader("Connection", "close");
        }
        hreq.send(post);
    }
}

function ac_ajax_proxy_call_url(base, url, post, cb) {
	if (post !== null)
		ac_ajax_call_url(base + "/ac_global/functions/ajax_proxy.php?post=1&url=" + ac_b64_encode(url), post, cb);
	else
		ac_ajax_call_url(base + "/ac_global/functions/ajax_proxy.php?url=" + ac_b64_encode(url), post, cb);
}

function ac_ajax_proxy_call_cb(base, url, func, cb) {
    if (url.match(/\?/))
        url = url + "&f=" + func;
    else
        url = url + "?f=" + func;

    url += "&rand=" + ac_b64_encode(Math.random().toString());

    if (arguments.length > 3) {
        for (var i = 4; i < arguments.length; i++)
            url += "&p[]=" + encodeURIComponent(arguments[i]);
    }

    ac_ajax_proxy_call_url(base, url, null, cb);
}

function ac_ajax_call(url, func) {
    if (arguments.length < 3)
        ac_ajax_call_cb(ac_str_url(url), func, null);
    else {
        ac_ajax_call_cb(ac_str_url(url), func, null, ac_ary_last(arguments, 2));
    }
}

function ac_ajax_call_cb(url, func, cb) {
    if (func) {
        if (url.match(/\?/))
            url = url + "&f=" + func;
        else
            url = url + "?f=" + func;
    }

    url += "&rand=" + ac_b64_encode(Math.random().toString());

    if (arguments.length > 3) {
        for (var i = 3; i < arguments.length; i++)
            url += "&p[]=" + encodeURIComponent(arguments[i]);
    }

    ac_ajax_call_url(url, null, cb);
}

function ac_ajax_post_cb(url, func, cb, post) {
    if (func) {
        if (url.match(/\?/))
            url = url + "&f=" + func;
        else
            url = url + "?f=" + func;
        }

    url += "&rand=" + ac_b64_encode(Math.random().toString());

    ac_ajax_call_url(url, post, cb);
}

function ac_ajax_handle(hreq, cb) {
    if (hreq !== null) {
        if (hreq.readyState == 4) {
            if (hreq.status == 200) {
                try {
                    var xml = hreq.responseXML;
					if (xml !== null) {
						if (cb === null)
							cb = eval("cb_" + xml.documentElement.nodeName);

						if (typeof cb == "function")
							cb(xml.documentElement, hreq.responseText);
					}
                } catch (e) {
                }
            }
        }
    }
}

function ac_ajax_cb(cbf) {
	return function(xml, text) {
		window.t_xml  = xml;
		window.t_text = text;
		var ary       = ac_dom_read_node(xml, null);
		window.t_ary  = ary;

		cbf(ary);
	}
}
// dom.js

function ac_dom_read(tag, filter) {
    return ac_dom_read_node(document.getElementsByTagName(tag).Items(0), filter);
}

function ac_dom_read_node(node, filter) {
	if (typeof(filter) != 'function') filter = null;
    var ary = new Array();
    var cnode = null;

    for (var i = 0; i < node.childNodes.length; i++) {
        cnode = node.childNodes[i];

        switch (cnode.nodeType) {
            case 3:     // TEXT_NODE
                ary["__text"] = cnode.nodeValue;
                break;
            case 4:     // CDATA_SECTION_NODE
                ary["__cdata"] = cnode.nodeValue;
                break;
            case 1:     // ELEMENT_NODE
                if (ac_dom_isnull(cnode.firstChild)) {
					var idx = cnode.nodeName.toLowerCase();

					if (ary[idx] === undefined || (typeof(ary[idx]) != "string" && typeof(ary[idx]) != "array" && typeof(ary[idx]) != "object"))
						ary[idx] = "";
					else {
						if (typeof(ary[idx]) == "string") {
							var tmp = ary[idx];
							ary[idx] = new Array();
							ary[idx].push(tmp);
						}
						ary[idx].push("");
					}
				} else if (ac_dom_istext(cnode.firstChild)) {
					var idx = cnode.nodeName.toLowerCase();
					var nodedata = ( cnode.textContent !== undefined ? cnode.textContent : cnode.firstChild.nodeValue );

					nodedata = nodedata.replace(/__--acenc:endcdata--__/, "]]>", nodedata);
					if (nodedata.match(/^-?[0-9]+$/) && !nodedata.match(/0+[0-9]+$/))
						nodedata = parseInt(nodedata, 10);

					if (ary[idx] === undefined || (typeof(ary[idx]) != "string" && typeof(ary[idx]) != "array" && typeof(ary[idx]) != "object"))
						ary[idx] = (filter === null) ? nodedata : filter(nodedata);
					else {
						if (typeof(ary[idx]) == "string") {
							var tmp = ary[idx];
							ary[idx] = new Array();
							ary[idx].push(tmp);
						} else if (typeof(ary[idx]) != "array" && typeof(ary[idx]) != "object") {
							alert(typeof(ary[idx]));
							//continue;
						}
						ary[idx].push((filter === null) ? nodedata : filter(nodedata));
					}
				} else {
                    var idx = cnode.nodeName.toLowerCase();

					if (ary[idx] === undefined || (typeof(ary[idx]) != "string" && typeof(ary[idx]) != "array" && typeof(ary[idx]) != "object")) {
                        ary[idx] = new Array();
					}

					ary[idx].push(ac_dom_read_node(cnode, filter));
                }
                break;
            default:
                break;
        }
    }

    return ary;
}

function ac_dom_istext(node) {
    return node.nodeType == 3 || node.nodeType == 4;    // TEXT_NODE || CDATA_SECTION_NODE
}

function ac_dom_isnull(node) {
    return node === null;
}

function ac_dom_toggle_display(id, val) {
	var disp = $(id).style.display;

	if (disp != "none")
		$(id).style.display = "none";
	else
		$(id).style.display = ( typeof val == "undefined" ? "" : val );
}

/*
function ac_dom_toggle_display(id, val) {
    var node = document.getElementById(id);

    if (val.match(/table(-row|-cell)?/) && navigator.userAgent.match(/MSIE [567]/))
        val = "block";

    if (node !== null)
        node.style.display = (node.style.display == val) ? "none" : val;
}
*/

function ac_dom_display_block(id) {
	$(id).style.display = "block";
}

function ac_dom_display_none(id) {
	$(id).style.display = "none";
}

function ac_dom_toggle_class(id, className1, className2) {
	var node = document.getElementById(id);
	if ( !node ) return;
	node.className = ( node.className == className1 ? className2 : className1 );
}

// We don't recurse to the child nodes here; this function itself is a
// shallow foreach.

function ac_dom_foreach_node(node, fun) {
    while (node !== null) {
        fun(node);
        node = node.nextSibling;
    }
}

// The idea here is to take an HTML collection and walk through it, as
// opposed to an actual node.  (You would use foreach_item, for example,
// with the result of a call to document.getElementsByTagName().)

function ac_dom_foreach_item(coll, fun) {
    for (var i = 0; i < coll.length; i++)
        fun(coll[i]);
}

function ac_dom_foreach_child(obj, fun) {
	for (var i = 0; i < obj.childNodes.length; i++)
		fun(obj.childNodes[i]);
}

// Useful for removing all children at once, which isn't a standard
// DOM function but does come up from time to time.

function ac_dom_remove_children(node) {
	var filter = null;

	if (arguments.length > 1) {
		// they passed a filter function
		filter = arguments[1];
	}

    for (var i = node.childNodes.length - 1; i >= 0; i--) {
		if (typeof filter != "function")
			node.removeChild(node.childNodes[i]);
		else if (filter(node.childNodes[i]))
			node.removeChild(node.childNodes[i]);
	}
}

function ac_dom_append_childtext(node, text) {
    node.appendChild(document.createTextNode(text));
}

// Create a new <option> element.

function ac_dom_new_option(val, label) {
    var opt = document.createElement("option");
    opt.value = val;
    opt.appendChild(document.createTextNode(label));
    return opt;
}

/*
try {
    function $(id) {
        if (typeof id == 'string')
            return document.getElementById(id);
        return id;
    }
} catch (e) {}
*/


// ASSIGN WINDOW.ONLOAD FUNCTIONS HERE
function ac_dom_onload_hook(func) {
	var oldonload = window.onload;
	if ( typeof window.onload != 'function' ) {
		window.onload = func;
	} else {
		window.onload = function() {
			oldonload();
			func();
		}
	}
}

function ac_dom_hook(func1, func2) {
	//var oldfunc = func1;
	eval('var oldfunc = ' + func1 + ';');
	if ( typeof oldfunc != 'function' ) {
		eval(func1 + ' = func2;');
		//func1 = func2;
	} else {
		eval(func1 + ' = function() { oldfunc(); func2(); }');
		/*func1 = function() {
			oldfunc();
			func2();
		}*/
	}
}

function ac_dom_find_posX(obj) {
	var curleft = 0;
	if ( obj.offsetParent )
		while ( 1 ) {
			curleft += obj.offsetLeft;
			if ( !obj.offsetParent ) break;
			obj = obj.offsetParent;
		}
	else if ( obj.x )
		curleft += obj.x;
	return curleft;
}

function ac_dom_find_posY(obj) {
	var curtop = 0;
	if ( obj.offsetParent )
	while ( 1 ) {
		curtop += obj.offsetTop;
		if ( !obj.offsetParent ) break;
		obj = obj.offsetParent;
	}
	else if(obj.y)
		curtop += obj.y;
	return curtop;
}


// clones an element of a parent object
// has an option to clear out inputs
// (convenient for dynamic "add more" actions)
// usage: x($('tableID'), 'tr', false, 1) === in table #tableID clone second row ( tr[1] ), don't clean inputs
function ac_dom_clone_node(node, elem, elementIndex, clearInputs) {
    if ( !elementIndex ) elementIndex = 0;
	var original = node.getElementsByTagName(elem)[elementIndex];
    var new_node = original.cloneNode(true);
    if ( clearInputs ) {
	    var newinput = new_node.getElementsByTagName('input');
	    for ( var i = 0; i < newinput.length; i++ ) {
	        if (newinput[i].type == 'text' || newinput[i].type == 'file') newinput[i].value = '';
	    }
	    var newarea = new_node.getElementsByTagName('textarea');
	    for ( var i = 0; i < newarea.length; i++ ) {
	        newarea[i].value = '';
	    }
    }
    node.appendChild(new_node);
    return new_node;
}

function ac_dom_liveedit_toggle(div) {
	ac_dom_toggle_display(div, 'inline');
	ac_dom_toggle_display(div + "_contain", 'inline');
}

function ac_dom_liveedit_showform(div) {
	$(div).style.display = "none";
	$(div + "_contain").style.display = "inline";
}

function ac_dom_liveedit_showtext(div) {
	$(div).style.display = "inline";
	$(div + "_contain").style.display = "none";
}

function ac_dom_unhighlight(id, cls) {
	var ctext = "";
	var spans = $(id).select("span." + cls);
	var par   = null;

	for (var i = 0; i < spans.length; i++) {
		ctext = spans[i].firstChild;
		par   = spans[i].parentNode;

		par.replaceChild(ctext, spans[i]);
	}
}

function ac_dom_keypress_doif(e, ch, cb) {
	var kcode;

	if (window.event)
		kcode = window.event.keyCode;
	else
		kcode = e.keyCode;

	if (kcode == ch)
		cb();
}

function ac_dom_keypress(e, cb) {
	var kcode;

	if (window.event)
		kcode = window.event.keyCode;
	else
		kcode = e.keyCode;

	cb(kcode);
}

// Examine each of the text subnodes in node for matches in the terms array.  If
// any are found, replace them with some fancy highlights.

function ac_dom_highlight(node, terms, full) {
	switch (node.nodeType) {
		case 3:
		case 4:
			node.nodeValue = ac_dom_highlight_text(node.nodeValue, terms, full);
			break;

		case 1:
			for (var i = 0; i < node.childNodes.length; i++) {
				if (node.nodeName != "SCRIPT" && node.nodeName != "TEXTAREA")	// to skip liveedit elements
					ac_dom_highlight(node.childNodes[i], terms, full);
			}
			break;
	}
}

function ac_dom_highlight_replace(node, terms, cls) {
	node.innerHTML = node.innerHTML.replace(/___:::([a-zA-Z0-9!_-]+):::___/gi, ac_dom_highlight_replace_cb(cls));
}

function ac_dom_highlight_cb(def) {
	if (def === null) {
		return function(m) {
			return sprintf("___:::%s:::___", ac_b64_encode(m));
		}
	} else {
		return function(m) {
			return sprintf("___:::%s:::___", ac_b64_encode(m + ",,," + def));
		}
	}
}

function ac_dom_highlight_replace_cb(cls) {
	return function(full, m) {
		return sprintf("<span class='%s'>%s</span>", cls, ac_b64_decode(m));
	}
}

function ac_dom_highlight_definition_cb(cls) {
	return function(full, m) {
		m       = ac_b64_decode(m);
		var ary = m.split(",,,");

		if (ary.length != 2)
			return m;

		return sprintf("<span class='%s' onmouseover='ac_tooltip_show(\"%s\", 200, \"\", true)' onmouseout='ac_tooltip_hide()'>%s</span>", cls, ac_b64_encode(ary[1]), ac_str_htmlescape(ary[0]));
	}
}

function ac_dom_highlight_text(text, terms, full, sens) {
	for (var i in terms) {
		if (typeof terms[i] != "string")
			continue;

		if (full)
			text = text.replace(new RegExp(sprintf("\\b(%s)\\b", i), "gim"), ac_dom_highlight_cb(terms[i]));
		else
			text = text.replace(new RegExp(sprintf("\\b(%s)\\b", i), "gim"), ac_dom_highlight_cb(null));
	}
	for (var i in sens) {
		if (typeof sens[i] != "string")
			continue;

		if (full)
			text = text.replace(new RegExp(sprintf("\\b(%s)\\b", i), "gm"), ac_dom_highlight_cb(terms[i]));
		else
			text = text.replace(new RegExp(sprintf("\\b(%s)\\b", i), "gm"), ac_dom_highlight_cb(null));
	}
	return text;
}

function ac_dom_highlight_definition(node, terms, cls) {
	node.innerHTML = node.innerHTML.replace(/___:::([a-zA-Z0-9!_-]+):::___/gi, ac_dom_highlight_definition_cb(cls));
}

function ac_dom_emptynode(node, props) {
	if ( !props ) props = { };
	var obj = Builder.node(node, props);
	obj.innerHTML = '&nbsp;';
	return obj;
}
// b64.js

var ac_b64_dec = {
    'A':  0, 'B':  1, 'C':  2, 'D':  3, 'E':  4, 'F':  5, 'G':  6, 'H':  7,
    'I':  8, 'J':  9, 'K': 10, 'L': 11, 'M': 12, 'N': 13, 'O': 14, 'P': 15,
    'Q': 16, 'R': 17, 'S': 18, 'T': 19, 'U': 20, 'V': 21, 'W': 22, 'X': 23,
    'Y': 24, 'Z': 25, 'a': 26, 'b': 27, 'c': 28, 'd': 29, 'e': 30, 'f': 31,
    'g': 32, 'h': 33, 'i': 34, 'j': 35, 'k': 36, 'l': 37, 'm': 38, 'n': 39,
    'o': 40, 'p': 41, 'q': 42, 'r': 43, 's': 44, 't': 45, 'u': 46, 'v': 47,
    'w': 48, 'x': 49, 'y': 50, 'z': 51, '0': 52, '1': 53, '2': 54, '3': 55,
    '4': 56, '5': 57, '6': 58, '7': 59, '8': 60, '9': 61, '-': 62, '!': 63,
    '=': 0
};

var ac_b64_enc = {
     0: 'A',  1: 'B',  2: 'C',  3: 'D',  4: 'E',  5: 'F',  6: 'G',  7: 'H',
     8: 'I',  9: 'J', 10: 'K', 11: 'L', 12: 'M', 13: 'N', 14: 'O', 15: 'P',
    16: 'Q', 17: 'R', 18: 'S', 19: 'T', 20: 'U', 21: 'V', 22: 'W', 23: 'X',
    24: 'Y', 25: 'Z', 26: 'a', 27: 'b', 28: 'c', 29: 'd', 30: 'e', 31: 'f',
    32: 'g', 33: 'h', 34: 'i', 35: 'j', 36: 'k', 37: 'l', 38: 'm', 39: 'n',
    40: 'o', 41: 'p', 42: 'q', 43: 'r', 44: 's', 45: 't', 46: 'u', 47: 'v',
    48: 'w', 49: 'x', 50: 'y', 51: 'z', 52: '0', 53: '1', 54: '2', 55: '3',
    56: '4', 57: '5', 58: '6', 59: '7', 60: '8', 61: '9', 62: '-', 63: '!'
};

function ac_b64_elshift(m, i, sh) {
    return (m.charCodeAt(i) << sh) & 63;
}

function ac_b64_ershift(m, i, sh) {
    return (m.charCodeAt(i) >> sh) & 63;
}

// Base-64 encode a string, essentially by taking a 3-character block
// and turning it into a 4-character block using the base-64 alphabet.
// If less than 3 characters exist in the last block, the equal sign is
// used as padding (2 equal signs if only 1 character, 1 equal sign if 2
// characters).

function ac_b64_encode(message) {
    var out = "";
    var buf0;
    var buf1;
    var buf2;
    var buf3;
    var i;

    for (i = 0; i < message.length; i += 3) {
        buf0 = ac_b64_enc[ac_b64_ershift(message, i+0, 2)];
        buf2 = "_";
        buf3 = "_";

        if ((i+1) < message.length)
            buf1 = ac_b64_enc[ac_b64_elshift(message, i+0, 4) | ac_b64_ershift(message, i+1, 4)];
        else
            buf1 = ac_b64_enc[ac_b64_elshift(message, i+0, 4)];

        if ((i+2) < message.length) {
            buf2 = ac_b64_enc[ac_b64_elshift(message, i+1, 2) | ac_b64_ershift(message, i+2, 6)];
            buf3 = ac_b64_enc[ac_b64_elshift(message, i+2, 0)];
        } else if ((i+1) < message.length)
            buf2 = ac_b64_enc[ac_b64_elshift(message, i+1, 2)];

        out += buf0 + buf1 + buf2 + buf3;
    }

    return out;
}

function ac_b64_dlshift(c, sh) {
    return (ac_b64_dec[c] << sh) & 255;
}

function ac_b64_drshift(c, sh) {
    return (ac_b64_dec[c] >> sh) & 255;
}

function ac_b64_decode(message) {
    var out = "";
    var i;

    // All base-64 blocks are multiples of four characters.  Try it:
    // encode a one-letter string.  You'll get four characters
    // in return.  If that's not the case with this message, then it's
    // not really base-64 encoded (or not encoded correctly).

    if ((message.length % 4) != 0)
        return message;

    // Each block of four encoded characters can be decoded to, at most,
    // three unencoded ones.  (Which makes sense: 4 * 6bits = 24bits,
    // and 3 * 8bits = 24bits.)  The bits in base-64 are encoded
    // left-to-right, that is, starting with the high-order bit and
    // moving to the low-order bit.  Each number we consider has a bit
    // mask of 255 applied, so only (low-order) 8 bits are considered at
    // any given moment.

    // The equal sign is considered "padding" in an encoded string, but
    // they also represent the end marker.  A block of four bytes with
    // two equal signs on the end is a signal that only one character is
    // encoded; with one equal sign, two characters encoded.  No equal
    // sign is necessary if the initial string's length was a multiple
    // of 3.

    for (i = 0; i < message.length; i += 4) {
        out += String.fromCharCode(ac_b64_dlshift(message.charAt(i+0), 2) | ac_b64_drshift(message.charAt(i+1), 4)); if (message.charAt(i+2) == '_') break;
        out += String.fromCharCode(ac_b64_dlshift(message.charAt(i+1), 4) | ac_b64_drshift(message.charAt(i+2), 2)); if (message.charAt(i+3) == '_') break;
        out += String.fromCharCode(ac_b64_dlshift(message.charAt(i+2), 6) | ac_b64_drshift(message.charAt(i+3), 0));
    }
    
    return out;
}
// str.js

/*
function ac_str_trim(str) {
    return str.replace(/^\s*(\S+)\s*$/, "$1");
}
*/
function ac_str_trim(str, chars) {
	return ac_str_ltrim(ac_str_rtrim(str, chars), chars);
}

function ac_str_ltrim(str, chars) {
	chars = chars || "\\s";
	return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}

function ac_str_rtrim(str, chars) {
	chars = chars || "\\s";
	return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}

function ac_str_repeat(str, times) {
	var out = "";

	while (times--)
		out += str;

	return out;
}

function ac_str_shorten(text, chars) {
	if ( !chars || chars == 0 ) return text;
    var textLength = text.length;
    text += ' ';
    text = text.substr(0, chars);
    var lastSpacePos = text.lastIndexOf(' ');
    if ( lastSpacePos != -1 )
        text = text.substr(0, lastSpacePos);
    if ( textLength > text.length )
        text += '...';

    return text;
}

function ac_str_middleshorten(text, front_chars, back_chars) {
	if ( !front_chars || front_chars == 0 ) return text;
	if ( !back_chars || back_chars == 0 ) return text;
	if ( text.length < front_chars + back_chars ) return text;
    var front = text.substr(0, front_chars);
    var back  = text.substr(text.length - back_chars, back_chars);
    return front + '...' + back;
}


function ac_str_array(str) {
    var ary = new Array();

    for (var i = 0; i < str.length; i++) {
        if (str[i] == '&') {
            var tmp = "";
            while (i < str.length) {
                tmp += str[i++];
                if (str[i-1] == ';')
                    break;
            }

            ary.push(tmp);
        } else {
            ary.push(str[i]);
        }
    }

    return ary;
}

function ac_array_has(ary, val) {
    //for (var i = 0; i < ary.length; i++) {
    for ( var i in ary ) {
        if (ary[i] == val)
            return true;
    }

    return false;
}

function ac_array_extract(str) {
    var ary = new Array();
    var tmp = str.split("||");

    for (var i = 0; i < tmp.length; i++) {
        var ent = tmp[i].split("=", 2);
        ary[ent[0]] = ent[1];
    }

    return ary;
}

function ac_str_array_len(ary) {
    for (var i = 0, c = 0; i < ary.length; i++)
        c += ary[i].length;
    return c;
}

function ac_str_array_substr(ary, off, len) {
    var tmp = "";
    for (var i = off; i < ary.length; i++) {
        if (i >= len)
            break;
        tmp += ary[i];
    }

    return tmp;
}

function ac_str_url(rel) {
    var ary = rel.split("/");
    var url = window.location.href.replace(/\/[^\/]*$/, "");

    for (var i = 0; i < ary.length; i++) {
        if (ary[i] == "..")
            url = url.replace(/\/[^\/]*$/, "");
        else
            url += "/" + ary[i];
    }

    return url;
}

function ac_ary_last(ary, begin) {
    var nary = new Array();

    for (var i = begin, j = 0; i < ary.length; i++, j++) {
        nary[j] = ary[i];
    }

    return nary;
}

function ac_str_rand_password(len) {
	var out = "";

	while (len--) {
		out += ac_str_rand_passchar();
	}

	return out;
}

function ac_str_rand_passchar() {
	var floor = Math.floor(Math.random() * 10.0);
	var chr;

	if (floor > 6) {
		chr = Math.floor(Math.random() * 10.0);
		chr = chr.toString();
	} else {
		var off = Math.floor(Math.random() * 100.0) % 26;
		chr = "a".charCodeAt(0) + off;
		chr = String.fromCharCode(chr);
	}

	return chr;
}

function ac_sprintf(fmt, args) {
    var out;
    var argi;

    out     = "";
    argi    = 0;

    for (var i = 0; i < fmt.length; i++) {
        var fmtc = fmt.charAt(i);
        switch (fmtc) {
            case "\\":
                i++;
                break;
            case "%":
                if (argi < args.length) {
                    fmtc = fmt.charAt(i+1);
                    out += ac_sprintf_spec(fmtc, args[argi]);
                    i++;
                    argi++;
                } else {
                    out += fmtc;
                }
                break;
            default:
                out += fmtc;
                break;
        }
    }

    return out;
}

function ac_sprintf_spec(ch, arg) {
    switch (ch) {
        case "d":
        case "f":
            return arg.toString();
        case "s":
        default:
            return arg;
    }

    return "";
}


// This code is in the public domain. Feel free to link back to http://jan.moesen.nu/
function sprintf() {
	if (!arguments || arguments.length < 1 || !RegExp)
	{
		return;
	}
	var str = arguments[0];
	var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/; // '
	var a = b = [], numSubstitutions = 0, numMatches = 0;
	while (a = re.exec(str))
	{
		var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
		var pPrecision = a[5], pType = a[6], rightPart = a[7];

		//alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);

		numMatches++;
		if (pType == '%')
		{
			subst = '%';
		}
		else
		{
			numSubstitutions++;
			if (numSubstitutions >= arguments.length)
			{
				//alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).\n\nString in question:\n' + str);
				return;
			}
			var param = arguments[numSubstitutions];
			var pad = '';
			       if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
			  else if (pPad) pad = pPad;
			var justifyRight = true;
			       if (pJustify && pJustify === "-") justifyRight = false;
			var minLength = -1;
			       if (pMinLength) minLength = parseInt(pMinLength);
			var precision = -1;
			       if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
			var subst = param;
			       if (pType == 'b') subst = parseInt(param).toString(2);
			  else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
			  else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
			  else if (pType == 'u') subst = Math.abs(param);
			  else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
			  else if (pType == 'o') subst = parseInt(param).toString(8);
			  else if (pType == 's') subst = param;
			  else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
			  else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
		}
		str = leftpart + subst + rightPart;
	}
	return str;
}


/*
 * This is the function that actually highlights a text string by
 * adding HTML tags before and after all occurrences of the search
 * term. You can pass your own tags if you'd like, or if the
 * highlightStartTag or highlightEndTag parameters are omitted or
 * are empty strings then the default <font> tags will be used.
 */
function ac_str_highlight(bodyText, searchTerm, highlightStartTag, highlightEndTag)
{
  // the highlightStartTag and highlightEndTag parameters are optional
  if ((!highlightStartTag) || (!highlightEndTag)) {
    highlightStartTag = "<font style='color:blue; background-color:yellow;'>";
    highlightEndTag = "</font>";
  }

  // find all occurences of the search term in the given text,
  // and add some "highlight" tags to them (we're not using a
  // regular expression search, because we want to filter out
  // matches that occur within HTML tags and script blocks, so
  // we have to do a little extra validation)
  var newText = "";
  var i = -1;
  var lcSearchTerm = searchTerm.toLowerCase();
  var lcBodyText = bodyText.toLowerCase();

  while (bodyText.length > 0) {
    i = lcBodyText.indexOf(lcSearchTerm, i+1);
    if (i < 0) {
      newText += bodyText;
      bodyText = "";
    } else {
      // skip anything inside an HTML tag
      if (bodyText.lastIndexOf(">", i) >= bodyText.lastIndexOf("<", i)) {
        if (
	      // skip anything inside a <script> block
          (lcBodyText.lastIndexOf("/script>", i) >= lcBodyText.lastIndexOf("<script", i))
        ||
    	  // skip anything inside a <style> block
          (lcBodyText.lastIndexOf("/style>", i) >= lcBodyText.lastIndexOf("<style", i))
        ) {
          newText += bodyText.substring(0, i) + highlightStartTag + bodyText.substr(i, searchTerm.length) + highlightEndTag;
          bodyText = bodyText.substr(i + searchTerm.length);
          lcBodyText = bodyText.toLowerCase();
          i = -1;
        }
      }
    }
  }

  return newText;
}


/*
 * This is sort of a wrapper function to the ac_str_highlight function.
 * It takes the searchText that you pass, optionally splits it into
 * separate words, transforms the text and returns it.
 * Only the "bodyText" and "searchText" parameters are required; all other parameters
 * are optional and can be omitted.
 */
function ac_str_highlight_phrase(bodyText, searchText, treatAsPhrase, customColorIndex)
{
  // if the treatAsPhrase parameter is true, then we should search for
  // the entire phrase that was entered; otherwise, we will split the
  // search string so that each word is searched for and highlighted
  // individually
  if (treatAsPhrase) {
    var searchArray = [searchText];
  } else {
    var searchArray = searchText.split(" ");
    if ( searchArray.length == 1 ) {
      var treatAsPhrase = true;
    }
  }

  var colors = [ 'yellow', '#99FF99', '#FFCCFF', '#CC99FF', '#99CCFF', '#FFCC99', '#CCCCFF', '#66CCFF' ];
  for (var i = 0; i < searchArray.length; i++) {
    // choose color
    if (!customColorIndex && customColorIndex != 0) {
      if (treatAsPhrase) {
        var colorIndex = 0;
      } else {
        var colorIndex = ( i % 7 ) + 1;
      }
    } else {
      colorIndex = customColorIndex;
    }
    var color = colors[colorIndex];
    highlightStartTag = '<font class="__highlight" style="background-color: ' + color + ';">';
    highlightEndTag = '</font>';
    bodyText = ac_str_highlight(bodyText, searchArray[i], highlightStartTag, highlightEndTag);
  }

  return bodyText;
}



/*
var __ac_highlight_tags = [];
var __ac_highlight_tag = '';
var __ac_highlight_i = 0;

function ac_str_highlight(str, terms, tag) {
	if ( tag == null || tag == undefined )
		var tag = '<b style="color: #000; background-color: #%s;">%s</b>';
	var orig = str;
	var colors = [ 'ff0', '0ff', 'f0f' ];
	var i = 0;
	if ( terms.length == 0 || ( terms.length == 1 && ac_str_trim(terms[0]) == '' ) ) return str;
	__ac_highlight_tags = [];
	for ( var i = 0; i < terms.length; i++ ) {
		// choose color
		var colorIndex = i % 3;
		var color = colors[colorIndex];
		if ( terms[i].length > 1 ) {
			// escape term
			var q = preg_quote(terms[i]);
			// If there are tags, we need to stay outside them
			__ac_highlight_tag = tag;
			__ac_highlight_i = i;
			if ( !str.match(/<.+>/) ) {
				// text
				str = str.replace(
					/(\b + q + \b)/ig,
					function(m) {
						alert(m);return m;
						var found = sprintf(__ac_highlight_tag, __ac_highlight_i, m[1]);
						var r = ac_b64_encode(found);
						__ac_highlight_tags[r] = found;
						return r;
					}
				);
			} else {
				// html
				str = str.replace(
					/(?<=>)([^<]+)?(\b/ + q + /\b)/ig,
					function(m) {
						var found = m[1] + sprintf(__ac_highlight_tag, __ac_highlight_i, m[2]);
						var r = ac_b64_encode(found);
						__ac_highlight_tags[r] = found;
						return r;
					}
				);
			}
		}
	}
	// do final replacements
	if ( __ac_highlight_tags.length > 0 ) {
		str = str.replace(ac_array_keys(__ac_highlight_tags), ac_array_values(__ac_highlight_tags));
	}
	return str;
}
*/

function nl2br(str) {
	if ( typeof(str) == "string" )
		return str.replace(/(\r\n)|(\n\r)|\r|\n/g,'<br />'); // '
	else
		return str;
}

function preg_quote( str ) {
	// Quote regular expression characters
	//
	// +    discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_preg_quote/
	// +       version: 801.2320
	// +   original by: booeyOH
	// +   improved by: Ates Goral (http://magnetiq.com)
	// *     example 1: preg_quote("$40");
	// *     returns 1: "\\\$40"
	// *     example 2: preg_quote("*RRRING* Hello?");
	// *     returns 2: "\\*RRRING\\* Hello\\?"
	// *     example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
	// *     returns 3: "\\\\\\.\\+\\*\\?\\[\\^\\]\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:"

	return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
}

function ac_str_urlsafe(str) {
	// strip all tags first
	str = strip_tags(str);
	// encode escaped octets
	str = str.replace(/%([a-fA-F0-9][a-fA-F0-9])/, '-=-$1-=-');
	// remove percent signs
	str = str.replace('%', '');
	// decode found octets
	str = str.replace(/-=-([a-fA-F0-9][a-fA-F0-9])-=-/g, '%$1');
	// do your best to mask all weird chars
	str = ac_str_remove_accents(str);
	// if string is in utf8
	if ( ac_utf_check(str) ) {
		// encode string for usage in url
		str = ac_utf_uri_encode(str, 200);
	}
	// paths should be lowercased
	str = str.toLowerCase();
	// remove all entities,
	str = str.replace(/&.+?;/g, '');
	// harmfull chars,
	str = str.replace(/[^%a-z0-9 _-]/g, '');
	// whitespaces
	str = str.replace(/\s+/g, '-');
	// and other...
	str = str.replace(/-+/g, '-');
	str = ac_str_trim(str, '-');
	// return clean string
	return str;
}



function ac_str_remove_accents(string) {
	// if none found, return the string right away
	if ( !string.match(/[\u80-\uff]/) ) {
		return string;
	}
	if ( ac_utf_check(string) ) {
		// if string is in utf8
		var chars = new Array();
		chars[((195 << 6) | 128).toString()] = 'A';
		chars[((195 << 6) | 129).toString()] = 'A';
		chars[((195 << 6) | 130).toString()] = 'A';
		chars[((195 << 6) | 131).toString()] = 'A';
		chars[((195 << 6) | 132).toString()] = 'A';
		chars[((195 << 6) | 133).toString()] = 'A';
		chars[((195 << 6) | 135).toString()] = 'C';
		chars[((195 << 6) | 136).toString()] = 'E';
		chars[((195 << 6) | 137).toString()] = 'E';
		chars[((195 << 6) | 138).toString()] = 'E';
		chars[((195 << 6) | 139).toString()] = 'E';
		chars[((195 << 6) | 140).toString()] = 'I';
		chars[((195 << 6) | 141).toString()] = 'I';
		chars[((195 << 6) | 142).toString()] = 'I';
		chars[((195 << 6) | 143).toString()] = 'I';
		chars[((195 << 6) | 145).toString()] = 'N';
		chars[((195 << 6) | 146).toString()] = 'O';
		chars[((195 << 6) | 147).toString()] = 'O';
		chars[((195 << 6) | 148).toString()] = 'O';
		chars[((195 << 6) | 149).toString()] = 'O';
		chars[((195 << 6) | 150).toString()] = 'O';
		chars[((195 << 6) | 153).toString()] = 'U';
		chars[((195 << 6) | 154).toString()] = 'U';
		chars[((195 << 6) | 155).toString()] = 'U';
		chars[((195 << 6) | 156).toString()] = 'U';
		chars[((195 << 6) | 157).toString()] = 'Y';
		chars[((195 << 6) | 159).toString()] = 's';
		chars[((195 << 6) | 160).toString()] = 'a';
		chars[((195 << 6) | 161).toString()] = 'a';
		chars[((195 << 6) | 162).toString()] = 'a';
		chars[((195 << 6) | 163).toString()] = 'a';
		chars[((195 << 6) | 164).toString()] = 'a';
		chars[((195 << 6) | 165).toString()] = 'a';
		chars[((195 << 6) | 167).toString()] = 'c';
		chars[((195 << 6) | 168).toString()] = 'e';
		chars[((195 << 6) | 169).toString()] = 'e';
		chars[((195 << 6) | 170).toString()] = 'e';
		chars[((195 << 6) | 171).toString()] = 'e';
		chars[((195 << 6) | 172).toString()] = 'i';
		chars[((195 << 6) | 173).toString()] = 'i';
		chars[((195 << 6) | 174).toString()] = 'i';
		chars[((195 << 6) | 175).toString()] = 'i';
		chars[((195 << 6) | 177).toString()] = 'n';
		chars[((195 << 6) | 178).toString()] = 'o';
		chars[((195 << 6) | 179).toString()] = 'o';
		chars[((195 << 6) | 180).toString()] = 'o';
		chars[((195 << 6) | 181).toString()] = 'o';
		chars[((195 << 6) | 182).toString()] = 'o';
		chars[((195 << 6) | 182).toString()] = 'o';
		chars[((195 << 6) | 185).toString()] = 'u';
		chars[((195 << 6) | 186).toString()] = 'u';
		chars[((195 << 6) | 187).toString()] = 'u';
		chars[((195 << 6) | 188).toString()] = 'u';
		chars[((195 << 6) | 189).toString()] = 'y';
		chars[((195 << 6) | 191).toString()] = 'y';
		chars[((196 << 6) | 128).toString()] = 'A';
		chars[((196 << 6) | 129).toString()] = 'a';
		chars[((196 << 6) | 130).toString()] = 'A';
		chars[((196 << 6) | 131).toString()] = 'a';
		chars[((196 << 6) | 132).toString()] = 'A';
		chars[((196 << 6) | 133).toString()] = 'a';
		chars[((196 << 6) | 134).toString()] = 'C';
		chars[((196 << 6) | 135).toString()] = 'c';
		chars[((196 << 6) | 136).toString()] = 'C';
		chars[((196 << 6) | 137).toString()] = 'c';
		chars[((196 << 6) | 138).toString()] = 'C';
		chars[((196 << 6) | 139).toString()] = 'c';
		chars[((196 << 6) | 140).toString()] = 'C';
		chars[((196 << 6) | 141).toString()] = 'c';
		chars[((196 << 6) | 142).toString()] = 'D';
		chars[((196 << 6) | 143).toString()] = 'd';
		chars[((196 << 6) | 144).toString()] = 'D';
		chars[((196 << 6) | 145).toString()] = 'd';
		chars[((196 << 6) | 146).toString()] = 'E';
		chars[((196 << 6) | 147).toString()] = 'e';
		chars[((196 << 6) | 148).toString()] = 'E';
		chars[((196 << 6) | 149).toString()] = 'e';
		chars[((196 << 6) | 150).toString()] = 'E';
		chars[((196 << 6) | 151).toString()] = 'e';
		chars[((196 << 6) | 152).toString()] = 'E';
		chars[((196 << 6) | 153).toString()] = 'e';
		chars[((196 << 6) | 154).toString()] = 'E';
		chars[((196 << 6) | 155).toString()] = 'e';
		chars[((196 << 6) | 156).toString()] = 'G';
		chars[((196 << 6) | 157).toString()] = 'g';
		chars[((196 << 6) | 158).toString()] = 'G';
		chars[((196 << 6) | 159).toString()] = 'g';
		chars[((196 << 6) | 160).toString()] = 'G';
		chars[((196 << 6) | 161).toString()] = 'g';
		chars[((196 << 6) | 162).toString()] = 'G';
		chars[((196 << 6) | 163).toString()] = 'g';
		chars[((196 << 6) | 164).toString()] = 'H';
		chars[((196 << 6) | 165).toString()] = 'h';
		chars[((196 << 6) | 166).toString()] = 'H';
		chars[((196 << 6) | 167).toString()] = 'h';
		chars[((196 << 6) | 168).toString()] = 'I';
		chars[((196 << 6) | 169).toString()] = 'i';
		chars[((196 << 6) | 170).toString()] = 'I';
		chars[((196 << 6) | 171).toString()] = 'i';
		chars[((196 << 6) | 172).toString()] = 'I';
		chars[((196 << 6) | 173).toString()] = 'i';
		chars[((196 << 6) | 174).toString()] = 'I';
		chars[((196 << 6) | 175).toString()] = 'i';
		chars[((196 << 6) | 176).toString()] = 'I';
		chars[((196 << 6) | 177).toString()] = 'i';
		chars[((196 << 6) | 178).toString()] = 'IJ';
		chars[((196 << 6) | 179).toString()] = 'ij';
		chars[((196 << 6) | 180).toString()] = 'J';
		chars[((196 << 6) | 181).toString()] = 'j';
		chars[((196 << 6) | 182).toString()] = 'K';
		chars[((196 << 6) | 183).toString()] = 'k';
		chars[((196 << 6) | 184).toString()] = 'k';
		chars[((196 << 6) | 185).toString()] = 'L';
		chars[((196 << 6) | 186).toString()] = 'l';
		chars[((196 << 6) | 187).toString()] = 'L';
		chars[((196 << 6) | 188).toString()] = 'l';
		chars[((196 << 6) | 189).toString()] = 'L';
		chars[((196 << 6) | 190).toString()] = 'l';
		chars[((196 << 6) | 191).toString()] = 'L';
		chars[((197 << 6) | 128).toString()] = 'l';
		chars[((197 << 6) | 129).toString()] = 'L';
		chars[((197 << 6) | 130).toString()] = 'l';
		chars[((197 << 6) | 131).toString()] = 'N';
		chars[((197 << 6) | 132).toString()] = 'n';
		chars[((197 << 6) | 133).toString()] = 'N';
		chars[((197 << 6) | 134).toString()] = 'n';
		chars[((197 << 6) | 135).toString()] = 'N';
		chars[((197 << 6) | 136).toString()] = 'n';
		chars[((197 << 6) | 137).toString()] = 'N';
		chars[((197 << 6) | 138).toString()] = 'n';
		chars[((197 << 6) | 139).toString()] = 'N';
		chars[((197 << 6) | 140).toString()] = 'O';
		chars[((197 << 6) | 141).toString()] = 'o';
		chars[((197 << 6) | 142).toString()] = 'O';
		chars[((197 << 6) | 143).toString()] = 'o';
		chars[((197 << 6) | 144).toString()] = 'O';
		chars[((197 << 6) | 145).toString()] = 'o';
		chars[((197 << 6) | 146).toString()] = 'OE';
		chars[((197 << 6) | 147).toString()] = 'oe';
		chars[((197 << 6) | 148).toString()] = 'R';
		chars[((197 << 6) | 149).toString()] = 'r';
		chars[((197 << 6) | 150).toString()] = 'R';
		chars[((197 << 6) | 151).toString()] = 'r';
		chars[((197 << 6) | 152).toString()] = 'R';
		chars[((197 << 6) | 153).toString()] = 'r';
		chars[((197 << 6) | 154).toString()] = 'S';
		chars[((197 << 6) | 155).toString()] = 's';
		chars[((197 << 6) | 156).toString()] = 'S';
		chars[((197 << 6) | 157).toString()] = 's';
		chars[((197 << 6) | 158).toString()] = 'S';
		chars[((197 << 6) | 159).toString()] = 's';
		chars[((197 << 6) | 160).toString()] = 'S';
		chars[((197 << 6) | 161).toString()] = 's';
		chars[((197 << 6) | 162).toString()] = 'T';
		chars[((197 << 6) | 163).toString()] = 't';
		chars[((197 << 6) | 164).toString()] = 'T';
		chars[((197 << 6) | 165).toString()] = 't';
		chars[((197 << 6) | 166).toString()] = 'T';
		chars[((197 << 6) | 167).toString()] = 't';
		chars[((197 << 6) | 168).toString()] = 'U';
		chars[((197 << 6) | 169).toString()] = 'u';
		chars[((197 << 6) | 170).toString()] = 'U';
		chars[((197 << 6) | 171).toString()] = 'u';
		chars[((197 << 6) | 172).toString()] = 'U';
		chars[((197 << 6) | 173).toString()] = 'u';
		chars[((197 << 6) | 174).toString()] = 'U';
		chars[((197 << 6) | 175).toString()] = 'u';
		chars[((197 << 6) | 176).toString()] = 'U';
		chars[((197 << 6) | 177).toString()] = 'u';
		chars[((197 << 6) | 178).toString()] = 'U';
		chars[((197 << 6) | 179).toString()] = 'u';
		chars[((197 << 6) | 180).toString()] = 'W';
		chars[((197 << 6) | 181).toString()] = 'w';
		chars[((197 << 6) | 182).toString()] = 'Y';
		chars[((197 << 6) | 183).toString()] = 'y';
		chars[((197 << 6) | 184).toString()] = 'Y';
		chars[((197 << 6) | 185).toString()] = 'Z';
		chars[((197 << 6) | 186).toString()] = 'z';
		chars[((197 << 6) | 187).toString()] = 'Z';
		chars[((197 << 6) | 188).toString()] = 'z';
		chars[((197 << 6) | 189).toString()] = 'Z';
		chars[((197 << 6) | 190).toString()] = 'z';
		chars[((197 << 6) | 191).toString()] = 's';
		chars[((226 << 12) | (130 << 6) | 172).toString()] = 'E';
		chars[((194 << 6) | 163).toString()] = '';
		// do the replacements
		for (var i = 0; i < string.length; i++) {
			var code = string.charCodeAt(i).toString();
			var chr = string[i];
			if (chars[code]) {
				string[i] = chars[code];
			}
		}
	} else {
		// assume it is ISO-8859-1 if not UTF-8
		var chars = {
			'in' :
				String.fromCharCode(128) + String.fromCharCode(131) + String.fromCharCode(138) + String.fromCharCode(142) + String.fromCharCode(154) + String.fromCharCode(158) + String.fromCharCode(159) +
				String.fromCharCode(162) + String.fromCharCode(165) + String.fromCharCode(181) + String.fromCharCode(192) + String.fromCharCode(193) + String.fromCharCode(194) + String.fromCharCode(195) +
				String.fromCharCode(196) + String.fromCharCode(197) + String.fromCharCode(199) + String.fromCharCode(200) + String.fromCharCode(201) + String.fromCharCode(202) + String.fromCharCode(203) +
				String.fromCharCode(204) + String.fromCharCode(205) + String.fromCharCode(206) + String.fromCharCode(207) + String.fromCharCode(209) + String.fromCharCode(210) + String.fromCharCode(211) +
				String.fromCharCode(212) + String.fromCharCode(213) + String.fromCharCode(214) + String.fromCharCode(216) + String.fromCharCode(217) + String.fromCharCode(218) + String.fromCharCode(219) +
				String.fromCharCode(220) + String.fromCharCode(221) + String.fromCharCode(224) + String.fromCharCode(225) + String.fromCharCode(226) + String.fromCharCode(227) + String.fromCharCode(228) +
				String.fromCharCode(229) + String.fromCharCode(231) + String.fromCharCode(232) + String.fromCharCode(233) + String.fromCharCode(234) + String.fromCharCode(235) + String.fromCharCode(236) +
				String.fromCharCode(237) + String.fromCharCode(238) + String.fromCharCode(239) + String.fromCharCode(241) + String.fromCharCode(242) + String.fromCharCode(243) + String.fromCharCode(244) +
				String.fromCharCode(245) + String.fromCharCode(246) + String.fromCharCode(248) + String.fromCharCode(249) + String.fromCharCode(250) + String.fromCharCode(251) + String.fromCharCode(252) +
				String.fromCharCode(253) + String.fromCharCode(255),
			'out' :
				'EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy',
			'inin' :
				[ String.fromCharCode(140), String.fromCharCode(156), String.fromCharCode(198), String.fromCharCode(208), String.fromCharCode(222), String.fromCharCode(223), String.fromCharCode(230), String.fromCharCode(240), String.fromCharCode(254) ],
			'outout' :
				[ 'OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th' ]
		};
		// replace single characters
		string = ac_str_strtr(string, chars['in'], chars['out']);
		// replace double characters
		string = ac_str_replace(chars['inin'], chars['outout'], string);
	}
	// return a clean string
	return string;
}

function ac_str_file_humansize(size) {
	var count = 0;
	var format = new Array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
	while( ( size / 1024 ) > 1 && count < 8 ) {
		size = size / 1024;
		count++;
	}
	//var decimals = size < 10;

	return Math.round(size) + ' ' + format[count];
}

// Always pass ac_strings.js vars decimalDelim and commaDelim if default
function ac_number_format(nStr, decimalDelim, commaDelim) {
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? decimalDelim + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + commaDelim + '$2');
	}
	return x1 + x2;
}

function ac_str_strtr(str, list) {
	if ( arguments[2] ) {
		var r = arguments[2];
		for ( var i = 0; i < list.length; i++ ) {
			str = str.replace( new RegExp(list.charAt(i), "g"), r.charAt(i) );
		}
	} else {
		for ( var c in list ) {
			str = str.replace( new RegExp(c, "g"), list[c] );
		}
	}
	return str;
}

function ac_str_replace(search, replace, subject) {
	if ( typeof(search) == "string" ) return subject.replace(RegExp(search, "g"), replace);
	for ( var i in search ) {
		if ( replace[i] && typeof(search[i]) + typeof(replace[i]) == "stringstring" )
			subject = subject.replace(RegExp(search[i], "g"), replace[i]);
	}
	return subject;
}

function strip_tags(str, trim) {
	var r = str.replace(/<\/?[^>]+>/gi, '');
	if ( trim ) r = ac_str_trim(r);
	return r;
}

function ac_str_escapeq(str) {
	str = str.replace(/\\/g, '\\\\');
	str = str.replace(/'/g, "\\'");
	str = str.replace(/"/g, '\\"');
	return str;
}

function ac_str_htmlescape(str) {
	str = str.replace(/&/g, "&amp;");
	str = str.replace(/</g, "&lt;");
	str = str.replace(/>/g, "&gt;");
	str = str.replace(/'/g, "&#039;"); //'
	str = str.replace(/"/g, "&quot;"); //"

	return str;
}

function ac_str_jsescape(str) {
	str = str.replace(/'/g, "\\'"); //"
	str = str.replace(/"/g, '\\"'); //'

	return str;
}

function ac_str_email(email) {
    return email.match( /^[\+_a-z0-9-']+(\.[\+_a-z0-9-']+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,7})$/i );
}

function ac_str_is_url(url) {
    return url.match( /((http|https|ftp):\/\/|www)[a-z0-9\-\._]+\/?[a-z0-9_\.\-\?\+\/~=&#%;:\|,\[\]]*[a-z0-9\/=?&;%\[\]]{1}/i );
}


/**
*
*  Javascript sprintf
*  http://www.webtoolkit.info/
*
*
**/

sprintfWrapper = {

	init : function () {

		if (typeof arguments == "undefined") { return null; }
		if (arguments.length < 1) { return null; }
		if (typeof arguments[0] != "string") { return null; }
		if (typeof RegExp == "undefined") { return null; }

		var string = arguments[0];
		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
		var matches = new Array();
		var strings = new Array();
		var convCount = 0;
		var stringPosStart = 0;
		var stringPosEnd = 0;
		var matchPosEnd = 0;
		var newString = '';
		var match = null;

		while (match = exp.exec(string)) {
			if (match[9]) { convCount += 1; }

			stringPosStart = matchPosEnd;
			stringPosEnd = exp.lastIndex - match[0].length;
			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);

			matchPosEnd = exp.lastIndex;
			matches[matches.length] = {
				match: match[0],
				left: match[3] ? true : false,
				sign: match[4] || '',
				pad: match[5] || ' ',
				min: match[6] || 0,
				precision: match[8],
				code: match[9] || '%',
				negative: parseInt(arguments[convCount]) < 0 ? true : false,
				argument: String(arguments[convCount])
			};
		}
		strings[strings.length] = string.substring(matchPosEnd);

		if (matches.length == 0) { return string; }
		if ((arguments.length - 1) < convCount) { return null; }

		var code = null;
		var match = null;
		var i = null;

		for (i=0; i<matches.length; i++) {

			if (matches[i].code == '%') { substitution = '%' }
			else if (matches[i].code == 'b') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'c') {
				matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'd') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'f') {
				matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'o') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 's') {
				matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'x') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'X') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
			}
			else {
				substitution = matches[i].match;
			}

			newString += strings[i];
			newString += substitution;

		}
		newString += strings[i];

		return newString;

	},

	convert : function(match, nosign){
		if (nosign) {
			match.sign = '';
		} else {
			match.sign = match.negative ? '-' : match.sign;
		}
		var l = match.min - match.argument.length + 1 - match.sign.length;
		var pad = new Array(l < 0 ? 0 : l).join(match.pad);
		if (!match.left) {
			if (match.pad == "0" || nosign) {
				return match.sign + pad + match.argument;
			} else {
				return pad + match.sign + match.argument;
			}
		} else {
			if (match.pad == "0" || nosign) {
				return match.sign + match.argument + pad.replace(/0/g, ' ');
			} else {
				return match.sign + match.argument + pad;
			}
		}
	}
}

sprintf = sprintfWrapper.init;
// array.js

function ac_array_keys( input, search_value, strict ) {
    // Return all the keys of an array
    //
    // +    discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_keys/
    // +       version: 801.3120
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: array_keys( {firstname: 'Kevin', surname: 'van Zonneveld'} );
    // *     returns 1: {0: 'firstname', 1: 'surname'}

    var tmp_arr = new Array(), strict = !!strict, include = true, cnt = 0;

    for ( key in input ) {
        include = true;
        if ( search_value != undefined ) {
            if ( strict && input[key] !== search_value ) {
                include = false;
            } else if ( input[key] != search_value ) {
                include = false;
            }
        }

        if ( include ) {
            tmp_arr[cnt] = key;
            cnt++;
        }
    }

    return tmp_arr;
}


function ac_array_values( input ) {
    // Return all the values of an array
    //
    // +    discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_values/
    // +       version: 801.3120
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: array_values( {firstname: 'Kevin', surname: 'van Zonneveld'} );
    // *     returns 1: {0: 'Kevin', 1: 'van Zonneveld'}

    var tmp_arr = new Array(), cnt = 0;

    for ( key in input ){
        tmp_arr[cnt] = input[key];
        cnt++;
    }

    return tmp_arr;
}


function ac_array_remove(node, arr, renum) {
	var newArr = new Array();
	for ( var i = 0; i < arr.length; i++ ) {
		if ( arr[i] != node ) {
			var j = ( renum ? newArr.length : i );
			newArr[j] = arr[i];
		}
	}
	return newArr;
}

function ac_array_remove_key(k, arr) {
	var newArr = { };
	for ( var i in arr ) {
		if ( i != k ) {
			newArr[i] = arr[i];
		}
	}
	return newArr;
}
// utf.js

function ac_utf_unescape(str) {
	return str.replace(/&#([0-9]+);/g, function(str, mat) { return String.fromCharCode(parseInt(mat, 10)); });
}

function ac_utf_check(str) {
	for ( var i = 0; i < str.length; i++ ) {
		if ( str.charCodeAt(i) < 0x80 ) {
			// do nothing if 0bbbbbbb
			continue;
		} else if ( ( str.charCodeAt(i) & 0xE0 ) == 0xC0 ) {
			// 110bbbbb
			n = 1;
		} else if ( ( str.charCodeAt(i) & 0xF0 ) == 0xE0 ) {
			// 1110bbbb
			n = 2;
		} else if ( ( str.charCodeAt(i) & 0xF8 ) == 0xF0 ) {
			// 11110bbb
			n = 3;
		} else if ( ( str.charCodeAt(i) & 0xFC ) == 0xF8 ) {
			// 111110bb
			n = 4;
		} else if ( ( str.charCodeAt(i) & 0xFE ) == 0xFC ) {
			// 1111110b
			n = 5;
		} else {
			// it does not match any model
			return false;
		}
		// loop through found bytes offset
		for ( var j = 0; j < n; j++ ) {
			if ( ( ++i == str.length ) || ( ( str.charCodeAt(i) & 0xC0 ) != 0x80 ) ) {
				return false;
			}
		}
	}
	// it is utf8 string, nothing bad found
	return true;
}

function ac_utf_reinterpret(str) {
	// If we have a UTF-8 string which we don't recognize as UTF-8 (each byte is interpreted
	// separately), put it back together.
	
	var _out = "";
	var a, b, c, d;

	for (var i = 0; i < str.length; i++) {
		a = str.charCodeAt(i);

		switch (ac_utf_codelen(a)) {
			case 1:
			default:
				_out += str.charAt(i);
				break;

			case 2:
				a = a & 31;
				b = str.charCodeAt(++i) & 63;
				_out += String.fromCharCode((a << 6) | b);
				break;

			case 3:
				a = a & 15;
				b = str.charCodeAt(++i) & 63;
				c = str.charCodeAt(++i) & 63;
				_out += String.fromCharCode((a << 12) | (b << 6) | c);
				break;

			case 4:
				a = a & 7;
				b = str.charCodeAt(++i) & 63;
				c = str.charCodeAt(++i) & 63;
				d = str.charCodeAt(++i) & 63;
				_out += String.fromCharCode((a << 18) | (b << 12) | (c << 6) | d);
				break;
		}
	}

	return _out;
}

function ac_utf_codelen(b) {
	if ((b & 240) == 240)
		return 4;
	if ((b & 224) == 224)
		return 3;
	if ((b & 192) == 192)
		return 2;
	return 1;
}

function ac_utf_uri_encode(str, length) {
	// define needed vars
	if ( !length ) length = 0;
	var unicode = '';
	var values = new Array();
	var octets = 1;
	// loop through string
	for ( i = 0; i < str.length; i++ ) {
		value = str.charCodeAt(i);
		if ( value < 128 ) {
			// if regular char
			if ( length && ( unicode.length + 1 > length ) ) {
				break;
			}
			unicode = unicode + String.fromCharCode(value);
		} else {
			// where is it?
			if ( values.length == 0 ) octets = ( value < 224 ? 2 : 3 );
			values.push(value);
			if ( length && ( unicode.length + octets * 3 > length ) ) {
				break;
			}
			// when found all parts, combine them
			if ( values.length == octets ) {
				unicode = unicode + '%' . values[0].toString(16) + '%' + values[1].toString(16);
				if ( octets == 3 ) unicode = unicode + '%' + values[2].toString(16);
				var values = new Array();
				var octets = 1;
			}
		}
	}
	return unicode;
}
// custom_fields.js

function ac_custom_fields_title(field, showhidden) {
	if (typeof showhidden == "undefined")
		showhidden = false;

    if (field.type != "6" || showhidden)
        return field.title;
}

function ac_custom_fields_bubble(node, field) {
	if ( !field.bubble_content ) return node;
	if ( field.bubble_content == '' ) return node;
	return Builder.node(
		"span",
		[
			node,
			Builder.node("div", { id: 'field' + field.id + 'bubble', className: 'ac_help', style: 'display: none;' }, [ Builder._text(field.bubble_content) ])
		]
	);
}

function ac_custom_fields_cons(field, showhidden) {
	if (typeof showhidden == "undefined")
		showhidden = false;

    var f_name = "field[" + field.id + "," + field.dataid + "]";
    var f_type = parseInt(field.type, 10);
   	var props = {};
    if ( field.bubble_content && field.bubble_content != '' ) {
		props.onmouseover = "ac_dom_toggle_display('field" + field.id + "bubble', 'block');";
		props.onmouseout  = "ac_dom_toggle_display('field" + field.id + "bubble', 'block');";
    }
    switch (f_type) {
        case 1:     // Text field
            if (field.val == "")
                field.val = field.onfocus;
            // properties
            props.type = "text";
            props.name = f_name;
            props.value = field.val;
            return ac_custom_fields_bubble(Builder.node("input", props), field);

        case 2:     // Text box
            var f_cols;
            var f_rows;
            if (field.onfocus != '') {
                var dim = field.onfocus.split("||");
                f_cols = dim[0];
                f_rows = dim[1];
            } else {
                f_cols = 30;
                f_rows = 5;
            }
            if (field.val == '')
                field.val = field.expl;
            // properties
            props.rows = f_rows;
            props.cols = f_cols;
            props.name = f_name;
            return ac_custom_fields_bubble(Builder.node("textarea", props, [ Builder._text(field.val) ]), field);

        case 3:     // Checkbox
            if (field.val == '')
                field.val = field.onfocus;
            // properties
            props.type = "checkbox";
            props.name = f_name;
            props.value = "checked";
            if (field.val == "checked")
                props.checked = "true";
            return Builder.node(
            	"span",
            	[
                    Builder.node("input", { type: "hidden", name: f_name, value: "unchecked" }),
                    ac_custom_fields_bubble(Builder.node("input", props), field)
                ]
            );

        case 4:     // Radio button(s)
            if (field.val == '')
                field.val = field.onfocus;
            var f_ary    = new Array();
            f_ary.push(Builder.node("input", { type: "hidden", name: f_name, value: "unchecked" }));

            field.expl = field.expl.replace(/\r?\n/g, "||");
            var list = field.expl.split("||");

            for (var i = 0; i < list.length; i += 2) {
				props = {};
                // properties
                props.type = "radio";
                props.name = f_name;
                props.value = list[i+1];
                if (field.val == list[i+1])
                    props.checked = "true";
                f_ary.push(Builder.node("input", props));
                f_ary.push(Builder._text(list[i+0]));
            }

            return Builder.node("div", f_ary);

        case 5:     // Dropdown
            if (field.val == '')
                field.val = field.onfocus;

            var f_ary = new Array();
            field.expl = field.expl.replace(/\r?\n/g, "||");
            var list = field.expl.split("||");

            var found = false;
            for (var i = 0; i < list.length; i += 2) {
                var f_opt = { value: list[i+1] };

                if (field.val == list[i+1]) {
                    f_opt.selected = "true";
                    found = true;
                }

                f_ary.push(Builder.node("option", f_opt, [ Builder._text(list[i+0]) ]));
            }

            // properties
            props.name = f_name;
            props.size = 1;
            var elem = Builder.node("select", props, f_ary);
            if ( found ) {
            	elem.value = field.val;
            }
            return ac_custom_fields_bubble(elem, field);

        case 6:     // Hidden field
            if (field.val == '')
                field.val = field.onfocus;

			if (showhidden)
				return Builder.node("input", { type: "text", name: f_name, value: field.val });
			else
				return Builder.node("input", { type: "hidden", name: f_name, value: field.val });

        case 7:     // List box (select with multiple)
			var div    = Builder.node("div");
			var input  = Builder.node("input", { type: "hidden", name: f_name, value: "~|" });
            field.expl = field.expl.replace(/\r?\n/g, "||");
            var list   = field.expl.split("||");
			var f_ary  = new Array();

            for (var i = 0; i < list.length; i += 2) {
                var f_opt = { value: list[i+1] };

                if (field.val == list[i+1]) {
                    f_opt.selected = "true";
                    found = true;
                }

                f_ary.push(Builder.node("option", f_opt, [ Builder._text(list[i+0]) ]));
            }

			var select = Builder.node("select", { name: f_name, multiple: true }, f_ary);
			div.appendChild(input);
			div.appendChild(ac_custom_fields_bubble(select, field));
			return div;
        case 8:     // Checkbox group
			var input  = Builder.node("input", { type: "hidden", name: f_name + "[]", value: "~|" });
            field.expl = field.expl.replace(/\r?\n/g, "||");
            var list   = field.expl.toString().split("||");
			var f_ary  = new Array();
			var values = field.val.toString().split("||");

			f_ary.push(input);

            for (var i = 0; i < list.length; i += 2) {
                var f_opt = { type: "checkbox", name: f_name + "[]", value: list[i+1] };

                if (values.indexOf(list[i+1]) > -1) {
                    f_opt.checked = "true";
                    found = true;
                }

				f_ary.push(ac_custom_fields_bubble(Builder.node("label", { className: "cFieldCheckboxGroup" }), field));
                f_ary.push(Builder.node("input", f_opt, [ Builder._text(list[i+0]) ]));
				f_ary.push(Builder._text(list[i]));
            }

			return Builder.node("div", f_ary);
        default:
            break;
    }

    return Builder._text("Sorry!  Unknown field");
}




var ACCustomFields = null;
var ACCustomFieldsObj = null;
var ACCustomFieldsResult = {};


/* CUSTOM FIELDS OBJECT */
if (typeof Class != "undefined") {
	ACCustomFields = Class.create();
	ACCustomFields.prototype = {
		// Make this true if you want hidden fields to be displayed (as text fields).
		showhidden: false,

		initialize:
			function(props) {
				if ( !props ) props = { };
				// if checkboxes are used, it will preserve the selection in this array
				this.selection = [];
				// this array holds the current relations list (RELIDs)
				this.rels = ( !props.rels ? [] : props.rels );
				// this array holds all handlers for ajax response
				// index is updating object id, and value is the type of list we'll build there
				// options for type are:
				// display (shows fields),
				// list (gives a list of fields with checkboxes),
				// pers (builds a personalization dropdown)
				this.handlers = {};
				// sourceType is determining what is holding the RELIDs.
				// can be SELECT or CHECKBOX
				// default: SELECT
				this.sourceType = ( !props.sourceType ? 'SELECT' : props.sourceType );
				// which SELECT object is holding the list of RELIDs
				// which DIV object is holding the list of RELID checkboxes
				this.sourceId = ( !props.sourceId ? 'parentsList' : props.sourceId );
				// what is the name of CHECKBOXES that hold RELIDs
				this.sourceName = ( !props.sourceName ? 'p[]' : props.sourceName );
				// which API function to call
				this.api = ( !props.api ? 'list.list_field_update' : props.api );
				// which index in API response holds fields array
				this.responseIndex = ( !props.responseIndex ? 'row' : props.responseIndex );
				// any additional handlers (for some other data)?
				this.additionalHandler = ( !props.additionalHandler ? null : props.additionalHandler );
				// if global custom fields should be fetched or not
				this.includeGlobals = ( !props.includeGlobals ? 0 : props.includeGlobals );
				// if some custom param should be sent
				this.apiParam = ( !props.apiParam? '' : props.apiParam );
			},

		addHandler:
			function(targetId, type) {
				this.handlers[targetId] = type;
			},

		addCustomHandler:
			function(targetId, func, responseIndex) {
				this.handlers[targetId] = { func: func, responseIndex: responseIndex};
			},

		removeHandler:
			function(targetId) {
				if (typeof this.handlers[targetId] != "undefined")
					delete this.handlers[targetId];
			},

		fetch:
			function(id) {
				// fetch relation ids
				if ( this.sourceType == 'SELECT' ) {
					this.rels = ac_form_select_extract($(this.sourceId));
				} else if ( this.sourceType == 'CHECKBOX' ) {
					this.rels = ac_form_check_selection_get($(this.sourceId), this.sourceName);
				} else if ( this.sourceType != 'STATIC' ) {
					this.rels = [];
				}
				ACCustomFieldsObj = this;
				ac_ui_api_call(jsLoading);
				ac_ajax_call_cb('api.php', this.api, this.handle, id, this.rels.join('-'), this.includeGlobals, this.apiParam);
				somethingChanged = true;
			},

		handle:
			function(xml) {
				// need to use ACCustomFieldsObj instead of this ( a copy used for callback )
				var ary = ac_dom_read_node(xml);
				ac_ui_api_callback();
				ACCustomFieldsResult = ary[ACCustomFieldsObj.responseIndex];
				for ( var i in ACCustomFieldsObj.handlers ) {
					var type = ACCustomFieldsObj.handlers[i];
					if ( typeof type != 'function' ) {
						var targetObj = $(i);
						if ( !targetObj ) targetObj = i;
						if ( typeof type.func == 'function' ) {
							if ( !type.responseIndex ) type.responseIndex = ACCustomFieldsObj.responseIndex;
							if ( !type.targetObj ) type.targetObj = targetObj;
							type.func(ary[type.responseIndex], type.targetObj);
						} else if ( type == 'list' ) {
							ACCustomFieldsObj.handleList(ACCustomFieldsResult, targetObj);
						} else if ( type == 'pers' ) {
							ACCustomFieldsObj.handlePersonalization(ACCustomFieldsResult, targetObj, 'tag');
						} else if ( type == 'pers-with-id-values' ) {
							ACCustomFieldsObj.handlePersonalization(ACCustomFieldsResult, targetObj, 'id');
						} else if ( type == 'display' ) {
							ACCustomFieldsObj.handleDisplay(ACCustomFieldsResult, targetObj);
						} else if ( typeof(type) == 'function' ) {
							type(ACCustomFieldsResult, targetObj);
						}
					}
				}
				if ( typeof(ACCustomFieldsObj.additionalHandler) == 'function') {
					ACCustomFieldsObj.additionalHandler(ary);
				}
			},



		/* HANDLERS */


		handleList:
			function(ary, rel) {
				ac_dom_remove_children(rel);
				var total = 0;
				if ( ary ) {
					for ( var i = 0; i < ary.length; i++ ) {
						var row = ary[i];
						var props = { name: 'fields[]', id: 'custom' + row.id + 'Field', type: 'checkbox', value: row.id };
						if ( !this.selection || ac_array_has(this.selection, row.id) ) {
							props.checked = 'checked';
						}
						rel.appendChild(
							Builder.node(
								"tr",
								[
									Builder.node("td", [ Builder._text(" ") ]),
									Builder.node(
										"td",
										[
											Builder.node(
												'label',
												[
													Builder.node(
														'input',
														props
													),
													Builder._text(row.title)
												]
											)
										]
									)
								]
							)
						);
						total++;
					}
				}
			},

		handlePersonalization:
			function(ary, rel, elem) {
				if ( !elem ) elem = 'tag';
				// custom fields
				var nodesin  = [];
				// check if there is an existing group
				// if yes, we'll remove it first
				var optgroups = rel.getElementsByTagName('optgroup');
				for ( var i = 0; i < optgroups.length; i++ ) {
					if ( optgroups[i].label == strPersListFields ) {
						rel.removeChild(optgroups[i]);
						break;
					}
				}
				for ( var i in ary ) {
					var f = ary[i];
					if ( typeof f != 'function' ) {
						if ( !f.tag ) {
							if ( !f.perstag || f.perstag == '' ) {
								f.perstag = 'PERS_' + f.id;
							}
							f.tag = '%' + f.perstag + '%';
						}
						nodesin.push( Builder.node('option', { value: f[elem] }, [ Builder._text(f.title) ]));
					}
				}
				if ( nodesin.length > 0 ) {
					rel.appendChild(Builder.node('optgroup', { label: strPersListFields }, nodesin));
				}
				rel.selectedIndex = 0;
				//alert('handle personalization now!' + nodesin.length + rel.id);
			},

		handleDisplay:
			function(ary, targetId) {
				var rel = $(targetId);
				ac_dom_remove_children(rel);
				var total = 0;
				var visible = 0;
				if ( ary ) {
					for ( var i = 0; i < ary.length; i++ ) {
						var row = ary[i];
						var node = ac_custom_fields_cons(row, this.showhidden);
						if ( parseInt(row.type, 10) != 6 || this.showhidden ) {
							rel.appendChild(Builder.node(
								"tr",
								[
									Builder.node("td", { valign: 'top'/*, width: "75"*/ }, [ Builder._text(ac_custom_fields_title(row, this.showhidden)) ]),
									Builder.node("td", [ node ])
								]
							));
						} else {
							rel.appendChild(Builder.node(
								"tr",
								[
									Builder.node("td", [ Builder._text(" ") ]),
									Builder.node("td", [ node ])
								]
							));
						}
						total++;
						if ( parseInt(row.type, 10) != 6 ) visible++;
					}
				}
			}
	};
}

