Source for "gorthaur's okoun multi-purpose script"

By gorthaur
Has no other scripts.


the source is over 100KB, syntax highlighting in the browser is too slow

// ==UserScript==
// @name           gorthaur's okoun multi-purpose script
// @namespace      gorthaur
// @description    vastly enhances okoun experience :) !Opera compatible!
// @include        http://www.okoun.cz/boards/*
// @include        http://www.okoun.cz/board.jsp?*
// @include        http://www.okoun.cz/postArticle.do*
// @include        http://www.okoun.cz/markWelcomeMsg.do*
// @include        http://www.okoun.cz/markArticles.do*
// @include        http://www.okoun.cz/markFavouriteBoards.do*
// ==/UserScript==

const gorthaursokounscript_version = '0.5.2';
//-----------------------------------------------------------------------------
//{{{
// fill in this object with your preferred settings
// look at the examples in DemoSettings() for inspiration

function UserSettings()
{
    if ( window.opera ) {
        this.image_encloseinAtag = false;       // not needed in Opera
    }
    //this.okounform_label_BR = '\u23CE';
    //if ( false )        // update BR formatbutton with the same label
    {
        if ( typeof this.okounform_label_BR == 'string' ) {
            R.set( 'okounform_label_BR', this.okounform_label_BR );
            delete this.okounform_label_BR;
        }
        this.formatbuttons = R.get( 'formatbuttons' );
        this.formatbuttons[ 10 ][ 1 ] = R.get( 'okounform_label_BR' );
        R.set( 'formatbuttons', this.formatbuttons );
        delete this.formatbuttons;
    }
    //this.navbar_labels = R.getDefault( 'navbar_labels_UNICODE' );
    //this.okounpost_linkmarkers = R.getDefault( 'okounpost_linkmarkers_UNICODE' );
    
}

//}}}
// ABSOLUTELY NO EDITING BELOW THIS LINE, UNLESS YOU ARE CERTIFIED HAXX0R
//-----------------------------------------------------------------------------
//{{{
// examples of how to make your own configuration in UserSettings() object

function DemoSettings()
{
    if ( window.opera ) {
        this.image_encloseinAtag = false;       // not needed in Opera
    }
    
    // disable particular operation on images
    //this.image_addalttext    = false;
    //this.image_addtitle      = false;
    //this.image_encloseinAtag = false;
    // or disable them all at once
    //this.image_processing    = false;
    
    // these are the defaults:
    //this.badaltpattern         = /^(\s)*$/;
    //this.imagealtreplacement   = '{IMG SRC="%s" ALT="%a" TITLE="%t" /}';
    //this.badtitlepattern       = /^(\s)*$/;
    //this.imagetitlereplacement = '%s';
    // suggested options:
    //this.imagealtreplacement   = '{IMG NO ALT}';
    //this.imagetitlereplacement = '%f';
    
    // these disable autojumping
    //this.autojumpto_locationhash = false;
    //this.autojumpto_oldestnewpost = false;
    
    // autoset post format options (unless a post is being previewed)
    //this.defaultbodyType = 'Radeox';
    //this.defaultbodyType = 'Text';
    //this.defaultbodyType = 'Html';
    //this.defaultpreviewFlag = 'Checked';
    //this.defaultpreviewFlag = 'Unchecked';      // can this be of any use?
    
    // +1 force keep, -1 force hide
    // 0 auto (keeps if %r not present in current menulayout)
    //this.okounpost_keepoldreplylink = +1;
    
    // set all layouts for readwrite mode
    //this.menulayout_rw_0 = '%v %w \n %o %p \n %r | %h | %X';
    // set all layouts for read mode
    //this.menulayout_r__0 = '%v %w \n %o %p \n %h | %X';
    // understands %v, %w, %o, %p, %r, %h,  , %b = \n, %X
    // particular menus for normal/context/root/search modes may be set
    
    // original contextId link text
    //this.okounpost_label_okolni = 'Okoln\u00ED p\u0159\u00EDsp\u011Bvky';
    
    if ( false )        // condensed menu design
    {
        this.menulayout_rw_0 = '%v %w %o %p \n %r | %h';
        this.menulayout_r__0 = '%v %w %o %p %h';
        this.okounpost_label_vlakno       = '\u00A0V\u00A0';
        this.okounpost_label_okolni       = '\u00A0O\u00A0';
        this.okounpost_label_vlakno2      = '[V]';
        this.okounpost_label_okolni2      = '[O]';
        this.okounpost_label_htmlcopier   = '[H]';
        this.okounpost_label_replycontrol = '[Re]';
    }
    
    // <BR /> button label default is:
    // Unicode Character 'DOWNWARDS ARROW WITH CORNER LEFTWARDS' (U+21B5)
    // http://www.fileformat.info/info/unicode/char/21b5/index.htm
    //
    // Unicode Character 'RETURN SYMBOL' (U+23CE)
    // http://www.fileformat.info/info/unicode/char/23ce/index.htm
    //this.okounform_label_BR = '\u23CE';
    // fall back to plain ASCII label
    //this.okounform_label_BR = 'BR';
    
    //if ( false )        // update BR formatbutton with the same label
    {
        if ( typeof this.okounform_label_BR == 'string' ) {
            R.set( 'okounform_label_BR', this.okounform_label_BR );
            delete this.okounform_label_BR;
        }
        this.formatbuttons = R.get( 'formatbuttons' );
        this.formatbuttons[ 10 ][ 1 ] = R.get( 'okounform_label_BR' );
        R.set( 'formatbuttons', this.formatbuttons );
        delete this.formatbuttons;
    }
    
    //this.okounpost_linkmarkers = [];            // all markers blank
    //this.okounpost_linkmarkers = R.getDefault( 'okounpost_linkmarkers' );
    // UNICODE version uses these two characters:
    // Unicode Character 'CLOCKWISE TOP SEMICIRCLE ARROW' (U+21B7)
    // http://www.fileformat.info/info/unicode/char/21b7/index.htm
    // Unicode Character 'VECTOR OR CROSS PRODUCT' (U+2A2F)
    // http://www.fileformat.info/info/unicode/char/2a2f/index.htm
    //this.okounpost_linkmarkers = R.getDefault( 'okounpost_linkmarkers_UNICODE' );
    if ( this.okounpost_linkmarkers instanceof Array ) {
        // no markers for local page links
        //this.okounpost_linkmarkers[ 0 ] = '';
        //this.okounpost_linkmarkers[ 1 ] = '';
        // Unicode Character 'DOWNWARDS ARROW' (U+2193)
        // http://www.fileformat.info/info/unicode/char/2193/index.htm
        //this.okounpost_linkmarkers[ 0 ] = '\u2193 ';
        //this.okounpost_linkmarkers[ 1 ] = ' \u2193';
        // Unicode Character 'MULTIPLICATION SIGN' (U+00D7)
        // http://www.fileformat.info/info/unicode/char/00d7/index.htm
        //this.okounpost_linkmarkers[ 4 ] = '\u00D7 ';
        //this.okounpost_linkmarkers[ 5 ] = ' \u00D7';
        // Unicode Character 'BLACK CIRCLE' (U+25CF)
        // http://www.fileformat.info/info/unicode/char/25cf/index.htm
        //this.okounpost_linkmarkers[ 4 ] = '\u25CF ';
        //this.okounpost_linkmarkers[ 5 ] = ' \u25CF';
    }
    //delete this.okounpost_linkmarkers;           // void all changes
    
    // 0 none, 1 assumed dead (default), 2 all
    //this.blockoutcominglinks = 1;
    
    // affects the way jumping to lower posts is performed
    // allowed values are 1, 2, 3, 4; 0 to completely disable jumping
    //this.postjump_mode = 0;
    
    // four values bellow are in pixels
    // margin above topmost post (takes magic string 'article-form-main')
    //this.postjump_extendtop    = 'article-form-main';
    // margin bellow bottommost post
    //this.postjump_extendbottom = 100;
    // count post as visible if only so much pixels is obscured
    //this.postjump_ignore       = 7;
    // the margin around jump target
    //this.postjump_margin       = 5;
    
    // disable jumping keyboard controls
    //this.keyboardjumping = false;
    
    // the default keybindings for jumping
    //this.jumpkeys_down    = 'nN';
    //this.jumpkeys_up      = 'bB';
    //this.jumpkeys_new     = 'hH';
    //this.jumpkeys_botttom = 'mM';
    //this.jumpkeys_top     = 'vV';
    //this.jumpkeys_menu    = '';
    
    // the delay between repeated jumps while holding mouse button
    // over the navigation bar (in miliseconds)
    // 0 for no repeat, -1 disables navbar
    //this.navjumpdelay = 333;    // default
    //this.navjumpdelay = 50;     // real fast
    
    //this.navbar_labels = R.getDefault( 'navbar_labels' );
    // use unicode characters for navbar labels
    //this.navbar_labels = R.getDefault( 'navbar_labels_UNICODE' );
    if ( this.navbar_labels instanceof Array ) {
        //this.navbar_labels[ 5 ] = '\u2605';   // black star (default in UC)
        //this.navbar_labels[ 5 ] = '\u2217';   // asterisk
        //this.navbar_labels[ 5 ] = '\u25CB';   // white circle
    }
    
    // default order
    //this.navbar_order = [ 1, 2, 3, 4, 5, 6, 7 ];
    // change the order to your liking, buttons may be omitted
    //this.navbar_order = [ 1, 0, 2, 4, 0, 3, 5 ];
    
    // change initial state of the 2 checkboxes
    //this.identry_chaddr_default = true;
    //this.identry_newtab_default = false;
    
    // the default flashing scheme
    //this.flash_repeat = 4;            // how many times switch colors
    //this.flash_timing = [ 40 ];       // delay(s) between switches in ms
    //this.flash_delay  = 1000;         // min 10, max 30000 (in ms)
    
    // erratic flashing mode
    //this.flash_repeat = 13; this.flash_timing = [ 50, 50, 50, 50, 250 ];
    //this.flash_repeat = 2; this.flash_timing = [ 150 ];       // calm mode
    //this.flash_repeat = 0;            // no flashing
    
    //this.flash_norepeat = 2500;       // min 10, max 30000 (in ms)
    
    // high contrast flashing
    //this.flashing_colors = R.getDefault( 'flashing_colors_HIGH_CONTRAST' );
    //this.flashing_colors = [ 'rgb( 100%, 0%, 0% )',
    //        '#0af19c', 'yellow', 'rgb( 10, -10, 160 )' ];       // eww
    
    // do not add the format buttons row
    //this.makeformatbuttons = false;
    if ( false )        // inserts some additional buttons
    {
        this.formatbuttons = R.get( 'formatbuttons' ).slice( 0, 3 );
        this.formatbuttons.push(
                [ 'strike',    'S',      '<strike>%c</strike>',
                                         '<strike>%r</strike>', 'h' ] );
        this.formatbuttons = this.formatbuttons.concat(
                R.get( 'formatbuttons' ).slice( 3, 7 ) );
        if ( false )    // more examples (not very useful)
        {
            this.formatbuttons.push(
                    [ 'small',     '-',      '<small>%c</small>',
                                             '<small>%r</small>',   'h' ],
                    [ 'big',       '+',      '<big>%c</big>',
                                             '<big>%r</big>',       'h' ],
                    [ 'sub',       'sub',    '<sub>%c</sub>',
                                             '<sub>%r</sub>',       'h' ],
                    [ 'sup',       'sup',    '<sup>%c</sup>',
                                             '<sup>%r</sup>',       'h' ] );
        }
        this.formatbuttons = this.formatbuttons.concat(
                R.get( 'formatbuttons' ).slice( 7 ) );
    }
    
    if ( false )        // reverses the order of first three buttons
    {
        this.formatbuttons = [
                    R.get( 'formatbuttons' )[ 2 ],
                    R.get( 'formatbuttons' )[ 1 ],
                    R.get( 'formatbuttons' )[ 0 ]
                ].concat( R.get( 'formatbuttons' ).slice( 3 ) );
    }
    
    // remove all but first four items from htmlents2
    //this.htmlents2 = R.getDefault( 'htmlents2' ).slice( 0, 4 );
    
    if ( false )        // adds some colors only to table bgcolors
    {
        this.bgcolors = R.getDefault( 'fontcolors' ).slice( 0, 8 );
        this.bgcolors.push( 'silver|st\u0159\u00EDbrn\u00E1' );
        this.bgcolors = this.bgcolors.concat(
                R.getDefault( 'fontcolors' ).slice( 8 ) );
        this.bgcolors.push( 'olive', 'maroon', 'orange|oran\u017Eov\u00E1' );
    }
    
    //this.max_table_cols = 10;         // default; max_max is 99
    //this.max_table_rows = 10;         // default; max_max is 99
    
    // disable the board pager link to current page recreation
    //this.reactivatelinktocurrentpage = false;
    
    // how to handle CTRL + ENTER? default is +1 for the new method
    // 0 to disable, -1 keeps the old, buggy style
    //this.ctrlenterhandling = 0;
    
    // run when DOM ready (bare document loaded)
    //this.runASAP = false;       // turn off one run
    // run when page loaded completely
    //this.runLATE = false;       // turn off the other one
    // if both are true, it makes one full run, and jumps to #anchor later
    // if both are false, the script never does its job
    
    // in order to have the first execution run really ASAP in Opera,
    // the script filename MUST NOT end with .user.js
    // (but it of course must end with .js )
    
    // do not jump second time after so much miliseconds has passed
    //this.cancelnextrunafter = 2000;     // 2 seconds timer (default)
    //this.cancelnextrunafter = 0;        // 0 never jumps twice
    
    if ( false )        // examples of Ignorowacz object usage
    {
        this.ignorelist = [
            // exact nick "gorthaur" in board with exact name "hokus"
            new Ignorowacz( /^hokus$/, 'u', /^gorthaur$/ ),
            // nick ends with "isto", except for "MacPhisto", in any board
            new Ignorowacz( '*', '*', /isto$/i, /^MacPhisto$/ ),
            // nick contains "igi", board name contains at least 1 character
            new Ignorowacz( /./, 'u', /igi/ ),
            // empty nick everywhere
            new Ignorowacz( '*', '*', /^$/ ),
            // every anonymous in boards containing "kompost" in title
            new Ignorowacz( /kompost/i, 'A' ),
            null ];
    }
    //this.ignorelist = null;     // the default is to not ignore anyone
    
    // this is also a good place to have some sections of globalstyle object
    //delete globalstyle.narrowspaces;            // either removed
    //globalstyle.narrowspaces[ 1 ] = null;       // or altered at will
    //globalstyle.other.push( '.article div.marks { border: 2px dashed black; }' );
    // watch out, changing some may make stuff ugly or downright disfunctional
}
DemoSettings = undefined;

//}}}
//-----------------------------------------------------------------------------
//{{{

