// Phorum object. Other JavaScript code for Phorum can extend
// this one to implement functionality without risking name
// name space collissions.
Phorum = {};

/* Added by module "core", file "include/ajax/client.js.php" */
// Create the Phorum object if it's not available. It it created in the
// core javascript.php, but when loading this code from an external
// page, it might not be available.
if (!document.Phorum || Phorum == undefined) Phorum = {};

Phorum.Ajax = {};

// The version of this lib
Phorum.Ajax.version = '1.0.0';

// The URL that we use to access the Phorum Ajax layer.
Phorum.Ajax.URL = 'http://forum.paticik.com/ajax.php';

// Storage for Ajax call return data. This acts as a local cache
// for keeping track of already retrieved items.
Phorum.Ajax.cache = {};

/**
 * Create an XMLHttpRequest object.
 * Used internally by Phorum.Ajax.call().
 * Raise an onFailure event in case no object can be created.
 * Return either an object or null if the object creation failed.
 */
Phorum.Ajax.getXMLHttpRequest = function(req)
{
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        var versions = [
            'MSXML2.XMLHttp.5.0',
            'MSXML2.XMLHttp.4.0',
            'MSXML2.XMLHttp.3.0',
            'MSXML2.XMLHttp',
            'Microsoft.XMLHttp'
        ];
        for (var i=0; i < versions.length; i++) {
            try { xhr = new ActiveXObject(versions[i]); } catch (e) { }
        }
    }

    if (xhr) {
        return xhr;
    }

    if (req.onFailure) req.onFailure(
        'Phorum: Unable to create an XMLHttpRequest object',
        -1, null
    );
    return null;
};

/**
 * Execute an Ajax Phorum call.
 */
Phorum.Ajax.call = function(req)
{
    // If the store property is set for the request, then check
    // if the data for the request is already available in the
    // local cache. If yes, then return the data immediately.
    if (req.store) {
        if (req.store != null && Phorum.Ajax.cache[req.store]) {
            if (req.onSuccess) {
                // true = data retrieved from cache.
                req.onSuccess(Phorum.Ajax.cache[req.store], true);
            }
            return;
        }
    }

    // Check the request data.
    if (! req['call']) {
        if (req.onFailure) req.onFailure(
            'Phorum.Ajax.call() error: missing property ' +
            '"call" for the request object.',
            -1, null
        );
        return;
    }

    // Check if there is an XMLHttpRequest object available.
    var xhr = Phorum.Ajax.getXMLHttpRequest(req);
    if (! xhr) return;

    // Convert the request object to JSON.
    var json = Phorum.JSON.encode(req);

    // Notify the start of the request loading stage.
    if (req.onRequest) req.onRequest(json);

    xhr.open("post", Phorum.Ajax.URL, true);
    xhr.setRequestHeader("Content-Type", "text/x-json");
    xhr.onreadystatechange = function()
    {
      if (req.onReadStateChange) req.onReadyStateChange(req);

      switch (xhr.readyState)
      {
          case 1:

              if (req.onLoading) req.onLoading(xhr);
              break;

          case 2:

              if (req.onLoaded) req.onLoaded(xhr);
              break;

          case 3:

              if (req.onInteractive) req.onInteractive(xhr);
              break;

          case 4:

              if (req.onComplete)req.onComplete(xhr);

              if (req.onResponse) req.onResponse(xhr.responseText);

              if (xhr.status == 200) {

                  // Evaluate the returned JSON code. If evaluation fails,
                  // then run the onFailure event for the Phorum.Ajax.call.
                  try {
                      var res = Phorum.JSON.decode(xhr.responseText);
                  } catch (e) {
                      if (req.onFailure) req.onFailure(
                        'Ajax Phorum API call succeeded, but the return ' +
                        'data could not be parsed as JSON data.',
                        xhr.status, xhr.responseText
                      );
                      return;
                  }

                  // If the req.store property is set, then we store
                  // the result data in the Phorum cache.
                  if (req.store) Phorum.Ajax.cache[req.store] = res;

                  // false = data not retrieved from store.
                  if (req.onSuccess) req.onSuccess(res, false);

              } else {

                  if (req.onFailure) req.onFailure(
                      'The Ajax Phorum API call failed',
                      xhr.status, xhr.responseText
                  );
              }

              break;
      }
    };
    xhr.send(json);
};

// Invalidate a single cache item of the full cache.
Phorum.Ajax.invalidateCache = function(key)
{
    if (key) {
        Phorum.Ajax.cache[key] = null;
    } else {
        Phorum.Ajax.cache = new Array();
    }
};

// Parse out javascript blocks from the data to eval them. Adding them
// to the page using innerHTML does not invoke parsing by the browser.
Phorum.Ajax.evalJavaScript = function(data)
{
    var cursor = 0;
    var start  = 1;
    var end    = 1;

    while (cursor < data.length && start > 0 && end > 0) {
        start = data.indexOf('<script', cursor);
        end   = data.indexOf('</script', cursor);
        if (end > start && end > -1) {
            if (start > -1) {
                var res = data.substring(start, end);
                start = res.indexOf('>') + 1;
                res = res.substring(start);
                if (res.length != 0) {
                    eval(res);
                }
            }
            cursor = end + 1;
        }
    }
};

// ======================================================================
// JSON encoder and decoder
// Based on byteson by Andrea Giammarchi
// (http://www.devpro.it/byteson/)
// ======================================================================

Phorum.JSON = {};

Phorum.JSON.common =
{
  // characters object, useful to convert some char in a JSON compatible way
  c:{'\b':'b','\t':'t','\n':'n','\f':'f','\r':'r','"':'"','\\':'\\','/':'/'},

  // decimal function, returns a string with length === 2 for date convertion
  d:function(n){return n < 10 ? '0'.concat(n) : n},

  // integer function, returns integer value from a piece of string
  i:function(e, p, l){return parseInt(e.substr(p, l))},

  // slash function, add a slash before a common.c char
  s:function(i,d){return '\\'.concat(Phorum.JSON.common.c[d])},

  // unicode function, return respective unicode string
  u:function(i,d){var n = d.charCodeAt(0).toString(16);return '\\u'.concat(n.length < 2 ? '000' : '00', n)}
};

Phorum.JSON.convert = function(params, result)
{
    switch(params.constructor) {
        case Number:
            result = isFinite(params) ? String(params) : 'null';
            break;
        case Boolean:
            result = String(params);
            break;
        case Date:
            result = concat(
                '"',
                params.getFullYear(), '-',
                Phorum.JSON.common.d(params.getMonth() + 1), '-',
                Phorum.JSON.common.d(params.getDate()), 'T',
                Phorum.JSON.common.d(params.getHours()), ':',
                Phorum.JSON.common.d(params.getMinutes()), ':',
                Phorum.JSON.common.d(params.getSeconds()),
                '"'
            );
            break;
        case String:
            if(/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/.test(params)){
                result = new Date;
                result.setHours(Phorum.JSON.common.i(params, 11, 2));
                result.setMinutes(Phorum.JSON.common.i(params, 14, 2));
                result.setSeconds(Phorum.JSON.common.i(params, 17, 2));
                result.setMonth(Phorum.JSON.common.i(params, 5, 2) - 1);
                result.setDate(Phorum.JSON.common.i(params, 9, 2));
                result.setFullYear(Phorum.JSON.common.i(params, 0, 4));
            };
            break;
        default:
            var n, tmp = [];
            if(result) {
                for(n in params) result[n] = params[n];
            } else {
                for(n in params) {
                    if(params.hasOwnProperty(n) && !!(result = Phorum.JSON.encode(params[n])))
                        tmp.push(Phorum.JSON.encode(n).concat(':', result));
                };
                result = '{'.concat(tmp.join(','), '}');
            };
            break;
    };
    return result;
};

Phorum.JSON.encode = function(params)
{
    var result = '';

    if(params === null)
    {
        result = 'null';
    }
    else if(!{'function':1,'undefined':1,'unknown':1}[typeof(params)])
    {
        switch(params.constructor)
        {
            case Array:
                for(var i = 0, j = params.length, tmp = []; i < j; i++) {
                    if(!!(result = Phorum.JSON.encode(params[i])))
                        tmp.push(result);
                };
                result = '['.concat(tmp.join(','), ']');
                break;

            case String:
                result = '"'.concat(params.replace(
                        /(\x5c|\x2F|\x22|[\x0c-\x0d]|[\x08-\x0a])/g, Phorum.JSON.common.s
                    ).replace(
                        /([\x00-\x07]|\x0b|[\x0e-\x1f])/g, Phorum.JSON.common.u
                    ), '"');
                break;

            default:
                result = Phorum.JSON.convert(params);
                break;
        };
    };
    return result;
};

Phorum.JSON.decode = function(json)
{
    eval('var res = '+json);
    if (res === undefined) {
        throw new SyntaxError('The Phorum JSON data cannot be parsed');
    }
    return res;
};



/* Added by module "editor_tools", file "mods/editor_tools/editor_tools.js" */
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2008  Phorum Development Team                               //
// http://www.phorum.org                                                     //
//                                                                           //
// This program is free software. You can redistribute it and/or modify      //
// it under the terms of either the current Phorum License (viewable at      //
// phorum.org) or the Phorum License that was distributed with this file     //
//                                                                           //
// This program is distributed in the hope that it will be useful,           //
// but WITHOUT ANY WARRANTY, without even the implied warranty of            //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      //
//                                                                           //
// You should have received a copy of the Phorum License                     //
// along with this program.                                                  //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Javascript code for the Phorum editor_tools module.

// Valid object ids for textarea objects to handle. The first object
// that can be matched will be use as the object to work with.
// This is done to arrange for backward compatibility between
// Phorum versions.
var editor_tools_textarea_ids = new Array(
    'phorum_textarea',  // Phorum 5.1
    'body',             // Phorum 5.2
    'message'           // PM interface
);

// Valid object ids for subject text field objects to handle.
var editor_tools_subject_ids = new Array(
    'phorum_subject',   // Phorum 5.1
    'subject'           // Phorum 5.2
);

// Storage for language translation strings from the Phorum language system.
var editor_tools_lang = new Array();

// Some variables for storing objects that we need globally.
var editor_tools_textarea_obj = null;
var editor_tools_subject_obj = null;
var editor_tools_help_picker_obj = null;

// A variable for storing the current selection range of the 
// textarea. Needed for working around an MSIE problem.
var editor_tools_textarea_range = null;

// A variable for storing all popup objects that we have, so we
// can hide them all at once.
var editor_tools_popup_objects = new Array();

// Storage for the tools that have to be added to the editor tools panel.
// The array value contains the following fields:
//
// 1) the id for the tool (must be unique)
// 2) a description to use as the tooltip title for the button
// 3) the icon image to display as a button.
// 4) the javascript action to run when the user clicks the button
// 5) optional: the width of the icon image
// 6) optional: the height of the icon image (presumed 20px by default)
//
// This array will be filled from PHP-generated javascript.
var editor_tools = new Array();

// Storage for help chapters that must be put under the editor tools
// help button. The array value contains the following fields:
//
// 1) a description that will be used as the clickable link text.
// 2) the url for the help page (absolute or relative to the Phorum dir).
//
// This array will be filled from PHP-generated javascript.
var editor_tools_help_chapters = new Array();

// The dimensions of the help window.
var editor_tools_help_width = '400px';
var editor_tools_help_height = '400px';

// The default height for our icons.
// This one is filled from PHP-generated javascript.
var editor_tools_default_iconheight;

// A simple browser check. We need to know the browser version, because
// the color picker won't work on at least MacOS MSIE 5.
var OLD_MSIE =
    navigator.userAgent.indexOf('MSIE')>=0 &&
    navigator.appVersion.replace(/.*MSIE (\d\.\d).*/g,'$1')/1 < 6;

// ----------------------------------------------------------------------
// Uitilty functions
// ----------------------------------------------------------------------

// Find the Phorum textarea object and return it. In case of
// problems, null will be returned.
function editor_tools_get_textarea()
{
    if (editor_tools_textarea_obj != null) {
        return editor_tools_textarea_obj;
    }

    for (var i=0; editor_tools_textarea_ids[i]; i++) {
        editor_tools_textarea_obj =
            document.getElementById(editor_tools_textarea_ids[i]);
        if (editor_tools_textarea_obj) break;
    }

    if (! editor_tools_textarea_obj) {
        alert('editor_tools.js library reports: ' +
              'no textarea found on the current page.');
        return null;
    }

    return editor_tools_textarea_obj;
}

// Find the Phorum subject field object and return it. In case of
// problems, null will be returned.
function editor_tools_get_subjectfield()
{
    if (editor_tools_subject_obj != null) {
        return editor_tools_subject_obj;
    }

    for (var i=0; editor_tools_subject_ids[i]; i++) {
        editor_tools_subject_obj =
            document.getElementById(editor_tools_subject_ids[i]);
        if (editor_tools_subject_obj) break;
    }

    if (! editor_tools_subject_obj) {
        return null;
    }

    return editor_tools_subject_obj;
}

// Return a translated string, based on the Phorum language system.
function editor_tools_translate(str)
{
    if (editor_tools_lang[str]) {
        return editor_tools_lang[str];
    } else {
        return str;
    }
}

// Strip whitespace from the start and end of a string.
function editor_tools_strip_whitespace(str, return_stripped)
{
    var strip_pre = '';
    var strip_post = '';

    // Strip whitespace from end of string.
    for (;;) {
        var lastchar = str.substring(str.length-1, str.length);
        if (lastchar == ' '  || lastchar == '\r' ||
            lastchar == '\n' || lastchar == '\t') {
            strip_post = lastchar + strip_post;

            str = str.substring(0, str.length-1);
        } else {
            break;
        }
    }

    // Strip whitespace from start of string.
    for (;;) {
        var firstchar = str.substring(0,1);
        if (firstchar == ' '  || firstchar == '\r' ||
            firstchar == '\n' || firstchar == '\t') {
            strip_pre += firstchar;
            str = str.substring(1);
        } else {
            break;
        }
    }

    if (return_stripped) {
        return new Array(str, strip_pre, strip_post);
    } else {
        return str;
    }
} 

// Close all popup windows and move the focus to the textarea.
function editor_tools_focus_textarea()
{
    var textarea_obj = editor_tools_get_textarea();
    if (textarea_obj == null) return;
    editor_tools_hide_all_popups();
    textarea_obj.focus();
}

// Close all popup windows and move the focus to the subject field.
function editor_tools_focus_subjectfield()
{
    var subjectfield_obj = editor_tools_get_subjectfield();
    if (subjectfield_obj == null) return;
    editor_tools_hide_all_popups();
    subjectfield_obj.focus();
}

// ----------------------------------------------------------------------
// Construction of the editor tools
// ----------------------------------------------------------------------

