MediaWiki:Gadget-HotCat.js

来自希灵百科
跳转至: 导航搜索

注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。

  • Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5Ctrl-R(Mac为⌘-R
  • Google Chrome:Ctrl-Shift-R(Mac为⌘-Shift-R
  • Internet Explorer:按住Ctrl的同时单击刷新,或按Ctrl-F5
  • Opera:前往菜单 → 设置(Mac为Opera → Preferences),然后隐私和安全 → 清除浏览数据 → 缓存的图片和文件
/* 
 * 鉴于维基共享的js会被墙,于是在这里提供去除注释、内置i18n(L15-33, 36, 48-56, 58, 69-75)、移除i18n判断(L219)的版本【原版参见[https://commons.wikimedia.org/wiki/MediaWiki:Gadget-HotCat.js]】。
 * 其著作权归所有者所有【参见[https://commons.wikimedia.org/wiki/Help:Gadget-HotCat/Version_history]】,
 * 并遵循Quadruple licensed GFDL, GPL, LGPL and Creative Commons Attribution 3.0 (CC-BY-3.0)【你可以任选一种】。
 * 帮助参见[[Help:HotCat小工具]],其他细节参见[https://commons.wikimedia.org/wiki/Help:Gadget-HotCat]
 */
//<nowiki>
/* jshint ignore:start */ //这么多warning我受不了了23333
(function() {
    var conf = window.mw ? mw.config.values : window;
    if ((window.HotCat && !window.HotCat.nodeName) || conf.wgAction == 'edit') {
        return;
    }
    window.HotCat = {
        messages: {
            cat_removed: '移除[[分类:$1]]',
            template_removed: '移除{{[[分类:$1]]}}',
            cat_added: '添加[[分类:$1]]',
            cat_keychange: '为[[分类:$1]]设定新索引:“$2”',
            cat_notFound: '分类“$1”未找到',
            cat_exists: '分类“$1”已存在,不执行添加操作',
            cat_resolved: '(已处理[[分类:$1]]的重定向)',
            uncat_removed: null, //萌百没有Template:Uncategorized
            separator: '; ',
            prefix: "",
            using: '——[[Help:HotCat小工具|HotCat]]',
            multi_change: '$1个分类',
            commit: '保存',
            ok: '确定',
            cancel: '取消',
            multi_error: '无法连接到萌百服务器,因此您的分类更改无法保存,由此引发的不便我们深表歉意。',
            short_catchange: null
        },
        category_regexp: '[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]',
        category_canonical: 'Category',
        categories: '分类',
        disambig_category: 'Disambiguation',
        redir_category: 'Category redirects',
        links: {
            change: '(±)',
            remove: '(\u2212)',
            add: '(+)',
            restore: '(×)',
            undo: '(×)',
            down: '(\u2193)',
            up: '(\u2191)'
        },
        tooltips: {
            change: '修改',
            remove: '移除',
            add: '新增一个分类',
            restore: '回退更改',
            undo: '回退更改',
            down: '打开已修改并显示子分类',
            up: '打开已修改并显示父分类'
        },
        addmulti: '<span>+<sup>+</sup></span>',
        multi_tooltip: '修改多个分类',
        disable: function() {
            var ns = conf.wgNamespaceNumber;
            var nsIds = conf.wgNamespaceIds;
            return (ns < 0 || ns === 10 || ns === 828 || ns === 8 || ns === 6 && conf.wgArticleId === 0 || ns === 2 && /\.(js|css)$/.test(conf.wgTitle) || nsIds && (ns === nsIds.creator || ns === nsIds.timedtext || ns === nsIds.institution));
        },
        uncat_regexp: /\{\{\s*([Uu]ncat(egori[sz]ed( image)?)?|[Nn]ocat|[Nn]eedscategory)[^}]*\}\}\s*(<\!--.*?--\>)?/g,
        existsYes: '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png',
        existsNo: '//upload.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png',
        template_regexp: '[Tt][Ee][Mm][Pp][Ll][Aa][Tt][Ee]',
        template_categories: {},
        engine_names: {
            searchindex: '搜索索引',
            pagelist: '页面列表',
            combined: '合并搜索',
            subcat: '子分类',
            parentcat: '父分类'
        },
        capitalizePageNames: true,
        upload_disabled: false,
        blacklist: null,
        bg_changed: '#F8CCB0',
        no_autocommit: false,
        del_needs_diff: false,
        suggest_delay: 100,
        editbox_width: 40,
        suggestions: 'combined',
        fixed_search: false,
        use_up_down: true,
        list_size: 5,
        single_minor: true,
        dont_add_to_watchlist: false,
        shortcuts: null,
        addShortcuts: function(map) {
            if (!map) return;
            window.HotCat.shortcuts = window.HotCat.shortcuts || {};
            for (var k in map) {
                if (!map.hasOwnProperty(k) || typeof k != 'string') continue;
                var v = map[k];
                if (typeof v != 'string') continue;
                k = k.replace(/^\s+|\s+$/g, "");
                v = v.replace(/^\s+|\s+$/g, "");
                if (k.length === 0 || v.length === 0) continue;
                window.HotCat.shortcuts[k] = v;
            }
        }
    };
    var ua = navigator.userAgent.toLowerCase();
    var is_ie6 = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(ua) !== null && parseFloat(RegExp.$1) <= 6.0;
    var is_ie_lt8 = /msie ([0-9]{1,}[\.0-9]{0,})/.exec(ua) !== null && parseFloat(RegExp.$1) < 8.0;
    var is_webkit = /applewebkit\/\d+/.test(ua) && ua.indexOf('spoofer') < 0;
    var getJSON = (function() {
        function getRequest() {
            var request = null;
            try {
                request = new window.XMLHttpRequest();
            } catch (anything) {
                if (window.ActiveXObject) {
                    try {
                        request = new window.ActiveXObject('Microsoft.XMLHTTP');
                    } catch (any) {}
                }
            }
            return request;
        }
        return function(settings) {
            var req = getRequest();
            if (!req && settings && settings.error) settings.error(req);
            if (!req || !settings || !settings.uri) return req;
            var uri = armorUri(settings.uri);
            var args = settings.data || null;
            var method;
            if (args && uri.length + args.length + 1 > 2000) {
                method = 'POST';
                req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            } else {
                method = 'GET';
                if (args) uri += '?' + args;
                args = null;
            }
            req.open(method, uri, true);
            req.onreadystatechange = function() {
                if (req.readyState != 4) return;
                if (req.status != 200 || !req.responseText || !(/^\s*[\{\[]/.test(req.responseText))) {
                    if (settings.error) settings.error(req);
                } else {
                    if (settings.success) settings.success(eval('(' + req.responseText + ')'));
                }
            };
            req.setRequestHeader('Pragma', 'cache=yes');
            req.setRequestHeader('Cache-Control', 'no-transform');
            req.send(args);
            return req;
        };
    })();
    function armorUri(uri) {
        if (uri.length >= 2 && uri.substring(0, 2) == '//') return document.location.protocol + uri;
        return uri;
    }
    function LoadTrigger(needed) {
        this.queue = [];
        this.toLoad = needed;
    }
    LoadTrigger.prototype = {
        register: function(callback) {
            if (this.toLoad <= 0) {
                callback();
            } else {
                this.queue[this.queue.length] = callback;
            }
        },
        loaded: function() {
            if (this.toLoad > 0) {
                this.toLoad--;
                if (this.toLoad === 0) {
                    for (var i = 0; i < this.queue.length; i++) this.queue[i]();
                    this.queue = [];
                }
            }
        }
    };
    var setupCompleted = new LoadTrigger(1);
    HotCat.runWhenReady = function(callback) {
        setupCompleted.register(callback);
    };
    var loadTrigger = new LoadTrigger(2);
    function load(uri) {
        var head = document.getElementsByTagName('head')[0];
        var s = document.createElement('script');
        s.setAttribute('src', armorUri(uri));
        s.setAttribute('type', 'text/javascript');
        var done = false;
        function afterLoad() {
            if (done) return;
            done = true;
            s.onload = s.onreadystatechange = s.onerror = null;
            if (head && s.parentNode) head.removeChild(s);
            loadTrigger.loaded();
        }
        s.onload = s.onreadystatechange = function() {
            if (done) return;
            if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') {
                afterLoad();
            }
        };
        s.onerror = afterLoad;
        head.insertBefore(s, head.firstChild);
    }
    function loadJS(page) {
        load(conf.wgServer + conf.wgScript + '?title=' + encodeURIComponent(page) + '&action=raw&ctype=text/javascript');
    }
    function loadURI(href) {
        var url = href;
        if (url.substring(0, 2) == '//') {
            url = window.location.protocol + url;
        } else if (url.substring(0, 1) == '/') {
            url = conf.wgServer + url;
        }
        load(url);
    }
    loadJS('MediaWiki:Gadget-HotCat.js/local_defaults');
    loadTrigger.loaded(); //由于i18n已内置,此处直接执行函数
    var wikiTextBlank = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000]+';
    var wikiTextBlankRE = new RegExp(wikiTextBlank, 'g');
    var wikiTextBlankOrBidi = '[\\t _\\xA0\\u1680\\u180E\\u2000-\\u200B\\u200E\\u200F\\u2028-\\u202F\\u205F\\u3000]*';
    var formattedNamespaces = conf.wgFormattedNamespaces;
    var namespaceIds = conf.wgNamespaceIds;
    function autoLocalize(namespaceNumber, fallback) {
    	if (!formattedNamespaces) return;
        function create_regexp_str(name) {
            if (!name || name.length === 0) return "";
            var regex_name = "";
            for (var i = 0; i < name.length; i++) {
                var initial = name.substr(i, 1);
                var ll = initial.toLowerCase();
                var ul = initial.toUpperCase();
                if (ll == ul) {
                    regex_name += initial;
                } else {
                    regex_name += '[' + ll + ul + ']';
                }
            }
            return regex_name.replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1').replace(wikiTextBlankRE, wikiTextBlank);
        }
        fallback = fallback.toLowerCase();
        var canonical = formattedNamespaces["" + namespaceNumber].toLowerCase();
        var regexp = create_regexp_str(canonical);
        if (fallback && canonical != fallback) regexp += '|' + create_regexp_str(fallback);
        if (namespaceIds) {
            for (var cat_name in namespaceIds) {
                if (typeof cat_name == 'string' && cat_name.toLowerCase() != canonical && cat_name.toLowerCase() != fallback && namespaceIds[cat_name] == namespaceNumber) {
                    regexp += '|' + create_regexp_str(cat_name);
                }
            }
        }
        return regexp;
    }
    if (formattedNamespaces['14']) {
        HotCat.category_canonical = formattedNamespaces['14'];
        HotCat.category_regexp = autoLocalize(14, 'category');
    }
    if (formattedNamespaces['10']) {
        HotCat.template_regexp = autoLocalize(10, 'template');
    }
    function bind(func, target) {
        var f = func,
            tgt = target;
        return function() {
            return f.apply(tgt, arguments);
        };
    }
    function make(arg, literal) {
        if (!arg) return null;
        return literal ? document.createTextNode(arg) : document.createElement(arg);
    }
    function param(name, uri) {
        if (typeof uri == 'undefined' || uri === null) uri = document.location.href;
        var re = new RegExp('[&?]' + name + '=([^&#]*)');
        var m = re.exec(uri);
        if (m && m.length > 1) return decodeURIComponent(m[1]);
        return null;
    }
    function title(href) {
        if (!href) return null;
        var script = conf.wgScript + '?';
        if (href.indexOf(script) === 0 || href.indexOf(conf.wgServer + script) === 0 || conf.wgServer.substring(0, 2) == '//' && href.indexOf(document.location.protocol + conf.wgServer + script) === 0) {
            return param('title', href);
        } else {
            var prefix = conf.wgArticlePath.replace('$1', "");
            if (href.indexOf(prefix) !== 0) prefix = conf.wgServer + prefix;
            if (href.indexOf(prefix) !== 0 && prefix.substring(0, 2) == '//') prefix = document.location.protocol + prefix;
            if (href.indexOf(prefix) === 0)
                return decodeURIComponent(href.substring(prefix.length));
        }
        return null;
    }
    function hasClass(elem, name) {
        return (' ' + elem.className + ' ').indexOf(' ' + name + ' ') >= 0;
    }
    function capitalize(str) {
        if (!str || str.length === 0) return str;
        return str.substr(0, 1).toUpperCase() + str.substr(1);
    }
    function wikiPagePath(pageName) {
        return conf.wgArticlePath.replace('$1', encodeURIComponent(pageName).replace(/%3A/g, ':').replace(/%2F/g, '/'));
    }
    function escapeRE(str) {
        return str.replace(/([\\\^\$\.\?\*\+\(\)\[\]])/g, '\\$1');
    }
    function substituteFactory(options) {
        options = options || {};
        var lead = options.indicator || '$';
        var indicator = escapeRE(lead);
        var lbrace = escapeRE(options.lbrace || '{');
        var rbrace = escapeRE(options.rbrace || '}');
        var re;
        re = new RegExp('(?:' + indicator + '(' + indicator + '))|' + '(?:' + indicator + '(\\d+))|' + '(?:' + indicator + '(?:' + lbrace + '([^' + lbrace + rbrace + ']+)' + rbrace + '))|' + '(?:' + indicator + '(?!(?:[' + indicator + lbrace + ']|\\d))(\\S+?)\\b)', 'g');
        return function(str, map) {
            if (!map) return str;
            return str.replace(re, function(match, prefix, idx, key, alpha) {
                if (prefix == lead) return lead;
                var k = alpha || key || idx;
                var replacement = typeof map[k] === 'function' ? map[k](match, k) : map[k];
                return typeof replacement === 'string' ? replacement : (replacement || match);
            });
        };
    }
    var substitute = substituteFactory();
    var replaceShortcuts = (function() {
        var replaceHash = substituteFactory({
            indicator: '#',
            lbrace: '[',
            rbrace: ']'
        });
        return function(str, map) {
            var s = replaceHash(str, map);
            return HotCat.capitalizePageNames ? capitalize(s) : s;
        };
    })();
    var findCatsRE = new RegExp('\\[\\[' + wikiTextBlankOrBidi + '(?:' + HotCat.category_regexp + ')' + wikiTextBlankOrBidi + ':[^\\]]+\\]\\]', 'g');
    function replaceByBlanks(match) {
        return match.replace(/(\s|\S)/g, ' ');
    }
    function find_category(wikitext, category, once) {
        var cat_regex = null;
        if (HotCat.template_categories[category]) {
            cat_regex = new RegExp('\\{\\{' + wikiTextBlankOrBidi + '(' + HotCat.template_regexp + '(?=' + wikiTextBlankOrBidi + ':))?' + wikiTextBlankOrBidi + '(?:' + HotCat.template_categories[category] + ')' + wikiTextBlankOrBidi + '(\\|.*?)?\\}\\}', 'g');
        } else {
            var cat_name = escapeRE(category);
            var initial = cat_name.substr(0, 1);
            cat_regex = new RegExp('\\[\\[' + wikiTextBlankOrBidi + '(' + HotCat.category_regexp + ')' + wikiTextBlankOrBidi + ':' + wikiTextBlankOrBidi + (initial == '\\' || !HotCat.capitalizePageNames ? initial : '[' + initial.toUpperCase() + initial.toLowerCase() + ']') + cat_name.substring(1).replace(wikiTextBlankRE, wikiTextBlank) + wikiTextBlankOrBidi + '(\\|.*?)?\\]\\]', 'g');
        }
        if (once) return cat_regex.exec(wikitext);
        var copiedtext = wikitext.replace(/<\!--(\s|\S)*?--\>/g, replaceByBlanks).replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, replaceByBlanks);
        var result = [];
        var curr_match = null;
        while ((curr_match = cat_regex.exec(copiedtext)) !== null) {
            result.push({
                match: curr_match
            });
        }
        result.re = cat_regex;
        return result;
    }
    var interlanguageRE = null;
    function change_category(wikitext, toRemove, toAdd, key, is_hidden) {
        function find_insertionpoint(wikitext) {
            var copiedtext = wikitext.replace(/<\!--(\s|\S)*?--\>/g, replaceByBlanks).replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, replaceByBlanks);
            var index = -1;
            findCatsRE.lastIndex = 0;
            while (findCatsRE.exec(copiedtext) !== null) index = findCatsRE.lastIndex;
            if (index < 0) {
                var match = null;
                if (!interlanguageRE) {
                    match = /((^|\n\r?)(\[\[\s*(([a-z]{2,3}(-[a-z]+)*)|simple|tokipona)\s*:[^\]]+\]\]\s*))+$/.exec(copiedtext);
                } else {
                    match = interlanguageRE.exec(copiedtext);
                }
                if (match) index = match.index;
                return {
                    idx: index,
                    onCat: false
                };
            }
            return {
                idx: index,
                onCat: index >= 0
            };
        }
        var summary = [];
        var nameSpace = HotCat.category_canonical;
        var cat_point = -1;
        if (key) key = '|' + key;
        var keyChange = (toRemove && toAdd && toRemove == toAdd && toAdd.length > 0);
        var matches;
        if (toRemove && toRemove.length > 0) {
            matches = find_category(wikitext, toRemove);
            if (!matches || matches.length === 0) {
                return {
                    text: wikitext,
                    'summary': summary,
                    error: HotCat.messages.cat_notFound.replace(/\$1/g, toRemove)
                };
            } else {
                var before = wikitext.substring(0, matches[0].match.index);
                var after = wikitext.substring(matches[0].match.index + matches[0].match[0].length);
                if (matches.length > 1) {
                    matches.re.lastIndex = 0;
                    after = after.replace(matches.re, "");
                }
                if (toAdd) {
                    nameSpace = matches[0].match[1] || nameSpace;
                    if (key === null) key = matches[0].match[2];
                }
                var i = before.length - 1;
                while (i >= 0 && before.charAt(i) != '\n' && before.substr(i, 1).search(/\s/) >= 0) i--;
                var j = 0;
                while (j < after.length && after.charAt(j) != '\n' && after.substr(j, 1).search(/\s/) >= 0)
                    j++;
                if (i >= 0 && before.charAt(i) == '\n' && (after.length === 0 || j < after.length && after.charAt(j) == '\n'))
                    i--;
                if (i >= 0) before = before.substring(0, i + 1);
                else before = "";
                if (j < after.length) after = after.substring(j);
                else after = "";
                if (before.length > 0 && before.substring(before.length - 1).search(/\S/) >= 0 && after.length > 0 && after.substr(0, 1).search(/\S/) >= 0)
                    before += ' ';
                cat_point = before.length;
                if (cat_point === 0 && after.length > 0 && after.substr(0, 1) == '\n') {
                    after = after.substr(1);
                }
                wikitext = before + after;
                if (!keyChange) {
                    if (HotCat.template_categories[toRemove]) {
                        summary.push(HotCat.messages.template_removed.replace(/\$1/g, toRemove));
                    } else {
                        summary.push(HotCat.messages.cat_removed.replace(/\$1/g, toRemove));
                    }
                }
            }
        }
        if (toAdd && toAdd.length > 0) {
            matches = find_category(wikitext, toAdd);
            if (matches && matches.length > 0) {
                return {
                    text: wikitext,
                    'summary': summary,
                    error: HotCat.messages.cat_exists.replace(/\$1/g, toAdd)
                };
            } else {
                var onCat = false;
                if (cat_point < 0) {
                    var point = find_insertionpoint(wikitext);
                    cat_point = point.idx;
                    onCat = point.onCat;
                } else {
                    onCat = true;
                }
                var newcatstring = '[[' + nameSpace + ':' + toAdd + (key || "") + ']]';
                if (cat_point >= 0) {
                    var suffix = wikitext.substring(cat_point);
                    wikitext = wikitext.substring(0, cat_point) + (cat_point > 0 ? '\n' : "") + newcatstring + (!onCat ? '\n' : "");
                    if (suffix.length > 0 && suffix.substr(0, 1) != '\n') {
                        wikitext += '\n' + suffix;
                    } else {
                        wikitext += suffix;
                    }
                } else {
                    if (wikitext.length > 0 && wikitext.substr(wikitext.length - 1, 1) != '\n')
                        wikitext += '\n';
                    wikitext += (wikitext.length > 0 ? '\n' : "") + newcatstring;
                }
                if (keyChange) {
                    var k = key || "";
                    if (k.length > 0) k = k.substr(1);
                    summary.push(substitute(HotCat.messages.cat_keychange, [null, toAdd, k]));
                } else {
                    summary.push(HotCat.messages.cat_added.replace(/\$1/g, toAdd));
                }
                if (HotCat.uncat_regexp && !is_hidden) {
                    var txt = wikitext.replace(HotCat.uncat_regexp, "");
                    if (txt.length != wikitext.length) {
                        wikitext = txt;
                        summary.push(HotCat.messages.uncat_removed);
                    }
                }
            }
        }
        return {
            text: wikitext,
            'summary': summary,
            error: null
        };
    }
    function evtKeys(e) {
        e = e || window.event || window.Event;
        var code = 0;
        if (typeof e.ctrlKey != 'undefined') {
            if (e.ctrlKey || e.metaKey) code |= 1;
            if (e.shiftKey) code |= 2;
        } else if (typeof e.modifiers != 'undefined') {
            if (e.modifiers & (Event.CONTROL_MASK | Event.META_MASK)) code |= 1;
            if (e.modifiers & Event.SHIFT_MASK) code |= 2;
        }
        return code;
    }
    function evtKill(e) {
        e = e || window.event || window.Event;
        if (typeof e.preventDefault != 'undefined') {
            e.preventDefault();
            e.stopPropagation();
        } else
            e.cancelBubble = true;
        return false;
    }
    function addEvent(node, evt, f, capture) {
        if (window.jQuery && (!capture || !node.addEventListener)) window.jQuery(node).bind(evt, f);
        else if (node.addEventListener) node.addEventListener(evt, f, capture);
        else if (node.attachEvent) node.attachEvent('on' + evt, f);
        else node['on' + evt] = f;
    }
    var catLine = null;
    var onUpload = false;
    var editors = [];
    var commitButton = null;
    var commitForm = null;
    var multiSpan = null;
    var pageText = null;
    var pageTime = null;
    var pageWatched = false;
    var watchCreate = false;
    var watchEdit = false;
    var minorEdits = false;
    var editToken = null;
    var is_rtl = false;
    var serverTime = null;
    var lastRevId = null;
    var pageTextRevId = null;
    var conflictingUser = null;
    var newDOM = false;
    function setMultiInput() {
        if (commitButton || onUpload) return;
        commitButton = make('input');
        commitButton.type = 'button';
        commitButton.value = HotCat.messages.commit;
        commitButton.onclick = multiSubmit;
        if (multiSpan) {
            multiSpan.parentNode.replaceChild(commitButton, multiSpan);
        } else {
            catLine.appendChild(commitButton);
        }
    }
    function checkMultiInput() {
        if (!commitButton) return;
        var has_changes = false;
        for (var i = 0; i < editors.length; i++) {
            if (editors[i].state != CategoryEditor.UNCHANGED) {
                has_changes = true;
                break;
            }
        }
        commitButton.disabled = !has_changes;
    }
    function currentTimestamp() {
        var now = new Date();
        var ts = "" + now.getUTCFullYear();
        function two(s) {
            return s.substr(s.length - 2);
        }
        ts = ts + two('0' + (now.getUTCMonth() + 1)) + two('0' + now.getUTCDate()) + two('00' + now.getUTCHours()) + two('00' + now.getUTCMinutes()) + two('00' + now.getUTCSeconds());
        return ts;
    }
    var saveInProgress = false;
    function initiateEdit(doEdit, failure) {
        if (saveInProgress) return;
        saveInProgress = true;
        var oldButtonState;
        if (commitButton) {
            oldButtonState = commitButton.disabled;
            commitButton.disabled = true;
        }
        function fail() {
            saveInProgress = false;
            if (commitButton) commitButton.disabled = oldButtonState;
            failure.apply(this, arguments);
        }
        getJSON({
            uri: conf.wgServer + conf.wgScriptPath + '/api.php',
            data: 'format=json&action=query&rawcontinue=&titles=' + encodeURIComponent(conf.wgPageName) + '&prop=info%7Crevisions%7Clanglinks&inprop=watched&intoken=edit&rvprop=content%7Ctimestamp%7Cids%7Cuser&lllimit=500' + '&rvlimit=2&rvdir=newer&rvstartid=' + conf.wgCurRevisionId + '&meta=siteinfo%7Cuserinfo&uiprop=options',
            success: function(json) {
                setPage(json);
                doEdit(fail);
            },
            error: function(req) {
                fail(req.status + ' ' + req.statusText);
            }
        });
    }
    function multiChangeMsg(count) {
        var msg = HotCat.messages.multi_change;
        if (typeof msg != 'string' && msg.length) {
            if (window.mw && mw.language && mw.language.convertPlural) {
                msg = mw.language.convertPlural(count, msg);
            } else {
                msg = msg[msg.length - 1];
            }
        }
        return substitute(msg, [null, "" + count]);
    }
    function performChanges(failure, singleEditor) {
        if (pageText === null) {
            failure(HotCat.messages.multi_error);
            return;
        }
        if (HotCat.messages.cat_keychange.indexOf('$2') < 0) HotCat.messages.cat_keychange += '"$2"';
        if (!HotCat.messages.short_catchange) HotCat.messages.short_catchange = '[[' + HotCat.category_canonical + ':$1]]';
        var action;
        var editingOldVersion = lastRevId !== null && lastRevId != conf.wgCurRevisionId || pageTextRevId !== null && pageTextRevId != conf.wgCurRevisionId;
        var selfEditConflict = editingOldVersion && conflictingUser && conflictingUser == conf.wgUserName;
        if (singleEditor && !singleEditor.noCommit && !HotCat.no_autocommit && editToken && !selfEditConflict) {
            commitForm.wpEditToken.value = editToken;
            action = commitForm.wpDiff;
            if (action) action.name = action.value = 'wpSave';
        } else {
            action = commitForm.wpSave;
            if (action) action.name = action.value = 'wpDiff';
        }
        var result = {
            text: pageText
        };
        var changed = [],
            added = [],
            deleted = [],
            changes = 0;
        var toEdit = !!singleEditor ? [singleEditor] : editors;
        var error = null;
        var i;
        for (i = 0; i < toEdit.length; i++) {
            if (toEdit[i].state == CategoryEditor.CHANGED) {
                result = change_category(result.text, toEdit[i].originalCategory, toEdit[i].currentCategory, toEdit[i].currentKey, toEdit[i].currentHidden);
                if (!result.error) {
                    changes++;
                    if (!toEdit[i].originalCategory || toEdit[i].originalCategory.length === 0) {
                        added.push(toEdit[i].currentCategory);
                    } else {
                        changed.push({
                            from: toEdit[i].originalCategory,
                            to: toEdit[i].currentCategory
                        });
                    }
                } else if (error === null) {
                    error = result.error;
                }
            } else if (toEdit[i].state == CategoryEditor.DELETED && toEdit[i].originalCategory && toEdit[i].originalCategory.length > 0) {
                result = change_category(result.text, toEdit[i].originalCategory, null, null, false);
                if (!result.error) {
                    changes++;
                    deleted.push(toEdit[i].originalCategory);
                } else if (error === null) {
                    error = result.error;
                }
            }
        }
        if (error !== null) {
            action = commitForm.wpSave;
            if (action) action.name = action.value = 'wpDiff';
        }
        commitForm.wpAutoSummary.value = 'd41d8cd98f00b204e9800998ecf8427e';
        commitForm.wpMinoredit.checked = minorEdits;
        commitForm.wpWatchthis.checked = conf.wgArticleId === 0 && watchCreate || watchEdit || pageWatched;
        if (conf.wgArticleId > 0 || !!singleEditor) {
            if (changes == 1) {
                if (result.summary && result.summary.length > 0)
                    commitForm.wpSummary.value = HotCat.messages.prefix + result.summary.join(HotCat.messages.separator) + HotCat.messages.using;
                commitForm.wpMinoredit.checked = HotCat.single_minor || minorEdits;
            } else if (changes > 1) {
                var summary = [];
                var shortSummary = [];
                for (i = 0; i < deleted.length; i++) {
                    summary.push('-' + substitute(HotCat.messages.short_catchange, [null, deleted[i]]));
                }
                if (deleted.length == 1)
                    shortSummary.push('-' + substitute(HotCat.messages.short_catchange, [null, deleted[0]]));
                else if (deleted.length > 1)
                    shortSummary.push('- ' + multiChangeMsg(deleted.length));
                for (i = 0; i < added.length; i++) {
                    summary.push('+' + substitute(HotCat.messages.short_catchange, [null, added[i]]));
                }
                if (added.length == 1)
                    shortSummary.push('+' + substitute(HotCat.messages.short_catchange, [null, added[0]]));
                else if (added.length > 1)
                    shortSummary.push('+ ' + multiChangeMsg(added.length));
                var arrow = is_rtl ? '\u2190' : '\u2192';
                for (i = 0; i < changed.length; i++) {
                    if (changed[i].from != changed[i].to) {
                        summary.push('±' + substitute(HotCat.messages.short_catchange, [null, changed[i].from]) + arrow + substitute(HotCat.messages.short_catchange, [null, changed[i].to]));
                    } else {
                        summary.push('±' + substitute(HotCat.messages.short_catchange, [null, changed[i].from]));
                    }
                }
                if (changed.length == 1) {
                    if (changed[0].from != changed[0].to) {
                        shortSummary.push('±' + substitute(HotCat.messages.short_catchange, [null, changed[0].from]) + arrow + substitute(HotCat.messages.short_catchange, [null, changed[0].to]));
                    } else {
                        shortSummary.push('±' + substitute(HotCat.messages.short_catchange, [null, changed[0].from]));
                    }
                } else if (changed.length > 1) {
                    shortSummary.push('± ' + multiChangeMsg(changed.length));
                }
                if (summary.length > 0) {
                    summary = summary.join(HotCat.messages.separator);
                    if (summary.length > 200 - HotCat.messages.prefix.length - HotCat.messages.using.length) {
                        summary = shortSummary.join(HotCat.messages.separator);
                    }
                    commitForm.wpSummary.value = HotCat.messages.prefix + summary + HotCat.messages.using;
                }
            }
        }
        commitForm.wpTextbox1.value = result.text;
        commitForm.wpStarttime.value = serverTime || currentTimestamp();
        commitForm.wpEdittime.value = pageTime || commitForm.wpStarttime.value;
        if (selfEditConflict) commitForm.oldid.value = "" + (pageTextRevId || conf.wgCurRevisionId);
        commitForm.hcCommit.click();
    }
    function resolveMulti(toResolve, callback) {
        var i;
        for (i = 0; i < toResolve.length; i++) {
            toResolve[i].dab = null;
            toResolve[i].dabInput = toResolve[i].lastInput;
        }
        if (noSuggestions) {
            callback(toResolve);
            return;
        }
        var args = 'action=query&prop=info%7Clinks%7Ccategories%7Ccategoryinfo&plnamespace=14' + '&pllimit=' + (toResolve.length * 10) + '&cllimit=' + (toResolve.length * 10) + '&format=json&titles=';
        for (i = 0; i < toResolve.length; i++) {
            var v = toResolve[i].dabInput;
            v = replaceShortcuts(v, HotCat.shortcuts);
            toResolve[i].dabInputCleaned = v;
            args += encodeURIComponent('Category:' + v);
            if (i + 1 < toResolve.length) args += '%7C';
        }
        getJSON({
            uri: conf.wgServer + conf.wgScriptPath + '/api.php',
            data: args,
            success: function(json) {
                resolveRedirects(toResolve, json);
                callback(toResolve);
            },
            error: function(req) {
                if (!req) noSuggestions = true;
                callback(toResolve);
            }
        });
    }
    function resolveOne(page, toResolve) {
        var cats = page.categories;
        var lks = page.links;
        var is_dab = false;
        var is_redir = typeof page.redirect == 'string';
        var is_hidden = page.categoryinfo && typeof page.categoryinfo.hidden == 'string';
        var is_missing = typeof page.missing == 'string';
        var i;
        for (i = 0; i < toResolve.length; i++) {
            if (toResolve.length > 1 && toResolve[i].dabInputCleaned != page.title.substring(page.title.indexOf(':') + 1)) continue;
            toResolve[i].currentHidden = is_hidden;
            toResolve[i].inputExists = !is_missing;
            toResolve[i].icon.src = armorUri(is_missing ? HotCat.existsNo : HotCat.existsYes);
        }
        if (is_missing) return;
        if (!is_redir && cats && (HotCat.disambig_category || HotCat.redir_category)) {
            for (var c = 0; c < cats.length; c++) {
                var cat = cats[c]['title'];
                if (cat) {
                    cat = cat.substring(cat.indexOf(':') + 1).replace(/_/g, ' ');
                    if (cat == HotCat.disambig_category) {
                        is_dab = true;
                        break;
                    } else if (cat == HotCat.redir_category) {
                        is_redir = true;
                        break;
                    }
                }
            }
        }
        if (!is_redir && !is_dab) return;
        if (!lks || lks.length === 0) return;
        var titles = [];
        for (i = 0; i < lks.length; i++) {
            if (lks[i]['ns'] == 14 && lks[i]['title'] && lks[i]['title'].length > 0) {
                var match = lks[i]['title'];
                match = match.substring(match.indexOf(':') + 1);
                if (!HotCat.blacklist || !HotCat.blacklist.test(match)) {
                    titles.push(match);
                }
            }
        }
        if (titles.length === 0) {
            return;
        }
        for (i = 0; i < toResolve.length; i++) {
            if (toResolve.length > 1 && toResolve[i].dabInputCleaned != page.title.substring(page.title.indexOf(':') + 1)) continue;
            toResolve[i].inputExists = true;
            toResolve[i].icon.src = armorUri(HotCat.existsYes);
            if (titles.length > 1) {
                toResolve[i].dab = titles;
            } else {
                toResolve[i].text.value = titles[0] + (toResolve[i].currentKey !== null ? '|' + toResolve[i].currentKey : "");
            }
        }
    }
    function resolveRedirects(toResolve, params) {
        if (!params || !params.query || !params.query.pages) return;
        for (var p in params.query.pages) resolveOne(params.query.pages[p], toResolve);
    }
    function multiSubmit() {
        var toResolve = [];
        for (var i = 0; i < editors.length; i++) {
            if (editors[i].state == CategoryEditor.CHANGE_PENDING || editors[i].state == CategoryEditor.OPEN)
                toResolve.push(editors[i]);
        }
        if (toResolve.length === 0) {
            initiateEdit(function(failure) {
                performChanges(failure);
            }, function(msg) {
                alert(msg);
            });
            return;
        }
        resolveMulti(toResolve, function(resolved) {
            var firstDab = null;
            var dontChange = false;
            for (var i = 0; i < resolved.length; i++) {
                if (resolved[i].lastInput != resolved[i].dabInput) {
                    dontChange = true;
                } else {
                    if (resolved[i].dab) {
                        if (!firstDab) firstDab = resolved[i];
                    } else {
                        if (resolved[i].acceptCheck(true)) resolved[i].commit();
                    }
                }
            }
            if (firstDab) {
                showDab(firstDab);
            } else if (!dontChange) {
                initiateEdit(function(failure) {
                    performChanges(failure);
                }, function(msg) {
                    alert(msg);
                });
            }
        });
    }
    var cat_prefix = null;
    var noSuggestions = false;
    var suggestionEngines = {
        opensearch: {
            uri: '/api.php?format=json&action=opensearch&namespace=14&limit=30&search=Category:$1',
            handler: function(queryResult, queryKey) {
                if (queryResult && queryResult.length >= 2) {
                    var key = queryResult[0].substring(queryResult[0].indexOf(':') + 1);
                    var titles = queryResult[1];
                    var exists = false;
                    if (!cat_prefix) cat_prefix = new RegExp('^(' + HotCat.category_regexp + ':)');
                    for (var i = 0; i < titles.length; i++) {
                        cat_prefix.lastIndex = 0;
                        var m = cat_prefix.exec(titles[i]);
                        if (m && m.length > 1) {
                            titles[i] = titles[i].substring(titles[i].indexOf(':') + 1);
                            if (key == titles[i]) exists = true;
                        } else {
                            titles.splice(i, 1);
                            i--;
                        }
                    }
                    titles.exists = exists;
                    if (queryKey != key) titles.normalized = key;
                    return titles;
                }
                return null;
            }
        },
        internalsearch: {
            uri: '/api.php?format=json&action=query&list=allpages&apnamespace=14&aplimit=30&apfrom=$1&apprefix=$1',
            handler: function(queryResult, queryKey) {
                if (queryResult && queryResult.query && queryResult.query.allpages) {
                    var titles = queryResult.query.allpages;
                    for (var i = 0; i < titles.length; i++) {
                        titles[i] = titles[i].title.substring(titles[i].title.indexOf(':') + 1);
                    }
                    return titles;
                }
                return null;
            }
        },
        exists: {
            uri: '/api.php?format=json&action=query&prop=info&titles=Category:$1',
            handler: function(queryResult, queryKey) {
                if (queryResult && queryResult.query && queryResult.query.pages && !queryResult.query.pages[-1]) {
                    for (var p in queryResult.query.pages) {
                        var title = queryResult.query.pages[p].title;
                        title = title.substring(title.indexOf(':') + 1);
                        var titles = [title];
                        titles.exists = true;
                        if (queryKey != title) titles.normalized = title;
                        return titles;
                    }
                }
                return null;
            }
        },
        subcategories: {
            uri: '/api.php?format=json&action=query&list=categorymembers' + (function(version) {
                var m = version.match(/^(\d+)\.(\d+)/);
                var major = 0,
                    minor = 0;
                if (m && m.length > 1) {
                    major = parseInt(m[1], 10);
                    minor = (m.length > 2 ? parseInt(m[2], 10) : 0);
                }
                if (major > 1 || major === 1 && minor > 17) return '&cmtype=subcat';
                return '&cmnamespace=14';
            })(conf.wgVersion) + '&cmlimit=max&cmtitle=Category:$1',
            handler: function(queryResult, queryKey) {
                if (queryResult && queryResult.query && queryResult.query.categorymembers) {
                    var titles = queryResult.query.categorymembers;
                    for (var i = 0; i < titles.length; i++) {
                        titles[i] = titles[i].title.substring(titles[i].title.indexOf(':') + 1);
                    }
                    return titles;
                }
                return null;
            }
        },
        parentcategories: {
            uri: '/api.php?format=json&action=query&prop=categories&titles=Category:$1&cllimit=max',
            handler: function(queryResult, queryKey) {
                if (queryResult && queryResult.query && queryResult.query.pages) {
                    for (var p in queryResult.query.pages) {
                        if (queryResult.query.pages[p].categories) {
                            var titles = queryResult.query.pages[p].categories;
                            for (var i = 0; i < titles.length; i++) {
                                titles[i] = titles[i].title.substring(titles[i].title.indexOf(':') + 1);
                            }
                            return titles;
                        }
                    }
                }
                return null;
            }
        }
    };
    var suggestionConfigs = {
        searchindex: {
            name: 'Search index',
            engines: ['opensearch'],
            cache: {},
            show: true,
            temp: false,
            noCompletion: false
        },
        pagelist: {
            name: 'Page list',
            engines: ['internalsearch', 'exists'],
            cache: {},
            show: true,
            temp: false,
            noCompletion: false
        },
        combined: {
            name: 'Combined search',
            engines: ['opensearch', 'internalsearch'],
            cache: {},
            show: true,
            temp: false,
            noCompletion: false
        },
        subcat: {
            name: 'Subcategories',
            engines: ['subcategories'],
            cache: {},
            show: true,
            temp: true,
            noCompletion: true
        },
        parentcat: {
            name: 'Parent categories',
            engines: ['parentcategories'],
            cache: {},
            show: true,
            temp: true,
            noCompletion: true
        }
    };
    function CategoryEditor() {
        this.initialize.apply(this, arguments);
    }
    CategoryEditor.UNCHANGED = 0;
    CategoryEditor.OPEN = 1;
    CategoryEditor.CHANGE_PENDING = 2;
    CategoryEditor.CHANGED = 3;
    CategoryEditor.DELETED = 4;
    var dummyElement = make('\xa0', true);
    function forceRedraw() {
        if (!is_ie6) return;
        if (dummyElement.parentNode) {
            document.body.removeChild(dummyElement);
        } else {
            document.body.appendChild(dummyElement);
        }
    }
    var BS = 8,
        TAB = 9,
        RET = 13,
        ESC = 27,
        SPACE = 32,
        PGUP = 33,
        PGDOWN = 34,
        UP = 38,
        DOWN = 40,
        DEL = 46,
        IME = 229;
    function makeActive(which) {
        if (which.is_active) return;
        for (var i = 0; i < editors.length; i++) {
            if (editors[i] !== which) editors[i].inactivate();
        }
        which.is_active = true;
        if (which.dab) {
            showDab(which);
        } else {
            var expectedInput = which.lastRealInput || which.lastInput || "";
            var actualValue = which.text.value || "";
            if (expectedInput.length === 0 && actualValue.length > 0 || expectedInput.length > 0 && actualValue.indexOf(expectedInput) !== 0) {
                which.showsList = false;
                var v = actualValue.split('|');
                which.lastRealInput = which.lastInput = v[0];
                if (v.length > 1) which.currentKey = v[1];
                if (which.lastSelection) which.lastSelection = {
                    start: v[0].length,
                    end: v[0].length
                };
            }
            if (which.showsList) which.displayList();
            if (which.lastSelection) {
                if (is_webkit) {
                    window.setTimeout(function() {
                        which.setSelection(which.lastSelection.start, which.lastSelection.end);
                    }, 1);
                } else {
                    which.setSelection(which.lastSelection.start, which.lastSelection.end);
                }
            }
        }
    }
    function showDab(which) {
        if (!which.is_active) {
            makeActive(which);
        } else {
            which.showSuggestions(which.dab, false, null, null);
            which.dab = null;
        }
    }
    CategoryEditor.prototype = {
        initialize: function(line, span, after, key, is_hidden) {
            if (!span) {
                this.isAddCategory = true;
                this.originalCategory = "";
                this.originalKey = null;
                this.originalExists = false;
                if (!newDOM) {
                    span = make('span');
                    span.className = 'noprint';
                    if (key) {
                        span.appendChild(make(' | ', true));
                        if (after) {
                            after.parentNode.insertBefore(span, after.nextSibling);
                            after = after.nextSibling;
                        } else {
                            line.appendChild(span);
                        }
                    } else if (line.firstChild) {
                        span.appendChild(make(' ', true));
                        line.appendChild(span);
                    }
                }
                this.linkSpan = make('span');
                this.linkSpan.className = 'noprint nopopups hotcatlink';
                var lk = make('a');
                lk.href = '#catlinks';
                lk.onclick = bind(this.open, this);
                lk.appendChild(make(HotCat.links.add, true));
                lk.title = HotCat.tooltips.add;
                this.linkSpan.appendChild(lk);
                span = make(newDOM ? 'li' : 'span');
                span.className = 'noprint';
                if (is_rtl) span.dir = 'rtl';
                span.appendChild(this.linkSpan);
                if (after)
                    after.parentNode.insertBefore(span, after.nextSibling);
                else
                    line.appendChild(span);
                this.normalLinks = null;
                this.undelLink = null;
                this.catLink = null;
            } else {
                if (is_rtl) span.dir = 'rtl';
                this.isAddCategory = false;
                this.catLink = span.firstChild;
                this.originalCategory = after;
                this.originalKey = (key && key.length > 1) ? key.substr(1) : null;
                this.originalExists = !hasClass(this.catLink, 'new');
                this.makeLinkSpan();
                if (!this.originalExists && this.upDownLinks) this.upDownLinks.style.display = 'none';
                span.appendChild(this.linkSpan);
            }
            this.originalHidden = is_hidden;
            this.line = line;
            this.engine = HotCat.suggestions;
            this.span = span;
            this.currentCategory = this.originalCategory;
            this.currentExists = this.originalExists;
            this.currentHidden = this.originalHidden;
            this.currentKey = this.originalKey;
            this.state = CategoryEditor.UNCHANGED;
            this.lastSavedState = CategoryEditor.UNCHANGED;
            this.lastSavedCategory = this.originalCategory;
            this.lastSavedKey = this.originalKey;
            this.lastSavedExists = this.originalExists;
            this.lastSavedHidden = this.originalHidden;
            if (this.catLink && this.currentKey) {
                this.catLink.title = this.currentKey;
            }
            editors[editors.length] = this;
        },
        makeLinkSpan: function() {
            this.normalLinks = make('span');
            var lk = null;
            if (this.originalCategory && this.originalCategory.length > 0) {
                lk = make('a');
                lk.href = '#catlinks';
                lk.onclick = bind(this.remove, this);
                lk.appendChild(make(HotCat.links.remove, true));
                lk.title = HotCat.tooltips.remove;
                this.normalLinks.appendChild(make(' ', true));
                this.normalLinks.appendChild(lk);
            }
            if (!HotCat.template_categories[this.originalCategory]) {
                lk = make('a');
                lk.href = '#catlinks';
                lk.onclick = bind(this.open, this);
                lk.appendChild(make(HotCat.links.change, true));
                lk.title = HotCat.tooltips.change;
                this.normalLinks.appendChild(make(' ', true));
                this.normalLinks.appendChild(lk);
                if (!noSuggestions && HotCat.use_up_down) {
                    this.upDownLinks = make('span');
                    lk = make('a');
                    lk.href = '#catlinks';
                    lk.onclick = bind(this.down, this);
                    lk.appendChild(make(HotCat.links.down, true));
                    lk.title = HotCat.tooltips.down;
                    this.upDownLinks.appendChild(make(' ', true));
                    this.upDownLinks.appendChild(lk);
                    lk = make('a');
                    lk.href = '#catlinks';
                    lk.onclick = bind(this.up, this);
                    lk.appendChild(make(HotCat.links.up, true));
                    lk.title = HotCat.tooltips.up;
                    this.upDownLinks.appendChild(make(' ', true));
                    this.upDownLinks.appendChild(lk);
                    this.normalLinks.appendChild(this.upDownLinks);
                }
            }
            this.linkSpan = make('span');
            this.linkSpan.className = 'noprint nopopups hotcatlink';
            this.linkSpan.appendChild(this.normalLinks);
            this.undelLink = make('span');
            this.undelLink.className = 'nopopups hotcatlink';
            this.undelLink.style.display = 'none';
            lk = make('a');
            lk.href = '#catlinks';
            lk.onclick = bind(this.restore, this);
            lk.appendChild(make(HotCat.links.restore, true));
            lk.title = HotCat.tooltips.restore;
            this.undelLink.appendChild(make(' ', true));
            this.undelLink.appendChild(lk);
            this.linkSpan.appendChild(this.undelLink);
        },
        invokeSuggestions: function(dont_autocomplete) {
            if (this.engine && suggestionConfigs[this.engine] && suggestionConfigs[this.engine].temp && !dont_autocomplete) {
                this.engine = HotCat.suggestions;
            }
            this.state = CategoryEditor.CHANGE_PENDING;
            var self = this;
            window.setTimeout(function() {
                self.textchange(dont_autocomplete);
            }, HotCat.suggest_delay);
        },
        makeForm: function() {
            var form = make('form');
            form.method = 'POST';
            form.onsubmit = bind(this.accept, this);
            this.form = form;
            var self = this;
            var text = make('input');
            text.type = 'text';
            text.size = HotCat.editbox_width;
            if (!noSuggestions) {
                text.onkeyup = function(evt) {
                    evt = evt || window.event || window.Event;
                    var key = evt.keyCode || 0;
                    if (self.ime && self.lastKey === IME && !self.usesComposition && (key === TAB || key === RET || key == ESC || key === SPACE)) self.ime = false;
                    if (self.ime) return true;
                    if (key === UP || key === DOWN || key === PGUP || key === PGDOWN) {
                        if (self.keyCount === 0) return self.processKey(evt);
                    } else {
                        if (key === ESC && self.lastKey !== IME) {
                            if (!self.resetKeySelection()) {
                                self.cancel();
                                return;
                            }
                        }
                        self.invokeSuggestions(key === BS || key === DEL || key === ESC);
                    }
                    return true;
                };
                text.onkeydown = function(evt) {
                    evt = evt || window.event || window.Event;
                    var key = evt.keyCode || 0;
                    self.lastKey = key;
                    self.keyCount = 0;
                    if (!self.ime && key === IME && !self.usesComposition) {
                        self.ime = true;
                    } else if (self.ime && key !== IME && !(key >= 16 && key <= 20 || key >= 91 && key <= 93 || key === 144)) {
                        self.ime = false;
                    }
                    if (self.ime) return true;
                    if (key === RET) return self.accept(evt);
                    return (key === ESC) ? evtKill(evt) : true;
                };
                text.onkeypress = function(evt) {
                    self.keyCount++;
                    return self.processKey(evt);
                };
                addEvent(text, 'focus', function() {
                    makeActive(self);
                });
                addEvent(text, (typeof text.onbeforedeactivate != 'undefined' && text.createTextRange) ? 'beforedeactivate' : 'blur', bind(this.saveView, this));
                try {
                    addEvent(text, 'compositionstart', function(evt) {
                        self.lastKey = IME;
                        self.usesComposition = true;
                        self.ime = true;
                    });
                    addEvent(text, 'compositionend', function(evt) {
                        self.lastKey = IME;
                        self.usesComposition = true;
                        self.ime = false;
                    });
                    addEvent(text, 'textInput', function(evt) {
                        self.ime = false;
                        self.invokeSuggestions(false);
                    });
                } catch (any) {}
                addEvent(text, 'blur', function(evt) {
                    self.usesComposition = false;
                    self.ime = false;
                });
            }
            this.text = text;
            this.icon = make('img');
            var list = null;
            if (!noSuggestions) {
                list = make('select');
                list.onclick = function(e) {
                    if (self.highlightSuggestion(0)) self.textchange(false, true);
                };
                list.ondblclick = function(e) {
                    if (self.highlightSuggestion(0)) self.accept(e);
                };
                list.onchange = function(e) {
                    self.highlightSuggestion(0);
                    self.text.focus();
                };
                list.onkeyup = function(evt) {
                    evt = evt || window.event || window.Event;
                    if (evt.keyCode === ESC) {
                        self.resetKeySelection();
                        self.text.focus();
                        window.setTimeout(function() {
                            self.textchange(true);
                        }, HotCat.suggest_delay);
                    } else if (evt.keyCode === RET) {
                        self.accept(evt);
                    }
                };
                if (!HotCat.fixed_search) {
                    var engineSelector = make('select');
                    for (var key in suggestionConfigs) {
                        if (suggestionConfigs[key].show) {
                            var opt = make('option');
                            opt.value = key;
                            if (key == this.engine) opt.selected = true;
                            opt.appendChild(make(suggestionConfigs[key].name, true));
                            engineSelector.appendChild(opt);
                        }
                    }
                    engineSelector.onchange = function() {
                        self.engine = self.engineSelector.options[self.engineSelector.selectedIndex].value;
                        self.text.focus();
                        self.textchange(true, true);
                    };
                    this.engineSelector = engineSelector;
                }
            }
            this.list = list;
            function button_label(id, defaultText) {
                var label = null;
                if (onUpload && typeof UFUI != 'undefined' && typeof UIElements != 'undefined' && typeof UFUI.getLabel == 'function') {
                    try {
                        label = UFUI.getLabel(id, true);
                        while (label && label.nodeType != 3) label = label.firstChild;
                    } catch (ex) {
                        label = null;
                    }
                }
                if (!label || !label.data) return defaultText;
                return label.data;
            }
            var OK = make('input');
            OK.type = 'button';
            OK.value = button_label('wpOkUploadLbl', HotCat.messages.ok);
            OK.onclick = bind(this.accept, this);
            this.ok = OK;
            var cancel = make('input');
            cancel.type = 'button';
            cancel.value = button_label('wpCancelUploadLbl', HotCat.messages.cancel);
            cancel.onclick = bind(this.cancel, this);
            this.cancelButton = cancel;
            var span = make('span');
            span.className = 'hotcatinput';
            span.style.position = 'relative';
            span.appendChild(text);
            span.appendChild(make('\xa0', true));
            span.style.whiteSpace = 'nowrap';
            if (list) span.appendChild(list);
            if (this.engineSelector) span.appendChild(this.engineSelector);
            if (!noSuggestions) span.appendChild(this.icon);
            span.appendChild(OK);
            span.appendChild(cancel);
            form.appendChild(span);
            form.style.display = 'none';
            this.span.appendChild(form);
        },
        display: function(evt) {
            if (this.isAddCategory && !onUpload) {
                var newAdder = new CategoryEditor(this.line, null, this.span, true);
            }
            if (!commitButton && !onUpload) {
                for (var i = 0; i < editors.length; i++) {
                    if (editors[i].state != CategoryEditor.UNCHANGED) {
                        setMultiInput();
                        break;
                    }
                }
            }
            if (!this.form) {
                this.makeForm();
            }
            if (this.list) this.list.style.display = 'none';
            if (this.engineSelector) this.engineSelector.style.display = 'none';
            this.currentCategory = this.lastSavedCategory;
            this.currentExists = this.lastSavedExists;
            this.currentHidden = this.lastSavedHidden;
            this.currentKey = this.lastSavedKey;
            this.icon.src = armorUri(this.currentExists ? HotCat.existsYes : HotCat.existsNo);
            this.text.value = this.currentCategory + (this.currentKey !== null ? '|' + this.currentKey : "");
            this.originalState = this.state;
            this.lastInput = this.currentCategory;
            this.inputExists = this.currentExists;
            this.state = this.state == CategoryEditor.UNCHANGED ? CategoryEditor.OPEN : CategoryEditor.CHANGE_PENDING;
            this.lastSelection = {
                start: this.currentCategory.length,
                end: this.currentCategory.length
            };
            this.showsList = false;
            if (this.catLink) this.catLink.style.display = 'none';
            this.linkSpan.style.display = 'none';
            this.form.style.display = 'inline';
            this.ok.disabled = false;
            var result = evtKill(evt);
            this.text.focus();
            this.text.readOnly = false;
            checkMultiInput();
            return result;
        },
        show: function(evt, engine, readOnly) {
            var result = this.display(evt);
            var v = this.lastSavedCategory;
            if (v.length === 0) return result;
            this.text.readOnly = !!readOnly;
            this.engine = engine;
            this.textchange(false, true);
            forceRedraw();
            return result;
        },
        open: function(evt) {
            return this.show(evt, (this.engine && suggestionConfigs[this.engine].temp) ? HotCat.suggestions : this.engine);
        },
        down: function(evt) {
            return this.show(evt, 'subcat', true);
        },
        up: function(evt) {
            return this.show(evt, 'parentcat');
        },
        cancel: function() {
            if (this.isAddCategory && !onUpload) {
                this.removeEditor();
                return;
            }
            this.inactivate();
            this.form.style.display = 'none';
            if (this.catLink) this.catLink.style.display = "";
            this.linkSpan.style.display = "";
            this.state = this.originalState;
            this.currentCategory = this.lastSavedCategory;
            this.currentKey = this.lastSavedKey;
            this.currentExists = this.lastSavedExists;
            this.currentHidden = this.lastSavedHidden;
            if (this.catLink) {
                if (this.currentKey && this.currentKey.length > 0) {
                    this.catLink.title = this.currentKey;
                } else {
                    this.catLink.title = "";
                }
            }
            if (this.state == CategoryEditor.UNCHANGED) {
                if (this.catLink) this.catLink.style.backgroundColor = 'transparent';
            } else {
                if (!onUpload) {
                    try {
                        this.catLink.style.backgroundColor = HotCat.bg_changed;
                    } catch (ex) {}
                }
            }
            checkMultiInput();
            forceRedraw();
        },
        removeEditor: function() {
            if (!newDOM) {
                var next = this.span.nextSibling;
                if (next) next.parentNode.removeChild(next);
            }
            this.span.parentNode.removeChild(this.span);
            for (var i = 0; i < editors.length; i++) {
                if (editors[i] == this) {
                    editors.splice(i, 1);
                    break;
                }
            }
            checkMultiInput();
            var self = this;
            window.setTimeout(function() {
                delete self;
            }, 10);
        },
        rollback: function(evt) {
            this.undoLink.parentNode.removeChild(this.undoLink);
            this.undoLink = null;
            this.currentCategory = this.originalCategory;
            this.currentKey = this.originalKey;
            this.currentExists = this.originalExists;
            this.currentHidden = this.originalHidden;
            this.lastSavedCategory = this.originalCategory;
            this.lastSavedKey = this.originalKey;
            this.lastSavedExists = this.originalExists;
            this.lastSavedHidden = this.originalHidden;
            this.state = CategoryEditor.UNCHANGED;
            if (!this.currentCategory || this.currentCategory.length === 0) {
                this.removeEditor();
            } else {
                this.catLink.removeChild(this.catLink.firstChild);
                this.catLink.appendChild(make(this.currentCategory, true));
                this.catLink.href = wikiPagePath(HotCat.category_canonical + ':' + this.currentCategory);
                this.catLink.title = this.currentKey || "";
                this.catLink.className = this.currentExists ? "" : 'new';
                this.catLink.style.backgroundColor = 'transparent';
                if (this.upDownLinks) this.upDownLinks.style.display = this.currentExists ? "" : 'none';
                checkMultiInput();
            }
            return evtKill(evt);
        },
        inactivate: function() {
            if (this.list) this.list.style.display = 'none';
            if (this.engineSelector) this.engineSelector.style.display = 'none';
            this.is_active = false;
        },
        acceptCheck: function(dontCheck) {
            this.sanitizeInput();
            var value = this.text.value.split('|');
            var key = null;
            if (value.length > 1) key = value[1];
            var v = value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, "");
            if (HotCat.capitalizePageNames) v = capitalize(v);
            this.lastInput = v;
            v = replaceShortcuts(v, HotCat.shortcuts);
            if (v.length === 0) {
                this.cancel();
                return false;
            }
            if (!dontCheck && (conf.wgNamespaceNumber === 14 && v == conf.wgTitle || HotCat.blacklist && HotCat.blacklist.test(v))) {
                this.cancel();
                return false;
            }
            this.currentCategory = v;
            this.currentKey = key;
            this.currentExists = this.inputExists;
            return true;
        },
        accept: function(evt) {
            this.noCommit = (evtKeys(evt) & 1) !== 0;
            var result = evtKill(evt);
            if (this.acceptCheck()) {
                var toResolve = [this];
                var original = this.currentCategory;
                resolveMulti(toResolve, function(resolved) {
                    if (resolved[0].dab) {
                        showDab(resolved[0]);
                    } else {
                        if (resolved[0].acceptCheck(true)) {
                            resolved[0].commit((resolved[0].currentCategory != original) ? HotCat.messages.cat_resolved.replace(/\$1/g, original) : null);
                        }
                    }
                });
            }
            return result;
        },
        close: function() {
            if (!this.catLink) {
                this.catLink = make('a');
                this.catLink.appendChild(make('foo', true));
                this.catLink.style.display = 'none';
                this.span.insertBefore(this.catLink, this.span.firstChild.nextSibling);
            }
            this.catLink.removeChild(this.catLink.firstChild);
            this.catLink.appendChild(make(this.currentCategory, true));
            this.catLink.href = wikiPagePath(HotCat.category_canonical + ':' + this.currentCategory);
            this.catLink.className = this.currentExists ? "" : 'new';
            this.lastSavedCategory = this.currentCategory;
            this.lastSavedKey = this.currentKey;
            this.lastSavedExists = this.currentExists;
            this.lastSavedHidden = this.currentHidden;
            this.inactivate();
            this.form.style.display = 'none';
            this.catLink.title = this.currentKey || "";
            this.catLink.style.display = "";
            if (this.isAddCategory) {
                if (onUpload) {
                    var newAdder = new CategoryEditor(this.line, null, this.span, true);
                }
                this.isAddCategory = false;
                this.linkSpan.parentNode.removeChild(this.linkSpan);
                this.makeLinkSpan();
                this.span.appendChild(this.linkSpan);
            }
            if (!this.undoLink) {
                var span = make('span');
                var lk = make('a');
                lk.href = '#catlinks';
                lk.onclick = bind(this.rollback, this);
                lk.appendChild(make(HotCat.links.undo, true));
                lk.title = HotCat.tooltips.undo;
                span.appendChild(make(' ', true));
                span.appendChild(lk);
                this.normalLinks.appendChild(span);
                this.undoLink = span;
                if (!onUpload) {
                    try {
                        this.catLink.style.backgroundColor = HotCat.bg_changed;
                    } catch (ex) {}
                }
            }
            if (this.upDownLinks) this.upDownLinks.style.display = this.lastSavedExists ? "" : 'none';
            this.linkSpan.style.display = "";
            this.state = CategoryEditor.CHANGED;
            checkMultiInput();
            forceRedraw();
        },
        commit: function(comment) {
            if ((this.currentCategory == this.originalCategory && (this.currentKey == this.originalKey || this.currentKey === null && this.originalKey.length === 0)) || conf.wgNamespaceNumber == 14 && this.currentCategory == conf.wgTitle || HotCat.blacklist && HotCat.blacklist.test(this.currentCategory)) {
                this.cancel();
                return;
            }
            if (commitButton || onUpload) {
                this.close();
            } else {
                this.close();
                var self = this;
                initiateEdit(function(failure) {
                    performChanges(failure, self);
                }, function(msg) {
                    alert(msg);
                });
            }
        },
        remove: function(evt) {
            this.doRemove(evtKeys(evt) & 1);
            return evtKill(evt);
        },
        doRemove: function(noCommit) {
            if (this.isAddCategory) {
                this.cancel();
                return;
            }
            if (!commitButton && !onUpload) {
                for (var i = 0; i < editors.length; i++) {
                    if (editors[i].state != CategoryEditor.UNCHANGED) {
                        setMultiInput();
                        break;
                    }
                }
            }
            if (commitButton) {
                this.catLink.title = "";
                this.catLink.style.cssText += '; text-decoration : line-through !important;';
                try {
                    this.catLink.style.backgroundColor = HotCat.bg_changed;
                } catch (ex) {}
                this.originalState = this.state;
                this.state = CategoryEditor.DELETED;
                this.normalLinks.style.display = 'none';
                this.undelLink.style.display = "";
                checkMultiInput();
            } else {
                if (onUpload) {
                    this.removeEditor();
                } else {
                    this.originalState = this.state;
                    this.state = CategoryEditor.DELETED;
                    this.noCommit = noCommit || HotCat.del_needs_diff;
                    var self = this;
                    initiateEdit(function(failure) {
                        performChanges(failure, self);
                    }, function(msg) {
                        self.state = self.originalState;
                        alert(msg);
                    });
                }
            }
        },
        restore: function(evt) {
            this.catLink.title = this.currentKey || "";
            this.catLink.style.textDecoration = "";
            this.state = this.originalState;
            if (this.state == CategoryEditor.UNCHANGED) {
                this.catLink.style.backgroundColor = 'transparent';
            } else {
                try {
                    this.catLink.style.backgroundColor = HotCat.bg_changed;
                } catch (ex) {}
            }
            this.normalLinks.style.display = "";
            this.undelLink.style.display = 'none';
            checkMultiInput();
            return evtKill(evt);
        },
        selectEngine: function(engineName) {
            if (!this.engineSelector) return;
            for (var i = 0; i < this.engineSelector.options.length; i++) {
                this.engineSelector.options[i].selected = this.engineSelector.options[i].value == engineName;
            }
        },
        sanitizeInput: function() {
            var v = this.text.value || "";
            v = v.replace(/^(\s|_)+/, "");
            var re = new RegExp('^(' + HotCat.category_regexp + '):');
            if (re.test(v)) {
                v = v.substring(v.indexOf(':') + 1).replace(/^(\s|_)+/, "");
            }
            if (HotCat.capitalizePageNames) v = capitalize(v);
            if (this.text.value !== null && this.text.value != v)
                this.text.value = v;
        },
        makeCall: function(url, callbackObj, engine, queryKey, cleanKey) {
            var cb = callbackObj;
            var e = engine;
            var v = queryKey;
            var z = cleanKey;
            var thisObj = this;
            function done() {
                cb.callsMade++;
                if (cb.callsMade === cb.nofCalls) {
                    if (cb.exists) cb.allTitles.exists = true;
                    if (cb.normalized) cb.allTitles.normalized = cb.normalized;
                    if (!cb.dontCache && !suggestionConfigs[cb.engineName].cache[z]) {
                        suggestionConfigs[cb.engineName].cache[z] = cb.allTitles;
                    }
                    thisObj.text.readOnly = false;
                    if (!cb.cancelled) thisObj.showSuggestions(cb.allTitles, cb.noCompletion, v, cb.engineName);
                    if (cb === thisObj.callbackObj) thisObj.callbackObj = null;
                    delete cb;
                }
            }
            getJSON({
                uri: url,
                success: function(json) {
                    var titles = e.handler(json, z);
                    if (titles && titles.length > 0) {
                        if (cb.allTitles === null) {
                            cb.allTitles = titles;
                        } else {
                            cb.allTitles = cb.allTitles.concat(titles);
                        }
                        if (titles.exists) cb.exists = true;
                        if (titles.normalized) cb.normalized = titles.normalized;
                    }
                    done();
                },
                error: function(req) {
                    if (!req) noSuggestions = true;
                    cb.dontCache = true;
                    done();
                }
            });
        },
        callbackObj: null,
        textchange: function(dont_autocomplete, force) {
            makeActive(this);
            this.sanitizeInput();
            var v = this.text.value;
            var pipe = v.indexOf('|');
            if (pipe >= 0) {
                this.currentKey = v.substring(pipe + 1);
                v = v.substring(0, pipe);
            } else {
                this.currentKey = null;
            }
            if (this.lastInput == v && !force) return;
            if (this.lastInput != v) checkMultiInput();
            this.lastInput = v;
            this.lastRealInput = v;
            this.ok.disabled = v.length > 0 && HotCat.blacklist && HotCat.blacklist.test(v);
            if (noSuggestions) {
                if (this.list) this.list.style.display = 'none';
                if (this.engineSelector) this.engineSelector.style.display = 'none';
                if (this.icon) this.icon.style.display = 'none';
                return;
            }
            if (v.length === 0) {
                this.showSuggestions([]);
                return;
            }
            var cleanKey = v.replace(/[\u200E\u200F\u202A-\u202E]/g, "").replace(wikiTextBlankRE, ' ');
            cleanKey = replaceShortcuts(cleanKey, HotCat.shortcuts);
            cleanKey = cleanKey.replace(/^\s+|\s+$/g, '');
            if (cleanKey.length === 0) {
                this.showSuggestions([]);
                return;
            }
            if (this.callbackObj) this.callbackObj.cancelled = true;
            var engineName = suggestionConfigs[this.engine] ? this.engine : 'combined';
            dont_autocomplete = dont_autocomplete || suggestionConfigs[engineName].noCompletion;
            if (suggestionConfigs[engineName].cache[cleanKey]) {
                this.showSuggestions(suggestionConfigs[engineName].cache[cleanKey], dont_autocomplete, v, engineName);
                return;
            }
            var engines = suggestionConfigs[engineName].engines;
            this.callbackObj = {
                allTitles: null,
                callsMade: 0,
                nofCalls: engines.length,
                noCompletion: dont_autocomplete,
                engineName: engineName
            };
            this.makeCalls(engines, this.callbackObj, v, cleanKey);
        },
        makeCalls: function(engines, cb, v, cleanKey) {
            for (var j = 0; j < engines.length; j++) {
                var engine = suggestionEngines[engines[j]];
                var url = conf.wgServer + conf.wgScriptPath + engine.uri.replace(/\$1/g, encodeURIComponent(cleanKey));
                this.makeCall(url, cb, engine, v, cleanKey);
            }
        },
        showSuggestions: function(titles, dontAutocomplete, queryKey, engineName) {
            this.text.readOnly = false;
            this.dab = null;
            this.showsList = false;
            if (!this.list) return;
            if (noSuggestions) {
                if (this.list) this.list.style.display = 'none';
                if (this.engineSelector) this.engineSelector.style.display = 'none';
                if (this.icon) this.icon.style.display = 'none';
                this.inputExists = true;
                return;
            }
            this.engineName = engineName;
            if (engineName) {
                if (!this.engineSelector) this.engineName = null;
            } else {
                if (this.engineSelector) this.engineSelector.style.display = 'none';
            }
            if (queryKey) {
                if (this.lastInput.indexOf(queryKey) !== 0) return;
                if (this.lastQuery && this.lastInput.indexOf(this.lastQuery) === 0 && this.lastQuery.length > queryKey.length)
                    return;
            }
            this.lastQuery = queryKey;
            var v = this.text.value.split('|');
            var key = v.length > 1 ? '|' + v[1] : "";
            v = (HotCat.capitalizePageNames ? capitalize(v[0]) : v[0]);
            var vNormalized = v;
            var knownToExist = titles && titles.exists;
            var i;
            if (titles) {
                if (titles.normalized && v.indexOf(queryKey) === 0) {
                    vNormalized = titles.normalized + v.substring(queryKey.length);
                }
                var vLow = vNormalized.toLowerCase();
                if (HotCat.blacklist) {
                    for (i = 0; i < titles.length; i++) {
                        if (HotCat.blacklist.test(titles[i])) {
                            titles.splice(i, 1);
                            i--;
                        }
                    }
                }
                titles.sort(function(a, b) {
                    if (a == b) return 0;
                    if (a.indexOf(b) === 0) return 1;
                    if (b.indexOf(a) === 0) return -1;
                    var prefixMatchA = (a.indexOf(vNormalized) === 0 ? 1 : 0);
                    var prefixMatchB = (b.indexOf(vNormalized) === 0 ? 1 : 0);
                    if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA;
                    var aLow = a.toLowerCase(),
                        bLow = b.toLowerCase();
                    prefixMatchA = (aLow.indexOf(vLow) === 0 ? 1 : 0);
                    prefixMatchB = (bLow.indexOf(vLow) === 0 ? 1 : 0);
                    if (prefixMatchA != prefixMatchB) return prefixMatchB - prefixMatchA;
                    if (a < b) return -1;
                    if (b < a) return 1;
                    return 0;
                });
                for (i = 0; i < titles.length; i++) {
                    if (i + 1 < titles.length && titles[i] == titles[i + 1] || conf.wgNamespaceNumber == 14 && titles[i] == conf.wgTitle) {
                        titles.splice(i, 1);
                        i--;
                    }
                }
            }
            if (!titles || titles.length === 0) {
                if (this.list) this.list.style.display = 'none';
                if (this.engineSelector) this.engineSelector.style.display = 'none';
                if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) {
                    if (this.icon) this.icon.src = armorUri(HotCat.existsNo);
                    this.inputExists = false;
                }
                return;
            }
            var firstTitle = titles[0];
            var completed = this.autoComplete(firstTitle, v, vNormalized, key, dontAutocomplete);
            var existing = completed || knownToExist || firstTitle == replaceShortcuts(v, HotCat.shortcuts);
            if (engineName && suggestionConfigs[engineName] && !suggestionConfigs[engineName].temp) {
                this.icon.src = armorUri(existing ? HotCat.existsYes : HotCat.existsNo);
                this.inputExists = existing;
            }
            if (completed) {
                this.lastInput = firstTitle;
                if (titles.length === 1) {
                    this.list.style.display = 'none';
                    if (this.engineSelector) this.engineSelector.style.display = 'none';
                    return;
                }
            }
            while (this.list.firstChild) this.list.removeChild(this.list.firstChild);
            for (i = 0; i < titles.length; i++) {
                var opt = make('option');
                opt.appendChild(make(titles[i], true));
                opt.selected = completed && (i === 0);
                this.list.appendChild(opt);
            }
            this.displayList();
        },
        displayList: function() {
            this.showsList = true;
            if (!this.is_active) {
                this.list.style.display = 'none';
                if (this.engineSelector) this.engineSelector.style.display = 'none';
                return;
            }
            var nofItems = (this.list.options.length > HotCat.list_size ? HotCat.list_size : this.list.options.length);
            if (nofItems <= 1) nofItems = 2;
            this.list.size = nofItems;
            this.list.style.align = is_rtl ? 'right' : 'left';
            this.list.style.zIndex = 5;
            this.list.style.position = 'absolute';
            var anchor = is_rtl ? 'right' : 'left';
            var listh = 0;
            if (this.list.style.display == 'none') {
                this.list.style.top = this.text.offsetTop + 'px';
                this.list.style[anchor] = '-10000px';
                this.list.style.display = "";
                listh = this.list.offsetHeight;
                this.list.style.display = 'none';
            } else {
                listh = this.list.offsetHeight;
            }
            var maxListHeight = listh;
            if (nofItems < HotCat.list_size) maxListHeight = (listh / nofItems) * HotCat.list_size;
            function viewport(what) {
                if (is_webkit && !document.evaluate)
                    return window['inner' + what];
                var s = 'client' + what;
                if (window.opera) return document.body[s];
                return (document.documentElement ? document.documentElement[s] : 0) || document.body[s] || 0;
            }
            function scroll_offset(what) {
                var s = 'scroll' + what;
                var result = (document.documentElement ? document.documentElement[s] : 0) || document.body[s] || 0;
                if (is_rtl && what == 'Left') {
                    if (result < 0) result = -result;
                    if (!is_webkit && !is_ie_lt8) {
                        result = scroll_offset('Width') - viewport('Width') - result;
                    }
                }
                return result;
            }
            function position(node) {
                if (node.getBoundingClientRect) {
                    var box = node.getBoundingClientRect();
                    return {
                        x: Math.round(box.left + scroll_offset('Left')),
                        y: Math.round(box.top + scroll_offset('Top'))
                    };
                }
                var t = 0,
                    l = 0;
                do {
                    t = t + (node.offsetTop || 0);
                    l = l + (node.offsetLeft || 0);
                    node = node.offsetParent;
                } while (node);
                return {
                    x: l,
                    y: t
                };
            }
            var textPos = position(this.text);
            var nl = 0;
            var nt = 0;
            var offset = 0;
            var textBoxWidth = this.text.offsetWidth || this.text.clientWidth;
            if (this.engineName) {
                this.engineSelector.style.zIndex = 5;
                this.engineSelector.style.position = 'absolute';
                this.engineSelector.style.width = textBoxWidth + 'px';
                if (this.engineSelector.style.display == 'none') {
                    this.engineSelector.style[anchor] = '-10000px';
                    this.engineSelector.style.top = '0px';
                    this.engineSelector.style.display = "";
                    offset = this.engineSelector.offsetHeight;
                    this.engineSelector.style.display = 'none';
                } else {
                    offset = this.engineSelector.offsetHeight;
                }
                this.engineSelector.style[anchor] = nl + 'px';
            }
            if (textPos.y < maxListHeight + offset + 1) {
                nt = this.text.offsetHeight + offset + 1;
                if (this.engineName) this.engineSelector.style.top = this.text.offsetHeight + 'px';
            } else {
                nt = -listh - offset - 1;
                if (this.engineName) this.engineSelector.style.top = -(offset + 1) + 'px';
            }
            this.list.style.top = nt + 'px';
            this.list.style.width = "";
            this.list.style[anchor] = nl + 'px';
            if (this.engineName) {
                this.selectEngine(this.engineName);
                this.engineSelector.style.display = "";
            }
            this.list.style.display = 'block';
            if (this.list.offsetWidth < textBoxWidth) {
                this.list.style.width = textBoxWidth + 'px';
                return;
            }
            var scroll = scroll_offset('Left');
            var view_w = viewport('Width');
            var w = this.list.offsetWidth;
            var l_pos = position(this.list);
            var left = l_pos.x;
            var right = left + w;
            if (left < scroll || right > scroll + view_w) {
                if (w > view_w) {
                    w = view_w;
                    this.list.style.width = w + 'px';
                    if (is_rtl) {
                        left = right - w;
                    } else {
                        right = left + w;
                    }
                }
                var relative_offset = 0;
                if (left < scroll) {
                    relative_offset = scroll - left;
                } else if (right > scroll + view_w) {
                    relative_offset = -(right - scroll - view_w);
                }
                if (is_rtl) relative_offset = -relative_offset;
                if (relative_offset !== 0) {
                    this.list.style[anchor] = (nl + relative_offset) + 'px';
                }
            }
        },
        autoComplete: function(newVal, actVal, normalizedActVal, key, dontModify) {
            if (newVal == actVal) return true;
            if (dontModify || this.ime || !this.canSelect()) return false;
            if (newVal.indexOf(actVal) !== 0) {
                if (normalizedActVal && newVal.indexOf(normalizedActVal) === 0) {
                    if (this.lastRealInput == actVal) this.lastRealInput = normalizedActVal;
                    actVal = normalizedActVal;
                } else {
                    return false;
                }
            }
            this.text.focus();
            this.text.value = newVal + key;
            this.setSelection(actVal.length, newVal.length);
            return true;
        },
        canSelect: function() {
            return this.text.setSelectionRange || this.text.createTextRange || typeof this.text.selectionStart != 'undefined' && typeof this.text.selectionEnd != 'undefined';
        },
        setSelection: function(from, to) {
            if (!this.text.value) return;
            if (this.text.setSelectionRange) {
                this.text.setSelectionRange(from, to);
            } else if (typeof this.text.selectionStart != 'undefined') {
                if (from > this.text.selectionStart) {
                    this.text.selectionEnd = to;
                    this.text.selectionStart = from;
                } else {
                    this.text.selectionStart = from;
                    this.text.selectionEnd = to;
                }
            } else if (this.text.createTextRange) {
                var new_selection = this.text.createTextRange();
                new_selection.move('character', from);
                new_selection.moveEnd('character', to - from);
                new_selection.select();
            }
        },
        getSelection: function() {
            var from = 0,
                to = 0;
            if (!this.text.value) {} else if (typeof this.text.selectionStart != 'undefined') {
                from = this.text.selectionStart;
                to = this.text.selectionEnd;
            } else if (document.selection && document.selection.createRange) {
                var rng = document.selection.createRange().duplicate();
                if (rng.parentElement() === this.text) {
                    try {
                        var textRng = this.text.createTextRange();
                        textRng.move('character', 0);
                        textRng.setEndPoint('EndToEnd', rng);
                        to = textRng.text.length;
                        textRng.setEndPoint('EndToStart', rng);
                        from = textRng.text.length;
                    } catch (notFocused) {
                        from = this.text.value.length;
                        to = from;
                    }
                }
            }
            return {
                start: from,
                end: to
            };
        },
        saveView: function(evt) {
            this.lastSelection = this.getSelection();
        },
        processKey: function(evt) {
            var dir = 0;
            switch (this.lastKey) {
                case UP:
                    dir = -1;
                case DOWN:
                    if (dir === 0) dir = 1;
                case PGUP:
                    if (dir === 0) dir = -HotCat.list_size;
                case PGDOWN:
                    if (dir === 0) dir = HotCat.list_size;
                    if (this.list.style.display != 'none') {
                        this.highlightSuggestion(dir);
                        return evtKill(evt);
                    } else if (this.keyCount <= 1 && (!this.callbackObj || this.callbackObj.callsMade == this.callbackObj.nofCalls)) {
                        this.textchange();
                    }
                    break;
                case ESC:
                    return evtKill(evt);
            }
            return true;
        },
        highlightSuggestion: function(dir) {
            if (noSuggestions || !this.list || this.list.style.display == 'none') return false;
            var curr = this.list.selectedIndex;
            var tgt = -1;
            if (dir === 0) {
                if (curr < 0 || curr >= this.list.options.length) return false;
                tgt = curr;
            } else {
                tgt = curr < 0 ? 0 : curr + dir;
                tgt = tgt < 0 ? 0 : tgt;
                if (tgt >= this.list.options.length) tgt = this.list.options.length - 1;
            }
            if (tgt != curr || dir === 0) {
                if (curr >= 0 && curr < this.list.options.length && dir !== 0) this.list.options[curr].selected = false;
                this.list.options[tgt].selected = true;
                var v = this.text.value.split('|');
                var key = v.length > 1 ? '|' + v[1] : "";
                var completed = this.autoComplete(this.list.options[tgt].text, this.lastRealInput, null, key, false);
                if (!completed || this.list.options[tgt].text == this.lastRealInput) {
                    this.text.value = this.list.options[tgt].text + key;
                    if (this.canSelect()) this.setSelection(this.list.options[tgt].text.length, this.list.options[tgt].text.length);
                }
                this.lastInput = this.list.options[tgt].text;
                this.inputExists = true;
                if (this.icon) this.icon.src = armorUri(HotCat.existsYes);
                this.state = CategoryEditor.CHANGE_PENDING;
            }
            return true;
        },
        resetKeySelection: function() {
            if (noSuggestions || !this.list || this.list.style.display == 'none') return false;
            var curr = this.list.selectedIndex;
            if (curr >= 0 && curr < this.list.options.length) {
                this.list.options[curr].selected = false;
                var v = this.text.value.split('|');
                var key = v.length > 1 ? '|' + v[1] : "";
                var result = v[0] != this.lastInput;
                if (v[0] != this.lastRealInput) {
                    this.text.value = this.lastRealInput + key;
                    result = true;
                }
                this.lastInput = this.lastRealInput;
                return result;
            }
            return false;
        }
    };
    function initialize() {
        var config = (typeof JSconfig != 'undefined' && JSconfig.keys) ? JSconfig.keys : {};
        HotCat.dont_add_to_watchlist = (typeof window.hotcat_dont_add_to_watchlist != 'undefined' ? !!window.hotcat_dont_add_to_watchlist : (typeof config.HotCatDontAddToWatchlist != 'undefined' ? config.HotCatDontAddToWatchlist : HotCat.dont_add_to_watchlist));
        HotCat.no_autocommit = (typeof window.hotcat_no_autocommit != 'undefined' ? !!window.hotcat_no_autocommit : (typeof config.HotCatNoAutoCommit != 'undefined' ? config.HotCatNoAutoCommit : HotCat.no_autocommit));
        HotCat.del_needs_diff = (typeof window.hotcat_del_needs_diff != 'undefined' ? !!window.hotcat_del_needs_diff : (typeof config.HotCatDelNeedsDiff != 'undefined' ? config.HotCatDelNeedsDiff : HotCat.del_needs_diff));
        HotCat.suggest_delay = window.hotcat_suggestion_delay || config['HotCatSuggestionDelay'] || HotCat.suggest_delay;
        HotCat.editbox_width = window.hotcat_editbox_width || config['HotCatEditBoxWidth'] || HotCat.editbox_width;
        HotCat.suggestions = window.hotcat_suggestions || config['HotCatSuggestions'] || HotCat.suggestions;
        if (typeof HotCat.suggestions != 'string' || !suggestionConfigs[HotCat.suggestions])
            HotCat.suggestions = 'combined';
        HotCat.fixed_search = (typeof window.hotcat_suggestions_fixed != 'undefined' ? !!window.hotcat_suggestions_fixed : (typeof config.HotCatFixedSuggestions != 'undefined' ? config.HotCatFixedSuggestions : HotCat.fixed_search));
        HotCat.single_minor = (typeof window.hotcat_single_changes_are_minor != 'undefined' ? !!window.hotcat_single_changes_are_minor : (typeof config.HotCatMinorSingleChanges != 'undefined' ? config.HotCatMinorSingleChanges : HotCat.single_minor));
        HotCat.bg_changed = window.hotcat_changed_background || config.HotCatChangedBackground || HotCat.bg_changed;
        HotCat.use_up_down = (typeof window.hotcat_use_category_links != 'undefined' ? !!window.hotcat_use_category_links : (typeof config.HotCatUseCategoryLinks != 'undefined' ? config.HotCatUseCategoryLinks : HotCat.use_up_down));
        HotCat.list_size = window.hotcat_list_size || config.HotCatListSize || HotCat.list_size;
        HotCat.list_size = parseInt(HotCat.list_size, 10);
        if (isNaN(HotCat.list_size) || HotCat.list_size < 5) HotCat.list_size = 5;
        if (HotCat.list_size > 15) HotCat.list_size = 15;
        if (HotCat.engine_names) {
            for (var key in HotCat.engine_names) {
                if (suggestionConfigs[key] && HotCat.engine_names[key]) {
                    suggestionConfigs[key].name = HotCat.engine_names[key];
                }
            }
        }
        is_rtl = hasClass(document.body, 'rtl');
        if (!is_rtl) {
            if (document.defaultView && document.defaultView.getComputedStyle) {
                is_rtl = document.defaultView.getComputedStyle(document.body, null).getPropertyValue('direction');
            } else if (document.body.currentStyle) {
                is_rtl = document.body.currentStyle['direction'];
            } else {
                is_rtl = document.body.style['direction'];
            }
            is_rtl = (is_rtl == 'rtl');
        }
    }
    function can_edit() {
        var container = null;
        switch (mw.config.get('skin')) {
            case 'cologneblue':
                container = document.getElementById('quickbar');
            case 'standard':
            case 'nostalgia':
                if (!container) container = document.getElementById('topbar');
                var lks = container.getElementsByTagName('a');
                for (var i = 0; i < lks.length; i++) {
                    if (param('title', lks[i].href) == conf.wgPageName && param('action', lks[i].href) == 'edit')
                        return true;
                }
                return false;
            default:
                return document.getElementById('ca-edit') !== null;
        }
        return false;
    }
    function setup_upload() {
        onUpload = true;
        var ip = document.getElementById('mw-htmlform-description') || document.getElementById('wpDestFile');
        if (!ip) {
            ip = document.getElementById('wpDestFile');
            while (ip && ip.nodeName.toLowerCase() != 'table') ip = ip.parentNode;
        }
        if (!ip) return;
        var reupload = document.getElementById('wpForReUpload');
        var destFile = document.getElementById('wpDestFile');
        if ((reupload && !!reupload.value) || (destFile && (destFile.disabled || destFile.readOnly)))
            return;
        var labelCell = make('td');
        var lineCell = make('td');
        catLine = make('div');
        catLine.className = 'catlinks';
        catLine.id = 'catlinks';
        catLine.style.textAlign = is_rtl ? 'right' : 'left';
        catLine.style.margin = '0';
        catLine.style.border = 'none';
        lineCell.appendChild(catLine);
        var label = null;
        if (typeof UFUI != 'undefined' && typeof UIElements != 'undefined' && typeof UFUI.getLabel == 'function') {
            try {
                label = UFUI.getLabel('wpCategoriesUploadLbl');
            } catch (ex) {
                label = null;
            }
        }
        if (!label) {
            labelCell.id = 'hotcatLabel';
            labelCell.appendChild(make(HotCat.categories, true));
        } else {
            labelCell.id = 'hotcatLabelTranslated';
            labelCell.appendChild(label);
        }
        labelCell.className = 'mw-label';
        labelCell.style.textAlign = 'right';
        labelCell.style.verticalAlign = 'middle';
        var form = document.getElementById('upload') || document.getElementById('mw-upload-form');
        if (form) {
            var newRow = ip.insertRow(-1);
            newRow.appendChild(labelCell);
            newRow.appendChild(lineCell);
            form.onsubmit = (function(oldSubmit) {
                return function() {
                    var do_submit = true;
                    if (oldSubmit) {
                        if (typeof oldSubmit == 'string')
                            do_submit = eval(oldSubmit);
                        else if (typeof oldSubmit == 'function')
                            do_submit = oldSubmit.apply(form, arguments);
                    }
                    if (!do_submit) return false;
                    closeForm();
                    var eb = document.getElementById('wpUploadDescription') || document.getElementById('wpDesc');
                    var addedOne = false;
                    for (var i = 0; i < editors.length; i++) {
                        var t = editors[i].currentCategory;
                        if (!t) continue;
                        var key = editors[i].currentKey;
                        var new_cat = '[[' + HotCat.category_canonical + ':' + t + (key ? '|' + key : "") + ']]';
                        var cleanedText = eb.value.replace(/<\!--(\s|\S)*?--\>/g, "").replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, "");
                        if (!find_category(cleanedText, t, true)) {
                            eb.value += '\n' + new_cat;
                            addedOne = true;
                        }
                    }
                    if (addedOne) {
                        eb.value = eb.value.replace(/\{\{subst:unc\}\}/g, "");
                    }
                    return true;
                };
            })(form.onsubmit);
        }
    }
    var cleanedText = null;
    function isOnPage(span) {
        var catTitle = title(span.firstChild.getAttribute('href', 2));
        if (!catTitle) return null;
        catTitle = catTitle.substr(catTitle.indexOf(':') + 1).replace(/_/g, ' ');
        if (HotCat.blacklist && HotCat.blacklist.test(catTitle)) return null;
        var result = {
            title: catTitle,
            match: ["", "", ""]
        };
        if (pageText === null) return result;
        if (cleanedText === null) {
            cleanedText = pageText.replace(/<\!--(\s|\S)*?--\>/g, "").replace(/<nowiki\>(\s|\S)*?<\/nowiki>/g, "");
        }
        result.match = find_category(cleanedText, catTitle, true);
        return result;
    }
    var initialized = false;
    var setupTimeout = null;
    function findByClass(scope, tag, className) {
        var result;
        if (window.jQuery) {
            result = window.jQuery(scope).find(tag + '.' + className);
        } else {
            result = getElementsByClassName(scope, tag, className);
        }
        return (result && result.length) ? result[0] : null;
    }
    function setup(additionalWork) {
        if (initialized) return;
        initialized = true;
        if (setupTimeout) {
            window.clearTimeout(setupTimeout);
            setupTimeout = null;
        }
        catLine = catLine || document.getElementById('mw-normal-catlinks') || findByClass(document, 'p', 'catlinks');
        var hiddenCats = document.getElementById('mw-hidden-catlinks');
        if (!catLine) {
            var footer = null;
            if (!hiddenCats) {
                footer = findByClass(document, 'div', 'printfooter');
                if (!footer) return;
            }
            catLine = make('div');
            catLine.id = 'mw-normal-catlinks';
            catLine.style.textAlign = is_rtl ? 'right' : 'left';
            var label = make('a');
            label.href = conf.wgArticlePath.replace('$1', 'Special:Categories');
            label.title = HotCat.categories;
            label.appendChild(make(HotCat.categories, true));
            catLine.appendChild(label);
            catLine.appendChild(make(':', true));
            var container = (hiddenCats ? hiddenCats.parentNode : document.getElementById('catlinks'));
            if (!container) {
                container = make('div');
                container.id = 'catlinks';
                footer.parentNode.insertBefore(container, footer.nextSibling);
            }
            container.className = 'catlinks noprint';
            container.style.display = "";
            if (!hiddenCats) {
                container.appendChild(catLine);
            } else {
                container.insertBefore(catLine, hiddenCats);
            }
        }
        if (is_rtl) catLine.dir = 'rtl';
        function createEditors(line, is_hidden) {
            var i;
            var cats = line.getElementsByTagName('li');
            if (cats.length > 0) {
                newDOM = true;
                line = cats[0].parentNode;
            } else {
                cats = line.getElementsByTagName('span');
            }
            var copyCats = new Array(cats.length);
            for (i = 0; i < cats.length; i++) copyCats[i] = cats[i];
            var editor = null;
            for (i = 0; i < copyCats.length; i++) {
                var test = isOnPage(copyCats[i]);
                if (test !== null && test.match !== null) {
                    editor = new CategoryEditor(line, copyCats[i], test.title, test.match[2], is_hidden);
                }
            }
            return copyCats.length > 0 ? copyCats[copyCats.length - 1] : null;
        }
        var lastSpan = createEditors(catLine, false);
        var editor = new CategoryEditor(newDOM ? catLine.getElementsByTagName('ul')[0] : catLine, null, null, lastSpan !== null, false);
        if (!onUpload) {
            if (pageText !== null && hiddenCats) {
                if (is_rtl) hiddenCats.dir = 'rtl';
                createEditors(hiddenCats, true);
            }
            var enableMulti = make('span');
            enableMulti.className = 'noprint';
            if (is_rtl) enableMulti.dir = 'rtl';
            catLine.insertBefore(enableMulti, catLine.firstChild.nextSibling);
            enableMulti.appendChild(make('\xa0', true));
            multiSpan = make('span');
            enableMulti.appendChild(multiSpan);
            multiSpan.innerHTML = '(<a>' + HotCat.addmulti + '</a>)';
            var lk = multiSpan.getElementsByTagName('a')[0];
            lk.onclick = function(evt) {
                setMultiInput();
                checkMultiInput();
                return evtKill(evt);
            };
            lk.title = HotCat.multi_tooltip;
            lk.style.cursor = 'pointer';
        }
        cleanedText = null;
        if (typeof additionalWork == 'function') additionalWork();
        setupCompleted.loaded();
        if (window.jQuery) jQuery('body').trigger('hotcatSetupCompleted');
    }
    function setPage(json) {
        var startTime = null;
        if (json && json.query) {
            if (json.query.pages) {
                var page = json.query.pages[conf.wgArticleId === 0 ? "-1" : "" + conf.wgArticleId];
                if (page) {
                    if (page.revisions && page.revisions.length > 0) {
                        pageText = page.revisions[0]['*'];
                        if (page.revisions[0].timestamp) pageTime = page.revisions[0].timestamp.replace(/\D/g, "");
                        if (page.revisions[0].revid) pageTextRevId = page.revisions[0].revid;
                        if (page.revisions.length > 1) conflictingUser = page.revisions[1].user;
                    }
                    if (page.lastrevid) lastRevId = page.lastrevid;
                    if (page.starttimestamp) startTime = page.starttimestamp.replace(/\D/g, "");
                    pageWatched = typeof page.watched == 'string';
                    editToken = page.edittoken;
                    if (page.langlinks && (!json['query-continue'] || !json['query-continue'].langlinks)) {
                        var re = "";
                        for (var i = 0; i < page.langlinks.length; i++) {
                            re += (i > 0 ? '|' : "") + page.langlinks[i].lang.replace(/([\\\^\$\.\?\*\+\(\)])/g, '\\$1');
                        }
                        if (re.length > 0) {
                            interlanguageRE = new RegExp('((^|\\n\\r?)(\\[\\[\\s*(' + re + ')\\s*:[^\\]]+\\]\\]\\s*))+$');
                        }
                    }
                }
            }
            if (json.query.general) {
                HotCat.capitalizePageNames = (json.query.general['case'] == 'first-letter');
                if (json.query.general.time && !startTime) startTime = json.query.general.time.replace(/\D/g, "");
            }
            serverTime = startTime;
            if (json.query.userinfo && json.query.userinfo.options) {
                watchCreate = !HotCat.dont_add_to_watchlist && json.query.userinfo.options.watchcreations == '1';
                watchEdit = !HotCat.dont_add_to_watchlist && json.query.userinfo.options.watchdefault == '1';
                minorEdits = json.query.userinfo.options.minordefault == 1;
                if (minorEdits) HotCat.single_minor = true;
            }
        }
    }
    function createCommitForm() {
        if (commitForm) return;
        var formContainer = make('div');
        formContainer.style.display = 'none';
        document.body.appendChild(formContainer);
        formContainer.innerHTML = '<form id="hotcatCommitForm" method="post" enctype="multipart/form-data" action="' + conf.wgScript + '?title=' + encodeURIComponent(conf.wgPageName) + '&action=edit">' + '<input type="hidden" name="wpTextbox1" />' + '<input type="hidden" name="model" value="wikitext" />' + '<input type="hidden" name="format" value="text/x-wiki" />' + '<input type="hidden" name="wpSummary" value="" />' + '<input type="checkbox" name="wpMinoredit" value="1" />' + '<input type="checkbox" name="wpWatchthis" value="1" />' + '<input type="hidden" name="wpAutoSummary" value="" />' + '<input type="hidden" name="wpEdittime" />' + '<input type="hidden" name="wpStarttime" />' + '<input type="hidden" name="wpDiff" value="wpDiff" />' + '<input type="hidden" name="oldid" value="0" />' + '<input type="submit" name="hcCommit" value="hcCommit" />' + '<input type="hidden" name="wpEditToken" />' + '<input type="hidden" name="wpUltimateParam" value="1" />' + '</form>';
        commitForm = document.getElementById('hotcatCommitForm');
    }
    function getPage() {
        if (conf.wgArticleId === 0) {
            if (conf.wgNamespaceNumber === 2) {
                return;
            }
            pageText = "";
            pageTime = null;
            setup(createCommitForm);
        } else {
            var url = conf.wgServer + conf.wgScriptPath + '/api.php?format=json&callback=HotCat.start&action=query&rawcontinue=&titles=' + encodeURIComponent(conf.wgPageName) + '&prop=info%7Crevisions&rvprop=content%7Ctimestamp%7Cids&meta=siteinfo&rvlimit=1&rvstartid=' + conf.wgCurRevisionId;
            var s = make('script');
            s.src = armorUri(url);
            s.type = 'text/javascript';
            HotCat.start = function(json) {
                setPage(json);
                setup(createCommitForm);
            };
            document.getElementsByTagName('head')[0].appendChild(s);
            setupTimeout = window.setTimeout(function() {
                setup(createCommitForm);
            }, 4000);
        }
    }
    function run() {
        if (HotCat.started) return;
        HotCat.started = true;
        loadTrigger.register(really_run);
    }
    function really_run() {
        initialize();
        if (is_rtl && is_ie6) return;
        if (!HotCat.upload_disabled && conf.wgNamespaceNumber === -1 && conf.wgCanonicalSpecialPageName == 'Upload' && conf.wgUserName) {
            setup_upload();
            setup(function() {
                if (typeof UploadForm != 'undefined' && typeof UploadForm.previous_hotcat_state != 'undefined' && UploadForm.previous_hotcat_state !== null) {
                    UploadForm.previous_hotcat_state = setState(UploadForm.previous_hotcat_state);
                }
            });
        } else {
            if (!conf.wgIsArticle || conf.wgAction != 'view' || param('diff') !== null || param('oldid') !== null || !can_edit() || HotCat.disable()) return;
            getPage();
        }
    }
    function closeForm() {
        for (var i = 0; i < editors.length; i++) {
            if (editors[i].state == CategoryEditor.OPEN) {
                editors[i].cancel();
            } else if (editors[i].state == CategoryEditor.CHANGE_PENDING) {
                editors[i].sanitizeInput();
                var value = editors[i].text.value.split('|');
                var key = null;
                if (value.length > 1) key = value[1];
                var v = value[0].replace(/_/g, ' ').replace(/^\s+|\s+$/g, "");
                if (v.length === 0) {
                    editors[i].cancel();
                } else {
                    editors[i].currentCategory = v;
                    editors[i].currentKey = key;
                    editors[i].currentExists = this.inputExists;
                    editors[i].close();
                }
            }
        }
    }
    function getState() {
        var result = null;
        for (var i = 0; i < editors.length; i++) {
            var text = editors[i].currentCategory;
            var key = editors[i].currentKey;
            if (text && text.length > 0) {
                if (key !== null) text += '|' + key;
                if (result === null)
                    result = text;
                else
                    result = result + '\n' + text;
            }
        }
        return result;
    }
    function setState(state) {
        var cats = state.split('\n');
        if (cats.length === 0) return null;
        if (initialized && editors.length == 1 && editors[0].isAddCategory) {
            var newSpans = [];
            var before = editors.length == 1 ? editors[0].span : null;
            var i;
            for (i = 0; i < cats.length; i++) {
                if (cats[i].length === 0) continue;
                var cat = cats[i].split('|');
                var key = cat.length > 1 ? cat[1] : null;
                cat = cat[0];
                var lk = make('a');
                lk.href = wikiPagePath(HotCat.category_canonical + ':' + cat);
                lk.appendChild(make(cat, true));
                lk.title = cat;
                var span = make('span');
                span.appendChild(lk);
                if (i === 0) catLine.insertBefore(make(' ', true), before);
                catLine.insertBefore(span, before);
                if (before && i + 1 < cats.length) parent.insertBefore(make(' | ', true), before);
                newSpans.push({
                    element: span,
                    title: cat,
                    'key': key
                });
            }
            if (before) {
                before.parentNode.insertBefore(make(' | ', true), before);
            }
            var editor = null;
            for (i = 0; i < newSpans.length; i++) {
                editor = new CategoryEditor(catLine, newSpans[i].element, newSpans[i].title, newSpans[i].key);
            }
        }
        return null;
    }
    window.hotcat_get_state = function() {
        return getState();
    };
    window.hotcat_set_state = function(state) {
        return setState(state);
    };
    window.hotcat_close_form = function() {
        closeForm();
    };
    if (window.mw) {
        mw.config.set('disableAJAXCategories', true);
    }
    var mwVersion = conf.wgVersion.split('.');
    if (mwVersion[0] >= 1 && parseFloat(mwVersion[1]) > 20) {
        if (parseFloat(mwVersion[1]) > 21) {
            var startHotCat = function() {
                mw.hook('wikipage.content').add(function() {
                    catLine = null;
                    editors = [];
                    initialized = false;
                    HotCat.started = false;
                    run();
                });
            };
        } else {
            var startHotCat = function() {
                jQuery(document).ready(run);
            };
        }
        mw.loader.using('user', startHotCat, startHotCat);
    } else {
        jQuery(document).ready(run);
    }
})();
/* jshint ignore:end */
//</nowiki>