var globalstyle = {
    iconframe: [
        'div.user-icon { width: 40px; height: 50px; padding: 0; }',
        null ],
    narrowspaces: [
        '.article, .item, .posted-item { margin-top: 2px; margin-bottom: 2px; }',
        '.separator { font-size: 6px; }',
        null ],
    compactposts: [
        'div.context { margin-bottom: 0; padding-bottom: 0; }',
        'ul.article-menu { margin: 1px; font-size: 90%; padding: 0 0 0.5em 1.5em; }',
        null ],
    activepage: [
        '#board-pager .active { font-size: 107%; text-decoration: line-through; }',
        '#board-pager .active a { text-decoration: line-through; margin: 0 0.5em; }',
        null ],
    other: [
        'div.reply-form h3 { margin-top: 2px; margin-bottom: 2px; }',
        null ],
    general: [
        '._MAX_W_100P { max-width: 100%; }',
        '._D_IB { display:-moz-inline-block; display:-moz-inline-box;'
        + 'display: inline-block; }', '._D_I { display: inline; }',
        '._T_A_C { text-align: center; }', '._T_A_R { text-align: right; }',
        '._RIGHT { margin-left: auto; margin-right: 0; }',
        '._CENTER { margin-left: auto; margin-right: auto; }',
        '._F_L { float: left; } ._F_R { float: right; }',
        '._C_L { clear: left; } ._C_B { clear: both; } ._C_R { clear: right; } ',
        'br._C_L, br._C_B, br._C_R { font-size: 1px; }',
        null ],
    toolboxes: [
        '.toolbox { background-color: silver; color: black; z-index: 100;'
        + ' width: auto; min-width: 100px; max-width: 70%;'
        + ' height: auto; min-height: 1.1em; max-height: 50%;'
        + ' margin: 0; border: 2px dashed black; padding: 5px; }',
        '.toolboxA { position: absolute; right: 2.5em; top: -20em; }',
        '.toolbox.shown { display: block; }',
        '.toolbox.hidden, .toolbox.shown.hidden {'
        + ' background-color: transparent; opacity: 0.0;'
        + ' display: none; top: -20em; z-index: -1; }',
        null ],
    dummyinput: [
        '.dummyinput, .dummyinput input {'
        + ' height: 0px; width: 0px; overflow: hidden;'
        + ' padding: 0; border: 0; margin: 0;'
        + ' background-color: inherit; color: silver; }',
        null ],
    minimized: [
        '.article.minimized > div, .item.minimized > div,'
        + ' .posted-item.minimized > div { display: none; }',
        '.article.minimized, .item.minimized, .posted-item.minimized {'
        + ' margin-bottom: 1em; margin-top: 0.3em;'
        + ' padding: 1px; border: 1px solid;'
        + ' float: left; clear: none; }',
        '.article .restore, .item .restore, .posted-item .restore {'
        + ' display: none; }',
        '.article.minimized .restore, .item.minimized .restore,'
        + ' .posted-item.minimized .restore { display: block;'
        + ' padding: 1px; border: 0; margin: 0 .4em; }',
        '.separator.minimized { display: none; }',
        '.minimized-author { font-weight: bold; }',
        '.minimized-author.anon { font-weight: normal; font-style: italic; }',
        null ],
    flashing: [],
    deletedarticle: [
        '.deleted-article { clear: both;'
        + ' padding: 0; border: 0; margin: 0; }',
        '.deleted-article .hr { overflow: hidden; height: 0px;'
        + 'padding: 0; border: 3px solid red; margin: 0; }',
        '.deleted-article br { font-size: 6px; }',
        '.deleted-article br.hidden { display: none; }',
        null ]
};

//}}}
//-----------------------------------------------------------------------------
//{{{

var R = {
    CVs: {},
    get: function get( name, depth ) {
        if ( typeof name != 'string' ) return undefined;
        var dD1 = R.DDs[ name ];
        if ( !( dD1 instanceof R.DDefinition ) ) return undefined;
        if ( R.CVs[ name ] !== undefined )
            return R.xport( R.CVs[ name ] );
        if ( dD1.defVal !== undefined )
            return R.xport( dD1.defVal );
        if ( !R.DDefinition.checkName( dD1.cascade ) )
            return undefined;
        if ( typeof depth != 'number' ) depth = 0;
        else {
            depth = Math.floor( depth );
            if ( depth > 7 ) return undefined;
            if ( depth < 0 ) depth = 1;
        }
        return R.get( dD1.cascade, depth + 1 );
    },
    getDefault: function getDefault( name, depth ) {
        if ( typeof name != 'string' ) return undefined;
        var dD1 = R.DDs[ name ];
        if ( !( dD1 instanceof R.DDefinition ) ) return undefined;
        if ( dD1.defVal !== undefined )
            return R.xport( dD1.defVal );
        if ( !R.DDefinition.checkName( dD1.cascade ) )
            return undefined;
        if ( typeof depth != 'number' ) depth = 0;
        else {
            depth = Math.floor( depth );
            if ( depth > 7 ) return undefined;
            if ( depth < 0 ) depth = 1;
        }
        return R.getDefault( dD1.cascade, depth + 1 );
    },
    xport: function xport( value ) {
        if ( value instanceof Array )
            return value.slice( 0 );
        return value;
    },
    set: function set( name, value ) {
        if ( typeof name != 'string' ) return false;
        var dD1 = R.DDs[ name ];
        if ( !( dD1 instanceof R.DDefinition ) ) {
            consolemsg( 'undefined name "' + name + '"' );
            return false;
        }
        var valid = false, v1 = value;
        switch ( dD1.type ) {
            case 's' :
                if ( typeof v1 == 'string' )
                    valid = true;
                break;
            case 'b' :
                if ( typeof v1 == 'boolean' ) {
                    valid = true;
                } else if ( is_true( v1 ) ) {
                    v1 = true;
                    valid = true;
                } else if ( is_false( v1 ) ) {
                    v1 = false;
                    valid = true;
                }
                break;
            case 'i' :
                var v2;
                if ( typeof v1 == 'string' ) {
                    v1 = trim( v1 );
                    if ( v1 == 'NaN' ) {
                        v1 = NaN;
                        valid = true;
                    } else {
                        v2 = Math.floor( Number( v1 ) );
                        if ( String( v2 ) != v1 )
                            break;
                        v1 = v2;
                        valid = true;
                    }
                } else if ( typeof v1 == 'number' ) {
                    if ( v1 == NaN ) {
                        valid = true;
                    } else {
                        v2 = Math.floor( v1 );
                        if ( v2 != v1 )
                            break;
                        v1 = v2;
                        valid = true;
                    }
                }
                if ( valid ) {
                    v2 = dD1.minVal;
                    if ( ( typeof v2 == 'number' ) &&
                            ( v2 != NaN ) && ( v2 > v1 ) ) {
                        valid = false;
                        break;
                    }
                    v2 = dD1.maxVal;
                    if ( ( typeof v2 == 'number' ) &&
                            ( v2 != NaN ) && ( v2 < v1 ) )
                        valid = false;
                }
                break;
            case 'r' :
                if ( v1 instanceof RegExp )
                    valid = true;
                break;
            case 'a' :
                if ( v1 instanceof Array )
                    valid = true;
                break;
        }
        if ( typeof dD1.specialCheck == 'function' ) {
            var v3 = dD1.specialCheck( value, v1, valid );
            if ( typeof v3 == 'boolean' )
                valid = v3;
            else if ( v3 instanceof Object ) {
                valid = true;
                v1 = v3[ 'value' ];
            }
        }
        if ( valid ) {
            R.CVs[ name ] = v1;
            return true;
        }
        return false;
    },
    DDs: {},
    DDefinition: function DDefinition( dName, properties ) {
        this.type = '';
        this.defVal = undefined;
        this.cascade = undefined;
        this.minVal = this.maxVal = undefined;
        this.specialCheck = null;
        
        this.set = function set( name, value ) {
            if ( typeof name != 'string' ) return false;
            if ( name == 'cascade' ) {
                if ( R.DDefinition.checkName( value ) ) {
                    this[ name ] = value;
                    return true;
                } else {
                    return false;
                }
            }
            var type = R.DDefinition.propertiesMap[ name ];
            if ( typeof type != 'string' ) return false;
            var valid = false;
            switch ( type ) {
                case '*' :
                    valid = true;
                    break;
                case 's' :
                    if ( typeof value != 'string' ) break;
                    valid = true;
                    break;
                case 'i' :
                    var v2;
                    if ( typeof value == 'string' ) {
                        value = trim( value );
                        v2 = Math.floor( Number( value ) );
                        if ( String( v2 ) != value )
                            break;
                        value = v2;
                        valid = true;
                    } else if ( typeof value == 'number' ) {
                        if ( value == NaN ) {
                            valid = true;
                            break;
                        }
                        v2 = Math.floor( value );
                        if ( v2 != value )
                            break;
                        value = v2;
                        valid = true;
                    }
                    break;
                case 'f' :
                    if ( value === null ) valid = true;
                    if ( typeof value == 'function' ) valid = true;
                    break;
            }
            if ( !valid ) return false;
            this[ name ] = value;
            return true;
        };
        
        this.toString = function toString() {
            var ret = 'DD: "' + this.type + '"';
            if ( this.defVal !== undefined ) ret += ', [' + this.defVal + ']';
            else if ( R.DDefinition.checkName( this.cascade ) )
                ret += ', => "' + this.cascade + '"';
            if ( typeof this.minVal == 'number' ) ret += ', ' + this.minVal + ' <';
            if ( typeof this.maxVal == 'number' ) ret += ', < ' + this.minVal + '';
            if ( typeof this.specialCheck == 'function' ) ret += ', specialCheck';
            return ret;
        }
        
        for ( var i in properties ) {
            this.set( i, properties[ i ] );
        };
        
        R.addDD( dName, this );
    },
    addDD: function addDD( name, dD1 ) {
        if ( ( typeof name != 'string' ) ||
                !( dD1 instanceof R.DDefinition ) )
            return false;
        var key = trim( name );
        if ( !R.DDefinition.checkName( key ) ) return false;
        R.DDs[ key ] = dD1;
        return true;
    },
    i: {}       // internal variables
};

R.DDefinition.propertiesMap = {
    type: 's',
    defVal: '*',
    cascade: 's',
    minVal: 'i',
    maxVal: 'i',
    specialCheck: 'f'
};

R.DDefinition.checkName = function( name ) {
    if ( typeof name != 'string' ) return false;
    if ( /^[A-Za-z_][A-Za-z_0-9]*$/.test( name ) ) return true;
    return false;
}