// Add the editor tools panel to the page.
function editor_tools_construct()
{
    var textarea_obj;
    var div_obj;
    var parent_obj;
    var a_obj;
    var img_obj;

    // If the browser does not support document.getElementById,
    // then the javascript code won't run. Do not display the
    // editor tools at all in that case.
    if (! document.getElementById) return;

    // No editor tools selected to display? Then we're done.
    if (editor_tools.length == 0) return;

    // Find the textarea and subject field object.
    textarea_obj = editor_tools_get_textarea();
    if (textarea_obj == null) return; // we consider this fatal.
    var subjectfield_obj = editor_tools_get_subjectfield();

    // Insert a <div> for containing the buttons, just before the textarea,
    // unless there is already an object with id "editor-tools". In that
    // case, the existing object is used instead.
    div_obj = document.getElementById('editor-tools');
    if (! div_obj) {
        parent_obj = textarea_obj.parentNode;
        div_obj = document.createElement('div');
        div_obj.id = 'editor-tools';
        parent_obj.insertBefore(div_obj, textarea_obj);
    }

    // Add the buttons to the new <div> for the editor tools.
    for (var i = 0; i < editor_tools.length; i++)
    {
        var toolinfo    = editor_tools[i];
        var tool        = toolinfo[0];
        var description = toolinfo[1];
        var icon        = toolinfo[2];
        var jsaction    = toolinfo[3];
        var iwidth      = toolinfo[4];
        var iheight     = toolinfo[5];
        var target      = toolinfo[6];

        // Do not use the color picker on MSIE 5. I tested this on a
        // Macintosh OS9 system and the color picker about hung MSIE.
        if (tool == 'color' && OLD_MSIE) continue;

        a_obj = document.createElement('a');
        a_obj.id = 'editor-tools-a-' + tool;
        a_obj.href = 'javascript:' + jsaction;

        img_obj = document.createElement('img');
        img_obj.id = 'editor-tools-img-' + tool;
        img_obj.className = 'editor-tools-button';
        img_obj.src = icon;
        img_obj.width = iwidth;
        img_obj.height = iheight;
        img_obj.style.padding = '2px';
        img_obj.alt = description;
	img_obj.title = description;

        // If an icon is added that is less high than our default icon
        // height, we try to make the button the same height as the
        // others by adding some dynamic padding to it.
        if (iheight < editor_tools_default_iconheight) {
            var fill = editor_tools_default_iconheight - iheight;
            var addbottom = Math.round(fill / 2);
            var addtop = fill - addbottom;
            img_obj.style.paddingTop = (addtop + 2) + 'px';
            img_obj.style.paddingBottom = (addbottom + 2) + 'px';
        }
        a_obj.appendChild(img_obj);

        // Add the button to the page.
        // target = subject is a feature that was added for supporting
        // the subjectsmiley tool. This one is added to the subject field
        // instead of the textarea. 
        if (target == 'subject') {
            // Find the subject text field. If we can't find one,
            // then simply ignore this tool.
            if (subjectfield_obj) {
                img_obj.style.verticalAlign = 'top';
                var parent = subjectfield_obj.parentNode;
                var sibling = subjectfield_obj.nextSibling;
                parent.insertBefore(a_obj, sibling);
            }
        } else {
            div_obj.appendChild(a_obj);
        }
    }

    // Hide any open popup when the user clicks the textarea or subject field.
    textarea_obj.onclick = function() {
        editor_tools_hide_all_popups();
    };
    if (subjectfield_obj) {
        subjectfield_obj.onclick = function() {
            editor_tools_hide_all_popups();
        }
    }
}

// ----------------------------------------------------------------------
// Popup window utilities
// ----------------------------------------------------------------------

// Create a popup window.
function editor_tools_construct_popup(create_id, anchor)
{
    // Create the outer div for the popup window.
    var popup_obj = document.createElement('div');
    popup_obj.id = create_id;
    popup_obj.className = 'editor-tools-popup';
    popup_obj.style.display = 'none';
    document.getElementById('editor-tools').appendChild(popup_obj);

    popup_obj._anchor = anchor;

    // Create the inner content div.
    var content_obj = document.createElement('div');
    content_obj.id = create_id + '-content';
    popup_obj.appendChild(content_obj);

    return new Array(popup_obj, content_obj);
}

// Toggle a popup window.
function editor_tools_toggle_popup(popup_obj, button_obj, width, leftoffset)
{
    // Determine where to show the popup on screen.
    var work_obj = button_obj;
    var top = work_obj.offsetTop + work_obj.offsetHeight + 2;
    var left = work_obj.offsetLeft;

    while (work_obj.offsetParent != null) {
        work_obj = work_obj.offsetParent;
        left += work_obj.offsetLeft;
        top += work_obj.offsetTop;
    }

    if (leftoffset) left -= leftoffset;
    if (width) popup_obj.style.width = width;

    // Move the popup window to the right place.
    if (popup_obj._anchor == 'r')
    {
        // Determine the screen width.
        var scrwidth = null;
        if (document.documentElement.clientWidth) {
            // Firefox screen width.
            scrwidth = document.documentElement.clientWidth;
        } else {
            scrwidth = document.body.clientWidth;
            // -16 for scrollbar that is counted in in some browsers.
            if (document.getElementById && !document.all) {
                scrwidth -= 16;
            }
        }

        var right = scrwidth - left - button_obj.offsetWidth;

        popup_obj.style.right = right + 'px';
        popup_obj.style.top = top + 'px';
    } else {
        popup_obj.style.left = left + 'px';
        popup_obj.style.top = top + 'px';
    }

    // Toggle the popup window's visibility.
    if (popup_obj.style.display == 'none') {
        editor_tools_hide_all_popups();
        popup_obj.style.display = 'block';
    } else {
        popup_obj.style.display = 'none';
        editor_tools_focus_textarea();
    }
}

// Register an object as a popup, so editor_tools_hide_all_popups() 
// can hide it.
function editor_tools_register_popup_object(object)
{
    if (! object) return;
    editor_tools_popup_objects[editor_tools_popup_objects.length] = object;
}

// Hide all objects that were registered as a popup.
function editor_tools_hide_all_popups()
{
    for (var i = 0; i < editor_tools_popup_objects.length; i++) {
        var object = editor_tools_popup_objects[i];
        object.style.display = 'none';
    }
}

// Save the selection range of the textarea. This is needed because
// sometimes clicking in a popup can clear the selection in MSIE.
function editor_tools_store_range()
{
    var ta = editor_tools_get_textarea();
    if (ta == null || ta.setSelectionRange || ! document.selection) return;
    ta.focus();
    editor_tools_textarea_range = document.selection.createRange();
}

// Restored a saved textarea selection range.
function editor_tools_restore_range()
{
    if (editor_tools_textarea_range != null)
    {
        editor_tools_textarea_range.select();
        editor_tools_textarea_range = null;
    }
}

// ----------------------------------------------------------------------
// Textarea manipulation
// ----------------------------------------------------------------------

// Add tags to the textarea. If some text is selected, then place the
// tags around the selected text. If no text is selected and a prompt_str
// is provided, then prompt the user for the data to place inside
// the tags.
function editor_tools_add_tags(pre, post, target, prompt_str)
{
    var text;
    var pretext;
    var posttext;
    var range;
    var ta = target ? target : editor_tools_get_textarea();
    if (ta == null) return;

    // Store the current scroll offset, so we can restore it after
    // adding the tags to its contents.
    var offset = ta.scrollTop;

    if (ta.setSelectionRange)
    {
        // Get the currently selected text.
        pretext = ta.value.substring(0, ta.selectionStart);
        text = ta.value.substring(ta.selectionStart, ta.selectionEnd);
        posttext = ta.value.substring(ta.selectionEnd, ta.value.length);

        // Prompt for input if no text was selected and a prompt is set.
        if (text == '' && prompt_str) {
            text = prompt(prompt_str, '');
            if (text == null) return;
        }

        // Strip whitespace from text selection and move it to the
        // pre- and post.
        var res = editor_tools_strip_whitespace(text, true);
        text = res[0];
        pre = res[1] + pre;
        post = post + res[2];

        ta.value = pretext + pre + text + post + posttext;

        // Reselect the selected text.
        var cursorpos1 = pretext.length + pre.length;
        var cursorpos2 = cursorpos1 + text.length;
        ta.setSelectionRange(cursorpos1, cursorpos2);
        ta.focus();
    }
    else if (document.selection) /* MSIE support */
    {
        // Get the currently selected text.
        ta.focus();
        range = document.selection.createRange();

        // Fumbling to work around newline selections at the end of
        // the text selection. MSIE does not include them in the
        // range.text, but it does replace them when setting range.text
        // to a new value :-/
        var virtlen = range.text.length;
        if (virtlen > 0) {
            while (range.text.length == virtlen) {
                range.moveEnd('character', -1);
            }
            range.moveEnd('character', +1);
        }

        // Prompt for input if no text was selected and a prompt is set.
        text = range.text;
        if (text == '' && prompt_str) {
            text = prompt(prompt_str, '');
            if (text == null) return;
        }

        // Strip whitespace from text selection and move it to the
        // pre- and post.
        var res = editor_tools_strip_whitespace(text, true);
        text = res[0];
        pre = res[1] + pre;
        post = post + res[2];

        // Add pre and post to the text.
        range.text = pre + text + post;

        // Reselect the selected text. Another MSIE anomaly has to be
        // taken care of here. MSIE will include carriage returns
        // in the text.length, but it does not take them into account
        // when using selection range moving methods :-/
        // By setting the range.text before, the cursor is now after
        // the replaced code, so we will move the start and the end
        // back in the text.
        var mvstart = post.length + text.length -
                      ((text + post).split('\r').length - 1);
        var mvend   = post.length +
                      (post.split('\r').length - 1);
        range.moveStart('character', -mvstart);
        range.moveEnd('character', -mvend);
        range.select();
    }
    else /* Support for really limited browsers, e.g. MSIE5 on MacOS */
    {
        ta.value = ta.value + pre + post;
    }

    ta.scrollTop = offset;
}

// ----------------------------------------------------------------------
// Tool: Help
// ----------------------------------------------------------------------

function editor_tools_handle_help()
{
    var c = editor_tools_help_chapters;

    // Shouldn't happen.
    if (c.length == 0) {
        alert('No help chapters available');
        return;
    }

    // Exactly one help chapter available. Immediately open the chapter.
    if (c.length == 1) {
        editor_tools_handle_help_select(c[0][1]);
        return;
    }

    // Multiple chapters available. Show a help picker menu with some
    // choices. Create the help picker on first access.
    if (!editor_tools_help_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-help-picker','r');
        editor_tools_help_picker_obj = popup[0];
        var content_obj = popup[1];

        // Populate the new popup.
        for (var i = 0; i < editor_tools_help_chapters.length; i++) 
        {
            var helpinfo = editor_tools_help_chapters[i];
            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_help_select("' + helpinfo[1] + '")';
            a_obj.innerHTML = helpinfo[0];
            content_obj.appendChild(a_obj);
            content_obj.appendChild(document.createElement('br'));
        }

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_help_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-help');
    editor_tools_toggle_popup(editor_tools_help_picker_obj, button_obj);
}

function editor_tools_handle_help_select(url)
{
    var help_window = window.open(
        url,
        'editor_tools_help',
        'resizable=yes,' +
        'menubar=no,' +
        'directories=no,' +
        'scrollbars=yes,' +
        'toolbar=no,' +
        'status=no,' +
        'width=' + editor_tools_help_width + ',' +
        'height=' + editor_tools_help_height
    );

    editor_tools_focus_textarea();
    help_window.focus();
}



/* Added by module "smileys", file "mods/smileys/smileys_editor_tools.js.php" */
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2007  Phorum Development Team                               //
// http://www.phorum.org                                                     //
//                                                                           //
// This program is free software. You can redistribute it and/or modify      //
// it under the terms of either the current Phorum License (viewable at      //
// phorum.org) or the Phorum License that was distributed with this file     //
//                                                                           //
// This program is distributed in the hope that it will be useful,           //
// but WITHOUT ANY WARRANTY, without even the implied warranty of            //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      //
//                                                                           //
// You should have received a copy of the Phorum License                     //
// along with this program.                                                  //
///////////////////////////////////////////////////////////////////////////////

// Javascript code for Smileys support in the Phorum editor_tools module.

// Some variables for storing objects that we need globally.
var editor_tools_smiley_picker_obj = null;
var editor_tools_subjectsmiley_picker_obj = null;

// Smileys for the smiley picker.
// *_s = search strings (smileys)
// *_r = replace strings (image urls)
var editor_tools_smileys = new Array();
var editor_tools_smileys_r = new Array();
var editor_tools_smileys_a = new Array();
var editor_tools_subjectsmileys = new Array();
var editor_tools_subjectsmileys_r = new Array();
var editor_tools_subjectsmileys_a = new Array();

// The width and offset to the left for the smiley picker popup menus.
// These values can be tweaked from the smiley module settings page.
var editor_tools_smileys_popupwidth = '150px';
var editor_tools_smileys_popupoffset = 0;
var editor_tools_subjectsmileys_popupwidth = '150px';
var editor_tools_subjectsmileys_popupoffset = 0;

// The available smileys.
editor_tools_smileys[0] = '(:P)';
editor_tools_smileys_r[0] = 'http://forum.paticik.com/./mods/smileys/images/smiley25.gif';
editor_tools_smileys_a[0] = 'spinning smiley sticking its tongue out';
editor_tools_smileys[1] = '(td)';
editor_tools_smileys_r[1] = 'http://forum.paticik.com/./mods/smileys/images/smiley23.gif';
editor_tools_smileys_a[1] = 'thumbs down';
editor_tools_smileys[2] = '(tu)';
editor_tools_smileys_r[2] = 'http://forum.paticik.com/./mods/smileys/images/smiley24.gif';
editor_tools_smileys_a[2] = 'thumbs up';
editor_tools_smileys[3] = ':)-D';
editor_tools_smileys_r[3] = 'http://forum.paticik.com/./mods/smileys/images/smiley15.gif';
editor_tools_smileys_a[3] = 'smileys with beer';
editor_tools_smileys[4] = '>:D<';
editor_tools_smileys_r[4] = 'http://forum.paticik.com/./mods/smileys/images/smiley14.gif';
editor_tools_smileys_a[4] = 'the finger smiley';
editor_tools_smileys[5] = '(:D';
editor_tools_smileys_r[5] = 'http://forum.paticik.com/./mods/smileys/images/smiley12.gif';
editor_tools_smileys_a[5] = 'smiling bouncing smiley';
editor_tools_smileys[6] = '8-)';
editor_tools_smileys_r[6] = 'http://forum.paticik.com/./mods/smileys/images/smilie8.gif';
editor_tools_smileys_a[6] = 'eye rolling smiley';
editor_tools_smileys[7] = ':)o';
editor_tools_smileys_r[7] = 'http://forum.paticik.com/./mods/smileys/images/smiley16.gif';
editor_tools_smileys_a[7] = 'drinking smiley';
editor_tools_smileys[8] = '::o';
editor_tools_smileys_r[8] = 'http://forum.paticik.com/./mods/smileys/images/smilie10.gif';
editor_tools_smileys_a[8] = 'eye popping smiley';
editor_tools_smileys[9] = 'B)-';
editor_tools_smileys_r[9] = 'http://forum.paticik.com/./mods/smileys/images/smilie7.gif';
editor_tools_smileys_a[9] = 'smoking smiley';
editor_tools_smileys[10] = ':(';
editor_tools_smileys_r[10] = 'http://forum.paticik.com/./mods/smileys/images/smilie2.gif';
editor_tools_smileys_a[10] = 'sad smiley';
editor_tools_smileys[11] = ':)';
editor_tools_smileys_r[11] = 'http://forum.paticik.com/./mods/smileys/images/smilie1.gif';
editor_tools_smileys_a[11] = 'smiling smiley';
editor_tools_smileys[12] = ':?';
editor_tools_smileys_r[12] = 'http://forum.paticik.com/./mods/smileys/images/smiley17.gif';
editor_tools_smileys_a[12] = 'moody smiley';
editor_tools_smileys[13] = ':D';
editor_tools_smileys_r[13] = 'http://forum.paticik.com/./mods/smileys/images/smilie5.gif';
editor_tools_smileys_a[13] = 'grinning smiley';
editor_tools_smileys[14] = ':P';
editor_tools_smileys_r[14] = 'http://forum.paticik.com/./mods/smileys/images/smilie6.gif';
editor_tools_smileys_a[14] = 'tongue sticking out smiley';
editor_tools_smileys[15] = ':S';
editor_tools_smileys_r[15] = 'http://forum.paticik.com/./mods/smileys/images/smilie11.gif';
editor_tools_smileys_a[15] = 'confused smiley';
editor_tools_smileys[16] = ':X';
editor_tools_smileys_r[16] = 'http://forum.paticik.com/./mods/smileys/images/smilie9.gif';
editor_tools_smileys_a[16] = 'angry smiley';
editor_tools_smileys[17] = ':o';
editor_tools_smileys_r[17] = 'http://forum.paticik.com/./mods/smileys/images/smilie4.gif';
editor_tools_smileys_a[17] = 'yawning smiley';
editor_tools_smileys[18] = ';)';
editor_tools_smileys_r[18] = 'http://forum.paticik.com/./mods/smileys/images/smilie3.gif';
editor_tools_smileys_a[18] = 'winking smiley';
editor_tools_smileys[19] = 'B)';
editor_tools_smileys_r[19] = 'http://forum.paticik.com/./mods/smileys/images/cool.gif';
editor_tools_smileys_a[19] = 'cool smiley';
editor_tools_smileys[20] = 'X(';
editor_tools_smileys_r[20] = 'http://forum.paticik.com/./mods/smileys/images/hot.gif';
editor_tools_smileys_a[20] = 'hot smiley';

// ----------------------------------------------------------------------
// Tool: smiley
// ----------------------------------------------------------------------

function editor_tools_handle_smiley()
{
    // Create the smiley picker on first access.
    if (!editor_tools_smiley_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-smiley-picker','l');
        editor_tools_smiley_picker_obj = popup[0];
        var content_obj = popup[1];

        editor_tools_smiley_picker_obj.style.width = editor_tools_smileys_popupwidth;

        // Populate the new popup.
        for (var i = 0; i < editor_tools_smileys.length; i++)
        {
            var s = editor_tools_smileys[i];
            var r = editor_tools_smileys_r[i];
            var a = editor_tools_smileys_a[i];
            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_smiley_select("'+s+'")';
            var img_obj = document.createElement('img');
            img_obj.src = r;
            img_obj.title = a;
            img_obj.alt = a;
            a_obj.appendChild(img_obj);

            content_obj.appendChild(a_obj);
        }

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_smiley_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-smiley');
    editor_tools_toggle_popup(
        editor_tools_smiley_picker_obj,
        button_obj,
        editor_tools_smileys_popupwidth,
        editor_tools_smileys_popupoffset
    );
}

// Called by the smiley picker.
function editor_tools_handle_smiley_select(smiley)
{
    smiley = editor_tools_strip_whitespace(smiley);
    editor_tools_add_tags(smiley, '');
    editor_tools_focus_textarea();
}

function editor_tools_handle_subjectsmiley()
{
    // Create the smiley picker on first access.
    if (!editor_tools_subjectsmiley_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-subjectsmiley-picker','l');
        editor_tools_subjectsmiley_picker_obj = popup[0];
        var content_obj = popup[1];

        // Populate the new popup.
        for (var i = 0; i < editor_tools_subjectsmileys.length; i++)
        {
            var s = editor_tools_subjectsmileys[i];
            var r = editor_tools_subjectsmileys_r[i];
            var a = editor_tools_subjectsmileys_a[i];

            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_subjectsmiley_select("'+s+'")';
            var img_obj = document.createElement('img');
            img_obj.src = r;
            img_obj.alt = a;
            img_obj.title = a;
            a_obj.appendChild(img_obj);
            content_obj.appendChild(a_obj);
        }

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_subjectsmiley_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-subjectsmiley');
    editor_tools_toggle_popup(
        editor_tools_subjectsmiley_picker_obj,
        button_obj,
        editor_tools_subjectsmileys_popupwidth,
        editor_tools_subjectsmileys_popupoffset
    );
}

// Called by the subject smiley picker.
function editor_tools_handle_subjectsmiley_select(smiley)
{
    smiley = editor_tools_strip_whitespace(smiley);
    editor_tools_add_tags(smiley, '', editor_tools_subject_obj);
    editor_tools_focus_subjectfield();
}

// ----------------------------------------------------------------------
// Tool: subject smiley
// ----------------------------------------------------------------------

function editor_tools_handle_subjectsmiley()
{
    // Create the smiley picker on first access.
    if (!editor_tools_subjectsmiley_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-subjectsmiley-picker','l');
        editor_tools_subjectsmiley_picker_obj = popup[0];
        var content_obj = popup[1];

        // Populate the new popup.
        for (var i = 0; i < editor_tools_subjectsmileys.length; i++)
        {
            var s = editor_tools_subjectsmileys[i];
            var r = editor_tools_subjectsmileys_r[i];
            var a = editor_tools_subjectsmileys_a[i];

            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_subjectsmiley_select("'+s+'")';
            var img_obj = document.createElement('img');
            img_obj.src = r;
            img_obj.alt = a;
            img_obj.title = a;
            a_obj.appendChild(img_obj);
            content_obj.appendChild(a_obj);
        }

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_subjectsmiley_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-subjectsmiley');
    editor_tools_toggle_popup(
        editor_tools_subjectsmiley_picker_obj,
        button_obj,
        editor_tools_subjectsmileys_popupwidth,
        editor_tools_subjectsmileys_popupoffset
    );
}

// Called by the subject smiley picker.
function editor_tools_handle_subjectsmiley_select(smiley)
{
    smiley = editor_tools_strip_whitespace(smiley);
    editor_tools_add_tags(smiley, '', editor_tools_subject_obj);
    editor_tools_focus_subjectfield();
}



/* Added by module "bbcode", file "mods/bbcode_video/bbcode_video.js" */
function bbcode_video_editor_tool()
{
    editor_tools_add_tags(
        '[video]', '[/video]',
        null,
        editor_tools_translate("enter video url")
    );

    editor_tools_focus_textarea();
}


/* Added by module "bbcode_spoiler", file "mods/bbcode_spoiler/bbcode_spoiler.js" */
function bbcode_spoiler_editor_tool()
{
    var description = prompt(
        editor_tools_translate("enter spoiler description"), ''
    );
    if (description == null) return; // Cancel clicked.
    description = editor_tools_strip_whitespace(description);

    var starttag = description == ''
                 ? "[spoiler]\n"
                 : "[spoiler=" + description + "]\n";

    editor_tools_add_tags(starttag, "\n[\/spoiler]\n", null, editor_tools_translate("enter spoiler content"));
    editor_tools_focus_textarea();
}

function bbcode_spoiler_show(spoiler_id)
{
    var s = document.getElementById('bbcode_spoiler_'+spoiler_id);
    if (!s) {
        alert("Internal error: can't find spoiler div");
        return true;
    }

    // An extra id which can be used in the spoiler template and which
    // will be made visible or invisible, along with the spoiler content.
    // It's intended use is to add some close link at the bottom of
    // the spoiler content.
    var c = document.getElementById('bbcode_spoiler_close_'+spoiler_id);

    // Switch visibility of the spoiler content if the spoiler's content
    // was already loaded. If the display style is "block" then the
    // content could have been included by loading the page through a
    // "view_spoiler" URL. For that case, we set "is_loaded" explicitly
    // here.
    if (s.is_loaded || s.style.display == 'block')
    {
        var a = document.getElementById('bbcode_spoiler_link_'+spoiler_id);

        if (s.style.display == 'block') {
            s.style.display = 'none';
            if (c) c.style.display = 'none';
            s.is_loaded = 1;
            if (a) a.className = 'bbcode_spoiler_link';
        } else {
            s.style.display = 'block';
            if (c) c.style.display = 'block';
            if (a) a.className = 'bbcode_spoiler_link_view';
        }
        return false;
    }

    // Create the XMLHttpRequest object that we can use to send an
    // Ajax request to the server.
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        var versions = [
            "MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0",
            "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp",
            "Microsoft.XMLHttp"
        ];
        for (var i=0; i < versions.length; i++)
          try { xhr = new ActiveXObject(versions[i]); } catch (e) { }
    }

    if (!xhr) return true;

    // Setup a loading... indicator.
    var a = document.getElementById('bbcode_spoiler_link_'+spoiler_id);
    if (a) a.className = 'bbcode_spoiler_link_loading';

    // Send the request to the server.
    xhr.open("post", bbcode_spoiler_ajax_url, true);
    xhr.setRequestHeader("Content-Type", "text\/plain");
    xhr.onreadystatechange = function()
    {
        if (xhr.readyState != 4) return;

        if (xhr.status == 200) {
            addToElement(s, xhr.responseText);
            if (a) a.className = 'bbcode_spoiler_link_view';
            if (c) c.style.display = 'block';
            s.style.display = 'block';
            s.is_loaded = 1;
        }
    }
    xhr.send("retrieve "+spoiler_id);

    return false;
}

function addToElement(elt, response)
{
    var cursor = 0;
    var start  = 1;
    var end    = 1;

    // Add the response data to the page element.
    elt.innerHTML = response;

    // Parse out javascript blocks to eval them. Adding them to the
    // page using innerHTML does not invoke parsing by the browser.
    while (cursor < response.length && start > 0 && end > 0) {
        start = response.indexOf('<script', cursor);
        end   = response.indexOf('<\/script', cursor);
        if (end > start && end > -1) {
            if (start > -1) {
                var res = response.substring(start, end);
                start = res.indexOf('>') + 1;
                res = res.substring(start);
                if (res.length != 0) {
                    eval(res);
                }
            }
            cursor = end + 1;
        }
    }
}


/* Added by module "jumpmenu", file "mods/jumpmenu/jumpmenu.js" */
var PhorumJumpMenu =
{
    'active'      : {},
    'visible'     : {},
    'menuspacing' : -1,
    'timer'       : null,
    'vroot'       : 0, // will be set separately from the jumpmenu.php code

    'init': function()
    {
        // Make sure that events will not fire at unload time, because that
        // generates JavaScript warnings in Firefox about PhorumJumpMenu
        // that does not exist anymore at that time.
        var oldunload = window.onunload;
        window.onunload = function()
        {
            if (oldunload) oldunload();
            var root = document.getElementById('mod_jumpmenu_root');
            if (root) {
                root.onmouseover = null;
                root.onmouseout  = null;
            }
            var ahrefs = document.getElementsByTagName('a');
            for (var i=0; i<ahrefs.length; i++)
            {
                if (!ahrefs[i].rel) continue;
                var obj = ahrefs[i];

                if (obj.rel.indexOf('mod_jumpmenu_') == 0) {
                    obj.onmouseover = null;
                    obj.onmouseout  = null;
                }
            }
        }

        // Events for the root jumpmenu item.
        var r = document.getElementById('mod_jumpmenu_root');
        if (!r) return;
        r.onmouseover = function() {
            PhorumJumpMenu.stopCloseTimer();
            PhorumJumpMenu.openSubMenu(null);
        };
        r.onmouseout  = function() {
            PhorumJumpMenu.startCloseTimer();
        };

        // Events for the folders and forums.
        var ahrefs = document.getElementsByTagName('a');
        for (var i=0; i<ahrefs.length; i++)
        {
            if (!ahrefs[i].rel) continue;
            var obj = ahrefs[i];

            if (obj.rel == 'mod_jumpmenu_forum')
            {
                obj.onmouseover = function() {
                    PhorumJumpMenu.stopCloseTimer();
                    PhorumJumpMenu.openSubMenu(this);
                };
                obj.onmouseout  = function() {
                    PhorumJumpMenu.startCloseTimer();
                };
            }
            else if (obj.rel.substring(0,19) == 'mod_jumpmenu_folder')
            {
                var info = obj.rel.substring(20, obj.rel.length-1).split(',');
                obj.menu_id   = info[0];
                obj.parent_id = info[1];

                obj.onmouseover = function() {
                    PhorumJumpMenu.stopCloseTimer();
                    PhorumJumpMenu.openSubMenu(this);
                };
                obj.onmouseout  = function() {
                    PhorumJumpMenu.startCloseTimer();
                };
            }
        }
    },

    'hideAll': function()
    {
        for (var depth in PhorumJumpMenu.visible) {
            for (var idx in PhorumJumpMenu.visible[depth]) {
                var o = PhorumJumpMenu.visible[depth][idx];
                o.style.display = 'none';

                if (o.work_around_iframe) {
                    o.work_around_iframe.style.display = 'none';
                }
            }
        }

        PhorumJumpMenu.active = {};
        PhorumJumpMenu.visible = {};
    },

    'startCloseTimer': function()
    {
        if (PhorumJumpMenu.timer != null) {
            clearTimeout(PhorumJumpMenu.timer);
        }
        PhorumJumpMenu.timer = setTimeout(function() {
            PhorumJumpMenu.timer = null;
            PhorumJumpMenu.hideAll();
        }, 500);
    },

    'stopCloseTimer': function()
    {
        if (PhorumJumpMenu.timer != null) {
            clearTimeout(PhorumJumpMenu.timer);
            PhorumJumpMenu.timer = null;
        }
    },

    // Thanks to www.quirksmode.org for info on viewport properties:
    // http://www.quirksmode.org/viewport/compatibility.html
    'getScreenInfo': function()
    {
        var width, height;
        // All, except Explorer.
        if (self.innerHeight) {
            width  = self.innerWidth;
            height = self.innerHeight;
        }
        // Explorer 6 Strict Mode.
        else if (document.documentElement &&
                 document.documentElement.clientHeight) {
            width  = document.documentElement.clientWidth;
            height = document.documentElement.clientHeight;
        }
        // Other Explorers.
        else if (document.body) {
            width  = document.body.clientWidth;
            height = document.body.clientHeight;
        }

        // -16 for scrollbar that is counted in in some browsers.
        width  -= 16;
        height -= 16;

        var scroll_x, scroll_y;
        // All, except Explorer.
        if (self.pageYOffset) {
                scroll_x = self.pageXOffset;
                scroll_y = self.pageYOffset;
        }
        // Explorer 6 Strict.
        else if (document.documentElement && document.documentElement.scrollTop) {
                scroll_x = document.documentElement.scrollLeft;
                scroll_y = document.documentElement.scrollTop;
        }
        // All other Explorers.
        else if (document.body) {
                scroll_x = document.body.scrollLeft;
                scroll_y = document.body.scrollTop;
        }

        return {
            'width'     : width,
            'height'    : height,
            'scroll_x'  : scroll_x,
            'scroll_y'  : scroll_y,
            'visible_x' : width + scroll_x,
            'visible_y' : height + scroll_y
        };
    },

    'getStyle': function(obj, element)
    {
        if (obj.currentStyle) {
            return obj.currentStyle[element];
        } else if (window.getComputedStyle) {
            var s = document.defaultView.getComputedStyle(obj, null);
            return s.getPropertyValue(element);
        } else {
            return null;
        }
    },

    'getScreenPos': function(obj)
    {
        var top = left = 0;
        var rel_top = rel_left = null;

        do {
            top  += obj.offsetTop;
            left += obj.offsetLeft;
            if (obj && rel_top == null) {
                var pos = PhorumJumpMenu.getStyle(obj, 'position');
                if (pos == 'relative' || pos == 'absolute') {
                    rel_top  = top;
                    rel_left = left;
                }
            }
            obj = obj.offsetParent;
        } while (obj);

        if (rel_left == null) {
            rel_left = left;
            rel_top  = top;
        }

        return {
            'top'      : top,
            'left'     : left,
            'rel_left' : rel_left,
            'rel_top'  : rel_top
        };
    },

    'openSubMenu': function(menu_item)
    {
        // If the menu item is not a folder, then find its parent menu.
        // This way, deeper submenus that are possibly opened
        // will be collapsed.
        var menu = menu_item;
        if (menu_item && menu_item.className.indexOf('mod_jumpmenu_folder') == -1) {
            var n = menu.parentNode.id;
            if (n.indexOf('mod_jumpmenu_menu_content_') == 0) {
                var menu_id = n.substr(26);
                if (menu_id == PhorumJumpMenu.vroot) {
                    menu = null;
                } else {
                    var pid = 'mod_jumpmenu_item_' + menu_id;
                    var p = document.getElementById(pid);
                    if (p) menu = p;
                }
            }
        }

        // Find the parent menu, parent item and child menu.
        var menu_id   = menu == null ? PhorumJumpMenu.vroot : menu.menu_id;
        var parent_id = menu == null ? null : menu.parent_id;
        var p_menu = menu_id == PhorumJumpMenu.vroot 
              ? null
              : document.getElementById('mod_jumpmenu_menu_' + parent_id);
        var p_item = menu_id == PhorumJumpMenu.vroot
              ? document.getElementById('mod_jumpmenu_root')
              : document.getElementById('mod_jumpmenu_item_' + menu_id);
        var c_menu = document.getElementById('mod_jumpmenu_menu_' + menu_id);


        // Handle highlighting of the active menu item.
        // Clear all highlights in the child menu. 
        if (c_menu) {
            var ahrefs = c_menu.getElementsByTagName('a');
            for (var i=0; i<ahrefs.length; i++) {
                var idx = ahrefs[i].className.indexOf(' mod_jumpmenu_highlighted'); 
                if (idx != -1) {
                    ahrefs[i].className = ahrefs[i].className.substring(0,idx);
                }
            }
        }
        // If the menu item is a folder, then we also cleanup the
        // parent menu (which is the menu that the user is currently
        // hovering over).
        if (menu_item && menu_item.className.indexOf('mod_jumpmenu_folder') != -1) {
            var ahrefs = p_menu.getElementsByTagName('a');
            for (var i=0; i<ahrefs.length; i++) {
                var idx = ahrefs[i].className.indexOf(' mod_jumpmenu_highlighted'); 
                if (idx != -1) {
                    ahrefs[i].className = ahrefs[i].className.substring(0,idx);
                }
            }
        }
        // Highlight the active menu item.
        if (menu_item && menu_item.className.indexOf(' mod_jumpmenu_highlighted') == -1) {
            menu_item.className += ' mod_jumpmenu_highlighted';
        }

        // If we did not find the required objects, then silently ignore
        // the problem and stop processing.
        if (!p_item || !c_menu) return;
        if (menu_id != PhorumJumpMenu.vroot && !p_menu) return;

        // Do some dimension handling and storage the first time that the
        // menu is opened.
        if (!c_menu.jumpmenu_init_done)
        {
            // Without making the menu visible, we don't know the width/height
            // of the menu div, because those are only available after rendering
            // the menu HTML code. So for positioning the menu, we have a
            // chicken/egg problem to fix. I fix it by moving the egg out of
            // the visible screen area before making it visible.
            c_menu.style.top  = '-500px';
            c_menu.style.left = '-500px';
            c_menu.style.display = 'block';

            // This should put the menus on top at most pages.
            c_menu.style.zIndex = 1000;

            // force the widths for the <a href="..."> tags. this is needed to
            // make the links hoverable and clickable over the full menu width
            // in msie6 :(
            // the "var w" is used to prevent variable tag widths due to
            // accidental resizing of the menu while setting the tag widths
            // (i've seen that happening in opera).
            var ahrefs = c_menu.getElementsByTagName('a');
            var w = null;
            for (var i=0; i<ahrefs.length; i++) {
                var a = ahrefs[i];
                if (!w) w = a.offsetWidth;
                a.style.width = w;
            }

            // store the displaying dimensions in the div object.
            c_menu.jumpmenu_width  = c_menu.offsetWidth;
            c_menu.jumpmenu_height = c_menu.offsetHeight;

            // In MSIE, we have to fix the problem that windowed controls
            // like <select> will always be on top of <div>s. We can use
            // some special behavior of <iframe> for this. It's ugly but
            // the only way to make this work cleanly.
            // We do a check for MSIE here. It's no problem if other browsers
            // use a modified userAgent for some reason, triggering this code.
            // I only want to make sure that it is at least used in MSIE.
            if (navigator.userAgent && navigator.userAgent.indexOf('MSIE')>=0)
            {
                var i = document.createElement('iframe');
                i.scrolling      = 'no';
                i.frameborder    = '0';
                i.src            = 'javascript:false';
                i.style.border   = 'none';
                i.style.display  = 'block';
                i.style.left     = '0px';
                i.style.top      = '0px';
                i.style.width    = c_menu.jumpmenu_width + 'px';
                i.style.height   = c_menu.jumpmenu_height + 'px';
                i.style.position = 'absolute';
                i.style.zIndex  = c_menu.style.zIndex - 1;

                c_menu.parentNode.appendChild(i);

                c_menu.work_around_iframe = i;
            }

            c_menu.jumpmenu_init_done = 1;
            c_menu.style.display = 'none';
        }

        // keep track of the menu depth and menu drawing direction.
        // first level menu.
        if (menu_id == PhorumJumpMenu.vroot)
        {
            c_menu.depth = 1;

            // at the first level, we look at the main menu item. if that one
            // uses rel="mod_jumpmenu_left", then the direction of the whole
            // menu structure will be left. by default, this direction is right.
            c_menu.direction = 'right';
            if (p_item.rel && p_item.rel == 'mod_jumpmenu_left') {
                c_menu.direction = 'left';
            }
        }
        // second level and deeper.
        else
        {
            c_menu.depth = p_menu.depth + 1;

            // inherit the parent's menu direction.
            c_menu.direction = p_menu.direction;
        }

        // determine the screen dimensions.
        var scr = PhorumJumpMenu.getScreenInfo();

        // determine the top-left of the parent menu item.
        var p_item_pos = PhorumJumpMenu.getScreenPos(p_item);
        var top  = p_item_pos.rel_top;
        var left = p_item_pos.rel_left;

        // determine the location of the child menu.
        // the first level menu is placed directly beneath the main menu object.
        if (menu_id == PhorumJumpMenu.vroot)
        {
            top  = top + p_item.offsetHeight;

            if (c_menu.direction == 'left')
            {
                left = left - (c_menu.jumpmenu_width - p_item.offsetWidth);
                if (left < scr.scroll_x) left = scr.scroll_x + 2;
            }
            else
            {
                left = left;
                if ((left + c_menu.jumpmenu_width) > scr.width) {
                    left = scr.width - c_menu.jumpmenu_width - 2;
                }
            }
        }
        // second level and deeper levels are handled as standard menu popups
        // (placed to the right or left of the selected item).
        else
        {
            var dir = c_menu.direction;

            var left_pos =
                left // the left side of the parent menu item
                - PhorumJumpMenu.menuspacing // handle menu spacing
                - p_item.parentNode.offsetLeft // adjustment for padding;
                - c_menu.jumpmenu_width; // add child menu width;

            var right_pos =
                left // the left side of the parent menu item
                + PhorumJumpMenu.menuspacing  // handle menu spacing
                - p_item.parentNode.offsetLeft // adjustment for padding;
                + p_menu.offsetWidth; // add parent menu width

            if (dir == 'left') {
                if (left_pos < scr.scroll_x) {
                    dir = 'right';
                } else {
                    left = left_pos;
                }
            }

            if (dir == 'right') {
                if ((right_pos + c_menu.jumpmenu_width) > scr.visible_x) {
                    left = left_pos;
                } else {
                    left = right_pos;
                }
            }
        }

        // take extra vertical space into account for adjusting for
        // padding of the menu div.
        if (menu_id != PhorumJumpMenu.vroot) {
            top -= p_item.parentNode.offsetTop;
        }

        // move the menu up if needed.
        if ((top + c_menu.jumpmenu_height) > scr.visible_y) {
            top = scr.visible_y - c_menu.jumpmenu_height - 2;
            if (top < scr.scroll_y) top = scr.scroll_y + 2;
        }

        // move the menu into position and make it visible.
        c_menu.style.top  = top  + 'px';
        c_menu.style.left = left + 'px';
        c_menu.style.display = 'block';

        // If we have an iframe for working around an MSIE problem, then
        // place that one as well. This one needs different placement in
        // case the menu is running within some absolute or relative div.
        if (c_menu.work_around_iframe) {
            i = c_menu.work_around_iframe;
            i.style.top  = top + 'px';
            i.style.left = left + 'px';
            i.style.display = 'block';
        }

        // keep track of the active menu for the current menu level.
        PhorumJumpMenu.active[c_menu.depth] = c_menu;

        // cleanup the menus that should not be visible anymore.
        for (var depth in PhorumJumpMenu.visible) {
            for (var idx in PhorumJumpMenu.visible[depth]) {
                var o = PhorumJumpMenu.visible[depth][idx];
                if (depth > c_menu.depth ||
                    o.id != PhorumJumpMenu.active[depth].id) {
                    o.style.display = 'none';

                    if (o.work_around_iframe) {
                        o.work_around_iframe.style.display = 'none';
                    }
                }
            }
        }

        // keep track of visible menus.
        PhorumJumpMenu.visible[c_menu.depth] = {};
        PhorumJumpMenu.visible[c_menu.depth][c_menu.id] = c_menu;
    }

};


/* Added by module "embed_images", file "mods/embed_images/embed_images.js" */
function mod_embed_images_loadimage(viewer_id, thumbnail_url, fullimage_url, ajax_url, target_url, message_id, max_w, max_h, loading_txt, rescheduled)
{
    var container = document.getElementById('imagediv_'+viewer_id);
    if (!container) return;

    // If the image for the viewer id is already on the page, then we are
    // handling a cached thumbnail for which no Ajax magic is required,
    // but which is already loaded in the page. We'll only use this function
    // for setting up a full size image viewer.
    var image = document.getElementById('image_'+viewer_id);
    if (image)
    {
        // If a function was loaded for a viewer to initialize the
        // viewer, then hand over the image data to that function.
        // Don't do this in case we have a target_url.
        if (window.mod_embed_images_initviewer && !target_url) {
            var link  = document.getElementById('link_'+viewer_id);
            mod_embed_images_initviewer(
                container, image, link, fullimage_url, message_id
            );
        }

        return;
    }

    if (!rescheduled)
    {
        // We use a bit of a strange hack here, by checking for readyState.
        // This is not availble in all browsers. That's no problem though.
        // We mainly want MSIE to check it and to let it postpone image
        // loading till after the page is fully loaded. When doing things
        // earlier in MSIE from script code that is not a direct descendant
        // of <body>, we might get "operation aborted" errors.
        if (document.readyState &&
            document.readyState != 'loaded' &&
            document.readyState != 'complete' &&
            window.attachEvent &&
            !window.opera) {
          window.attachEvent('onload', function() {
              mod_embed_images_loadimage(
                  viewer_id, thumbnail_url, fullimage_url,
                  ajax_url, target_url, message_id,
                  max_w, max_h, loading_txt, true
              );
          });
          return;
        }

        // Display a "Loading ..." message to the user.
        container.innerHTML =
            '<div class="mod_embed_images_loading">' +
            loading_txt +
            '<\/div>';
    }

    // Create the XMLHttpRequest object that we can use to send an
    // Ajax request to the server.
    var xhr;
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        var versions = [
            "MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0",
            "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp",
            "Microsoft.XMLHttp"
        ];
        for (var i=0; i < versions.length; i++)
          try { xhr = new ActiveXObject(versions[i]); } catch (e) { }
    }

    // No XMLHttpRequest object found? Fallback to a simpler way of
    // displaying the thumbnail image. This way we won't have
    // loading or error feedback and full size viewer support,
    // but at least we do show the image. This should't happen for
    // modern browsers.
    if (!xhr)
    {
        target.innerHTML =
            (target_url ? '<a href="'+target_url+'">' : '') +
            '<img id="image_'+viewer_id+'" src="'+thumbnail_url+'"/>' +
            (target_url ? '<\/a>' : '');
        return;
    }

    // Setup the XMLHttpRequest object for the request.
    xhr.open("get", ajax_url, true);
    xhr.setRequestHeader("Content-Type", "text/plain");
    xhr.onreadystatechange = function()
    {
        if (xhr.readyState == 4 && xhr.status == 200)
        {
            var res = xhr.responseText;

            // An "OK <w>x<h> <scw>x<sch>" message was returned.
            if (res.substr(0,2) == 'OK')
            {
                // Parse the respones message.
                // I know... a bit old school parsing.
                var dim   = res.substr(3);
                var xpos  = dim.indexOf('x');
                var spos  = dim.indexOf(' ');
                var origw = dim.substr(0,xpos);
                var origh = dim.substr(xpos+1, spos-xpos-1);
                    dim   = dim.substr(spos+1);
                    xpos  = dim.indexOf('x');
                var w     = dim.substr(0,xpos);
                var h     = dim.substr(xpos+1);

                var origsize  = origw+"x"+origh;
                var scalesize = w+"x"+h;
                var is_scaled = (origsize != scalesize);

                // Opera does not seem to load images that are not visible :(
                // So for those, we never get an onload event. Therefore,
                // we make the image 0x0 pixels and resize it to the real
                // size after loading.
                var html =
                    (target_url ? '<a href="'+target_url+'">' : '') +
                    '<img style="width:0px;height:0px" ' +
                    'id="image_'+viewer_id+'" ' +
                    'onload="' +
                    'mod_embed_images_image_loaded(this,'+w+','+h+')" ' +
                    'src="'+thumbnail_url+'"/>' +
                    (target_url ? '<\/a>' : '');

                container.innerHTML += html;

                // Go to extended viewer mode if the image was scaled down
                // or if a target URL was provided.
                if (is_scaled || target_url)
                {
                    var info = document.getElementById('info_'+viewer_id);
                    if (info) info.style.display = 'block';

                    var div = document.getElementById('div_'+viewer_id);
                    if (div) div.className = 'mod_embed_images_extended';
                }

                // If a function was loaded for a viewer to initialize the
                // viewer, then hand over the image data to that function.
                if (window.mod_embed_images_initviewer) {
                    var image = document.getElementById('image_'+viewer_id);
                    var link  = document.getElementById('link_'+viewer_id);
                    mod_embed_images_initviewer(
                        container, image, link, fullimage_url, message_id
                    );
                }
            }

            // Some error message was returned. Show the error to the user.
            else container.innerHTML =
                '<div class="mod_embed_images_error">' +
                '<strong>Image error<\/strong><br\/>' +
                res + '<br/>' +
                '<a href="' + fullimage_url + '">open image URL<\/a>' +
                '<\/div>';
        }
    }

    // Send the request to the server.
    xhr.send('');
}

function mod_embed_images_image_loaded(image, w, h)
{
    image.style.width = w+'px';
    image.style.height = h+'px';

    var container = image.parentNode;
    while (container.className != 'mod_embed_images_image') {
        container = container.parentNode;
        if (!container) return; // Should not happen.
    }

    container.style.width = image.width + 'px';
    container.parentNode.style.width = parseInt(image.width) + 'px';
    container.style.height = image.height + 'px';
    for (var i = 0; i < container.childNodes.length; i++) {
        if (container.childNodes[i].className == 'mod_embed_images_loading') {
            container.childNodes[i].style.display = 'none';
        }
    }
}



/* Added by module "embed_images/viewer:slimbox2", file "mods/embed_images/viewers/slimbox2/code/js/mootools.js" */
//MooTools, <http://mootools.net>, My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

var MooTools={version:"1.2dev",build:""};var Native=function(J){J=J||{};var F=J.afterImplement||function(){};var G=J.generics;G=(G!==false);var H=J.legacy;var E=J.initialize;var B=J.protect;var A=J.name;var C=E||H;C.constructor=Native;C.$family={name:"native"};if(H&&E){C.prototype=H.prototype}C.prototype.constructor=C;if(A){var D=A.toLowerCase();C.prototype.$family={name:D};Native.typize(C,D)}var I=function(M,K,N,L){if(!B||L||!M.prototype[K]){M.prototype[K]=N}if(G){Native.genericize(M,K,B)}F.call(M,K,N);return M};C.implement=function(L,K,N){if(typeof L=="string"){return I(this,L,K,N)}for(var M in L){I(this,M,L[M],K)}return this};C.alias=function(M,K,N){if(typeof M=="string"){M=this.prototype[M];if(M){I(this,K,M,N)}}else{for(var L in M){this.alias(L,M[L],K)}}return this};return C};Native.implement=function(D,C){for(var B=0,A=D.length;B<A;B++){D[B].implement(C)}};Native.genericize=function(B,C,A){if((!A||!B[C])&&typeof B.prototype[C]=="function"){B[C]=function(){var D=Array.prototype.slice.call(arguments);return B.prototype[C].apply(D.shift(),D)}}};Native.typize=function(A,B){if(!A.type){A.type=function(C){return($type(C)===B)}}};Native.alias=function(E,B,A,F){for(var D=0,C=E.length;D<C;D++){E[D].alias(B,A,F)}};(function(B){for(var A in B){Native.typize(B[A],A)}})({"boolean":Boolean,"native":Native,object:Object});(function(B){for(var A in B){new Native({name:A,initialize:B[A],protect:true})}})({String:String,Function:Function,Number:Number,Array:Array,RegExp:RegExp,Date:Date});(function(B,A){for(var C=A.length;C--;C){Native.genericize(B,A[C],true)}return arguments.callee})(Array,["pop","push","reverse","shift","sort","splice","unshift","concat","join","slice","toString","valueOf","indexOf","lastIndexOf"])(String,["charAt","charCodeAt","concat","indexOf","lastIndexOf","match","replace","search","slice","split","substr","substring","toLowerCase","toUpperCase","valueOf"]);function $chk(A){return !!(A||A===0)}function $clear(A){clearTimeout(A);clearInterval(A);return null}function $defined(A){return(A!=undefined)}function $empty(){}function $arguments(A){return function(){return arguments[A]}}function $lambda(A){return(typeof A=="function")?A:function(){return A}}function $extend(C,A){for(var B in (A||{})){C[B]=A[B]}return C}function $unlink(C){var B;switch($type(C)){case"object":B={};for(var E in C){B[E]=$unlink(C[E])}break;case"hash":B=$unlink(C.getClean());break;case"array":B=[];for(var D=0,A=C.length;D<A;D++){B[D]=$unlink(C[D])}break;default:return C}return B}function $merge(){var E={};for(var D=0,A=arguments.length;D<A;D++){var B=arguments[D];if($type(B)!="object"){continue}for(var C in B){var G=B[C],F=E[C];E[C]=(F&&$type(G)=="object"&&$type(F)=="object")?$merge(F,G):$unlink(G)}}return E}function $pick(){for(var B=0,A=arguments.length;B<A;B++){if(arguments[B]!=undefined){return arguments[B]}}return null}function $random(B,A){return Math.floor(Math.random()*(A-B+1)+B)}function $splat(B){var A=$type(B);return(A)?((A!="array"&&A!="arguments")?[B]:B):[]}var $time=Date.now||function(){return new Date().getTime()};function $try(){for(var B=0,A=arguments.length;B<A;B++){try{return arguments[B]()}catch(C){}}return null}function $type(A){if(A==undefined){return false}if(A.$family){return(A.$family.name=="number"&&!isFinite(A))?false:A.$family.name}if(A.nodeName){switch(A.nodeType){case 1:return"element";case 3:return(/\S/).test(A.nodeValue)?"textnode":"whitespace"}}else{if(typeof A.length=="number"){if(A.callee){return"arguments"}else{if(A.item){return"collection"}}}}return typeof A}var Hash=new Native({name:"Hash",initialize:function(A){if($type(A)=="hash"){A=$unlink(A.getClean())}for(var B in A){this[B]=A[B]}return this}});Hash.implement({getLength:function(){var B=0;for(var A in this){if(this.hasOwnProperty(A)){B++}}return B},forEach:function(B,C){for(var A in this){if(this.hasOwnProperty(A)){B.call(C,this[A],A,this)}}},getClean:function(){var B={};for(var A in this){if(this.hasOwnProperty(A)){B[A]=this[A]}}return B}});Hash.alias("forEach","each");function $H(A){return new Hash(A)}Array.implement({forEach:function(C,D){for(var B=0,A=this.length;B<A;B++){C.call(D,this[B],B,this)}}});Array.alias("forEach","each");function $A(C){if(C.item){var D=[];for(var B=0,A=C.length;B<A;B++){D[B]=C[B]}return D}return Array.prototype.slice.call(C)}function $each(C,B,D){var A=$type(C);((A=="arguments"||A=="collection"||A=="array")?Array:Hash).each(C,B,D)}var Browser=new Hash({Engine:{name:"unknown",version:""},Platform:{name:(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase()},Features:{xpath:!!(document.evaluate),air:!!(window.runtime)},Plugins:{}});if(window.opera){Browser.Engine={name:"presto",version:(document.getElementsByClassName)?950:925}}else{if(window.ActiveXObject){Browser.Engine={name:"trident",version:(window.XMLHttpRequest)?5:4}}else{if(!navigator.taintEnabled){Browser.Engine={name:"webkit",version:(Browser.Features.xpath)?420:419}}else{if(document.getBoxObjectFor!=null){Browser.Engine={name:"gecko",version:(document.getElementsByClassName)?19:18}}}}}Browser.Engine[Browser.Engine.name]=Browser.Engine[Browser.Engine.name+Browser.Engine.version]=true;if(window.orientation!=undefined){Browser.Platform.name="ipod"}Browser.Platform[Browser.Platform.name]=true;Browser.Request=function(){return $try(function(){return new XMLHttpRequest()},function(){return new ActiveXObject("MSXML2.XMLHTTP")})};Browser.Features.xhr=!!(Browser.Request());Browser.Plugins.Flash=(function(){var A=($try(function(){return navigator.plugins["Shockwave Flash"].description},function(){return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")})||"0 r0").match(/\d+/g);return{version:parseInt(A[0]||0+"."+A[1]||0),build:parseInt(A[2]||0)}})();function $exec(B){if(!B){return B}if(window.execScript){window.execScript(B)}else{var A=document.createElement("script");A.setAttribute("type","text/javascript");A.text=B;document.head.appendChild(A);document.head.removeChild(A)}return B}Native.UID=1;var $uid=(Browser.Engine.trident)?function(A){return(A.uid||(A.uid=[Native.UID++]))[0]}:function(A){return A.uid||(A.uid=Native.UID++)};var Window=new Native({name:"Window",legacy:(Browser.Engine.trident)?null:window.Window,initialize:function(A){$uid(A);if(!A.Element){A.Element=$empty;if(Browser.Engine.webkit){A.document.createElement("iframe")}A.Element.prototype=(Browser.Engine.webkit)?window["[[DOMElement.prototype]]"]:{}}return $extend(A,Window.Prototype)},afterImplement:function(B,A){window[B]=Window.Prototype[B]=A}});Window.Prototype={$family:{name:"window"}};new Window(window);var Document=new Native({name:"Document",legacy:(Browser.Engine.trident)?null:window.Document,initialize:function(A){$uid(A);A.head=A.getElementsByTagName("head")[0];A.html=A.getElementsByTagName("html")[0];A.window=A.defaultView||A.parentWindow;if(Browser.Engine.trident4){$try(function(){A.execCommand("BackgroundImageCache",false,true)})}return $extend(A,Document.Prototype)},afterImplement:function(B,A){document[B]=Document.Prototype[B]=A}});Document.Prototype={$family:{name:"document"}};new Document(document);Array.implement({every:function(C,D){for(var B=0,A=this.length;B<A;B++){if(!C.call(D,this[B],B,this)){return false}}return true},filter:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){if(D.call(E,this[B],B,this)){C.push(this[B])}}return C},clean:function(){return this.filter($defined)},indexOf:function(C,D){var A=this.length;for(var B=(D<0)?Math.max(0,A+D):D||0;B<A;B++){if(this[B]===C){return B}}return -1},map:function(D,E){var C=[];for(var B=0,A=this.length;B<A;B++){C[B]=D.call(E,this[B],B,this)}return C},some:function(C,D){for(var B=0,A=this.length;B<A;B++){if(C.call(D,this[B],B,this)){return true}}return false},associate:function(C){var D={},B=Math.min(this.length,C.length);for(var A=0;A<B;A++){D[C[A]]=this[A]}return D},link:function(C){var A={};for(var E=0,B=this.length;E<B;E++){for(var D in C){if(C[D](this[E])){A[D]=this[E];delete C[D];break}}}return A},contains:function(A,B){return this.indexOf(A,B)!=-1},extend:function(C){for(var B=0,A=C.length;B<A;B++){this.push(C[B])}return this},getLast:function(){return(this.length)?this[this.length-1]:null},getRandom:function(){return(this.length)?this[$random(0,this.length-1)]:null},include:function(A){if(!this.contains(A)){this.push(A)}return this},combine:function(C){for(var B=0,A=C.length;B<A;B++){this.include(C[B])}return this},erase:function(B){for(var A=this.length;A--;A){if(this[A]===B){this.splice(A,1)}}return this},empty:function(){this.length=0;return this},flatten:function(){var D=[];for(var B=0,A=this.length;B<A;B++){var C=$type(this[B]);if(!C){continue}D=D.concat((C=="array"||C=="collection"||C=="arguments")?Array.flatten(this[B]):this[B])}return D},hexToRgb:function(B){if(this.length!=3){return null}var A=this.map(function(C){if(C.length==1){C+=C}return C.toInt(16)});return(B)?A:"rgb("+A+")"},rgbToHex:function(D){if(this.length<3){return null}if(this.length==4&&this[3]==0&&!D){return"transparent"}var B=[];for(var A=0;A<3;A++){var C=(this[A]-0).toString(16);B.push((C.length==1)?"0"+C:C)}return(D)?B:"#"+B.join("")}});Function.implement({extend:function(A){for(var B in A){this[B]=A[B]}return this},create:function(B){var A=this;B=B||{};return function(D){var C=B.arguments;C=(C!=undefined)?$splat(C):Array.slice(arguments,(B.event)?1:0);if(B.event){C=[D||window.event].extend(C)}var E=function(){return A.apply(B.bind||null,C)};if(B.delay){return setTimeout(E,B.delay)}if(B.periodical){return setInterval(E,B.periodical)}if(B.attempt){return $try(E)}return E()}},pass:function(A,B){return this.create({arguments:A,bind:B})},attempt:function(A,B){return this.create({arguments:A,bind:B,attempt:true})()},bind:function(B,A){return this.create({bind:B,arguments:A})},bindWithEvent:function(B,A){return this.create({bind:B,event:true,arguments:A})},delay:function(B,C,A){return this.create({delay:B,bind:C,arguments:A})()},periodical:function(A,C,B){return this.create({periodical:A,bind:C,arguments:B})()},run:function(A,B){return this.apply(B,$splat(A))}});Number.implement({limit:function(B,A){return Math.min(A,Math.max(B,this))},round:function(A){A=Math.pow(10,A||0);return Math.round(this*A)/A},times:function(B,C){for(var A=0;A<this;A++){B.call(C,A,this)}},toFloat:function(){return parseFloat(this)},toInt:function(A){return parseInt(this,A||10)}});Number.alias("times","each");(function(B){var A={};B.each(function(C){if(!Number[C]){A[C]=function(){return Math[C].apply(null,[this].concat($A(arguments)))}}});Number.implement(A)})(["abs","acos","asin","atan","atan2","ceil","cos","exp","floor","log","max","min","pow","sin","sqrt","tan"]);String.implement({test:function(A,B){return((typeof A=="string")?new RegExp(A,B):A).test(this)},contains:function(A,B){return(B)?(B+this+B).indexOf(B+A+B)>-1:this.indexOf(A)>-1},trim:function(){return this.replace(/^\s+|\s+$/g,"")},clean:function(){return this.replace(/\s+/g," ").trim()},camelCase:function(){return this.replace(/-\D/g,function(A){return A.charAt(1).toUpperCase()})},hyphenate:function(){return this.replace(/[A-Z]/g,function(A){return("-"+A.charAt(0).toLowerCase())})},capitalize:function(){return this.replace(/\b[a-z]/g,function(A){return A.toUpperCase()})},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1")},toInt:function(A){return parseInt(this,A||10)},toFloat:function(){return parseFloat(this)},hexToRgb:function(B){var A=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);return(A)?A.slice(1).hexToRgb(B):null},rgbToHex:function(B){var A=this.match(/\d{1,3}/g);return(A)?A.rgbToHex(B):null},stripScripts:function(B){var A="";var C=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi,function(){A+=arguments[1]+"\n";return""});if(B===true){$exec(A)}else{if($type(B)=="function"){B(A,C)}}return C},substitute:function(A,B){return this.replace(B||(/\\?\{([^}]+)\}/g),function(D,C){if(D.charAt(0)=="\\"){return D.slice(1)}return(A[C]!=undefined)?A[C]:""})}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(B){for(var A in this){if(this.hasOwnProperty(A)&&this[A]===B){return A}}return null},hasValue:function(A){return(Hash.keyOf(this,A)!==null)},extend:function(A){Hash.each(A,function(C,B){Hash.set(this,B,C)},this);return this},combine:function(A){Hash.each(A,function(C,B){Hash.include(this,B,C)},this);return this},erase:function(A){if(this.hasOwnProperty(A)){delete this[A]}return this},get:function(A){return(this.hasOwnProperty(A))?this[A]:null},set:function(A,B){if(!this[A]||this.hasOwnProperty(A)){this[A]=B}return this},empty:function(){Hash.each(this,function(B,A){delete this[A]},this);return this},include:function(B,C){var A=this[B];if(A==undefined){this[B]=C}return this},map:function(B,C){var A=new Hash;Hash.each(this,function(E,D){A.set(D,B.call(C,E,D,this))},this);return A},filter:function(B,C){var A=new Hash;Hash.each(this,function(E,D){if(B.call(C,E,D,this)){A.set(D,E)}},this);return A},every:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&!B.call(C,this[A],A)){return false}}return true},some:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&B.call(C,this[A],A)){return true}}return false},getKeys:function(){var A=[];Hash.each(this,function(C,B){A.push(B)});return A},getValues:function(){var A=[];Hash.each(this,function(B){A.push(B)});return A},toQueryString:function(A){var B=[];Hash.each(this,function(F,E){if(A){E=A+"["+E+"]"}var D;switch($type(F)){case"object":D=Hash.toQueryString(F,E);break;case"array":var C={};F.each(function(H,G){C[G]=H});D=Hash.toQueryString(C,E);break;default:D=E+"="+encodeURIComponent(F)}if(F!=undefined){B.push(D)}});return B.join("&")}});Hash.alias({keyOf:"indexOf",hasValue:"contains"});var Event=new Native({name:"Event",initialize:function(A,F){F=F||window;var K=F.document;A=A||F.event;if(A.$extended){return A}this.$extended=true;var J=A.type;var G=A.target||A.srcElement;while(G&&G.nodeType==3){G=G.parentNode}if(J.test(/key/)){var B=A.which||A.keyCode;var M=Event.Keys.keyOf(B);if(J=="keydown"){var D=B-111;if(D>0&&D<13){M="f"+D}}M=M||String.fromCharCode(B).toLowerCase()}else{if(J.match(/(click|mouse|menu)/i)){K=(!K.compatMode||K.compatMode=="CSS1Compat")?K.html:K.body;var I={x:A.pageX||A.clientX+K.scrollLeft,y:A.pageY||A.clientY+K.scrollTop};var C={x:(A.pageX)?A.pageX-F.pageXOffset:A.clientX,y:(A.pageY)?A.pageY-F.pageYOffset:A.clientY};if(J.match(/DOMMouseScroll|mousewheel/)){var H=(A.wheelDelta)?A.wheelDelta/120:-(A.detail||0)/3}var E=(A.which==3)||(A.button==2);var L=null;if(J.match(/over|out/)){switch(J){case"mouseover":L=A.relatedTarget||A.fromElement;break;case"mouseout":L=A.relatedTarget||A.toElement}if(!(function(){while(L&&L.nodeType==3){L=L.parentNode}return true}).create({attempt:Browser.Engine.gecko})()){L=false}}}}return $extend(this,{event:A,type:J,page:I,client:C,rightClick:E,wheel:H,relatedTarget:L,target:G,code:B,key:M,shift:A.shiftKey,control:A.ctrlKey,alt:A.altKey,meta:A.metaKey})}});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Event.implement({stop:function(){return this.stopPropagation().preventDefault()},stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation()}else{this.event.cancelBubble=true}return this},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault()}else{this.event.returnValue=false}return this}});var Class=new Native({name:"Class",initialize:function(B){B=B||{};var A=function(E){for(var D in this){this[D]=$unlink(this[D])}for(var F in Class.Mutators){if(!this[F]){continue}Class.Mutators[F](this,this[F]);delete this[F]}this.constructor=A;if(E===$empty){return this}var C=(this.initialize)?this.initialize.apply(this,arguments):this;if(this.options&&this.options.initialize){this.options.initialize.call(this)}return C};$extend(A,this);A.constructor=Class;A.prototype=B;return A}});Class.implement({implement:function(){Class.Mutators.Implements(this.prototype,Array.slice(arguments));return this}});Class.Mutators={Implements:function(A,B){$splat(B).each(function(C){$extend(A,($type(C)=="class")?new C($empty):C)})},Extends:function(self,klass){var instance=new klass($empty);delete instance.parent;delete instance.parentOf;for(var key in instance){var current=self[key],previous=instance[key];if(current==undefined){self[key]=previous;continue}var ctype=$type(current),ptype=$type(previous);if(ctype!=ptype){continue}switch(ctype){case"function":if(!arguments.callee.caller){self[key]=eval("("+String(current).replace(/\bthis\.parent\(\s*(\))?/g,function(full,close){return"arguments.callee._parent_.call(this"+(close||", ")})+")")}self[key]._parent_=previous;break;case"object":self[key]=$merge(previous,current)}}self.parent=function(){return arguments.callee.caller._parent_.apply(this,arguments)};self.parentOf=function(descendant){return descendant._parent_.apply(this,Array.slice(arguments,1))}}};var Chain=new Class({chain:function(){this.$chain=(this.$chain||[]).extend(arguments);return this},callChain:function(){return(this.$chain&&this.$chain.length)?this.$chain.shift().apply(this,arguments):false},clearChain:function(){if(this.$chain){this.$chain.empty()}return this}});var Events=new Class({addEvent:function(C,B,A){C=Events.removeOn(C);if(B!=$empty){this.$events=this.$events||{};this.$events[C]=this.$events[C]||[];this.$events[C].include(B);if(A){B.internal=true}}return this},addEvents:function(A){for(var B in A){this.addEvent(B,A[B])}return this},fireEvent:function(C,B,A){C=Events.removeOn(C);if(!this.$events||!this.$events[C]){return this}this.$events[C].each(function(D){D.create({bind:this,delay:A,"arguments":B})()},this);return this},removeEvent:function(B,A){B=Events.removeOn(B);if(!this.$events||!this.$events[B]){return this}if(!A.internal){this.$events[B].erase(A)}return this},removeEvents:function(C){for(var D in this.$events){if(C&&C!=D){continue}var B=this.$events[D];for(var A=B.length;A--;A){this.removeEvent(D,B[A])}}return this}});Events.removeOn=function(A){return A.replace(/^on([A-Z])/,function(B,C){return C.toLowerCase()})};var Options=new Class({setOptions:function(){this.options=$merge.run([this.options].extend(arguments));if(!this.addEvent){return this}for(var A in this.options){if($type(this.options[A])!="function"||!(/^on[A-Z]/).test(A)){continue}this.addEvent(A,this.options[A]);delete this.options[A]}return this}});Document.implement({newElement:function(A,B){if(Browser.Engine.trident&&B){["name","type","checked"].each(function(C){if(!B[C]){return }A+=" "+C+'="'+B[C]+'"';if(C!="checked"){delete B[C]}});A="<"+A+">"}return $.element(this.createElement(A)).set(B)},newTextNode:function(A){return this.createTextNode(A)},getDocument:function(){return this},getWindow:function(){return this.defaultView||this.parentWindow},purge:function(){var C=this.getElementsByTagName("*");for(var B=0,A=C.length;B<A;B++){Browser.freeMem(C[B])}}});var Element=new Native({name:"Element",legacy:window.Element,initialize:function(A,B){var C=Element.Constructors.get(A);if(C){return C(B)}if(typeof A=="string"){return document.newElement(A,B)}return $(A).set(B)},afterImplement:function(A,B){if(!Array[A]){Elements.implement(A,Elements.multi(A))}Element.Prototype[A]=B}});Element.Prototype={$family:{name:"element"}};Element.Constructors=new Hash;var IFrame=new Native({name:"IFrame",generics:false,initialize:function(){var E=Array.link(arguments,{properties:Object.type,iframe:$defined});var C=E.properties||{};var B=$(E.iframe)||false;var D=C.onload||$empty;delete C.onload;C.id=C.name=$pick(C.id,C.name,B.id,B.name,"IFrame_"+$time());B=new Element(B||"iframe",C);var A=function(){var F=$try(function(){return B.contentWindow.location.host});if(F&&F==window.location.host){var H=new Window(B.contentWindow);var G=new Document(B.contentWindow.document);$extend(H.Element.prototype,Element.Prototype)}D.call(B.contentWindow,B.contentWindow.document)};(!window.frames[C.id])?B.addListener("load",A):A();return B}});var Elements=new Native({initialize:function(F,B){B=$extend({ddup:true,cash:true},B);F=F||[];if(B.ddup||B.cash){var G={},E=[];for(var C=0,A=F.length;C<A;C++){var D=$.element(F[C],!B.cash);if(B.ddup){if(G[D.uid]){continue}G[D.uid]=true}E.push(D)}F=E}return(B.cash)?$extend(F,this):F}});Elements.implement({filter:function(A,B){if(!A){return this}return new Elements(Array.filter(this,(typeof A=="string")?function(C){return C.match(A)}:A,B))}});Elements.multi=function(A){return function(){var B=[];var F=true;for(var D=0,C=this.length;D<C;D++){var E=this[D][A].apply(this[D],arguments);B.push(E);if(F){F=($type(E)=="element")}}return(F)?new Elements(B):B}};Window.implement({$:function(B,C){if(B&&B.$family&&B.uid){return B}var A=$type(B);return($[A])?$[A](B,C,this.document):null},$$:function(A){if(arguments.length==1&&typeof A=="string"){return this.document.getElements(A)}var F=[];var C=Array.flatten(arguments);for(var D=0,B=C.length;D<B;D++){var E=C[D];switch($type(E)){case"element":E=[E];break;case"string":E=this.document.getElements(E,true);break;default:E=false}if(E){F.extend(E)}}return new Elements(F)},getDocument:function(){return this.document},getWindow:function(){return this}});$.string=function(C,B,A){C=A.getElementById(C);return(C)?$.element(C,B):null};$.element=function(A,D){$uid(A);if(!D&&!A.$family&&!(/^object|embed$/i).test(A.tagName)){var B=Element.Prototype;for(var C in B){A[C]=B[C]}}return A};$.object=function(B,C,A){if(B.toElement){return $.element(B.toElement(A),C)}return null};$.textnode=$.whitespace=$.window=$.document=$arguments(0);Native.implement([Element,Document],{getElement:function(A,B){return $(this.getElements(A,true)[0]||null,B)},getElements:function(A,D){A=A.split(",");var C=[];var B=(A.length>1);A.each(function(E){var F=this.getElementsByTagName(E.trim());(B)?C.extend(F):C=F},this);return new Elements(C,{ddup:B,cash:!D})}});Element.Storage={get:function(A){return(this[A]||(this[A]={}))}};Element.Inserters=new Hash({before:function(B,A){if(A.parentNode){A.parentNode.insertBefore(B,A)}},after:function(B,A){if(!A.parentNode){return }var C=A.nextSibling;(C)?A.parentNode.insertBefore(B,C):A.parentNode.appendChild(B)},bottom:function(B,A){A.appendChild(B)},top:function(B,A){var C=A.firstChild;(C)?A.insertBefore(B,C):A.appendChild(B)}});Element.Inserters.inside=Element.Inserters.bottom;Element.Inserters.each(function(C,B){var A=B.capitalize();Element.implement("inject"+A,function(D){C(this,$(D,true));return this});Element.implement("grab"+A,function(D){C($(D,true),this);return this})});Element.implement({getDocument:function(){return this.ownerDocument},getWindow:function(){return this.ownerDocument.getWindow()},getElementById:function(D,C){var B=this.ownerDocument.getElementById(D);if(!B){return null}for(var A=B.parentNode;A!=this;A=A.parentNode){if(!A){return null}}return $.element(B,C)},set:function(D,B){switch($type(D)){case"object":for(var C in D){this.set(C,D[C])}break;case"string":var A=Element.Properties.get(D);(A&&A.set)?A.set.apply(this,Array.slice(arguments,1)):this.setProperty(D,B)}return this},get:function(B){var A=Element.Properties.get(B);return(A&&A.get)?A.get.apply(this,Array.slice(arguments,1)):this.getProperty(B)},erase:function(B){var A=Element.Properties.get(B);(A&&A.erase)?A.erase.apply(this,Array.slice(arguments,1)):this.removeProperty(B);return this},match:function(A){return(!A||Element.get(this,"tag")==A)},inject:function(B,A){Element.Inserters.get(A||"bottom")(this,$(B,true));return this},wraps:function(B,A){B=$(B,true);return this.replaces(B).grab(B,A)},grab:function(B,A){Element.Inserters.get(A||"bottom")($(B,true),this);return this},appendText:function(B,A){return this.grab(this.getDocument().newTextNode(B),A)},adopt:function(){Array.flatten(arguments).each(function(A){A=$(A,true);if(A){this.appendChild(A)}},this);return this},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this},clone:function(D,C){switch($type(this)){case"element":var H={};for(var G=0,E=this.attributes.length;G<E;G++){var B=this.attributes[G],L=B.nodeName.toLowerCase();if(Browser.Engine.trident&&(/input/i).test(this.tagName)&&(/width|height/).test(L)){continue}var K=(L=="style"&&this.style)?this.style.cssText:B.nodeValue;if(!$chk(K)||L=="uid"||(L=="id"&&!C)){continue}if(K!="inherit"&&["string","number"].contains($type(K))){H[L]=K}}var J=new Element(this.nodeName.toLowerCase(),H);if(D!==false){for(var I=0,F=this.childNodes.length;I<F;I++){var A=Element.clone(this.childNodes[I],true,C);if(A){J.grab(A)}}}return J;case"textnode":return document.newTextNode(this.nodeValue)}return null},replaces:function(A){A=$(A,true);A.parentNode.replaceChild(this,A);return this},hasClass:function(A){return this.className.contains(A," ")},addClass:function(A){if(!this.hasClass(A)){this.className=(this.className+" "+A).clean()}return this},removeClass:function(A){this.className=this.className.replace(new RegExp("(^|\\s)"+A+"(?:\\s|$)"),"$1").clean();return this},toggleClass:function(A){return this.hasClass(A)?this.removeClass(A):this.addClass(A)},getComputedStyle:function(B){if(this.currentStyle){return this.currentStyle[B.camelCase()]}var A=this.getWindow().getComputedStyle(this,null);return(A)?A.getPropertyValue([B.hyphenate()]):null},empty:function(){$A(this.childNodes).each(function(A){Browser.freeMem(A);Element.empty(A);Element.dispose(A)},this);return this},destroy:function(){Browser.freeMem(this.empty().dispose());return null},getSelected:function(){return new Elements($A(this.options).filter(function(A){return A.selected}))},toQueryString:function(){var A=[];this.getElements("input, select, textarea").each(function(B){if(!B.name||B.disabled){return }var C=(B.tagName.toLowerCase()=="select")?Element.getSelected(B).map(function(D){return D.value}):((B.type=="radio"||B.type=="checkbox")&&!B.checked)?null:B.value;$splat(C).each(function(D){if(D){A.push(B.name+"="+encodeURIComponent(D))}})});return A.join("&")},getProperty:function(C){var B=Element.Attributes,A=B.Props[C];var D=(A)?this[A]:this.getAttribute(C,2);return(B.Bools[C])?!!D:(A)?D:D||null},getProperties:function(){var A=$A(arguments);return A.map(function(B){return this.getProperty(B)},this).associate(A)},setProperty:function(D,E){var C=Element.Attributes,B=C.Props[D],A=$defined(E);if(B&&C.Bools[D]){E=(E||!A)?true:false}else{if(!A){return this.removeProperty(D)}}(B)?this[B]=E:this.setAttribute(D,E);return this},setProperties:function(A){for(var B in A){this.setProperty(B,A[B])}return this},removeProperty:function(D){var C=Element.Attributes,B=C.Props[D],A=(B&&C.Bools[D]);(B)?this[B]=(A)?false:"":this.removeAttribute(D);return this},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this}});(function(){var A=function(D,B,I,C,F,H){var E=D[I||B];var G=[];while(E){if(E.nodeType==1&&(!C||Element.match(E,C))){G.push(E);if(!F){break}}E=E[B]}return(F)?new Elements(G,{ddup:false,cash:!H}):$(G[0],H)};Element.implement({getPrevious:function(B,C){return A(this,"previousSibling",null,B,false,C)},getAllPrevious:function(B,C){return A(this,"previousSibling",null,B,true,C)},getNext:function(B,C){return A(this,"nextSibling",null,B,false,C)},getAllNext:function(B,C){return A(this,"nextSibling",null,B,true,C)},getFirst:function(B,C){return A(this,"nextSibling","firstChild",B,false,C)},getLast:function(B,C){return A(this,"previousSibling","lastChild",B,false,C)},getParent:function(B,C){return A(this,"parentNode",null,B,false,C)},getParents:function(B,C){return A(this,"parentNode",null,B,true,C)},getChildren:function(B,C){return A(this,"nextSibling","firstChild",B,true,C)},hasChild:function(B){B=$(B,true);return(!!B&&$A(this.getElementsByTagName(B.tagName)).contains(B))}})})();Element.Properties=new Hash;Element.Properties.style={set:function(A){this.style.cssText=A},get:function(){return this.style.cssText},erase:function(){this.style.cssText=""}};Element.Properties.tag={get:function(){return this.tagName.toLowerCase()}};Element.Properties.href={get:function(){return(!this.href)?null:this.href.replace(new RegExp("^"+document.location.protocol+"//"+document.location.host),"")}};Element.Properties.html={set:function(){return this.innerHTML=Array.flatten(arguments).join("")}};Native.implement([Element,Window,Document],{addListener:function(B,A){if(this.addEventListener){this.addEventListener(B,A,false)}else{this.attachEvent("on"+B,A)}return this},removeListener:function(B,A){if(this.removeEventListener){this.removeEventListener(B,A,false)}else{this.detachEvent("on"+B,A)}return this},retrieve:function(B,A){var D=Element.Storage.get(this.uid);var C=D[B];if($defined(A)&&!$defined(C)){C=D[B]=A}return $pick(C)},store:function(B,A){var C=Element.Storage.get(this.uid);C[B]=A;return this},eliminate:function(A){var B=Element.Storage.get(this.uid);delete B[A];return this}});Element.Attributes=new Hash({Props:{html:"innerHTML","class":"className","for":"htmlFor",text:(Browser.Engine.trident)?"innerText":"textContent"},Bools:["compact","nowrap","ismap","declare","noshade","checked","disabled","readonly","multiple","selected","noresize","defer"],Camels:["value","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"]});Browser.freeMem=function(A){if(!A){return }if(Browser.Engine.trident&&(/object/i).test(A.tagName)){for(var B in A){if(typeof A[B]=="function"){A[B]=$empty}}Element.dispose(A)}if(A.uid&&A.removeEvents){A.removeEvents()}};(function(B){var C=B.Bools,A=B.Camels;B.Bools=C=C.associate(C);Hash.extend(Hash.combine(B.Props,C),A.associate(A.map(function(D){return D.toLowerCase()})));B.erase("Camels")})(Element.Attributes);window.addListener("unload",function(){window.removeListener("unload",arguments.callee);document.purge();if(Browser.Engine.trident){CollectGarbage()}});Element.Properties.events={set:function(A){this.addEvents(A)}};Native.implement([Element,Window,Document],{addEvent:function(E,G){var H=this.retrieve("events",{});H[E]=H[E]||{keys:[],values:[]};if(H[E].keys.contains(G)){return this}H[E].keys.push(G);var F=E,A=Element.Events.get(E),C=G,I=this;if(A){if(A.onAdd){A.onAdd.call(this,G)}if(A.condition){C=function(J){if(A.condition.call(this,J)){return G.call(this,J)}return false}}F=A.base||F}var D=function(){return G.call(I)};var B=Element.NativeEvents[F]||0;if(B){if(B==2){D=function(J){J=new Event(J,I.getWindow());if(C.call(I,J)===false){J.stop()}}}this.addListener(F,D)}H[E].values.push(D);return this},removeEvent:function(D,C){var B=this.retrieve("events");if(!B||!B[D]){return this}var G=B[D].keys.indexOf(C);if(G==-1){return this}var A=B[D].keys.splice(G,1)[0];var F=B[D].values.splice(G,1)[0];var E=Element.Events.get(D);if(E){if(E.onRemove){E.onRemove.call(this,C)}D=E.base||D}return(Element.NativeEvents[D])?this.removeListener(D,F):this},addEvents:function(A){for(var B in A){this.addEvent(B,A[B])}return this},removeEvents:function(B){var A=this.retrieve("events");if(!A){return this}if(!B){for(var C in A){this.removeEvents(C)}A=null}else{if(A[B]){while(A[B].keys[0]){this.removeEvent(B,A[B].keys[0])}A[B]=null}}return this},fireEvent:function(D,B,A){var C=this.retrieve("events");if(!C||!C[D]){return this}C[D].keys.each(function(E){E.create({bind:this,delay:A,"arguments":B})()},this);return this},cloneEvents:function(D,A){D=$(D);var C=D.retrieve("events");if(!C){return this}if(!A){for(var B in C){this.cloneEvents(D,B)}}else{if(C[A]){C[A].keys.each(function(E){this.addEvent(A,E)},this)}}return this}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1};(function(){var A=function(B){var C=B.relatedTarget;if(C==undefined){return true}if(C===false){return false}return($type(this)!="document"&&C!=this&&C.prefix!="xul"&&!this.hasChild(C))};Element.Events=new Hash({mouseenter:{base:"mouseover",condition:A},mouseleave:{base:"mouseout",condition:A},mousewheel:{base:(Browser.Engine.gecko)?"DOMMouseScroll":"mousewheel"}})})();Element.Properties.styles={set:function(A){this.setStyles(A)}};Element.Properties.opacity={set:function(A,B){if(!B){if(A==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden"}}else{if(this.style.visibility!="visible"){this.style.visibility="visible"}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1}if(Browser.Engine.trident){this.style.filter=(A==1)?"":"alpha(opacity="+A*100+")"}this.style.opacity=A;this.store("opacity",A)},get:function(){return this.retrieve("opacity",1)}};Element.implement({setOpacity:function(A){return this.set("opacity",A,true)},getOpacity:function(){return this.get("opacity")},setStyle:function(B,A){switch(B){case"opacity":return this.set("opacity",parseFloat(A));case"float":B=(Browser.Engine.trident)?"styleFloat":"cssFloat"}B=B.camelCase();if($type(A)!="string"){var C=(Element.Styles.get(B)||"@").split(" ");A=$splat(A).map(function(E,D){if(!C[D]){return""}return($type(E)=="number")?C[D].replace("@",Math.round(E)):E}).join(" ")}else{if(A==String(Number(A))){A=Math.round(A)}}this.style[B]=A;return this},getStyle:function(G){switch(G){case"opacity":return this.get("opacity");case"float":G=(Browser.Engine.trident)?"styleFloat":"cssFloat"}G=G.camelCase();var A=this.style[G];if(!$chk(A)){A=[];for(var F in Element.ShortStyles){if(G!=F){continue}for(var E in Element.ShortStyles[F]){A.push(this.getStyle(E))}return A.join(" ")}A=this.getComputedStyle(G)}if(A){A=String(A);var C=A.match(/rgba?\([\d\s,]+\)/);if(C){A=A.replace(C[0],C[0].rgbToHex())}}if(Browser.Engine.presto||(Browser.Engine.trident&&!$chk(parseInt(A)))){if(G.test(/^(height|width)$/)){var B=(G=="width")?["left","right"]:["top","bottom"],D=0;B.each(function(H){D+=this.getStyle("border-"+H+"-width").toInt()+this.getStyle("padding-"+H).toInt()},this);return this["offset"+G.capitalize()]-D+"px"}if(Browser.Engine.presto&&String(A).test("px")){return A}if(G.test(/(border(.+)Width|margin|padding)/)){return"0px"}}return A},setStyles:function(B){for(var A in B){this.setStyle(A,B[A])}return this},getStyles:function(){var A={};Array.each(arguments,function(B){A[B]=this.getStyle(B)},this);return A}});Element.Styles=new Hash({left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"});Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(G){var F=Element.ShortStyles;var B=Element.Styles;["margin","padding"].each(function(H){var I=H+G;F[H][I]=B[I]="@px"});var E="border"+G;F.border[E]=B[E]="@px @ rgb(@, @, @)";var D=E+"Width",A=E+"Style",C=E+"Color";F[E]={};F.borderWidth[D]=F[E][D]=B[D]="@px";F.borderStyle[A]=F[E][A]=B[A]="@";F.borderColor[C]=F[E][C]=B[C]="rgb(@, @, @)"});(function(){Element.implement({scrollTo:function(H,I){if(B(this)){this.getWindow().scrollTo(H,I)}else{this.scrollLeft=H;this.scrollTop=I}return this},getSize:function(){if(B(this)){return this.getWindow().getSize()}return{x:this.offsetWidth,y:this.offsetHeight}},getScrollSize:function(){if(B(this)){return this.getWindow().getScrollSize()}return{x:this.scrollWidth,y:this.scrollHeight}},getScroll:function(){if(B(this)){return this.getWindow().getScroll()}return{x:this.scrollLeft,y:this.scrollTop}},getScrolls:function(){var I=this,H={x:0,y:0};while(I&&!B(I)){H.x+=I.scrollLeft;H.y+=I.scrollTop;I=I.parentNode}return H},getOffsetParent:function(){var H=this;if(B(H)){return null}if(!Browser.Engine.trident){return H.offsetParent}while((H=H.parentNode)&&!B(H)){if(D(H,"position")!="static"){return H}}return null},getOffsets:function(){var I=this,H={x:0,y:0};if(B(this)){return H}while(I&&!B(I)){H.x+=I.offsetLeft;H.y+=I.offsetTop;if(Browser.Engine.gecko){if(!F(I)){H.x+=C(I);H.y+=G(I)}var J=I.parentNode;if(J&&D(J,"overflow")!="visible"){H.x+=C(J);H.y+=G(J)}}else{if(I!=this&&(Browser.Engine.trident||Browser.Engine.webkit)){H.x+=C(I);H.y+=G(I)}}I=I.offsetParent;if(Browser.Engine.trident){while(I&&!I.currentStyle.hasLayout){I=I.offsetParent}}}if(Browser.Engine.gecko&&!F(this)){H.x-=C(this);H.y-=G(this)}return H},getPosition:function(K){if(B(this)){return{x:0,y:0}}var L=this.getOffsets(),I=this.getScrolls();var H={x:L.x-I.x,y:L.y-I.y};var J=(K&&(K=$(K)))?K.getPosition():{x:0,y:0};return{x:H.x-J.x,y:H.y-J.y}},getCoordinates:function(J){if(B(this)){return this.getWindow().getCoordinates()}var H=this.getPosition(J),I=this.getSize();var K={left:H.x,top:H.y,width:I.x,height:I.y};K.right=K.left+K.width;K.bottom=K.top+K.height;return K},computePosition:function(H){return{left:H.x-E(this,"margin-left"),top:H.y-E(this,"margin-top")}},position:function(H){return this.setStyles(this.computePosition(H))}});Native.implement([Document,Window],{getSize:function(){var I=this.getWindow();if(Browser.Engine.presto||Browser.Engine.webkit){return{x:I.innerWidth,y:I.innerHeight}}var H=A(this);return{x:H.clientWidth,y:H.clientHeight}},getScroll:function(){var I=this.getWindow();var H=A(this);return{x:I.pageXOffset||H.scrollLeft,y:I.pageYOffset||H.scrollTop}},getScrollSize:function(){var I=A(this);var H=this.getSize();return{x:Math.max(I.scrollWidth,H.x),y:Math.max(I.scrollHeight,H.y)}},getPosition:function(){return{x:0,y:0}},getCoordinates:function(){var H=this.getSize();return{top:0,left:0,bottom:H.y,right:H.x,height:H.y,width:H.x}}});var D=Element.getComputedStyle;function E(H,I){return D(H,I).toInt()||0}function F(H){return D(H,"-moz-box-sizing")=="border-box"}function G(H){return E(H,"border-top-width")}function C(H){return E(H,"border-left-width")}function B(H){return(/^(?:body|html)$/i).test(H.tagName)}function A(H){var I=H.getDocument();return(!I.compatMode||I.compatMode=="CSS1Compat")?I.html:I.body}})();Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y},getWidth:function(){return this.getSize().x},getScrollTop:function(){return this.getScroll().y},getScrollLeft:function(){return this.getScroll().x},getScrollHeight:function(){return this.getScrollSize().y},getScrollWidth:function(){return this.getScrollSize().x},getTop:function(){return this.getPosition().y},getLeft:function(){return this.getPosition().x}});Element.Events.domready={onAdd:function(A){if(Browser.loaded){A.call(this)}}};(function(){var B=function(){if(Browser.loaded){return }Browser.loaded=true;window.fireEvent("domready");document.fireEvent("domready")};switch(Browser.Engine.name){case"webkit":(function(){(["loaded","complete"].contains(document.readyState))?B():arguments.callee.delay(50)})();break;case"trident":var A=document.createElement("div");(function(){($try(function(){A.doScroll("left");return $(A).inject(document.body).set("html","temp").dispose()}))?B():arguments.callee.delay(50)})();break;default:window.addEvent("load",B);document.addEvent("DOMContentLoaded",B)}})();var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:"ignore",transition:function(A){return -(Math.cos(Math.PI*A)-1)/2}},initialize:function(A){this.subject=this.subject||this;this.setOptions(A);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();var B=this.options.wait;if(B===false){this.options.link="cancel"}},step:function(){var A=$time();if(A<this.time+this.options.duration){var B=this.options.transition((A-this.time)/this.options.duration);this.set(this.compute(this.from,this.to,B))}else{this.set(this.compute(this.from,this.to,1));this.complete()}},set:function(A){return A},compute:function(C,B,A){return Fx.compute(C,B,A)},check:function(A){if(!this.timer){return true}switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));return false}return false},start:function(B,A){if(!this.check(arguments.callee,B,A)){return this}this.from=B;this.to=A;this.time=0;this.startTimer();this.onStart();return this},complete:function(){if(this.stopTimer()){this.onComplete()}return this},cancel:function(){if(this.stopTimer()){this.onCancel()}return this},onStart:function(){this.fireEvent("start",this.subject)},onComplete:function(){this.fireEvent("complete",this.subject);if(!this.callChain()){this.fireEvent("chainComplete",this.subject)}},onCancel:function(){this.fireEvent("cancel",this.subject).clearChain()},pause:function(){this.stopTimer();return this},resume:function(){this.startTimer();return this},stopTimer:function(){if(!this.timer){return false}this.time=$time()-this.time;this.timer=$clear(this.timer);return true},startTimer:function(){if(this.timer){return false}this.time=$time()-this.time;this.timer=this.step.periodical(Math.round(1000/this.options.fps),this);return true}});Fx.compute=function(C,B,A){return(B-C)*A+C};Fx.Durations={"short":250,normal:500,"long":1000};Fx.CSS=new Class({Extends:Fx,prepare:function(D,E,B){B=$splat(B);var C=B[1];if(!$chk(C)){B[1]=B[0];B[0]=D.getStyle(E)}var A=B.map(this.parse);return{from:A[0],to:A[1]}},parse:function(A){A=$lambda(A)();A=(typeof A=="string")?A.split(" "):$splat(A);return A.map(function(C){C=String(C);var B=false;Fx.CSS.Parsers.each(function(F,E){if(B){return }var D=F.parse(C);if($chk(D)){B={value:D,parser:F}}});B=B||{value:C,parser:Fx.CSS.Parsers.String};return B})},compute:function(D,C,B){var A=[];(Math.min(D.length,C.length)).times(function(E){A.push({value:D[E].parser.compute(D[E].value,C[E].value,B),parser:D[E].parser})});A.$family={name:"fx:css:value"};return A},serve:function(C,B){if($type(C)!="fx:css:value"){C=this.parse(C)}var A=[];C.each(function(D){A=A.concat(D.parser.serve(D.value,B))});return A},render:function(A,D,C,B){A.setStyle(D,this.serve(C,B))},search:function(A){if(Fx.CSS.Cache[A]){return Fx.CSS.Cache[A]}var B={};Array.each(document.styleSheets,function(E,D){var C=E.href;if(C&&C.contains("://")&&!C.contains(document.domain)){return }var F=E.rules||E.cssRules;Array.each(F,function(I,G){if(!I.style){return }var H=(I.selectorText)?I.selectorText.replace(/^\w+/,function(J){return J.toLowerCase()}):null;if(!H||!H.test("^"+A+"$")){return }Element.Styles.each(function(K,J){if(!I.style[J]||Element.ShortStyles[J]){return }K=String(I.style[J]);B[J]=(K.test(/^rgb/))?K.rgbToHex():K})})});return Fx.CSS.Cache[A]=B}});Fx.CSS.Cache={};Fx.CSS.Parsers=new Hash({Color:{parse:function(A){if(A.match(/^#[0-9a-f]{3,6}$/i)){return A.hexToRgb(true)}return((A=A.match(/(\d+),\s*(\d+),\s*(\d+)/)))?[A[1],A[2],A[3]]:false},compute:function(C,B,A){return C.map(function(E,D){return Math.round(Fx.compute(C[D],B[D],A))})},serve:function(A){return A.map(Number)}},Number:{parse:parseFloat,compute:Fx.compute,serve:function(B,A){return(A)?B+A:B}},String:{parse:$lambda(false),compute:$arguments(1),serve:$arguments(0)}});Fx.Tween=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A)},set:function(B,A){if(arguments.length==1){A=B;B=this.property||this.options.property}this.render(this.element,B,A,this.options.unit);return this},start:function(C,E,D){if(!this.check(arguments.callee,C,E,D)){return this}var B=Array.flatten(arguments);this.property=this.options.property||B.shift();var A=this.prepare(this.element,this.property,B);return this.parent(A.from,A.to)}});Element.Properties.tween={set:function(A){var B=this.retrieve("tween");if(B){B.cancel()}return this.eliminate("tween").store("tween:options",$extend({link:"cancel"},A))},get:function(A){if(A||!this.retrieve("tween")){if(A||!this.retrieve("tween:options")){this.set("tween",A)}this.store("tween",new Fx.Tween(this,this.retrieve("tween:options")))}return this.retrieve("tween")}};Element.implement({tween:function(A,C,B){this.get("tween").start(arguments);return this},fade:function(C){var E=this.get("tween"),D="opacity",A;C=$pick(C,"toggle");switch(C){case"in":E.start(D,1);break;case"out":E.start(D,0);break;case"show":E.set(D,1);break;case"hide":E.set(D,0);break;case"toggle":var B=this.retrieve("fade:flag",this.get("opacity")==1);E.start(D,(B)?0:1);this.store("fade:flag",!B);A=true;break;default:E.start(D,arguments)}if(!A){this.eliminate("fade:flag")}return this},highlight:function(C,A){if(!A){A=this.retrieve("highlight:original",this.getStyle("background-color"));A=(A=="transparent")?"#fff":A}var B=this.get("tween");B.start("background-color",C||"#ffff88",A).chain(function(){this.setStyle("background-color",this.retrieve("highlight:original"));B.callChain()}.bind(this));return this}});Fx.Morph=new Class({Extends:Fx.CSS,initialize:function(B,A){this.element=this.subject=$(B);this.parent(A)},set:function(A){if(typeof A=="string"){A=this.search(A)}for(var B in A){this.render(this.element,B,A[B],this.options.unit)}return this},compute:function(E,D,C){var A={};for(var B in E){A[B]=this.parent(E[B],D[B],C)}return A},start:function(B){if(!this.check(arguments.callee,B)){return this}if(typeof B=="string"){B=this.search(B)}var E={},D={};for(var C in B){var A=this.prepare(this.element,C,B[C]);E[C]=A.from;D[C]=A.to}return this.parent(E,D)}});Element.Properties.morph={set:function(A){var B=this.retrieve("morph");if(B){B.cancel()}return this.eliminate("morph").store("morph:options",$extend({link:"cancel"},A))},get:function(A){if(A||!this.retrieve("morph")){if(A||!this.retrieve("morph:options")){this.set("morph",A)}this.store("morph",new Fx.Morph(this,this.retrieve("morph:options")))}return this.retrieve("morph")}};Element.implement({morph:function(A){this.get("morph").start(A);return this}});

/* Added by module "embed_images/viewer:slimbox2", file "mods/embed_images/viewers/slimbox2/code/js/slimbox.js" */
/*
	Slimbox v1.64 - The ultimate lightweight Lightbox clone
	(c) 2007-2008 Christophe Beyls <http://www.digitalia.be>
	MIT-style license.
*/
var Slimbox;(function(){var G=0,F,L,B,S,T,O,E,M,J=new Image(),K=new Image(),X,a,P,H,W,Z,I,Y,C;window.addEvent("domready",function(){$(document.body).adopt($$([X=new Element("div",{id:"lbOverlay"}).addEvent("click",N),a=new Element("div",{id:"lbCenter"}),Z=new Element("div",{id:"lbBottomContainer"})]).setStyle("display","none"));P=new Element("div",{id:"lbImage"}).injectInside(a).adopt(H=new Element("a",{id:"lbPrevLink",href:"#"}).addEvent("click",D),W=new Element("a",{id:"lbNextLink",href:"#"}).addEvent("click",R));I=new Element("div",{id:"lbBottom"}).injectInside(Z).adopt(new Element("a",{id:"lbCloseLink",href:"#"}).addEvent("click",N),Y=new Element("div",{id:"lbCaption"}),C=new Element("div",{id:"lbNumber"}),new Element("div",{styles:{clear:"both"}}));E={overlay:new Fx.Tween(X,{property:"opacity",duration:500}).set(0),image:new Fx.Tween(P,{property:"opacity",duration:500,onComplete:A}),bottom:new Fx.Tween(I,{property:"margin-top",duration:400})}});Slimbox={open:function(e,d,c){F=$extend({loop:false,overlayOpacity:0.8,resizeDuration:400,resizeTransition:false,initialWidth:250,initialHeight:250,animateCaption:true,showCounter:true,counterText:"Image {x} of {y}"},c||{});if(typeof e=="string"){e=[[e,d]];d=0}L=e;F.loop=F.loop&&(L.length>1);b();Q(true);O=window.getScrollTop()+(window.getHeight()/15);E.resize=new Fx.Morph(a,$extend({duration:F.resizeDuration,onComplete:A},F.resizeTransition?{transition:F.resizeTransition}:{}));a.setStyles({top:O,width:F.initialWidth,height:F.initialHeight,marginLeft:-(F.initialWidth/2),display:""});E.overlay.start(F.overlayOpacity);G=1;return U(d)}};Element.implement({slimbox:function(c,d){$$(this).slimbox(c,d);return this}});Elements.implement({slimbox:function(c,f,e){f=f||function(g){return[g.href,g.title]};e=e||function(){return true};var d=this;d.removeEvents("click").addEvent("click",function(){var g=d.filter(e,this);return Slimbox.open(g.map(f),g.indexOf(this),c)});return d}});function b(){X.setStyles({top:window.getScrollTop(),height:window.getHeight()})}function Q(c){["object",window.ie?"select":"embed"].forEach(function(e){Array.forEach(document.getElementsByTagName(e),function(f){if(c){f._slimbox=f.style.visibility}f.style.visibility=c?"hidden":f._slimbox})});X.style.display=c?"":"none";var d=c?"addEvent":"removeEvent";window[d]("scroll",b)[d]("resize",b);document[d]("keydown",V)}function V(c){switch(c.code){case 27:case 88:case 67:N();break;case 37:case 80:D();break;case 39:case 78:R()}return false}function D(){return U(S)}function R(){return U(T)}function U(c){if((G==1)&&(c>=0)){G=2;B=c;S=((B||!F.loop)?B:L.length)-1;T=B+1;if(T==L.length){T=F.loop?0:-1}$$(H,W,P,Z).setStyle("display","none");E.bottom.cancel().set(0);E.image.set(0);a.className="lbLoading";M=new Image();M.onload=A;M.src=L[c][0]}return false}function A(){switch(G++){case 2:a.className="";P.setStyles({backgroundImage:"url("+L[B][0]+")",display:""});$$(P,I).setStyle("width",M.width);$$(P,H,W).setStyle("height",M.height);Y.set("html",L[B][1]||"");C.set("html",(F.showCounter&&(L.length>1))?F.counterText.replace(/{x}/,B+1).replace(/{y}/,L.length):"");if(S>=0){J.src=L[S][0]}if(T>=0){K.src=L[T][0]}if(a.clientHeight!=P.offsetHeight){E.resize.start({height:P.offsetHeight});break}G++;case 3:if(a.clientWidth!=P.offsetWidth){E.resize.start({width:P.offsetWidth,marginLeft:-P.offsetWidth/2});break}G++;case 4:Z.setStyles({top:O+a.clientHeight,marginLeft:a.style.marginLeft,visibility:"hidden",display:""});E.image.start(1);break;case 5:if(S>=0){H.style.display=""}if(T>=0){W.style.display=""}if(F.animateCaption){E.bottom.set(-I.offsetHeight).start(0)}Z.style.visibility="";G=1}}function N(){if(G){G=0;M.onload=$empty;for(var c in E){E[c].cancel()}$$(a,Z).setStyle("display","none");E.overlay.chain(Q).start(0)}return false}})();

// AUTOLOAD CODE BLOCK (MAY BE CHANGED OR REMOVED)
Slimbox.scanPage = function() {
	var links = $$("a").filter(function(el) {
		return el.rel && el.rel.test(/^lightbox/i);
	});
	$$(links).slimbox({/* Put custom options here */}, null, function(el) {
		return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel));
	});
};
window.addEvent("load", Slimbox.scanPage);


/* Added by module "embed_images/viewer:slimbox2", file "mods/embed_images/viewers/slimbox2/viewer.js" */
// We do not use the lightbox init code for setting up the thumbnails.
// Instead, we setup the required events and data ourselves for each image,
// right after it is loaded. This is useful in case we dynamically add images
// to the page (e.g. through spoilers) and for making the image viewer act
// on image clicks as soon as possible.

function mod_embed_images_initviewer(container, image, link, url, message_id)
{
    var a = document.createElement('a');
    a.href = url;
    container.appendChild(a);
    a.rel = 'lightbox['+message_id+']';
    a.appendChild(image);

    $$(a).slimbox(
        {/* Put custom options here */},
        null,
        function(el) {
            return (this == el) ||
                   ((this.rel.length > 8) && (this.rel == el.rel));
        }
    );

    if (link) {
        $$(link).slimbox(
            {/* Put custom options here */},
            null,
            function(el) {
                return (this == el) ||
                       ((this.rel.length > 8) && (this.rel == el.rel));
            }
        );
    }
}



/* Added by module "bbcode", file "mods/bbcode/bbcode_editor_tools.js" */
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Copyright (C) 2008  Phorum Development Team                               //
// http://www.phorum.org                                                     //
//                                                                           //
// This program is free software. You can redistribute it and/or modify      //
// it under the terms of either the current Phorum License (viewable at      //
// phorum.org) or the Phorum License that was distributed with this file     //
//                                                                           //
// This program is distributed in the hope that it will be useful,           //
// but WITHOUT ANY WARRANTY, without even the implied warranty of            //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                      //
//                                                                           //
// You should have received a copy of the Phorum License                     //
// along with this program.                                                  //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

// Javascript code for BBcode support in the Phorum editor_tools module.

// Some variables for storing objects that we need globally.
var editor_tools_size_picker_obj = null;
var editor_tools_list_picker_obj = null;

// Valid sizes to select from for the size picker. If you add or change sizes,
// remember to change the module language file to supply some display strings.
var editor_tools_size_picker_sizes = new Array(
    'x-large',
    'large',
    'medium',
    'small',
    'x-small'
);

// Valid list types to select from for the list picker. If you add or change
// types, remember to change the module language file to supply some
// display strings.
var editor_tools_list_picker_types = new Array(
    'b', // bullets
    '1', // numbers
    'a', // letters
    'A', // capital letters
    'i', // roman numbers
    'I'  // capital roman numbers
);

// Helper function: quote a bbcode argument if needed.
function quote_bbcode_argument(str)
{
    // Check if quoting is required.
    if (str.indexOf(' ') != -1 ||
        str.indexOf('"') != -1 ||
        str.indexOf(']') != -1)
    {
        var quoted = '';
        for (var i = 0; i < str.length; i++) {
            var c = str[i];
            if (c == '\\' || c == '"') {
                quoted += '\\';
            }
            quoted += c;
        }

        return '"' + quoted + '"';
    }
    else
    {
        return str;
    }
}

// ----------------------------------------------------------------------
// Tool: [hr] or [hline] (horizontal line)
// ----------------------------------------------------------------------

function editor_tools_handle_hr() {
    editor_tools_add_tags('\n[hr]\n', '');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [b]...[/b] (bold)
// ----------------------------------------------------------------------

function editor_tools_handle_b() {
    editor_tools_add_tags('[b]', '[/b]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [s]...[/s] (strike through)
// ----------------------------------------------------------------------

function editor_tools_handle_s() {
    editor_tools_add_tags('[s]', '[/s]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [u]...[/u] (underline)
// ----------------------------------------------------------------------

function editor_tools_handle_u() {
    editor_tools_add_tags('[u]', '[/u]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [i]...[/i] (italic)
// ----------------------------------------------------------------------

function editor_tools_handle_i() {
    editor_tools_add_tags('[i]', '[/i]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [center]...[/center] (center text)
// ----------------------------------------------------------------------

function editor_tools_handle_center() {
    editor_tools_add_tags('[center]', '[/center]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [sub]...[/sub] (subscript)
// ----------------------------------------------------------------------

function editor_tools_handle_sub() {
    editor_tools_add_tags('[sub]', '[/sub]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [sup]...[/sup] (superscript)
// ----------------------------------------------------------------------

function editor_tools_handle_sup() {
    editor_tools_add_tags('[sup]', '[/sup]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [small]...[/small] (small font)
// ----------------------------------------------------------------------

function editor_tools_handle_small() {
    editor_tools_add_tags('[small]', '[/small]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [large]...[/large] (large font)
// ----------------------------------------------------------------------

function editor_tools_handle_large() {
    editor_tools_add_tags('[large]', '[/large]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [code]...[/code] (formatted code)
// ----------------------------------------------------------------------

function editor_tools_handle_code() {
    editor_tools_add_tags('[code]\n', '\n[/code]\n');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [email]...[/email] (email address link)
// ----------------------------------------------------------------------

function editor_tools_handle_email()
{
    var email = prompt(editor_tools_translate("enter email"), '');
    if (email == null) return;
    email = editor_tools_strip_whitespace(email);

    var subject = prompt(editor_tools_translate("enter subject"), '');
    if (subject == null) return;
    subject = editor_tools_strip_whitespace(subject);
    if (subject != '') {
        subject = ' subject=' + quote_bbcode_argument(subject);
    }

    if (email == '') {
        editor_tools_add_tags('[email'+subject+']', '[/email]');
    } else {
        editor_tools_add_tags('[email'+subject+']'+email+'[/email]', '');
    }

    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [url=...]...[/url] (URL link)
// ----------------------------------------------------------------------

function editor_tools_handle_url()
{
    var url = 'http://';

    for (;;)
    {
        // Read input.
        url = prompt(editor_tools_translate("enter url"), url);
        if (url == null) return; // Cancel clicked.
        url = editor_tools_strip_whitespace(url);

        // Check the URL scheme (http, https, ftp and mailto are allowed).
        copy = url.toLowerCase();
        if (copy == 'http://' || (
            copy.substring(0,7) != 'http://' &&
            copy.substring(0,8) != 'https://' &&
            copy.substring(0,6) != 'ftp://' &&
            copy.substring(0,7) != 'mailto:')) {
            alert(editor_tools_translate("invalid url"));
            continue;
        }

        break;
    }

    editor_tools_add_tags('[url=' + url + ']', '[/url]', null, editor_tools_translate("enter url description"));
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [color=...]...[/color] (text color)
// ----------------------------------------------------------------------

function editor_tools_handle_color()
{
    editor_tools_store_range();

    // Display the color picker.
    var img_obj = document.getElementById('editor-tools-img-color');
    showColorPicker(img_obj);
    return;
}

// Called by the color picker library.
function editor_tools_handle_color_select(color)
{
    editor_tools_restore_range();

    editor_tools_add_tags('[color=' + color + ']', '[/color]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [size=...]...[/size] (text size)
// ----------------------------------------------------------------------

function editor_tools_handle_size()
{
    editor_tools_store_range();

    // Create the size picker on first access.
    if (!editor_tools_size_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-size-picker','l');
        editor_tools_size_picker_obj = popup[0];
        var content_obj = popup[1];

        // Populate the new popup.
        for (var i = 0; i < editor_tools_size_picker_sizes.length; i++)
        {
            var size = editor_tools_size_picker_sizes[i];
            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_size_select("' + size + '")';
            a_obj.style.fontSize = size;
            a_obj.innerHTML = editor_tools_translate(size);
            content_obj.appendChild(a_obj);

            var br_obj = document.createElement('br');
            content_obj.appendChild(br_obj);
        }

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_size_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-size');
    editor_tools_toggle_popup(editor_tools_size_picker_obj, button_obj);
}

function editor_tools_handle_size_select(size)
{
    editor_tools_hide_all_popups();
    editor_tools_restore_range();
    size = editor_tools_strip_whitespace(size);
    editor_tools_add_tags('[size=' + size + ']', '[/size]');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [img]...[/img] (Image URL)
// ----------------------------------------------------------------------

function editor_tools_handle_img()
{
    var url = 'http://';

    for (;;)
    {
        // Read input.
        url = prompt(editor_tools_translate("enter image url"), url);
        if (url == null) return; // Cancel clicked.
        url = editor_tools_strip_whitespace(url);

        // Check the URL scheme (http, https, ftp and mailto are allowed).
        var copy = url.toLowerCase();
        if (copy == 'http://' || (
            copy.substring(0,7) != 'http://' &&
            copy.substring(0,8) != 'https://' &&
            copy.substring(0,6) != 'ftp://')) {
            alert(editor_tools_translate("invalid image url"));
            continue;
        }

        break;
    }

    editor_tools_add_tags('[img]' + url + '[/img]', '');
    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [quote]...[/quote] (add a quote)
// ----------------------------------------------------------------------

function editor_tools_handle_quote()
{
    // Read input.
    var who = prompt(editor_tools_translate("enter who you quote"), '');
    if (who == null) return;
    who = editor_tools_strip_whitespace(who);

    if (who == '') {
        editor_tools_add_tags('[quote]', '[/quote]');
    }
    else
    {
        who = quote_bbcode_argument(who);
        editor_tools_add_tags('[quote=' + who + "]\n", "\n[/quote]");
    }

    editor_tools_focus_textarea();
}

// ----------------------------------------------------------------------
// Tool: [list] [*]item1 [*]item2 [/list]
// ----------------------------------------------------------------------

function editor_tools_handle_list()
{
    // Create the list picker on first access.
    if (!editor_tools_list_picker_obj)
    {
        // Create a new popup.
        var popup = editor_tools_construct_popup('editor-tools-list-picker', 'l');
        editor_tools_list_picker_obj = popup[0];
        var content_obj = popup[1];

        // Populate the new popup.
        var wrapper = document.createElement('div');
        wrapper.style.marginLeft = '1em';
        for (var i = 0; i < editor_tools_list_picker_types.length; i++)
        {
            var type = editor_tools_list_picker_types[i];

            var list;
            if (type == 'b') {
                list = document.createElement('ul');
            } else {
                list = document.createElement('ol');
                list.type = type;
            }
            list.style.padding = 0;
            list.style.margin = 0;
            var item = document.createElement('li');

            var a_obj = document.createElement('a');
            a_obj.href = 'javascript:editor_tools_handle_list_select("' + type + '")';
            a_obj.innerHTML = editor_tools_translate('list type ' + type);

            item.appendChild(a_obj);
            list.appendChild(item);
            wrapper.appendChild(list);
        }
        content_obj.appendChild(wrapper);

        // Register the popup with the editor tools.
        editor_tools_register_popup_object(editor_tools_list_picker_obj);
    }

    // Display the popup.
    var button_obj = document.getElementById('editor-tools-img-list');
    editor_tools_toggle_popup(editor_tools_list_picker_obj, button_obj);
}

function editor_tools_handle_list_select(type)
{
    editor_tools_hide_all_popups();

    var items = new Array();
    var idx = 0;

    // Read items.
    for (;;)
    {
        var item = prompt(editor_tools_translate('enter new list item'), '');
        if (item == null) return;
        item = editor_tools_strip_whitespace(item);
        if (item == '') break;
        items[idx++] = item;
    }

    if (items.length == 0) {
        items = new Array(
            '...',
            '...'
        );
    }

    var itemlist = '';
    for (var i = 0; i < items.length; i++) {
        itemlist += '[*] ' + items[i] + "\n";
    }

    if (type == 'b') {
        type = '';
    } else {
        type = '='+type;
    }

    editor_tools_add_tags("[list"+type+"]\n"+itemlist+"[/list]\n", '');
}