R.DDs.toString = function toString() {
    var ret = '[', cnt = 0;
    for ( var i in R.DDs ) {
        if ( !( R.DDs[ i ] instanceof R.DDefinition ) ) continue;
        if ( cnt++ >= 0 ) ret += '\n';
        ret += i + ' => ' + R.DDs[ i ];
    }
    if ( cnt > 0 ) ret += '\n';
    ret += ']';
    return ret;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function RDD( name, properties ) {
    new R.DDefinition( name, properties );
}

RDD( 'image_processing',      { type: 'b', defVal: true } );
RDD( 'image_addalttext',      { type: 'b', defVal: true } );
RDD( 'image_addtitle',        { type: 'b', defVal: true } );
RDD( 'image_encloseinAtag',   { type: 'b', defVal: true } );
RDD( 'badaltpattern',         { type: 'r', defVal: /^(\s)*$/ } );
RDD( 'imagealtreplacement',   { type: 's', defVal: '{IMG SRC="%s" ALT="%a" TITLE="%t" /}' } );
RDD( 'badtitlepattern',       { type: 'r', defVal: /^(\s)*$/ } );
RDD( 'imagetitlereplacement', { type: 's', defVal: '%s' } );
RDD( 'autojumpto_locationhash',  { type: 'b', defVal: true } );
RDD( 'autojumpto_oldestnewpost', { type: 'b', defVal: true } );
RDD( 'defaultbodyType',    { type: 's', defVal: '' } );
RDD( 'defaultpreviewFlag', { type: 's', defVal: '' } );
RDD( 'okounpost_keepoldreplylink', { type: 'i', defVal: 0, minVal: -1, maxVal: +1 } );
RDD( 'menulayout_rw_0', { type: 's', defVal: '%v %w \n %o %p \n %r | %h' } );
RDD( 'menulayout_r__0', { type: 's', defVal: '%v %w \n %o %p \n %h' } );
RDD( 'menulayout_rw_normal',  { type: 's', cascade: 'menulayout_rw_0' } );
RDD( 'menulayout_rw_context', { type: 's', cascade: 'menulayout_rw_0' } );
RDD( 'menulayout_rw_root',    { type: 's', cascade: 'menulayout_rw_0' } );
RDD( 'menulayout_rw_search',  { type: 's', cascade: 'menulayout_rw_0' } );
RDD( 'menulayout_r__normal',  { type: 's', cascade: 'menulayout_r__0' } );
RDD( 'menulayout_r__context', { type: 's', cascade: 'menulayout_r__0' } );
RDD( 'menulayout_r__root',    { type: 's', cascade: 'menulayout_r__0' } );
RDD( 'menulayout_r__search',  { type: 's', cascade: 'menulayout_r__0' } );
RDD( 'okounpost_label_vlakno', { type: 's', defVal: 'Vl\u00E1kno' } );
RDD( 'okounpost_label_okolni', { type: 's', defVal: 'Okoln\u00ED' } );
RDD( 'okounpost_label_vlakno2', { type: 's', defVal: '<V>' } );
RDD( 'okounpost_label_okolni2', { type: 's', defVal: '<Op>' } );
RDD( 'okounpost_label_htmlcopier', { type: 's', defVal: '<H>' } );
RDD( 'okounpost_label_replycontrol', { type: 's', defVal: '<Re>' } );
RDD( 'okounform_label_BR',           { type: 's', defVal: '\u21B5' } );
RDD( 'okounpost_linkmarkers',        { type: 'a', defVal: [
        '# ', ' #', '-> ', ' ->', 'X ', ' X' ] } );
RDD( 'okounpost_linkmarkers_UNICODE', { type: 'a', defVal: [
        '# ', ' #', '\u21B7 ', ' \u21B7', '\u2A2F ', ' \u2A2F' ] } );
RDD( 'blockoutcominglinks',   { type: 'i', defVal: 1, minVal: 0, maxVal: 2 } );
RDD( 'postjump_mode',         { type: 'i', defVal: 3, minVal: 0, maxVal: 4 } );
RDD( 'postjump_ignore',       { type: 'i', defVal: 7, minVal: 0, maxVal: 100 } );
RDD( 'postjump_margin',       { type: 'i', defVal: 5, minVal: 0, maxVal: 100 } );
RDD( 'postjump_extendbottom', { type: 'i', defVal: 100, minVal: 0, maxVal: 1000 } );
RDD( 'postjump_extendtop',
        { type: 'i', defVal: 'article-form-main', minVal: 0, maxVal: 1000,
            specialCheck: function specialCheck( value, newVal, valid )
            {
                if ( value === 'article-form-main' )
                    return true;
                return undefined;
            }
        } );
RDD( 'keyboardjumping',  { type: 'b', defVal: true } );
RDD( 'jumpkeys_down',    { type: 's', defVal: 'nN' } );
RDD( 'jumpkeys_up',      { type: 's', defVal: 'bB' } );
RDD( 'jumpkeys_new',     { type: 's', defVal: 'hH' } );
RDD( 'jumpkeys_botttom', { type: 's', defVal: 'mM' } );
RDD( 'jumpkeys_top',     { type: 's', defVal: 'vV' } );
RDD( 'jumpkeys_menu',    { type: 's', defVal: '' } );
RDD( 'navjumpdelay',  { type: 'i', defVal: 333, minVal: -1, maxVal: 2000 } );
RDD( 'navbar_labels', { type: 'a', defVal: [
        'm', '|<', '/\\', '\\/', '>|', '*', '#'
        ] } );
RDD( 'navbar_labels_UNICODE', { type: 'a', defVal: [
        '\u21F1', '\u25F8', '\u25B3', '\u25BD', '\u25FF', '\u2605', '#'
        ] } );
RDD( 'navbar_order',  { type: 'a', defVal: [ 1, 2, 3, 4, 5, 6, 7 ] } );
RDD( 'identry_chaddr_default', { type: 'b', defVal: false } );
RDD( 'identry_newtab_default', { type: 'b', defVal: true } );
RDD( 'flash_repeat',     { type: 'i', defVal: 4, minVal: 0, maxVal: 50 } );
RDD( 'flash_timing',     { type: 'a', defVal: [ 40 ] } );
RDD( 'flash_delay',      { type: 'i', defVal: 1000, minVal: 10, maxVal: 30000 } );
RDD( 'flash_norepeat',   { type: 'i', defVal: 2500, minVal: 10, maxVal: 30000 } );
RDD( 'flashing_colors',  { type: 'a', defVal:
        [ 'lightgray', 'gray', '#33ccff', '#ffccdd' ] } );
RDD( 'flashing_colors_HIGH_CONTRAST',  { type: 'a', defVal:
        [ 'white', 'black', 'black', 'white' ] } );
RDD( 'makeformatbuttons', { type: 'b', defVal: true } );
RDD( 'formatbuttons', { type: 'a', defVal: [
        [ 'bold',      'B',      '<strong>%c</strong>',
                                 '<strong>%r</strong>', 'h' ],
        [ 'italic',    'I',      '<em>%c</em>',
                                 '<em>%r</em>',         'h' ],
        [ 'underline', 'U',      '<u>%c</u>',
                                 '<u>%r</u>',           'h' ],
        [ 'tagpair',   '<?>',    '<%1%3>%2</%1>',
                                 '<%1%3>%2</%1>',       'h', 'tagpair', '2' ],
        [ 'url',       'URL',    '<a href="%1" %3>%2</a>',
                                 '%b',                  'h', 'url', '2' ],
        [ 'img',       'IMG',    '<img src="%1" %2%3/>',
                                 '%b',                  'h', 'img', '1' ],
        [ 'font',      'FONT',  '<font %1%2>%3</font>',
                                 '%b',                  'h', 'font', '3' ],
        [ 'code',      '{c}',    '{code}%c{code}',
                                 '{code}%r{code}',      'r' ],
        [ 'table',     'T',      '<table%3>\n%4%c%5</table>',
                                 '<table>\n<tr><td>%r</td></tr>\n</table>',
                                                        'h', 'table', '4' ],
        [ 'html',      '&X;',    '%1',
                                 '%1',                  'h', 'html', '1' ],
        [ 'br',        'BR',     '<br />\n',
                                 '<p>%r</p>\n',         'h' ],
        null ] } );
RDD( 'htmlents1',  { type: 'a', defVal: [
        '>lt', '<nbsp', '<gt', '/',
        '<amp', '<quot', '<apos', '/',
        'bdquo', 'ldquo', 'sbquo', 'lsquo', 'hellip', 'mdash', 'ndash', '/',
        null ] } );
RDD( 'htmlents2',  { type: 'a', defVal: [
        'plusmn', 'minus', 'frasl', 'divide', 'times', 'middot', 'bull', '/',
        'equiv', 'cong', 'asymp', 'sim', 'ne', 'le', 'ge', '/',
        'radic', 'sum', 'prod', 'pi', 'micro', 'infin', '#x2300', '/',
        'empty', 'and', 'or', 'not', 'deg', 'prime', 'Prime', '/',
        'sup1', 'sup2', 'sup3', 'frac14', 'frac12', 'frac34', 'permil', '/',
        'copy', 'reg', 'trade', 'brvbar', 'cent', 'euro', '/',
        'alefsym', 'iexcl', 'iquest', '#x2642', '#x2640', 'para', 'crarr', '/',
        'larr', 'uarr', 'darr', 'rarr', '#x2195', 'harr', '/',
        'lArr', 'uArr', 'dArr', 'rArr', '#x21d5', 'hArr', '/',
        null ] } );
RDD( 'taglist',  { type: 'a', defVal: [
        'strike', 'sup', 'sub', 'pre',
        'center', 'blockquote', 'code', 'cite', 'big', 'small',
        'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
        null ] } );
RDD( 'fontcolors',  { type: 'a', defVal: [
        'fuchsia|fialov\u00E1', 'blue/white|modr\u00E1',
        'cyan|azurov\u00E1', 'lime|zelen\u00E1',
        'yellow/black|y)\u017Elut\u00E1', 'red|r)\u010Derven\u00E1',
        'white/black|w)b\u00EDl\u00E1',
        'lightgray/black|\u0161ed\u00E1 17%',
        //'silver|st\u0159\u00EDbrn\u00E1', // = 25% g(r)ay
        'darkgray|\u0161ed\u00E1 34%', 'gray|g)\u0161ed\u00E1 50%',
        'black/white|b)\u010Dern\u00E1',
        'violet', 'purple',
        'navy/white', 'teal', 'green',
        //'olive', 'maroon',
        //'orange|oran\u017Eov\u00E1',
        null ] } );
RDD( 'bgcolors', { type: 'a', cascade: 'fontcolors' } );
RDD( 'max_table_cols', { type: 'i', defVal: 10, minVal: 1, maxVal: 99 } );
RDD( 'max_table_rows', { type: 'i', defVal: 10, minVal: 1, maxVal: 99 } );
RDD( 'reactivatelinktocurrentpage', { type: 'b', defVal: true } );
RDD( 'ctrlenterhandling',  { type: 'i', defVal: +1, minVal: -1, maxVal: +1 } );
RDD( 'forceoperamode', { type: 'i', defVal: 0, minVal: -1, maxVal: +1 } );
RDD( 'runASAP', { type: 'b', defVal: true } );
RDD( 'runLATE', { type: 'b', defVal: true } );
RDD( 'cancelnextrunafter', { type: 'i', defVal: 2000, minVal: 0, maxVal: 99000 } );
RDD( 'ignorelist', { type: 'a', defVal: null,
            specialCheck: function specialCheck( value, newVal, valid )
            {
                if ( value === null )
                    return true;
                return undefined;
            }
        } );

RDD = undefined;

//}}}
//-----------------------------------------------------------------------------
//{{{

function applySettings() {
    for ( i in this )
        if ( this.hasOwnProperty( i ) )
            R.set( i, this[ i ] );
}

if ( typeof DemoSettings == 'function' ) {
    try {
        DemoSettings.prototype.applySettings = applySettings;
        new DemoSettings().applySettings();
    } finally {
        DemoSettings = undefined;
    }
}

if ( typeof UserSettings == 'function' ) {
    try {
        UserSettings.prototype.applySettings = applySettings;
        new UserSettings().applySettings();
    } finally {
        UserSettings = undefined;
    }
}

if ( typeof ExternSettings == 'function' ) {
    try {
        ExternSettings.prototype.applySettings = applySettings;
        new ExternSettings().applySettings();
    } finally {
        ExternSettings = undefined;
    }
}

applySettings = undefined;

//}}}
//-----------------------------------------------------------------------------
//{{{

R.putToInternal = function putToInternal() {
    const names = [
            'image_addalttext', 'image_addtitle', 'image_encloseinAtag',
            'image_processing',
            'badaltpattern', 'imagealtreplacement',
            'badtitlepattern', 'imagetitlereplacement',
            'okounpost_keepoldreplylink',
            'okounpost_label_vlakno', 'okounpost_label_okolni',
            'okounpost_label_vlakno2', 'okounpost_label_okolni2',
            'okounpost_label_htmlcopier', 'okounpost_label_replycontrol',
            'okounform_label_BR', 'okounpost_linkmarkers',
            'blockoutcominglinks',
            'postjump_mode', 'postjump_extendtop', 'postjump_extendbottom',
            'postjump_ignore', 'postjump_margin',
            'jumpkeys_down', 'jumpkeys_up', 'jumpkeys_new',
            'jumpkeys_botttom', 'jumpkeys_top', 'jumpkeys_menu',
            'navjumpdelay',
            'flash_repeat', 'flash_timing', 'flash_delay',
            'flash_norepeat', 'flashing_colors',
            'ignorelist',
            null ];
    for ( var j = 0; j < names.length; j++ )
        if ( typeof names[ j ] == 'string' )
            R.i[ names[ j ] ] = R.get( names[ j ] );
}
R.putToInternal();

R.i.globalstyle = globalstyle;
globalstyle = undefined;

//}}}
//-----------------------------------------------------------------------------
//{{{

function gorthaursokounscript_init() {
    if ( !/okoun\.cz\/(board|post|mark)/.test( window.location.href ) )
        return;
    
    R.i.goruncounter = 0;               // int >= 0
    R.i.boardadddresspattern =          // RegExp
            /^([^?&%=#]*okoun\.cz\/boards\/([^?&=#]*))(;jsessionid=[\dA-F]+)?$/;
    R.i.boardaddress = null;            // null | string | false
    R.i.boardname    = null;            // null | string | false
    R.i.autojumpto   = null;            // null | string "#id"
    R.i.oldestnewid  = NaN;             // NaN | int >= 1 | string "#id"
    R.i.keycaptureon = false;           // boolean
    R.i.pagelayout   = '';              // string { '', 'n', 'r', 'c', 's' }
    R.i.cancelnextruntimer = null;      // null | int TimerID
    R.i.nextruncancelled  = false;      // boolean
    R.i.documentheadelement = null;     // null | Node | false
    R.i.posteditempreview = null;       // null | Node | false
    R.i.mainform = null;                // null | Node | false
    R.i.mainformtextarea  = null;       // null | Node | false
    R.i.activetextarea2 = null;         // null | Node
    R.i.formatbuttons2 = null;          // null | Node | false
    R.i.formatbuttons1 = null;          // null | Node | false
    R.i.fbatarget = null;               // null | Node
    
    var state = 1, fom = R.get( 'forceoperamode' ),
            runASAP = R.get( 'runASAP' ), runLATE = R.get( 'runLATE' );
    if ( fom != -1 ) {
        if ( typeof document.readyState == 'string' ) {
            if ( document.readyState == 'interactive' )
                state = 0;
            else if ( document.readyState == 'complete' )
                state = 2;
            else
                state = 0;      // should this even happen?
        }
    }
    if ( state == 2 )
    {
        if ( runASAP || runLATE ) gorthaursokounscript_go();
    }
    else
    {
        if ( runASAP ) {
            if ( ( state == 0 ) || ( fom == +1 ) ) {
                window.addEventListener( 'DOMContentLoaded',
                        gorthaursokounscript_go, false );
            } else if ( state == 1 ) {
                 gorthaursokounscript_go();
            }
        }
        if ( runLATE ) {
            window.addEventListener( 'load', gorthaursokounscript_go, false );
        }
    }
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var AIDs = {
    a: [],
    m: {},
    ordered: true,
    init: function init() {
        AIDs.a = [];
        AIDs.m = {};
        AIDs.ordered = false;
    },
    AID: function AID( articleId, dead ) {
        if ( !/^\d\d*$/.test( articleId ) ) {
            this.articleId = null;
            this.dead = null;
        } else {
            this.articleId = Number( articleId );
            this.dead = is_true( dead );
        }
    },
    add: function add( articleId, dead ) {
        if ( !/^\d\d*$/.test( articleId ) ) return false;
        var hash = Number( articleId );
        var aid = new AIDs.AID( hash, dead );
        if ( aid.articleId !== hash ) return false;
        if ( AIDs.m[ hash ] === undefined ) {
            AIDs.m[ hash ] = AIDs.a.length;
            AIDs.a.push( aid );
        } else {
            AIDs.a[ AIDs.m[ hash ] ] = aid;
        }
        AIDs.ordered = false;
    },
    get: function get( articleId ) {
        if ( !/^\d\d*$/.test( articleId ) ) return null;
        if ( AIDs.ordered !== true )
            AIDs.sort();
        var i = AIDs.m[ Number( articleId ) ];
        if ( ( typeof i != 'number' ) || !( AIDs.a[ i ] instanceof AIDs.AID ) )
            return null;
        return AIDs.a[ i ];
    },
    isDead: function isDead( articleId ) {
        var aid = AIDs.get( articleId );
        if ( aid instanceof AIDs.AID )
            return aid.dead;
        return null;
    },
    newestId: function newestId() {
        if ( AIDs.a.length < 1 )
            return null;
        if ( AIDs.ordered !== true )
            AIDs.sort();
        return AIDs.a[ AIDs.a.length - 1 ].articleId;
    },
    oldestId: function oldestId() {
        if ( AIDs.a.length < 1 )
            return null;
        if ( AIDs.ordered !== true )
            AIDs.sort();
        return AIDs.a[ 0 ].articleId;
    },
    sort: function sort() {
        AIDs.a.sort( AIDs.sort.sortFunc );
        AIDs.m = {};
        for ( var i = 0; i < AIDs.a.length; i++ )
            AIDs.m[ AIDs.a[ i ].articleId ] = i;
        AIDs.ordered = true;
    },
    findLiveNeighbors: function findLiveNeighbors( articleId ) {
        if ( !/^\d\d*$/.test( articleId ) ) return null;
        if ( AIDs.ordered !== true )
            AIDs.sort();
        var target = as_intInRange(
                AIDs.m[ Number( articleId ) ], false, 0, null );
        if ( typeof target != 'number' ) return null;
        if ( !( AIDs.a[ target ] instanceof AIDs.AID ) )
            return null;
        var newer = NaN, older = NaN, i;
        for ( i = target - 1 ; i >= 0; i-- )
            if ( !is_true( AIDs.a[ i ].dead ) ) {
                newer = AIDs.a[ i ].articleId;
                break;
            }
        for ( i = target + 1 ; i < AIDs.a.length; i++ )
            if ( !is_true( AIDs.a[ i ].dead ) ) {
                older = AIDs.a[ i ].articleId;
                break;
            }
        return { newer: newer, older: older };
    },
    countLive: function countLive() {
        var cnt = 0;
        for ( var i = 0; i < AIDs.a.length; i++ )
            if ( !is_true( AIDs.a[ i ].dead ) ) cnt++;
        return cnt;
    },
    getLiveIDs: function getLiveIDs() {
        var ret = [];
        for ( var i = 0; i < AIDs.a.length; i++ )
            if ( !is_true( AIDs.a[ i ].dead ) )
                ret.push( AIDs.a[ i ].articleId );
        return ret;
    }
}

AIDs.sort.sortFunc = function sortFunc( a, b ) {
    return a.articleId - b.articleId;
};

//}}}
//-----------------------------------------------------------------------------
//{{{

//2do: add related
var AIDUtils = {
    getArticleNodeID: function getArticleNodeID( element, mode ) {
        var ae = getparenarticle( element );
        if ( !ae ) return null;
        var articleId = ae.getAttribute( 'id' );
        var pr, p1 = /^article-(\d\d*)$/;
        if ( !( pr = p1.exec( articleId ) ) ) return null;
        var m = as_intInRange( mode, false, 1, 3 );
        if ( typeof m != 'number' ) m = 1;
        if ( m == 2 ) articleId = String( pr[ 1 ] );
        else if ( m == 3 ) articleId = Number( pr[ 1 ] );
        return articleId;
    },
    getArticleNumber: function getArticleNumber( source, modes ) {
        var m = as_intInRange( modes, false, +1, null );
        if ( typeof m == 'number' ) m = m & 7;
        else m = 7;
        var ret = source;
        if ( ( m & 2 ) && ( typeof ret == 'string' ) ) {
            if ( m & 4 ) {
                if ( ret.charAt( 0 ) == '#' )
                    ret = ret.substring( 1 );
            }
            var pr, p1 = /^article-(\d\d*)$/;
            if ( pr = p1.exec( ret ) ) {
                ret = Number( pr[ 1 ] );
                if ( ret > 0 )
                    return ret;
            }
        }
        if ( m & 1 ) {
            ret = as_intInRange( source, false, +1, null );
            if ( typeof ret == 'number' )
                return ret;
        }
        return null;
    },
    getCompleteAID: function getCompleteAID( source, modes ) {
        var m = as_intInRange( modes, false, +1, null );
        if ( typeof m == 'number' ) m = m & 7;
        else m = 7;
        var ret = source;
        if ( ( m & 2 ) && ( typeof ret == 'string' ) ) {
            if ( m & 4 ) {
                if ( ret.charAt( 0 ) == '#' )
                    ret = ret.substring( 1 );
            }
            var pr, p1 = /^article-(\d\d*)$/;
            if ( pr = p1.exec( ret ) ) {
                if ( Number( pr[ 1 ] ) > 0 )
                    return ret;
            }
        }
        if ( m & 1 ) {
            ret = as_intInRange( source, false, +1, null );
            if ( typeof ret == 'number' )
                return 'article-' + ret;
        }
        return null;
    }
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function hilitedeletedarticle( articleId ) {
    var an = AIDUtils.getArticleNumber( articleId );
    if ( typeof an != 'number' ) return false;
    var ln = AIDs.findLiveNeighbors( an );
    if ( !ln ) return false;
    var above = true, top = false, id = null, e1;
    if ( R.i.pagelayout == 'r' ) {
        id = ln.older;
        if ( typeof as_intInRange( ln.newer, false, 1, null ) != 'number' )
            top = true;
    }
    else id = ln.newer;
    id = AIDUtils.getCompleteAID( id );
    if ( typeof id == 'string' )
        e1 = document.getElementById( id );
    if ( !e1 ) {
        above = false;
        if ( R.i.pagelayout == 'r' ) id = ln.newer;
        else id = ln.older;
        id = AIDUtils.getCompleteAID( id );
        if ( typeof id == 'string' )
            e1 = document.getElementById( id );
    }
    if ( !e1 ) return false;
    classNameUtil( R.i.deletedarticlemarker.firstChild,
            'hidden', ( top ? -1 : +1 ) );
    var before;
    if ( above ) before = e1;
    else before = e1.nextSibling;
    e1.parentNode.insertBefore( R.i.deletedarticlemarker, before );
    R.i.deletedarticlemarker.id = 'deleted-article-' + an;
    return true;
}

function jumptodeletedarticle( setLocation ) {
    var id = R.i.deletedarticlemarker.id;
    if ( ( typeof id != 'string' ) || ( id.length < 1 ) ) return false;
    if ( is_true( setLocation ) && ( window.location.hash == ( '#' + id ) ) )
    {
        window.location.hash = '#' + id;
    } else {
        jumptoelement( R.i.deletedarticlemarker );
    }
}

function hidedeletedarticle() {
    if ( R.i.deletedarticlemarker.parentNode )
        R.i.deletedarticlemarker.parentNode.removeChild(
                R.i.deletedarticlemarker );
    R.i.deletedarticlemarker.id = '';
}

function hilitelinkedarticleEVENT( event ) {
    if ( !event ) event = window.event;
    var ret = hilitelinkedarticle( this );
    if ( ret ) return true;
    else return consumeEVENT( event );
}

function hilitelinkedarticle( ael ) {
    var state = 0, articleId;
    do {
        if ( !ael || ( ael.nodeType != 1 ) ) break;
        if ( ael.tagName.toLowerCase() != 'a' ) break;
        if ( void2str( ael.href ).length < 1 ) break;
        if ( ael.getAttribute( 'isDeadLink' ) == 'true' )
            state = 2;
        else
            state = 1;
        var pr, p1 = /^[^#]*#(article-\d\d*)$/;
        if ( !( pr = p1.exec( ael.href ) ) ) break;
        articleId = pr[ 1 ];
        var e1 = document.getElementById( articleId );
        if ( !e1 ) break;
        hiliteArticleNode( e1 );
        if ( window.location.hash == ( '#' + articleId ) )
            jumptoelement( e1 );
        else
            window.location.hash = '#' + articleId;
        state = 3;
    } while ( false );
    switch ( state ) {
        case 3 :
            break;
        case 2 :
            hilitedeletedarticle( articleId );
            if ( R.i.blockoutcominglinks >= 1 ) {
                jumptodeletedarticle();
                break;
            }
        case 1 :
            if ( R.i.blockoutcominglinks >= 2 ) break;
        default :
            return true;
    }
    return false;
}

function hiliteArticleNode( articleNode, hiliteOption ) {
    if ( !articleNode || ( articleNode.nodeType !== 1 ) )
        return false;
    var hiliteOption = as_intInRange( hiliteOption, false, 0, null );
    if ( typeof hiliteOption == 'number' ) hiliteOption = hiliteOption & 7;
    else hiliteOption = 3;
    if ( !( hiliteOption & 4 ) &&
            ( classNameUtil( articleNode, 'article', 0 ) !== true ) )
        return false;
    if ( ( hiliteOption & 2 ) && hilitedArticle &&
            ( hilitedArticle != articleNode ) )
    {
        classNameUtil( hilitedArticle, 'context-article', -1 );
    }
    classNameUtil( articleNode, 'context-article', +1 );
    if ( ( hiliteOption & 1 ) || !hilitedArticle )
        hilitedArticle = articleNode;
    return true;
}

function hiliteAndJumpToArticle( articleId, setLocation, hiliteOption ) {
    var articleId = AIDUtils.getCompleteAID( articleId );
    if ( typeof articleId != 'string' )
        return false;
    var e1 = document.getElementById( articleId );
    if ( !e1 )
        return false;
    hiliteArticleNode( e1, hiliteOption );
    if ( is_true( setLocation ) )
        window.location.hash = '#' + articleId;
    else
        jumptoelement( e1 );
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var hilitedArticle = null;

function hiliteArticleIfExists( articleId ) {
    var elementId = "article-" + articleId;
    var article = document.getElementById( elementId );
    if ( !article ) return true;
    if ( hilitedArticle && ( hilitedArticle != article ) )
        classNameUtil( hilitedArticle, 'context-article', -1 );
    classNameUtil( article, 'context-article', +1 );
    hilitedArticle = article;
    window.location.href = "#" + elementId;
    return false;
}

var REPLY_PREV_PFX  = 'replyFormPrev-';
var REPLY_TITLE_PFX = 'replyFormTitle-';
var REPLY_BODY_PFX  = 'replyFormBody-';
var REPLY_NICK_PFX  = 'replyNick-';

function renderArticleReplyForm( articleId, mainFormId, label,
        labelTitle, labelBody, labelSubmit, labelNick ) {
    var PFX_RPL = 'replyForm-';
    var PFX_ART = 'article-';
    var replyFormId = PFX_RPL + articleId;
    var replyForm = document.getElementById( replyFormId );
    if ( replyForm ) {
        var disp = replyForm.style.display;
        if ( !disp || ( disp =='block' ) )
            replyForm.style.display = 'none';
        else
            replyForm.style.display = 'block';
    } else {
        var articleWrapperId = PFX_ART + articleId;
        var el = document.getElementById( articleWrapperId );
        if ( el ) {
            var replyTitleId = REPLY_TITLE_PFX + articleId;
            var replyBodyId  = REPLY_BODY_PFX  + articleId;
            var replyNickId  = REPLY_NICK_PFX  + articleId;
            var replyPrevId  = REPLY_PREV_PFX  + articleId;
            var newdiv = document.createElement( 'div' );
            newdiv.className = 'reply-form posted-item-form';
            newdiv.id = replyFormId;
            var innerHTML = ''
                    + '<h3>' + label + '</h3>'
                    + '<input id="' + replyPrevId + '" type="hidden"'
                    + ' name="parentId" value="' + articleId + '" />';
            if ( labelNick ) {
                innerHTML += ''
                        + '<div class="form-item form-item-text" >'
                        + '<label for="' + replyNickId + '">' + labelNick + '</label>'
                        + '<input id="' + replyNickId + '" type="text" name="anonymousNick" />'
                        + '</div>';
            }
            innerHTML += ''
                    + '<div class="form-item form-item-text" >'
                    + '<label for="' + replyTitleId + '">' + labelTitle + '</label>'
                    + '<input id="' + replyTitleId + '" type="text" name="title" />'
                    + '</div>' + '<div class="form-item form-item-text" >'
                    + '<label for="' + replyBodyId + '">' + labelBody + '</label>'
                    + '<textarea id="' + replyBodyId + '" name="body"></textarea>'
                    + '</div>' + '<input type="button" value="' + labelSubmit
                    + '" onclick="return copyReplyFormAndSubmitArticle(\''
                    + articleId + "', '" + mainFormId + '\');" />';
            newdiv.innerHTML = innerHTML;
            el.appendChild( newdiv );
        }
    }
}

function ctrlenterEVENT( event ) {
    if ( !event ) event = window.event;
    if ( !event.ctrlKey || ( event.keyCode != 13 ) ) return;
    var srcEl = event.srcElement ? event.srcElement : event.target;
    var formEl = null;
    for ( var el = srcEl; el; el = el.parentNode ) {
        if ( ( typeof el.tagName == 'string' ) &&
                ( el.tagName.toLowerCase() == 'form' ) ) {
            formEl = el;
            break;
        } else if ( ( typeof el.tagName == 'string' ) &&
                ( el.tagName.toLowerCase() == 'div' ) &&
                ( /(^|\s)reply-form(\s|$)/.test( el.className ) ) )
        {
            formEl = el;
            break;
        }
    }
    if ( !formEl ) return;
    var fired = false;
    if ( formEl.id == 'article-form-main' ) {
        formEl.submit(); fired = true;
    } else {
        var pr, p1 = /^replyForm-(\d\d*)$/;
        if ( pr = p1.exec( formEl.id ) ) {
            try {
                copyReplyFormAndSubmitArticle( pr[ 1 ], 'article-form-main' );
            } catch ( e ) {
                consolemsg( 'exception in ctrlenterEVENT(): ' + e );
            }
            fired = true;
        }
    }
    if ( fired )
        return consumeEVENT( event );
}

function PATCHED() {};
PATCHED.hiliteArticleIfExists = hiliteArticleIfExists;
PATCHED.renderArticleReplyForm = renderArticleReplyForm;
PATCHED.ctrlenterEVENT = ctrlenterEVENT;
PATCHED.patch = function patch() {
    addJStodocument( PATCHED.hiliteArticleIfExists.toString() );
    addJStodocument( PATCHED.renderArticleReplyForm.toString() );
    if ( R.get( 'ctrlenterhandling' ) == 0 ) {
        addJStodocument( 'document.body.onkeydown = undefined;' );
    }
    if ( R.get( 'ctrlenterhandling' ) == 1 ) {
        addJStodocument( 'document.body.onkeydown = '
                + PATCHED.ctrlenterEVENT.toString() );
    }
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function classNameRegExp( className, mods ) {
    if ( typeof className != 'string' ) return null;
    if ( mods === undefined ) mods = '';
    else if ( typeof mods != 'string' ) mods = '';
    var classNameEscaped = className.replace( /([.?*{+}(|)[\]\\\/^$])/g, '\\$1' );
    var pattern = new RegExp( '(^|\\s)' + classNameEscaped + '(\\s|$)', mods );
    return pattern;
}

function classNameUtil( element, className, operation ) {
    if ( !element || ( element.nodeType != 1 ) ) return undefined;
    if ( typeof operation != 'number' ) operation = 0;
    else {              // 0: test, +1: set, -1: remove, 2: flip
        operation = Math.floor( operation );
        if ( ( operation < -1 ) || ( operation > 2 ) )
            operation = 0;
    }
    if ( !checkClassName( className ) ) return undefined;
    var p1 = classNameRegExp( className, 'g' );
    if ( !( p1 instanceof RegExp ) ) return undefined;
    var classes = element.className;
    if ( typeof classes != 'string' ) classes = '';
    var after, before = p1.test( classes );
    if ( before ) {
        if ( ( operation == -1 ) || ( operation == 2 ) ) {
            classes = classes.replace( p1, ' ' );
            after = false;
        }
        else after = true;
    } else {
        if ( ( operation == 1 ) || ( operation == 2 ) ) {
            classes += ' ' + className;
            after = true;
        }
        else after = false;
    }
    if ( operation != 0 ) {
        element.className = classes.replace(
                /^\s*|\s*$/g, '' ).replace( /\s\s*/g, ' ' );
    }
    return after;
}

function consolemsg( text ) {
    if ( typeof text == 'string' )
        {}
    else if ( ( typeof text == 'number' ) || ( typeof text == 'boolean' ) )
        text = String( text );
    else if ( !text )
        return;
    else try {
        text = String( text );
    } catch ( e ) {
        text = 'consolemsg() exception: ' + e;
    }
    if ( window.opera && ( typeof window.opera.postError == 'function' ) ) {
        window.opera.postError( text );
    } else if ( typeof GM_log == 'function' ) {
        GM_log( text );
    }
}

function consumeEVENT( event ) {
    if ( !event ) event = window.event;
    if ( typeof event.preventDefault == 'function' ) {
        event.preventDefault();
    }
    //else
    if ( typeof event.returnValue == 'boolean' ) {
        event.returnValue = false;
    }
    return false;
}

function getparenarticle( element ) {
    if ( !element ) return null;
    if ( element.nodeType !== 1 ) {
        if ( typeof element.parentNode == 'object' )
            element = element.parentNode;
        else return null;
    }
    for ( ; ; element = element.parentNode ) {
        if ( !element || ( element.nodeType !== 1 ) ) return null;
        if ( /(^|\s)article(\s|$)/.test( element.className ) )
            return element;
    }
    return null;
}

function getAncestorByTagANDClassName( element, tagName, className ) {
    if ( !element.parentNode ) return null;
    var p1;
    if ( className == '*' ) {}
    else if ( !checkClassName( className ) ) return null;
    else {
        p1 = classNameRegExp( className, '' );
        if ( !( p1 instanceof RegExp ) ) return null;
    }
    for ( element = element.parentNode; element; element = element.parentNode )
    {
        if ( element.nodeType != 1 ) continue;
        if ( tagName == '*' ) {}
        else if ( element.tagName.toLowerCase() == tagName.toLowerCase() ) {}
        else continue;
        if ( className == '*' ) {}
        else if ( p1.test( element.className ) ) {}
        else continue;
        return element;
    }
    return null;
}

function getChildrenByTagANDClassName( element, tagName, className ) {
    var ret = [];
    if ( !element.firstChild ) return ret;
    var p1;
    if ( className == '*' ) {}
    else if ( !checkClassName( className ) ) return null;
    else {
        p1 = classNameRegExp( className, '' );
        if ( !( p1 instanceof RegExp ) ) return null;
    }
    for ( element = element.firstChild; element; element = element.nextSibling )
    {
        if ( element.nodeType != 1 ) continue;
        if ( tagName == '*' ) {}
        else if ( element.tagName.toLowerCase() == tagName.toLowerCase() ) {}
        else continue;
        if ( className == '*' ) {}
        else if ( p1.test( element.className ) ) {}
        else continue;
        ret.push( element );
    }
    return ret;
}

function checkId( id ) {
    if ( typeof id != 'string' ) return false;
    var ret = false;
    do {
        if ( id.length < 1 ) break;
        if ( /\s/.test( id ) ) break;
        //ret = /^[A-Za-z0-9_.-]+$/.test( id ); break;
        //ret = /^[!-~]+$/.test( id ); break;
        //ret = /^[^\s](.*[^\s])?$/.test( id ); break;
        ret = true;
    } while ( false );
    //consolemsg( 'checkId( ' + id + ' ): ' + String( ret ) );
    return ret;
}

function checkTagName( tagName ) {
    if ( typeof tagName != 'string' ) return false;
    var ret = false;
    do {
        if ( tagName.length < 1 ) break;
        //if ( /[\s<>]/.test( tagName ) ) break;
        //ret = /^[Hh][1-6]$|^[A-Za-z]{1,10}$/.test( tagName ); break;
        ret = /^[A-Za-z_][A-Za-z0-9_.-]*$/.test( tagName ); break;
        //ret = /^[^\s<>]+$/.test( tagName ); break;
        //ret = true;
    } while ( false );
    //consolemsg( 'checkTagName( ' + tagName + ' ): ' + String( ret ) );
    return ret;
}

function checkClassName( className ) {
    if ( typeof className != 'string' ) return false;
    var ret = false;
    do {
        if ( className.length < 1 ) break;
        //if ( /\s/.test( className ) ) break;
        ret = /^[A-Za-z_][A-Za-z0-9_.-]*$/.test( className ); break;
        //ret = /^[^\s]+$/.test( className ); break;
        //ret = true;
    } while ( false );
    //consolemsg( 'checkClassName( ' + className + ' ): ' + String( ret ) );
    return ret;
}

function checkColor( color, rgb ) {
    if ( typeof color != 'string' ) return false;
    if ( /^#([0-9A-Fa-f]{3}){1,2}$/.test( color ) ) return true;
    if ( /^[A-Za-z]{3,25}$/.test( color ) ) return true;
    if ( !is_true( rgb ) ) return false;
    if ( /^[rR][gG][bB]\s*\(\s*-?\d\d*(%?)\s*(,\s*-?\d\d*\1\s*){2}\)\s*$/.test( color ) )
        return true;
    return false;
}

function checkClasses( classes ) {
    if ( typeof classes != 'string' ) return null;
    classes = trim( classes );
    if ( classes.length < 1 ) return classes;
    var ca = classes.split( /\s\s*/ ), cno = {}, i;
    for ( i = 0; i < ca.length; i++ ) {
        if ( checkClassName( ca[ i ] ) )
            cno[ ca[ i ] ] = ca[ i ];
    }
    classes = ''; i = 0;
    for ( cn in cno ) {
        if ( i++ > 0 ) classes += ' ';
        classes += cn;
    }
    return classes;
}

function createElement( tagName, id, classes, attributes ) {
    if ( !checkTagName( tagName ) ) return null;
    if ( ( id !== undefined ) && ( id !== null ) &&
            !checkId( id ) ) return null;
    if ( typeof classes == 'string' ) classes = trim( classes );
    else if ( ( classes !== undefined ) && ( classes !== null ) ) return null;
    if ( ( attributes !== undefined ) && ( attributes !== null ) &&
            ( typeof attributes != 'object' ) ) return null;
    classes = checkClasses( classes );
    var e1;
    try {
        //try {
        e1 = document.createElement( tagName );
        //} catch ( e ) { consolemsg( '<' + tagName + '> : ' + e ); return null; }
        if ( ( typeof id == 'string' ) && ( id != '' ) )
            e1.id = id;
        if ( ( typeof classes == 'string' ) && ( classes != '' ) )
            e1.className = classes;
        if ( attributes instanceof Object )
            for ( var attr in attributes )
                if ( attributes.hasOwnProperty( attr ) )
                    e1.setAttribute( attr, attributes[ attr ] );
    } catch ( e ) { return null; }
    return e1;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function AAuthor( articleNode ) {
    var fail = false;
    this.failed = function failed() {
        if ( typeof fail != 'boolean' ) fail = true;
        return fail;
    };
    do {
        if ( !articleNode || ( typeof articleNode != 'object' ) ||
                ( articleNode.nodeType !== 1 ) )
        {
            fail = true; break;
        }
        var e1;
        for ( e1 = articleNode.firstChild; ; e1 = e1.nextSibling ) {
            if ( !e1 ) { fail = true; break; }
            if ( e1.nodeType != 1 ) continue;
            if ( /(^|\s)article-header(\s|$)/.test( e1.className ) ) break;
        }
        if ( fail ) break;
        var e2;
        for ( e2 = e1.firstChild; ; e2 = e2.nextSibling ) {
            if ( !e2 ) { fail = true; break; }
            if ( e2.nodeType != 1 ) continue;
            if ( /(^|\s)author(\s|$)/.test( e2.className ) ) break;
        }
        if ( fail ) break;
        e2 = e2.firstChild;
        if ( !e2 || ( e2.nodeType != 3 ) ) fail = true;
    } while ( false );
    if ( fail ) {
        this.nick = '';
        this.anonymous = undefined;
        return this;
    }
    this.anonymous = undefined;
    this.nick = e2.nodeValue.replace( /^\s+/, '' );
    var i = this.nick.indexOf( '\r' );
    if ( i >= 0 ) this.nick = this.nick.substring( 0, i );
    i = this.nick.indexOf( '\n' );
    if ( i >= 0 ) this.nick = this.nick.substring( 0, i );
    this.nick = this.nick.replace( /\s+$/, '' );
    if ( ( e2.nextSibling.nodeType == 8 ) &&
            ( /^ *anonym *$/.test( e2.nextSibling.nodeValue ) ) )
    {
        this.anonymous = true;
    }
    do {
        for ( e2 = e1.firstChild; e2; e2 = e2.nextSibling ) {
            if ( e2.nodeType != 1 ) continue;
            if ( /(^|\s)author-icon(\s|$)/.test( e2.className ) ) break;
        }
        if ( !e2 ) break;
        e2 = e2.firstChild;
        if ( !e2 || ( e2.nodeType != 1 ) ) break;
        if ( e2.tagName.toLowerCase() != 'a' ) break;
        if ( /\/msgbox\.do\?rcpt=$/.test( e2.href ) )
            this.anonymous = true;
        else if ( /\/msgbox\.do\?rcpt=[^?&=#]+$/.test( e2.href ) )
            this.anonymous = false;
    } while ( false );
    return this;
}

AAuthor.prototype.getNick = function getNick( u, a, e, f )
{           // undef -> bool, anon prefix, "" replace, failed replace
    if ( this.failed() ) {
        if ( typeof f == 'string' )
            return f;
        else return '[???]';
    }
    if ( this.anonymous === false )
        return this.nick;
    if ( ( this.anonymous !== true ) && ( u !== true ) )
        return this.nick;
    if ( this.nick.length < 1 ) {
        if ( typeof e == 'string' )
            return e;
        return '[anonym]';
    }
    if ( typeof a == 'string' )
        return a + this.nick;
    else return '[anonym:] ' + this.nick;
};

//}}}
//-----------------------------------------------------------------------------
//{{{

function Ignorowacz( _boards, _mode, _users, _except ) {
    var boards, mode, users, except;
    var valid = false;
    this.isValid = function isValid() { return valid; };
    if ( typeof _mode != 'string' ) return null;
    if ( !( _boards instanceof RegExp ) && ( _boards !== '*' ) ) return null;
    if ( _mode == 'A' ) {
        if ( ( _users !== undefined ) || ( _except !== undefined ) )
            return null;
        boards = _boards;
        mode = 'A';
        valid = true;
    } else if ( ( _mode == 'a' ) || ( _mode =='u' ) || ( _mode == '*' ) ) {
        if ( !( _users instanceof RegExp ) )
            return null;
        if ( _except instanceof RegExp )
            except = _except;
        else if ( _except !== undefined )
            return null;
        boards = _boards;
        mode = _mode;
        users = _users;
        valid = true;
    } else {
        return null;
    }
    
    this.toString = function toString() {
        var ret = '[ ' + boards.toString() + ' ' + mode;
        if ( mode != 'A' ) {
            ret += ' ' + users.toString();
            if ( except instanceof RegExp )
                ret += ' \\' + except.toString();
        }
        ret += ' ]';
        return ret;
    }
    
    this.testBoard = function testBoard( board ) {
        if ( !valid || ( typeof board != 'string' ) )
            return undefined;
        if ( boards === '*' ) return true;
        if ( !( boards instanceof RegExp ) ) return undefined;
        return boards.test( board );
    };
    
    this.testAuthor = function testAuthor( author, u, f )
    {           // undefined -> boolean, failed -> return boolean
        if ( !valid || !( author instanceof AAuthor ) )
            return undefined;
        if ( author.failed() ) {
            if ( typeof f == 'boolean' )
                return f;
            return undefined;
        }
        var isanon = author.anonymous;
        if ( typeof isanon != 'boolean' ) {
            if ( typeof u == 'boolean' )
                isanon = u
            else
                isanon = false;
        }
        if ( mode == 'A' )
            return isanon;
        if ( isanon ) {
            if ( mode == 'u' )
                return false;
        } else {
            if ( mode == 'a' )
                return false;
        }
        if ( !users.test( author.nick ) )
            return false;
        if ( ( except instanceof RegExp ) && except.test( author.nick ) )
            return false;
        return true;
    };
    
    return this;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function AInfo( articleNode ) {
    this.init();
    this.fill( articleNode );
    return this;
}

AInfo.prototype.init = function init() {
    this.adiv = this.adiv = null;
    this.menuul = null;
    this.cdiv = this.ca = this.chref = null;
    this.rdiv = this.ra = this.rhref = this.rid = null;
    this.pdiv = this.pa = this.phref = this.pid = null;
    this.aa = null;
    this.fatal = null; this.errs = [];
}

AInfo.prototype.fill = function fill( articleNode ) {
    if ( articleNode === null ) {
        this.fatal = 'articleNode is null'; return; }
    if ( typeof articleNode != 'object' ) {
        this.fatal = 'articleNode is not an object'; return; }
    if ( articleNode.nodeType !== 1 ) {
        this.fatal = 'articleNode.nodeType !== 1'; return; }
    if ( !/(^|\s)article(\s|$)/.test( articleNode.className ) ) {
        this.fatal = 'bad articleNode.className \'' + articleNode.className
        + '\''; return; }
    this.adiv = articleNode;
    this.aa = new AAuthor( articleNode );
    if ( this.aa.failed() )
        this.errs.push( 'error retrieving article author info' );
    var ea1, p1, pr;
    do {
        ea1 = getChildrenByTagANDClassName( articleNode, 'div', 'marks' );
        if ( ea1.length != 1 ) {
            this.errs.push( 'not precisely 1 div.marks element' ); break;
        }
        ea1 = getChildrenByTagANDClassName( ea1[ 0 ], 'ul', 'article-menu' );
        if ( ea1.length != 1 ) {
            this.errs.push( 'not precisely 1 ul.article-menu element' ); break;
        }
        this.menuul = ea1[ 0 ];
        p1 = /^article-(\d\d*)$/;
        if ( pr = p1.exec( articleNode.id ) )
            this.aid = pr[ 1 ];
        else
            this.errs.push( 'article.id \'' + articleNode.id + '\' test fail' );
        var ea2 = getChildrenByTagANDClassName( this.menuul, 'div', '*' );
        for ( var i = 0; i < ea2.length; i++ ) {
            if ( /(^|\s)root-link(\s|$)/.test( ea2[ i ].className ) )
                this.rdiv = ea2[ i ];
            else if ( /(^|\s)context-link(\s|$)/.test( ea2[ i ].className ) )
                this.cdiv = ea2[ i ];
        }
        if ( this.rdiv ) {
            ea1 = getChildrenByTagANDClassName( this.rdiv, 'a', '*' );
            if ( ea1.length == 1 ) {
                this.ra = ea1[ 0 ];
                this.rhref = this.ra.href;
                p1 = /^.*[?&]rootId=(\d\d*).*$/;
                if ( pr = p1.exec( this.rhref ) )
                    this.rid = pr[ 1 ];
                else
                    this.errs.push( 'root href \'' + this.rhref + '\' test fail' );
            } else
                this.errs.push( 'not precisely 1 a element in div.root-link' );
        } else
            this.errs.push( 'div.root-link not found' );
        if ( this.cdiv ) {
            ea1 = getChildrenByTagANDClassName( this.cdiv, 'a', '*' );
            if ( ea1.length == 1 ) {
                this.ca = ea1[ 0 ];
                this.chref = this.ca.href;
                p1 = /^.*[?&]contextId=(\d\d*).*$/;
                if ( pr = p1.exec( this.chref ) ) {
                    if ( this.aid == null )
                        this.aid = pr[ 1 ];
                    else if ( this.aid != pr[ 1 ] )
                        this.errs.push( 'context and article id mismatch' );
                }
                else
                    this.errs.push( 'context href \'' + this.chref + '\' test fail' );
            } else
                this.errs.push( 'not precisely 1 a element in div.context-link' );
        }
    } while ( false );
    ea1 = getChildrenByTagANDClassName( articleNode, 'div', 'context' );
    if ( ea1.length == 1 ) {
        this.pdiv = ea1[ 0 ];
        ea1 = getChildrenByTagANDClassName( this.pdiv, 'a', '*' );
        if ( ea1.length == 1 ) {
            this.pa = ea1[ 0 ];
            this.phref = this.pa.href;
            p1 = /^[^#]+#article-(\d\d*)$/;
            if ( pr = p1.exec( this.phref ) )
                this.pid = pr[ 1 ];
            else
                this.errs.push( 'parent href \'' + this.phref + '\' test fail' );
        } else
            this.errs.push( 'not precisely 1 a element in div.context' );
    }
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function escapehtml( str ) {
    if ( typeof str != 'string' ) return '';
    return str.replace( /&/g, '&amp;' )
            .replace( /</g, '&lt;' ).replace( />/g, '&gt;' );
}

function escapequot( str ) {
    if ( typeof str != 'string' ) return '';
    return str.replace( /"/g, '&quot;' );
}

function trim( str ) {
    if ( typeof str != 'string' ) return '';
    var	str = str.replace( /^\s\s*/, '' ), wsp = /\s/, i = str.length;
    while ( wsp.test( str.charAt( --i ) ) );
    return str.slice( 0, i + 1 );
}

function void2str( ref, convertothertypes ) {
    if ( ( ref === undefined ) || ( ref === null ) ) return '';
    if ( typeof ref == 'string' ) return ref;
    if ( ( convertothertypes === true ) || ( convertothertypes === 1 ) )
    {
        return String( ref );
    }
    return ref;
}

function is_true( val ) {
    if ( ( val === true ) || ( val === 1 ) || ( val === '1' ) ) return true;
    return false;
}

function is_false( val ) {
    if ( ( val === false ) || ( val === 0 ) || ( val === '0' ) ) return false;
    return true;
}

function as_int( val, autofloor ) {
    var ret;
    if ( typeof val == 'number' ) {
        ret = Math.floor( val );
        if ( ret == NaN )
            return null;
        if ( is_true( autofloor ) || ( ret == val ) )
            return ret;
        return null;
    } else if ( typeof val == 'string' ) {
        val = trim( val );
        ret = Number( val );
        if ( ret == NaN )
            return null;
        if ( is_true( autofloor ) ) {
            ret = Math.floor( ret );
            if ( ret == NaN )
                return null;
            return ret;
        }
        if ( ret == Math.floor( ret ) )
            return ret;
    }
    return null;
}

function as_intInRange( val, autofloor, min, max ) {
    var ret = as_int( val, autofloor );
    if ( typeof ret != 'number' )
        return null;
    if ( ( typeof min == 'number' ) && ( ret < min ) )
        return null;
    if ( ( typeof max == 'number' ) && ( ret > max ) )
        return null;
    return ret;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function removeSIDfromhref( href ) {
    if ( typeof href != 'string' ) return null;
    var pr, p1 = /^([^?&%=#]*okoun\.cz\/[^?&=#]*)(;jsessionid=[A-F0-9]+)?([?#].*)?$/;
    if ( !( pr = p1.exec( href ) ) ) return null;
    return '' + pr[ 1 ] + void2str( pr[ 3 ] );
}

function getY( element ) {
    if ( !element ) return null;
    if ( element.offsetParent ) {
        for ( var posY = 0; element.offsetParent;
                element = element.offsetParent ) {
            posY += element.offsetTop;
        }
        return posY;
    }
    if ( element.y ) return element.y;
    return null;
}

function filterElementsByClassName( elements, className ) {
    var i, ret = [];
    if ( !checkClassName( className ) ) return ret;
    var p1 = classNameRegExp( className, '' );
    if ( !( p1 instanceof RegExp ) ) return ret;
    for ( i = 0; i < elements.length; i++ ) {
        if ( p1.test( elements[ i ].className ) )
            ret.push( elements[ i ] );
    }
    return ret;
}

function sprintflite( template, map ) {
    if ( typeof template != 'string' ) return null;
    for ( var k in map ) {
        if ( ( typeof k == 'string' ) && ( k.length == 1 ) &&
                ( typeof map[ k ] == 'string' ) ) {}
        else map[ k ] = undefined;
    }
    if ( typeof map[ '%' ] != 'string' ) map[ '%' ] = '%';
    var i, ret = '';
    for ( i = 0; i < template.length; i++ ) {
        if ( template.charAt( i ) != '%' ) {
            ret += template.charAt( i );
            continue;
        } else {
            if ( ( ( i + 1 ) >= template.length ) ||
                    ( typeof map[ template.charAt( i + 1 ) ] != 'string' ) )
            {
                //ret += '%';
            } else {
                ret += map[ template.charAt( ++i ) ];
            }
        }
    }
    return ret;
}

function sprintfheavy( template, map ) {
    if ( typeof template != 'string' ) return null;
    for ( var k in map ) {
        if ( ( typeof k == 'string' ) && ( k.length == 1 ) &&
                ( typeof map[ k ] == 'string' ) ) {}
        else map[ k ] = undefined;
    }
    if ( typeof map[ '%' ] != 'string' ) map[ '%' ] = '%';
    var i, result = '', log = [];
    for ( i = 0; i < template.length; i++ ) {
        if ( template.charAt( i ) != '%' ) {
            result += template.charAt( i );
            continue;
        } else {
            if ( ( ( i + 1 ) >= template.length ) ||
                    ( typeof map[ template.charAt( i + 1 ) ] != 'string' ) )
            {
                //result += '%';
            } else {
                var c = template.charAt( ++i );
                var s = map[ c ];
                log.push( { key: c, pos: result.length, len: s.length } );
                result += s;
            }
        }
    }
    return { result: result, log: log };
}

function getboardaddress() {
    if ( typeof R.i.boardaddress == 'string' ) return R.i.boardaddress;
    if ( R.i.boardaddress === false ) return null;
    R.i.boardaddress = false;
    var e1 = document.getElementById( 'board-main' );
    if ( !e1 ) return null;
    var ea1 = getChildrenByTagANDClassName( e1, 'h2', '*' );
    if ( ea1.length != 1 ) return null;
    ea1 = getChildrenByTagANDClassName( ea1[ 0 ], 'a', '*' );
    if ( ea1.length != 1 ) return null;
    e1 = ea1[ 0 ];
    if ( !R.i.boardadddresspattern.test( e1.href ) ) return null;
    R.i.boardaddress = e1.href;
    return R.i.boardaddress;
}

function getboardname() {
    if ( typeof R.i.boardname == 'string' ) return R.i.boardname;
    if ( R.i.boardname === false ) return null;
    R.i.boardname = false;
    var ba = getboardaddress();
    if ( typeof ba != 'string' ) return null;
    var pr = R.i.boardadddresspattern.exec( ba );
    if ( !pr ) return null;
    R.i.boardname = void2str( pr[ 2 ] );
    return R.i.boardname;
}

function gethead() {
    if ( R.i.documentheadelement && ( R.i.documentheadelement.nodeType === 1 ) )
        return R.i.documentheadelement;
    if ( R.i.documentheadelement === false ) return null;
    R.i.documentheadelement = document.getElementsByTagName( 'head' )[ 0 ];
    if ( !R.i.documentheadelement ) {
        R.i.documentheadelement = false;
        return null;
    }
    return R.i.documentheadelement;
}

function addStyleOoAoS( ooaos ) {
    if ( ( typeof ooaos != 'object' ) || !ooaos ) return null;
    var style = '';
    for ( i in ooaos ) {
        if ( ooaos[ i ] instanceof Array )
            for ( j = 0; j < ooaos[ i ].length; j++ )
                if ( typeof ooaos[ i ][ j ] == 'string' ) {
                    if ( style.length > 0 ) style += '\n';
                    style += ooaos[ i ][ j ];
                }
    }
    addStyle( style );
}

function addStyle( newstyle ) {
    if ( typeof newstyle != 'string' ) return;
    if ( ( newstyle = trim( newstyle ) ).length == 0 ) return;
    if ( typeof GM_addStyle == 'function' ) {
        GM_addStyle( newstyle );
        return;
    }
    gethead();
    var stylenode = document.createElement( 'style' );
    stylenode.setAttribute( 'type', 'text/css' );
    stylenode.appendChild( document.createTextNode( newstyle ) );
    R.i.documentheadelement.appendChild( stylenode );
}

function addJStodocument( src ) {
    gethead();
    var scriptnode = document.createElement( 'script' );
    scriptnode.setAttribute( 'type', 'text/javascript' );
    scriptnode.appendChild( document.createTextNode( src ) );
    R.i.documentheadelement.appendChild( scriptnode );
}

function setinnertext( element, text, destroynontext ) {
    if ( !element || ( element.nodeType != 1 ) ) return false;
    if ( ( typeof text != 'string' ) && ( text !== null ) ) return false;
    if ( ( destroynontext === true ) || ( destroynontext === 1 ) )
        destroynontext = true;
    else destroynontext = false;
    if ( element.hasChildNodes() )
    {
        var i, children = element.childNodes;
        if ( !destroynontext )
            for ( i = 0; i < children.length; i++ )
                if ( children[ i ].nodeType != 3 )
                    return false;
        while ( element.hasChildNodes() )
            element.removeChild( element.lastChild );
    }
    if ( typeof text == 'string' )
        element.appendChild( document.createTextNode( text ) );
    return true;
}

function shiftenterEVENT( event ) {
    if ( !event ) event = window.event;
    if ( !event.shiftKey ) return;
    var code, str, rp;
    code = event.keyCode;
    if ( ( code == 0 ) && ( event.charCode > 0 ) ) code = event.charCode;
    if ( code == 13 ) {
        str = "<br />\n"; rp = "<p>%r</p>\n";
    } else if ( code == 32 ) {
        str = "&nbsp;"; rp = insertText.IDLE;
    } else { //consolemsg( [event.keyCode, event.charCode] );
        return;
    }
    var srcEl = event.srcElement ? event.srcElement : event.target;
    if ( ( srcEl.nodeType == 1 ) &&
            ( srcEl.tagName.toLowerCase() == 'textarea' ) ) {
        insertText( srcEl, str, rp );
        return consumeEVENT( event );
    }
}

function startkeycaptureEVENT( event ) {
    R.i.keycaptureon = true;
}

function releasekeycaptureEVENT( event ) {
    if ( R.i.keycaptureon === false ) return;        // nothing to do
    if ( !event ) event = window.event;
    var srcEl = event.srcElement ? event.srcElement : event.target;
    if ( !srcEl || ( srcEl.nodeType != 1 ) ) return;
    var tnlc = srcEl.tagName.toLowerCase();
    if ( ( tnlc == 'textarea' ) || ( tnlc == 'select' ) ) {
        R.i.keycaptureon = false;
    } else if ( tnlc == 'input' ) {
        var type = srcEl.getAttribute( 'type' );
        if ( typeof type != 'string' ) return;
        if ( ( type == 'text' ) || ( type == 'password' ) )
            R.i.keycaptureon = false;
    }
}

function keyboardjumpEVENT( event ) {
    if ( !R.i.keycaptureon ) return;
    if ( !event ) event = window.event;
    if ( event.ctrlKey || event.altKey ) return;
    var srcEl = event.srcElement ? event.srcElement : event.target;
    var code = ( typeof event.charCode == 'number' ) ?
            event.charCode : event.keyCode;
    code = String.fromCharCode( code );
    var fired = false;
    if ( R.i.jumpkeys_down.indexOf( code ) >= 0 ) {
        jumparticles( 'down' ); fired = true;
    } else if ( R.i.jumpkeys_up.indexOf( code ) >= 0 ) {
        jumparticles( 'up' ); fired = true;
    } else if ( R.i.jumpkeys_new.indexOf( code ) >= 0 ) {
        jumptonew(); fired = true;
    } else if ( R.i.jumpkeys_botttom.indexOf( code ) >= 0 ) {
        jumparticles( 'bottom' ); fired = true;
    } else if ( R.i.jumpkeys_top.indexOf( code ) >= 0 ) {
        jumparticles( 'top' ); fired = true;
    } else if ( R.i.jumpkeys_menu.indexOf( code ) >= 0 ) {
        window.scrollTo( 0, 0 );; fired = true;
    }
    if ( fired )
        return consumeEVENT( event );
}

function jumptonewEVENT( event ) {
    jumptonew();
    return consumeEVENT( event );
}

function jumptonew() {
    if ( typeof R.i.oldestnewid == 'string' ) {
        jumptoid( R.i.oldestnewid );
        flashid( R.i.oldestnewid );
    }
}

function findfragmenttarget( id, searchatags, taketop ) {
    if ( ( typeof id != 'string' ) || ( id == '' ) ) return null;
    if ( id == '#' ) {
        if ( is_true( taketop ) ) return document.body;
        else return null;
    }
    if ( id.charAt( 0 ) == '#' )
        id = id.substring( 1 );
    //if ( !checkId( id ) ) return null;
    var e1 = document.getElementById( id );
    if ( e1 ) return e1;
    if ( !is_true( searchatags ) ) return null;
    var ea1 = document.getElementsByTagName( 'a' );
    for ( var i = 0; i < ea1.length; i++ )
        if ( ea1[ i ].name == id )
            return ea1[ i ];
    return null;
}

function jumptoelement( element, margin ) {
    if ( typeof margin != 'number' )
        margin = 0;
    else {
        margin = Math.floor( margin );
        if ( ( margin < 1 ) || ( margin > 1000 ) )
            margin = 0;
    }
    var r1 = Rect.fromElement( element ), rw = Rect.fromWindow();
    if ( !r1 || !rw ) return false;
    if ( margin ) r1.expand( null, margin );
    rw.lookat( r1, 0, 1 );
    rw.wscroll();
    return true;
}

function jumptoid( id ) {
    const margin = 10;
    do {
        var e1 = findfragmenttarget( id, true, true );
        if ( !e1 ) break;
        if ( !jumptoelement( e1, margin ) ) break;
        return;
    } while ( false );
    //window.location.hash = "#" + id;  // sucks
}

function jumparticles( direction ) {
    var mode, extendtop = 100, extendbottom = 100, igno = 10, margin = 10;
    if ( typeof R.i.postjump_mode != 'number' ) return;
    mode = Math.floor( R.i.postjump_mode );
    if ( ( mode < 1 ) || ( mode > 4 ) ) return;
    if ( typeof R.i.postjump_extendtop != 'number' ) {}
    else extendtop = Math.max( 0, Math.floor( R.i.postjump_extendtop ) );
    if ( typeof R.i.postjump_extendbottom != 'number' ) {}
    else extendbottom = Math.max( 0, Math.floor( R.i.postjump_extendbottom ) );
    if ( typeof R.i.postjump_ignore != 'number' ) {}
    else igno = Math.max( 0, Math.floor( R.i.postjump_ignore ) );
    if ( typeof R.i.postjump_margin != 'number' ) {}
    else margin = Math.max( 0, Math.floor( R.i.postjump_margin ) );
    
    if ( typeof direction != 'string' ) return;
    var e1 = document.getElementById( 'board-articles' );
    if ( !e1 ) return;
    var ea1 = getChildrenByTagANDClassName( e1, 'form', '*' );
    if ( ea1.length != 1 ) return;
    e1 = ea1[ 0 ];
    ea1 = getChildrenByTagANDClassName( e1, 'div', 'article' );
    if ( ea1.length < 1 ) return;
    var aa = [];
    var r1, rw = Rect.fromWindow();
    if ( !rw ) return;
    var y;
    if ( R.i.posteditempreview ) {
        r1 = Rect.fromElement( R.i.posteditempreview );
        if ( !r1 ) return;
        r1.E = R.i.posteditempreview;
        aa.push( r1 );
    }
    
    for ( i = 0; i < ea1.length ; i++ ) {
        e1 = ea1[ i ];
        r1 = Rect.fromElement( e1 );
        if ( !r1 ) return;
        r1.E = e1;
        aa.push( r1 );
    }
    
    var top = 0;
    var bottom = aa.length - 1;
    for ( i = 1; i < aa.length; i++ ) {
        if ( aa[ i ].top    < aa[ top    ].top    ) top    = i;
        if ( aa[ i ].bottom > aa[ bottom ].bottom ) bottom = i;
    }
    
    do {
        if ( ( !R.i.posteditempreview ) &&
                ( R.i.postjump_extendtop != 'article-form-main' ) )
            break;
        if ( !R.i.mainform ) break;
        r1 = Rect.fromElement( R.i.mainform );
        if ( !r1 ) break;
        extendtop = Math.max( extendtop, aa[ top ].top - r1.top );
    } while ( false );
    
    var target;
    if ( direction == 'top' ) target = top;
    else if ( direction == 'bottom' ) target = bottom;
    else if ( direction == 'up' ) {
        target = top;
        for ( i = 0; i < aa.length; i++ )
            if ( ( aa[ i ].top < ( rw.top - igno ) ) &&
                    ( aa[ i ].top > aa[ target ].top ) )
                target = i;
    } else if ( direction == 'down' ) {
        target = bottom;
        if ( mode == 1 ) {
            for ( i = 0; i < aa.length; i++ )
                if ( ( aa[ i ].top > ( rw.top + igno + margin ) ) &&
                        ( aa[ i ].bottom <= aa[ target ].bottom ) )
                    target = i;
        } else if ( mode == 2 ) {
            for ( i = 0; i < aa.length; i++ )
                if ( ( aa[ i ].bottom > ( rw.bottom + igno ) ) &&
                        ( aa[ i ].top > ( rw.top + igno + margin ) ) &&
                        ( aa[ i ].bottom <= aa[ target ].bottom ) )
                    target = i;
        } else if ( ( mode == 3 ) || ( mode == 4 ) ) {
            for ( i = 0; i < aa.length; i++ )
                if ( ( aa[ i ].bottom > ( rw.bottom + igno ) ) &&
                        ( aa[ i ].bottom <= aa[ target ].bottom ) )
                    target = i;
        } else return;
    } else return;
    
    if ( ( direction == 'up' ) || ( direction == 'top' ) ) {
        y = aa[ target ].top - margin;
        if ( ( direction == 'top' ) || ( ( rw.top - igno ) <= aa[ top ].top ) )
        {
            y -= extendtop;
        }
        if ( y < 0 ) y = 0;
        if ( ( y >= ( rw.top - igno ) ) && (
                ( direction != 'top' ) || ( y <= ( rw.top + igno ) ) ) ) {
            y = null;
        }
    } else {
        if ( mode == 1 ) {
            if ( ( direction == 'bottom' ) ||
                    ( ( rw.top + igno + margin ) >= aa[ bottom ].top ) )
            {
                y = aa[ bottom ].bottom + margin + extendbottom - rw.height;
            } else
                y = aa[ target ].top - margin;
        }
        else
        {
            y = aa[ target ].bottom + margin - rw.height;
            if ( y < 0 ) y = 0;
            if ( ( direction == 'bottom' ) ||
                    ( ( rw.bottom + igno ) >= aa[ bottom ].bottom ) || (
                    ( mode == 2 ) &&
                    ( ( rw.top    + igno ) >= aa[ bottom ].top    ) ) )
            {
                y += extendbottom;
            }
            else if ( (
                        ( mode == 2 ) &&
                        ( y > ( aa[ target ].top - igno - margin ) )
                        ) || (
                        ( mode == 3 ) &&
                        ( y > ( aa[ target ].top - igno - margin ) ) &&
                        ( rw.top < ( aa[ target ].top - igno - margin ) )
                        ) )
            {
                y = aa[ target ].top - margin;
            }
        }
        if ( ( y < 0 ) || ( y <= ( rw.top - igno - margin ) ) ) {
            y = null;
        }
    }
    
    if ( typeof y == 'number' ) {
        rw.movetoLT( null, y );
        rw.wscroll();
    }
    
    flashnorepeat( aa[ target ].E );
}

function checkarticlelife( articleId, add ) {
    var hash = AIDUtils.getArticleNumber( articleId );
    if ( typeof hash != 'number' ) return undefined;
    var isdead = AIDs.isDead( hash );
    if ( isdead === false ) return 1;
    if ( isdead === true ) return 2;
    var ret = 0;
    if ( is_true( add ) ) {
        if ( ( ( R.i.pagelayout == 'n' ) || ( R.i.pagelayout == 'c' ) ) &&
                ( hash > AIDs.oldestId() ) && ( hash < AIDs.newestId() ) )
            ret = 2;
        else if ( R.i.pagelayout == 'r' )
            ret = 2;
        if ( ret == 2 )
            AIDs.add( hash, true );
    }
    return ret;
}

function forgecontexthref( articleId ) {
    var articleId = AIDUtils.getArticleNumber( articleId );
    if ( typeof articleId != 'number' ) return null;
    var href = getboardaddress();
    if ( !href ) return null;
    return href + '?contextId=' + articleId + '#article-' + articleId;
}

insertText.IDLE    = -1;
insertText.REPLACE = 1;
insertText.APPEND  = 3;
insertText.ENCLOSE = 7;

function getSelectedText( inputField ) {
    if ( !inputField.selectionStart && ( inputField.selectionStart != '0' ) )
        return '';
    var startPos = inputField.selectionStart;
    var endPos = inputField.selectionEnd;
    if ( startPos == endPos )
        return '';
    return inputField.value.substring( startPos, endPos );
}

function insertText( inputField, insertValue, replacePattern, customMap )
{
    var before, after, newPos;
    var map, a, i;
    if ( typeof insertValue != 'string' )
        insertValue = '';
    else
        insertValue = insertValue.replace( /\r\n?/g, '\n' );
    if ( !customMap || ( typeof customMap != 'object' ) )
        customMap = {};
    if ( typeof ArgMap == 'function' )
        customMap = new ArgMap( customMap ).map;
    for ( i in customMap ) {
        if ( ( typeof i != 'string' ) || ( i.length != 1 ) ||
                ( typeof customMap[ i ] != 'string' ) )
            customMap[ i ] = undefined;
    }
    map = customMap;
    map[ 'c' ] = '';
    a = sprintfheavy( insertValue, map );
    newPos = a[ 'result' ].length;
    for ( i = 0; i < a[ 'log' ].length; i++ ) {
        if ( a[ 'log' ][ i ][ 'key' ] == 'c' ) {
            newPos = a[ 'log' ][ i ][ 'pos' ];
            break;
        }
    }
    before = a[ 'result' ].substring( 0, newPos );
    after = a[ 'result' ].substring( newPos );
    insertValue = a[ 'result' ];
    if ( !inputField.selectionStart && ( inputField.selectionStart != '0' ) )
    {
        inputField.value += insertValue;
        return;
    }
    var startPos = inputField.selectionStart;
    var endPos = inputField.selectionEnd;
    if ( startPos == endPos ) {
        if ( ( before + after ).length < 1 )
            return;
    }
    
    if ( startPos != endPos ) {
        if ( typeof replacePattern == 'string' ) {
            replacePattern = replacePattern.replace( /\r\n?/g, '\n' );
        } else if ( replacePattern == insertText.REPLACE ) {
            replacePattern = '%i';
        } else if ( replacePattern == insertText.APPEND ) {
            replacePattern = '%r%i';
        } else if ( replacePattern == insertText.ENCLOSE ) {
            replacePattern = '%i%r%i';
        } else return;
        if ( typeof insertValue != 'string' ) insertValue = '';
        map = customMap;
        map[ 'c' ] = '';
        map[ 'b' ] = before;
        map[ 'a' ] = after;
        map[ 'r' ] = inputField.value.substring( startPos, endPos );
        a = sprintfheavy( replacePattern, map );
        newPos = a[ 'result' ].length;
        for ( i = 0; i < a[ 'log' ].length; i++ ) {
            if ( a[ 'log' ][ i ][ 'key' ] == 'c' ) {
                newPos = a[ 'log' ][ i ][ 'pos' ];
                break;
            }
        }
        before = a[ 'result' ].substring( 0, newPos );
        after = a[ 'result' ].substring( newPos );
        insertValue = a[ 'result' ];
    }
    var nlcount = 0;
    for ( i = 0; i < newPos; i++ ) {
        if ( insertValue.charAt( i ) == '\n' )
            nlcount++;
    }
    
    inputField.value = inputField.value.substring( 0, startPos )
            + insertValue
            + inputField.value.substring( endPos, inputField.value.length );
    if ( window.opera ) {
        newPos += nlcount;
    }
    newPos += startPos;
    if ( typeof inputField.setSelectionRange == 'function' ) {
        inputField.focus();
        inputField.setSelectionRange( newPos, newPos );
    } else
    if ( typeof inputField.createTextRange == 'function' ) {
        var range = inputField.createTextRange();
        range.collapse( true );
        range.moveEnd( 'character', newPos );
        range.moveStart( 'character', newPos );
        range.select();
    } else {
        inputField.selectionEnd = inputField.selectionStart = newPos;
    }
}

//}}}
//-----------------------------------------------------------------------------
//{{{

// 2do: change to R.i.* or turn all to OOP
var flashtimer = null;
var flashedelement = null;
var flashcounter = -1;
var flashnorepeattimer = null;
var flashrepeated = false;

function flashparentarticleEVENT( event ) {
    if ( ( this.nodeType != 1 ) || ( this.tagName.toLowerCase() != 'a' ) )
        return;
    var pr, p1 = /^[^#]+#(article-\d\d*)$/;
    if ( pr = p1.exec( this.href ) )
    var target = document.getElementById( pr[ 1 ] );
    if ( target ) {
        if ( flashedelement && ( flashedelement != target ) )
            unflash( flashedelement );
        flashedelement = target;
        flashrepeated = true;
        flashelement( flashedelement );
    }
}

function flashrepeatstopEVENT( event ) {
    if ( flashedelement ) unflash( flashedelement );
    flashedelement = null;
    flashrepeated = false;
}

function flashnorepeat( element ) {
    var now = new Date().getTime();
    if ( flashnorepeattimer && ( typeof flashnorepeattimer == 'number' ) ) {
        if ( ( now < flashnorepeattimer ) &&
                ( now > ( flashnorepeattimer - 30000 ) ) ) {}
        else flashnorepeattimer = null;
    }
    else flashnorepeattimer = null;
    if ( !flashnorepeattimer )
        flashelement( element );
    flashnorepeatset( 'default' );
}

function flashnorepeatset( ms ) {
    if ( ms === null ) { flashnorepeattimer = null; return; }
    if ( ms === 'default' ) ms = R.i.flash_norepeat;
    if ( ( typeof ms != 'number' ) || ( ms < 1 ) ) return;
    if ( ms < 10 ) ms = 10;
    else if ( ms > 30000 ) ms = 30000;
    flashnorepeattimer = new Date().getTime() + ms;
}

function unflash( target ) {
    if ( !target ) {
        if ( !flashedelement ) return;
        else target = flashedelement;
    }
    flashnorepeatset( 'default' );
    classNameUtil( target, 'flashed',  -1 );
    classNameUtil( target, 'flashed2', -1 );
    if ( flashtimer ) clearTimeout( flashtimer );
    flashtimer = null;
}

function flashid( id ) {
    if ( ( typeof id != 'string' ) || ( id == '' ) || ( id == '#' ) )
        return;
    if ( id.charAt( 0 ) == '#' )
        id = id.substring( 1 );
    var target = document.getElementById( id );
    if ( target ) flashelement( target );
}

function flashelement( element ) {
    do {
        if ( typeof R.i.flash_repeat != 'number' ) break;
        if ( R.i.flash_repeat < 1 ) break;
        else if ( R.i.flash_repeat > 50 ) R.i.flash_repeat = 50;
        if ( flashedelement && ( flashedelement != element ) )
            unflash( flashedelement );
        flashedelement = element;
        return flashstart();
    } while ( false );
    if ( flashedelement ) unflash( flashedelement );
    return false;
}

function flashstart() {
    if ( !flashedelement ) return false;
    flashcounter = 0;
    classNameUtil( flashedelement, 'flashed', +1 );
    flashdo();
    flashnorepeatset( 'default' );
    return true;
}

function flashdo() {
    if ( !flashelement ) return;
    var stop = false;
    do {
        if ( typeof flashcounter != 'number' )
            flashcounter = -1;
        if ( flashcounter < 0 ) {
            unflash( flashedelement );
            break;
        }
        var nexttimer = 0;
        if ( flashcounter >= R.i.flash_repeat ) {
            stop = true;
            unflash( flashedelement );
        } else {
            classNameUtil( flashedelement, 'flashed2',
                    ( flashcounter % 2 ) ? +1 : -1 );
            if ( R.i.flash_timing.length ) {
                nexttimer = Number( R.i.flash_timing[
                            flashcounter % R.i.flash_timing.length ] );
            }
        }
        flashcounter++;
        if ( stop == true ) {
            if ( !is_true( flashrepeated ) )
                break;
            nexttimer = R.i.flash_delay;
        }
        if ( nexttimer < 10 ) nexttimer = 10;
        if ( stop == true ) {
            flashtimer = setTimeout( flashstart, nexttimer );
            break;
        } else {
            flashtimer = setTimeout( flashdo, nexttimer );
        }
    } while ( false );
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function showlinkcopyboxEVENT( event ) {
    showlinkcopybox( this, this.getAttribute( 'linkcopyaddress' ), "" );
}

var linkcopyboxtimeout = null;

function showlinkcopybox( element, href, text ) {
    var y = getY( element );
    if ( !y ) return false;
    var box = document.getElementById( "linkcopybox" );
    if ( !box ) return false;
    var input = document.getElementById( "linkcopyinput" );
    if ( !input ) return false;
    box.style.top = ( y - 60 ) + "px";
    classNameUtil( box, "hidden", -1 );
    classNameUtil( box, "shown",  +1 );
    input.value = '<a href="' + href + '" >' + text + "</a>";
    setlinkcopyboxtimeout( 3000 );
}

function hilightlinkcopyinput() {
    setlinkcopyboxtimeout( null );
    var input = document.getElementById( "linkcopyinput" );
    if ( !input ) return;
    input.focus(); input.select();
}

function hidelinkcopybox() {
    setlinkcopyboxtimeout( null );
    var box = document.getElementById( "linkcopybox" );
    if ( !box ) return false;
    box.style.top = "";
    classNameUtil( box, "shown",  -1 );
    classNameUtil( box, "hidden", +1 );
}

function setlinkcopyboxtimeout( ms ) {
    if ( linkcopyboxtimeout ) clearTimeout( linkcopyboxtimeout );
    if ( ( typeof ms == "number" ) && ( ms > 0 ) )
        linkcopyboxtimeout = setTimeout( hidelinkcopybox, ms );
    else linkcopyboxtimeout = null;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function showhtmlcopyboxEVENT( event ) {
    showhtmlcopybox( this );
}

var htmlcopyboxtimeout = null;

function showhtmlcopybox( element ) {
    var y = getY( element );
    if ( !y ) return;
    var box = document.getElementById( "htmlcopybox" );
    if ( !box ) return;
    var area = document.getElementById( "htmlcopyarea" );
    if ( !area ) return;
    box.style.top = ( y + 40 ) + "px";
    classNameUtil( box, "hidden", -1 );
    classNameUtil( box, "shown",  +1 );
    area.value = getbodyhtml( element );
    if ( area.value )
        area.value = area.value.replace( /^\s+|\s+$/g, "" );
    sethtmlcopyboxtimeout( 3000 );
}

function hilighthtmlcopyarea() {
    sethtmlcopyboxtimeout( null );
    var area = document.getElementById( "htmlcopyarea" );
    if ( !area ) return;
    area.focus(); area.select();
}

function getbodyhtml( element ) {
    var ea = getChildrenByTagANDClassName(
            getparenarticle( element ), 'div', 'body' );
    if ( ea.length != 1 ) return null;
    return ea[ 0 ].innerHTML;
}

function hidehtmlcopybox() {
    sethtmlcopyboxtimeout( null );
    var box = document.getElementById( "htmlcopybox" );
    if ( !box ) return;
    box.style.top = "";
    classNameUtil( box, "shown",  -1 );
    classNameUtil( box, "hidden", +1 );
}

function sethtmlcopyboxtimeout( ms ) {
    if ( htmlcopyboxtimeout ) clearTimeout( htmlcopyboxtimeout );
    if ( ( typeof ms == "number" ) && ( ms > 0 ) )
        htmlcopyboxtimeout = setTimeout( hidehtmlcopybox, ms );
    else htmlcopyboxtimeout = null;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var replyparentlink_click     = null;
var replyparentlink_mouseover = null;
var replyparentlink_mouseout  = null;

function hiliteparentarticleEVENT( event ) {
    if ( !event ) event = window.event;
    hilitelinkedarticle( this );
    return consumeEVENT( event );
}

function replyparentlink_purge() {
    var e1 = document.getElementById( 'replyparentlink' );
    if ( !e1 ) return null;
    if ( replyparentlink_click     ) e1.removeEventListener(
            'click',     replyparentlink_click,     false );
    if ( replyparentlink_mouseover ) e1.removeEventListener(
            'mouseover', replyparentlink_mouseover, false );
    if ( replyparentlink_mouseout  ) e1.removeEventListener(
            'mouseout',  replyparentlink_mouseout,  false );
    replyparentlink_click     = null;
    replyparentlink_mouseover = null;
    replyparentlink_mouseout  = null;
    return e1;
}

function replyparentboxupdate() {
    var show = 0, e1 = getmainparentelement();
    do {
        if ( !e1 ) break;
        var pid = e1.value;
        if ( /^\d\d*$/.test( pid ) ) show = 2;
        else { show = 1; break; }
        var currentpage = false, author = null;
        if ( e1 = document.getElementById( 'article-' + pid ) ) {
            currentpage = true;
            author = new AAuthor( e1 );
        }
        if ( e1 = replyparentlink_purge() ) {
            setinnertext( e1, pid, false );
            var phref = forgecontexthref( pid );
            e1.href = phref;
            if ( currentpage ) {
                replyparentlink_mouseover = flashparentarticleEVENT;
                replyparentlink_mouseout = flashrepeatstopEVENT;
                replyparentlink_click = hiliteparentarticleEVENT;
                e1.addEventListener( 'mouseover', replyparentlink_mouseover, false );
                e1.addEventListener( 'mouseout', replyparentlink_mouseout, false );
                e1.addEventListener( 'click', replyparentlink_click, false );
            } else {
                replyparentlink_click = consumeEVENT;
                e1.addEventListener( 'click', replyparentlink_click, false );
            }
            
            var before, after;
            if ( !R.i.okounpost_linkmarkers instanceof Array )
                R.i.okounpost_linkmarkers = [];
            if ( currentpage ) {
                before = R.i.okounpost_linkmarkers[ 0 ];
                after  = R.i.okounpost_linkmarkers[ 1 ];
            } else if ( checkarticlelife( pid, false ) != 2 ) {
                before = R.i.okounpost_linkmarkers[ 2 ];
                after  = R.i.okounpost_linkmarkers[ 3 ];
            } else {
                before = R.i.okounpost_linkmarkers[ 4 ];
                after  = R.i.okounpost_linkmarkers[ 5 ];
            }
            var e2;
            if ( typeof before != 'string' ) before = null;
            {
                e2 = e1.previousSibling;
                if ( e2 && ( e2.nodeType == 1 ) &&
                        ( e2.tagName.toLowerCase() == 'span' ) )
                    setinnertext( e2, before, false );
            }
            if ( typeof after != 'string' ) after = null;
            {
                e2 = e1.nextSibling;
                if ( e2 && ( e2.nodeType == 1 ) &&
                        ( e2.tagName.toLowerCase() == 'span' ) )
                    setinnertext( e2, after, false );
            }
        }
        
        if ( e1 = document.getElementById( 'replyparentauthor' ) ) {
            if ( currentpage ) {
                if ( ( author instanceof AAuthor ) && !author.failed() )
                {
                    setinnertext( e1, author.getNick(), false );
                    if ( author.anonymous === true ) {
                        classNameUtil( e1, 'anon', +1 );
                    } else {
                        classNameUtil( e1, 'anon', -1 );
                    }
                } else {
                    classNameUtil( e1, 'anon', +1 );
                    setinnertext( e1, ( ( author instanceof AAuthor ) ?
                            author.getNick() : '[???]' ), false );
                }
                classNameUtil( e1, 'hidden', -1 );
            } else {
                classNameUtil( e1, 'hidden', +1 );
            }
        }
        
    } while ( false );
    e1 = document.getElementById( 'replyparentnone' );
    if ( e1 ) classNameUtil( e1, 'hidden', ( show == 1 ) ? -1 : +1 );
    e1 = document.getElementById( 'replyparentgiven' );
    if ( e1 ) classNameUtil( e1, 'hidden', ( show == 2 ) ? -1 : +1 );
}

function replyparentfromcurrentarticleEVENT( event ) {
    if ( !event ) event = window.event;
    var articleId = AIDUtils.getArticleNumber( currentarticleId );
    if ( typeof articleId != 'number' ) return consumeEVENT( event );
    replyparentsetnew( articleId );
    replyparentboxupdate();
    replycontrolboxX( this );
    jumptoid( '#board-postArticle' );
    return consumeEVENT( event );
}

function getmainparentelement() {
    if ( !R.i.mainform ) return null;
    var i, children = R.i.mainform.childNodes;
    for ( i = 0; i < children.length; i++ )
        if ( ( children[ i ].nodeType == 1 ) &&
                ( children[ i ].tagName.toLowerCase() == 'input' ) &&
                ( children[ i ].name == 'parentId' ) )
            break;
    if ( i < children.length ) return children[ i ];
    else return null;
}

function replyparentsetnew( pid ) {
    if ( typeof pid == 'number' ) pid = String( pid );
    else if ( typeof pid != 'string' ) return false;
    if ( !/^\d*$/.test( pid ) ) return false;
    var e1 = getmainparentelement();
    if ( !e1 ) return false;
    e1.value = pid;
    return ( e1.value === pid );
}

function replyparentX() {
    e1 = document.getElementById( 'replyparentnone' );
    if ( e1 ) classNameUtil( e1, 'hidden', -1 );
    e1 = document.getElementById( 'replyparentgiven' );
    if ( e1 ) classNameUtil( e1, 'hidden', +1 );
    if ( !replyparentsetnew( '' ) )
        replyparentboxupdate();
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var mainFMTControls = {
    
    fmtNodeIds: {
        r: 'format-radeox',
        t: 'format-text',
        h: 'format-html',
        p: 'preview-flag'
    },
    
    fmtKeys: [ 'r', 't', 'h' ],
    
    getId: function getId( key ) {
        var ret = this.fmtNodeIds[ key ];
        if ( typeof ret != 'string' ) ret = null;
        return ret;
    },
    
    getNode: function getNode( key ) {
        var ret = null, id = this.fmtNodeIds[ key ];
        if ( typeof id == 'string' ) {
            ret = document.getElementById( id );
            if ( !ret || ( ret.nodeType != 1 ) ) ret = null;
        }
        return ret;
    },
    
    getFormat: function getFormat() {
        var key, i = 0;
        for ( ; i < this.fmtKeys.length; i++ ) {
            key = this.fmtKeys[ i ];
            var id = this.fmtNodeIds[ key ];
            if ( typeof id != 'string' ) continue;
            var e1 = document.getElementById( id );
            if ( !e1 || ( e1.nodeType != 1 ) ) continue;
            if ( e1.checked ) break;
        }
        if ( i < this.fmtKeys.length ) return key;
        return '';
    },
    
    setFormat: function setFormat( key ) {
        var e1 = this.getNode( key );
        if ( e1 ) {
            e1.checked = true;
            mainFMTControls.mirror( 'down' );
            return true;
        }
        return false;
    },
    
    setPreviewFlag: function setPreviewFlag( checked ) {
        if ( typeof checked != 'boolean' ) return false;
        var e1 = this.getNode( 'p' );
        if ( e1 ) {
            e1.checked = checked;
            return true;
        }
        return false;
    },
    
    setDefaults: function setDefaults( defaultbodyType, defaultpreviewFlag ) {
        var v = null;
        if ( typeof defaultbodyType == 'string' ) {
            if ( /^R(a(d(e(ox?)?)?)?)?$/i.test( defaultbodyType ) )
                v = 'r';
            else if ( /^T(e(xt?)?)?$/i.test( defaultbodyType ) )
                v = 't';
            else if ( /^H(t(ml?)?)?$/i.test( defaultbodyType ) )
                v = 'h';
            if ( typeof v == 'string' )
                this.setFormat( v );
        }
        if ( typeof defaultpreviewFlag == 'string' ) {
            v = null;
            if ( /^C(h(e(c(k(ed?)?)?)?)?)?$/i.test( defaultpreviewFlag ) )
                v = true;
            else if ( /^U(n(c(h(e(c(k(ed?)?)?)?)?)?)?)?$/i.test(
                    defaultpreviewFlag ) )
                v = false;
            if ( typeof v == 'boolean' )
                this.setPreviewFlag( v );
        }
    },
    
    shadowNodeIds: {},
    
    setShadowNodeIds: function setShadowNodeIds( snids ) {
        if ( ( typeof snids != 'object' ) || !snids ) return false;
        var ret = true;
        for ( i in this.fmtNodeIds ) {
            var ok = false;
            if ( typeof snids[ i ] == 'string' ) {
                var id = trim( snids[ i ] );
                if ( id.length > 0 ) {
                    this.shadowNodeIds[ i ] = id;
                    ok = true;
                }
            }
            if ( !ok ) {
                this.shadowNodeIds[ i ] = undefined;
                ret = false;
            }
        }
        return ret;
    },
    
    mirror: function mirror( direction ) {
        if ( typeof direction != 'string' ) return false;
        var e1, e2, i, id, ret = true;
        for ( i in this.fmtNodeIds ) {
            id = this.fmtNodeIds[ i ];
            e1 = document.getElementById( id );
            id = this.shadowNodeIds[ i ];
            if ( typeof id != 'string' ) { ret = false; continue }
            e2 = document.getElementById( id );
            if ( !e1 || !e2 ) { ret = false; continue }
            if ( direction == 'up' )        e1.checked = e2.checked;
            else if ( direction == 'down' ) e2.checked = e1.checked;
            else { ret = false; break; }
        }
        return ret;
    }
    
}

//}}}
//-----------------------------------------------------------------------------
//{{{

function showreplycontrolboxEVENT( event ) {
    showreplycontrolbox( this );
}

function updatereplycontrolupEVENT( event ) {
    updatereplycontrol( 'up' );
}

function updatereplycontroldownEVENT( event ) {
    updatereplycontrol( 'down' );
}

function replycontrolboxXEVENT( event ) {
    replycontrolboxX( this );
    return consumeEVENT( event );
}

function replyFormDLXEVENT( event ) {
    if ( !event ) event = window.event;
    hidereplycontrolbox();
    var articleId = AIDUtils.getArticleNodeID( this, 3 );
    var done = replyFormDLX( articleId );
    if ( done )
        return consumeEVENT( event );
}

// 2do: change to R.i.* or turn all to OOP
var currentarticleId = null;

function changeActiveTextarea( element ) {
    var ata = element;
    if ( !ata || ( ata.nodeType !== 1 ) ||
            ( ata.tagName.toLowerCase() != 'textarea' ) ) {
        if ( ata === null ) {
            R.i.activetextarea2 = null;
            if ( R.i.formatbuttons2.parentNode ) {
                R.i.formatbuttons2.parentNode.removeChild( R.i.formatbuttons2 );
            }
            return true;
        } else {
            return false;
        }
    }
    if ( !R.i.formatbuttons2 ) return false;
    R.i.activetextarea2 = ata;
    if ( ata.parentNode == R.i.formatbuttons2.parentNode ) {}
    else {
        ata.parentNode.insertBefore( R.i.formatbuttons2, ata );
    }
    return true;
}

function showreplycontrolbox( starter ) {
    currentarticleId = null;
    if ( !starter || ( starter.nodeType !== 1 ) ) return false;
    var box = document.getElementById( 'replycontrolbox' );
    if ( !box ) return false;
    if ( !updatereplycontrol( 'down' ) ) { //return false;
    }
    var articleId = AIDUtils.getArticleNodeID( starter, 3 );
    if ( !articleId ) return false;
    var rfid = 'replyForm-' + articleId;
    var replyForm = document.getElementById( rfid );
    if ( !replyForm ) {
        replyFormDLX( articleId );
        replyForm = document.getElementById( rfid );
        if ( !replyForm ) return false;
    } else if ( replyForm.getAttribute( 'DLXed' ) != 'true' ) {
        replyFormDLX( articleId );
    } else {
        replyForm.style.display = 'block';
    }
    
    var area = document.getElementById( 'replyFormBody-' + articleId );
    if ( area ) changeActiveTextarea( area );
    
    var r1 = Rect.fromElement( starter );
    if ( !r1 ) return false;
    var fromRF = /(^|\s)DLX-button(\s|$)/.test( starter.className );
    var y = r1.bottom + ( fromRF ? 5 : 5 );
    var rf = Rect.fromElement( replyForm );
    if ( !rf ) return false;
    currentarticleId = articleId;
    y = Math.max( y, rf.top + 5 );
    box.style.top = y + 'px';
    classNameUtil( box, 'left', fromRF ? + 1 : -1 );
    classNameUtil( box, 'hidden', -1 );
    classNameUtil( box, 'shown',  +1 );
    do {
        var rw = Rect.fromWindow();
        if ( !rw ) break;
        r1.merge( Rect.fromElement( getparenarticle( starter ) ) );
        r1.merge( Rect.fromElement( replyForm ) );
        r1.merge( Rect.fromElement( box ) );
        rw.lookat( r1, fromRF ? 1 : 2, 2 );
        rw.wscroll();
    } while ( false );
    
    if ( area ) area.focus();
}

function replyFormDLX( articleId ) {
    var articleId = AIDUtils.getArticleNumber( articleId );
    if ( typeof articleId != 'number' ) return false;
    var replyForm = document.getElementById( 'replyForm-' + articleId );
    if ( !replyForm ) {
        var article = document.getElementById( 'article-' + articleId );
        var RARFcode = getRARFcode( article );
        if ( !RARFcode ) return false;
        try {
            eval( decodeURI( RARFcode ) );
        } catch ( e ) {
            consolemsg( 'exception in replyFormDLX(): ' + e );
        }
        replyForm = document.getElementById( 'replyForm-' + articleId );
        if ( !replyForm ) return false;
    }
    if ( replyForm.getAttribute( 'DLXed' ) == 'true' ) return false;
    
    var ea1 = getChildrenByTagANDClassName( replyForm, 'input', '*' );
    var submit = null;
    for ( var i = 0; i < ea1.length; i++ ) {
        if ( ( ea1[ i ].type == 'button' )
                || ( ea1[ i ].type == 'submit' )
                )
        {
            submit = ea1[ i ];
            break;
        }
    }
    if ( !submit ) return false;
    
    var e2 = document.createElement( 'div' );
    e2.className = '_MAX_W_100P';
    replyForm.insertBefore( e2, submit );
    var e3 = document.createElement( 'div' );
    e3.className = '_F_R';
    e2.appendChild( e3 );
    e2.appendChild( submit );
    
    e2 = createElement( 'input', null, 'DLX-button', { type: 'button' } );
    e2.value = '\u2026';
    e2.addEventListener( 'click', showreplycontrolboxEVENT, false );
    e3.appendChild( e2 );
    e2 = createElement( 'input', null, 'DLX-button', { type: 'button' } );
    e2.value = 'X';
    e2.addEventListener( 'click', replycontrolboxXEVENT, false );
    e3.appendChild( e2 );
    
    replyForm.addEventListener( 'keypress', shiftenterEVENT, false );
    
    replyForm.setAttribute( 'DLXed', 'true' );
    return true;
}

function replycontrolboxX( element ) {
    var fromRF = false;
    if ( element && ( element.nodeType === 1 ) &&
            /(^|\s)DLX-button(\s|$)/.test( element.className ) )
        fromRF = true;
    var articleId = fromRF ? AIDUtils.getArticleNodeID( element, 3 )
            : AIDUtils.getArticleNumber( currentarticleId );
    do {
        if ( typeof articleId != 'number' ) break;
        var replyForm = document.getElementById( 'replyForm-' + articleId );
        if ( !replyForm ) break;
        replyForm.style.display = 'none';
        if ( R.i.activetextarea2 && R.i.activetextarea2.parentNode &&
                R.i.activetextarea2.parentNode.parentNode &&
                ( replyForm == R.i.activetextarea2.parentNode.parentNode ) )
            changeActiveTextarea( null );
    } while ( false );
    hidereplycontrolbox();
}

function findRARFlink( element ) {
    var found = 0;
    for ( ; ; element = element.parentNode ) {
        if ( !element ) return null;
        if ( element.nodeType === 3 ) continue;
        if ( element.nodeType !== 1 ) return null;
        if ( /(^|\s)article(\s|$)/.test( element.className ) ) {
            found = 1; break;
        } else if ( /(^|\s)article-menu(\s|$)/.test( element.className ) ) {
            found = 2; break;
        }
    }
    var ea;
    if ( found == 1 ) {
        ea = getChildrenByTagANDClassName( element, 'div', 'marks' );
        if ( ea.length != 1 ) return null;
        ea = getChildrenByTagANDClassName( ea[ 0 ], 'ul', 'article-menu' );
        if ( ea.length != 1 ) return null;
        element = ea[ 0 ];
        found = 2;
    }
    if ( found != 2 ) return null;
    ea = getChildrenByTagANDClassName( element, 'li', '*' );
    if ( ea.length < 1 ) return null;
    // assuming the reply link is in the last li element
    // no solid seeking effort made
    element = ea[ ea.length - 1 ].firstChild;
    if ( element.tagName.toLowerCase() != 'a' ) return null;
    if ( !/^javascript:/i.test( element.href ) ) return null;
    return element;
}

function getRARFcode( element ) {
    element = findRARFlink( element );
    if ( !element ) return null;
    return element.href.replace( /^javascript:/i, '' );
}

function updatereplycontrol( direction ) {
    return mainFMTControls.mirror( direction );
}

function replycontrolboxRe() {
    var articleId = AIDUtils.getArticleNumber( currentarticleId );
    if ( typeof articleId != 'number' ) return false;
    var replyForm = document.getElementById( 'replyForm-' + articleId );
    if ( !replyForm ) return;
    var area = document.getElementById( 'replyFormBody-' + articleId );
    if ( !area ) return;
    var nick, author = new AAuthor(
            document.getElementById( 'article-' + articleId ) );
    if ( ( author.anonymous == true ) && ( author.nick.length < 1 ) )
        nick = 'anonym';
    else
        nick = author.nick;
    replyForm.style.display = 'block';
    var temp = '';
    switch ( mainFMTControls.getFormat() ) {
       case 'r': temp = '**' + nick + '**'; break;
       case 'h': temp = '<b>' + nick + '</b>'; break;
       default: temp = nick; break;
    }
    temp = trim( temp );
    if ( ( void2str( area.value ).length >= temp.length ) &&
            ( trim( area.value ).substring( 0, temp.length ) == temp ) )
    {
    } else {
        area.value = temp + ':' + area.value;
    }
    area.focus();
}

function hidereplycontrolbox() {
    var box = document.getElementById( 'replycontrolbox' );
    if ( !box ) return false;
    box.style.top = '';
    classNameUtil( box, 'shown',  -1 );
    classNameUtil( box, 'hidden', +1 );
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var RNGSELUtils = {
  NOT_SUPPORTED: {},
  DOM: {
    getElementWithId: function() {
      var func=function() { return RNGSELUtils.NOT_SUPPORTED; }
      if(document.getElementById) {
        func=function(id) {
          return document.getElementById(id);
        }
      } else if(document.all) {
        func=function(id) {
          return document.all[id];
        }
      }
      return (this.getElementWithId=func)();
    }
  },
  Ranges: {
    create: function() {
      var func=function() { return RNGSELUtils.NOT_SUPPORTED};
      if(document.body && document.body.createTextRange) {
        func=function() { return document.body.createTextRange(); }
      } else if(document.createRange) {
        func=function() { return document.createRange(); }
      }
      return (this.create=func)();
    },
    selectNode: function(node, originalRng) {
      var func=function() { return RNGSELUtils.NOT_SUPPORTED; };
      var rng=this.create(), method="";
      if(rng.moveToElementText) method="moveToElementText";
      else if(rng.selectNode) method="selectNode";
      if(method)
        func=function(node, rng) {
          rng=rng||RNGSELUtils.Ranges.create();
          rng[method](node);
          return rng;
        }
      return rng=null,(this.selectNode=func)(node, originalRng);
    }
  },
  Selection: {
    clear: function() {
      var func=function() { return RNGSELUtils.NOT_SUPPORTED};
      if(window.getSelection) {
        var sel=window.getSelection();
        if(sel.removeAllRanges) {
          func=function() {
            window.getSelection().removeAllRanges();
          }
        }
        sel=null;
      } else if(typeof document.selection!="undefined") {
        func=function() {
          if(document.selection && document.selection.empty) {
            return (RNGSELUtils.Selection.clear=function() {
              if(document.selection)
                document.selection.empty();
            })();
          }
        }
      }
      return (this.clear=func)();
    },
    add: function(originalRng) {
      var func=function() { return RNGSELUtils.NOT_SUPPORTED};
      var rng=RNGSELUtils.Ranges.create();
      if(rng.select) {
        func=function(rng) {rng.select(); }
      } else if(window.getSelection) {
        var sel=window.getSelection();
        if(sel.addRange) {
          func=function(rng) {window.getSelection().addRange(rng); }
        }
        sel=null;
      }
      return (this.add=func)(originalRng);
    }
  }
};

//}}}
//-----------------------------------------------------------------------------
//{{{

function ArgMap( source ) {
    this.init();
    if ( typeof source == 'object' ) this.merge( source );
}

ArgMap.prototype.init = function init() {
    this.map = {};
}
ArgMap.prototype.merge = function merge( object ) {
    var object = ( object instanceof ArgMap ) ? object.map : object;
    if ( ( object === null ) || ( typeof object != 'object' ) ) return;
    for ( var i in object )
        if ( ( String( i ).length == 1 ) &&
                ( typeof object[ i ] == 'string' ) )
            this.map[ String( i ) ] = object[ i ];
}
ArgMap.prototype.set = function set( name, value ) {
    if ( ( typeof name != 'string' ) || ( name.length != 1 ) ||
            ( typeof value != 'string' ) )
        return;
    this.map[ name ] = value;
}
ArgMap.prototype.get = function get( name ) {
    if ( typeof name != 'string' ) return null;
    var ret = this.map[ name ];
    if ( typeof ret != 'string' ) return null;
    return ret;
}
ArgMap.prototype.toString = function toString() {
    var ret = '[', cnt = 0;
    for ( var i in this.map ) {
        if ( cnt++ > 0 ) ret += ', ';
        ret += i + ' => ' + this.map[ i ];
    }
    ret += ']';
    return ret;
}

//}}}
//-----------------------------------------------------------------------------
//{{{

var FBs = {
    FBAction: {
        IDLE: {},
        INSERT: {},
        BOX_RAISED: {},
        BOX_FAILED: {},
        OTHER_ERROR: {},
        INSERTED: {}
    },
    fBAction2str: function fBAction2str( a ) {
        if ( a === FBs.FBAction.IDLE )        return 'IDLE';
        if ( a === FBs.FBAction.INSERT )      return 'INSERT';
        if ( a === FBs.FBAction.BOX_RAISED )  return 'BOX_RAISED';
        if ( a === FBs.FBAction.BOX_FAILED )  return 'BOX_FAILED';
        if ( a === FBs.FBAction.OTHER_ERROR ) return 'OTHER_ERROR';
        if ( a === FBs.FBAction.INSERTED )    return 'INSERTED';
        return 'UNKNOWN';
    },
    FBAs: {
        registered: {},
        register: function register(