Newer
Older
WebInquirer / Inquirer.js
/*
 * Web Inquirer V 0.7g
 * Copyright 2016-2018 XWolfOverride@gmail.com
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var inquirer = inquirer || new function () {

    var icon = "data:image/gif;base64,R0lGODlhIAAgAKECADIyMjMzM////////yH5BAEKAAIALAAAAAAgACAAAAJulI8Zke2PFoC0LlZzW7qf633XGGHeiJqcaKWgsQov5JLvTNeYq+kM36vBUJNgaujDiVDIpLK58ylIiiU0NjWVZscHgAuUUXPOpfbhjD1bwmFIrHsvv+3Qrd4Byzda7N7h9zclmEOIFmgolgj4VgAAOw==", //
        bugico = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAWlBMVEUkJSMuMC01NzQ+Pz1HSEZPUU5YWldfYV5pa2h6e3iOkI2YmpeipKGpq6ifwFWqxma4urezzHa50YHJy8jC1pLL3aLS4K3a3NnZ5rvo6+fn8NXv8+L19/D9//y9fxQqAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+EBBAwFN28edE4AAABVaVRYdENvbW1lbnQAAAAAAENvcHlyaWdodCBJTkNPUlMgR21iSCAod3d3Lmljb25leHBlcmllbmNlLmNvbSkgLSBVbmxpY2Vuc2VkIHByZXZpZXcgaW1hZ2VYrophAAAC6UlEQVRYw+2X2barIAxA0U5qK2jFAor//5uXSUUS2q5z1n07vNhC2JCYSbL8cpA/wAeAGswQPwc0xI3qO4BWcPVs95/gvNYQIAhpgGBtATcw3RLSpgBtRYdU8oLeQNhZlQCUnazDny7YrfM2uK8Hh+fDTopUBavuOfwuH+4xlB5QdP5vEU69xdfaAMOONT8fQg012UY1CNGuV1HxraK3UGw6XEhm+BveYw0igNWh3OyJD6fD1WqF+EG7glUeYJdFEWsQe6I1WTG8BdjVMn6JB8DNvXTjY12R2X9HnDMCqNPqSxmCebl6UWatFHgwmdtdl4XzoGcyrHav3rp3IXLRqEq9SEqf5qQq3X8xao+UjstyEvlwNgZglNLePMX9FJ1e203cLDEn9CYfvKgdTLqgaWsDKa6NM4xkbol/SCheyiBek4+8zh04yz4sUP0WMNN9sHHywrNk0bR8C+jpYbDcXBZAEWGWTM5vAHMiSzGAzAH8i4aAdM46GgSI7lrAw5zJKdSrvLRJSmtc9tWprNUXm6z3akH29N0sE5CdELsYI7hse90BPvt1OABOjiFlXFeA338WNpCgxSGAL9qnzUo7gK+ANp+Cl0BfC0J9bmXTEEioHi4fc+S2GUAgNAZQ7zWJI7cN8QkAPrvfDGDYaxrHZMcMwFW4u7VBV3fBKaBs/wZgNrZJLEB1WUavTDBN3wFeWcD8HUDmwxkDPCkWYWg4KyjMQEKyhtVoYVGnFhoBA0hTdwQEmLJUwYTA0BzRuDKVAEzRNS2M/AwYF20KX6HTjBQcugc5jYELtD74j4C1b5kBAGaIQ0dHou7ihnhjCuBrAiqOABHqPwiIWSNePEQ6kEgDhYTUNCNRoEmaVF3jsvXEcSmU0zG97D10GQOcBu3eJjAMwOZjt9ylAIEF9ktiMWg9IbTmZLvT/dirhI08ZLTx2BaYNqxKHAl+2EgbWtyatJcafAyJbz555rHvOePTb77atP77cv3/gH8Wkk7NciByTQAAAABJRU5ErkJggg==", //
        VERSION = "0.7g",//
        alertIcon,
        config = {
            color: {
                normal: "#000",
                string: "#0A0",
                number: "#00B",
                keyword: "#809",
            },
        }; //

    // Locals
    var inq = this, inqapp;

    // Types
    function BasicError(data) {
        this.merge(data);
    }

    // Tools
    function uuid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    function objectResumeLink(obj) {
        var a = document.createElement("a"), isError;
        a.href = "#";
        if (obj instanceof Error) {
            a.appendChild(document.createTextNode(obj));
            isError = true;
        }
        else if (obj instanceof BasicError) {
            a.appendChild(document.createTextNode(obj.message));
            isError = true;
        } else
            a.appendChild(document.createTextNode(objectResumeText(obj)));
        a.style.merge({
            color: "black",
            textDecoration: "none"
        });
        a.onclick = function () {
            if (isError)
                getApp().showError(obj);
            else
                inq.inspect(obj);
            return false;
        }
        return a;
    }

    /** A formatter tool for console output */
    function formatter(rtd) {
        var r, p, rtp, i;
        r = document.createElement("span");
        for (i in rtd) {
            rtp = rtd[i];
            if (!rtp)
                continue;
            if (rtp instanceof Node)
                r.appendChild(rtp);
            else {
                p = document.createElement("span");
                p.data = rtp;
                if (rtp.c)
                    p.style.color = rtp.c;
                p.innerText = rtp.v;
                r.appendChild(p);
            }
        }
        return r;
    }

    /** expandable object resume */
    function compactObject(m, d) {
        var r, f, mn, dn;
        r = document.createElement("span");
        f = document.createElement("span");
        mn = formatter(m);
        function open() {
            f.innerText = "▼ ";
            if (r.contains(mn))
                r.removeChild(mn);
            if (dn == null) {
                if (typeof d === "function")
                    d = d();
                dn = formatter(d);
            }
            r.appendChild(dn);
            f.onclick = close;
            return r;
        }
        function close() {
            f.innerText = "▶︎ ";
            if (r.contains(dn))
                r.removeChild(dn);
            r.appendChild(mn);
            f.onclick = open;
            return r;
        }
        f.style.cursor = "pointer";
        r.appendChild(f);
        r.close = close;
        r.open = open;
        close();
        return r;
    }

    /** formatice function details */
    function functionDetails(f) {
        var s, r = [];
        if (f) {
            s = f.toString().trim();
            r.push({ c: config.color.keyword, v: "function " });
            if (s.substr(0, 8) === "function")
                s = s.substr(8).trim();
            r.push({ c: config.color.normal, v: s });
        }
        return r;
    }

    /** formatice object resume */
    function objectResume(obj) {
        var r = [], k, max = 10, first = true;
        if (Array.isArray(obj)) {
            r.push({ c: config.color.normal, v: "Array (" + obj.length + ")" });
            r.push(inspectorLink(obj));
        } else {
            if (obj.constructor)
                r.push({ c: config.color.normal, v: functionName(obj.constructor) + " " });
            r.push(inspectorLink(obj));
            r.push({ c: config.color.normal, v: "{" });
            for (k in obj) {
                if (max-- <= 0) {
                    r.push({ c: config.color.normal, v: "..." });
                    break;
                }
                if (first)
                    first = false;
                else
                    r.push({ c: config.color.normal, v: ", " });
                r.push({ c: config.color.keyword, v: k });
            }
            r.push({ c: config.color.normal, v: "}" });
        }
        return r;
    }

    /** foramtice object details */
    function objectDetails(obj) {
        return function () {
            var r = [], k, d;
            if (Array.isArray(obj)) {
                r.push({ c: config.color.normal, v: "Array (" + obj.length + ")" });
                r.push(inspectorLink(obj));
                r.push({ c: config.color.normal, v: "[" });
            } else {
                if (obj.constructor)
                    r.push({ c: config.color.normal, v: functionName(obj.constructor) + " " });
                r.push(inspectorLink(obj));
                r.push({ c: config.color.normal, v: "{" });
            }
            for (k in obj) {
                r.push(d = document.createElement("div"));
                d.appendChild(formatter([
                    { c: config.color.keyword, v: k },
                    { c: config.color.normal, v: ": " },
                    objectRow(obj[k])
                ]))
                d.style.paddingLeft = "8px";
            }
            r.push({ c: config.color.normal, v: Array.isArray(obj) ? "]" : "}" });
            return r;
        };
    }

    /** return the function name */
    function functionName(f) {
        if (!f)
            return "";
        if (f.name)
            return f.name;
        var funcNameRegex, result;
        funcNameRegex = /function (.{1,})\(/;
        result = (funcNameRegex).exec(f.toString());//(this).constructor.toString());
        result = (result && result.length > 1) ? result[1] : "";
        if (result.length && result.length > 128)
            result = "";
        return result;
    }

    /** Advanced way to show object on screen */
    function objectRow(obj, full, expanded) {
        var row, robj;
        row = document.createElement("span");
        if (obj === null)
            row.innerText = "<null>";
        else if (obj === undefined)
            row.innerText = "<undefined>";
        else switch (typeof obj) {
            case "string":
                if (!full && obj.length > 512)
                    row.appendChild(formatter([
                        { c: config.color.normal, v: '"' },
                        { c: config.color.string, v: obj.substr(0, 512) },
                        { c: config.color.normal, v: '..."' },
                    ]))
                else
                    row.appendChild(formatter([
                        { c: config.color.normal, v: '"' },
                        { c: config.color.string, v: obj },
                        { c: config.color.normal, v: '"' },
                    ]))
                break;
            case "number":
                row.appendChild(formatter([
                    { c: config.color.number, v: obj },
                ]));
                break;
            case "function":
                row.appendChild(robj = compactObject([
                    { c: config.color.keyword, v: "function" },
                    obj.name ? { c: config.color.normal, v: " " + functionName(obj) } : null,
                    { c: config.color.normal, v: "() {...}" },
                ],
                    functionDetails(obj)
                ));
                break;
            case "object":
                row.appendChild(robj = compactObject(objectResume(obj), objectDetails(obj)));
                break;
            default:
                row.innerText = obj;
                break;
        }
        if (expanded)
            robj.open();
        return row;
    }

    function inspectorLink(object) {
        var lnk = document.createElement("IMG");
        lnk.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABBElEQVQ4T6XTvyvFURjH8delGJTJoMRA+bGIjDax2cxS18Km5B+wyGJQDP4C/gKlsCgTBgMSokh2g0U6Om7H1/1+u9c96/k87/N5Ps9zSho8pQbr5QE6MIon3OIz76EsoBVrWKICP8Us7qpBsoANzGMFx+jBOtqjo/csJAUE229YwE4i7MQDlrFdBJjCAfpj36n2HBfR3S9G6mAA15jEYaJqxgu2sFrkoAknaME0XhGKN1HGCG6KAOGuD/voxhW6YoAhvEVcRpcVTrU9aMMcxvCIPQxjN4Y8EeHfkFo3cTCONUwktDaO+3oAQTuEI5xhBh/1AoK+F88/xf8B/NnmWjPI/bRf61ssEdnALW4AAAAASUVORK5CYII=";
        lnk.style.merge({
            verticalAlign: "middle",
            cursor: "pointer",
        });
        lnk.onclick = function () {
            openInspector(object);
        };
        return lnk;
    }

    // Methods
    /**
     * Error window handling
     * @param {*string} eMessage Error message
     * @param {*string} eData Error message extended information
     */
    function openErrorBox(eMessage, eData) {
        var wid, win, wwidth = 400, wheight = 150;
        wid = "error";// + uuid();
        win = getApp().windows[wid];
        if (!win) {
            win = merger.ui.window(wid, {
                title: "Error",
                width: wwidth,
                height: wheight,
                content: [merger.ui.picture("Iico", {
                    src: bugico,
                    top: 0,
                    left: 0,
                    width: 32,
                    height: 32,
                }),
                merger.ui.label("Lerror", {
                    top: 0,
                    left: 37,
                    width: wwidth - 37,
                    height: 32,
                    text: "",
                }),
                merger.ui.label("Tinfo", {
                    top: 37,
                    left: -5,
                    width: wwidth,
                    height: wheight - 37 - 25 - 10,
                    multiple: true,
                    style: {
                        whiteSpace: "pre",
                        fontFamily: "Lucida Console, Monospace",
                        border: "0",
                        overflow: "scroll",
                        background: "#EEE",
                        padding: "5px",
                    },
                }),
                merger.ui.button("Bok", {
                    top: wheight - 20,
                    left: wwidth - 35,
                    width: 35,
                    height: 20,
                    text: "Ok",
                    onClick: function (e) {
                        this.getWindow().close();
                    }
                }),
                ],
                onClose: function () {
                    this.hide();
                    //getApp().removeWindow(win);
                },
                load: function () {
                    win.content.Lerror.setText(eMessage);
                    win.content.Tinfo.setText(eData);
                }
            });
            getApp().addWindow(win);
        }
        win.load();
        win.show();
        return win;
    }

    /** 
     * Get the console window
     */
    function getConsole() {
        var wid, win, wwidth = 300, wheight = 250, inputHeight = 20;
        wid = "console";
        win = getApp().windows[wid];
        if (document.body.scrollWidth)
            wwidth = Math.max(wwidth, document.body.scrollWidth - 200);
        if (document.body.scrollHeight)
            wheight = Math.max(wheight, document.body.scrollHeight - 150);
        if (!win) {
            win = merger.ui.window(wid, {
                title: "Console",
                width: wwidth,
                height: wheight,
                resizable: true,
                content: [
                    merger.ui.html("Hconsole", {
                        top: 0,
                        left: 0,
                        width: wwidth,
                        height: wheight - (inputHeight - 5),
                        anchor: "TRBL",
                        style: {
                            overflow: "scroll",
                        },
                    }),
                    merger.ui.textbox("Tinput", {
                        top: wheight - (inputHeight - 5),
                        left: -5,
                        width: wwidth + 5,
                        height: inputHeight,
                        placeholder: "javascript code here",
                        anchor: "LBR",
                        //multiple: true,
                        style: {
                            whiteSpace: "pre",
                            fontFamily: "Lucida Console, Monospace",
                            border: "0",
                            overflow: "scroll",
                            background: "#EEE",
                            padding: "3px",
                        },
                        onkeydown: function (e) {
                            var t, stop;
                            switch (e.keyCode) {
                                case 13:
                                    this.getWindow().exec(this.getText());
                                    t = "";
                                    stop = true;
                                    break;
                                case 38:
                                    t = this.getWindow().conhis.up();
                                    stop = true;
                                    break;
                                case 40:
                                    t = this.getWindow().conhis.down();
                                    stop = true;
                                    break;
                            }
                            if (t != undefined) {
                                this.setText(t);
                            }
                            if (stop)
                                return false;
                        },
                    }),
                ],
                conhis: {
                    data: [],
                    sel: 0,
                    add: function (code) {
                        var idx = this.data.indexOf(code);
                        if (idx >= 0)
                            this.data.splice(idx, 1);
                        this.data.push(code);
                        this.sel = this.data.length;
                    },
                    up: function () {
                        if (this.sel > 0)
                            this.sel--;
                        return this.data[this.sel];
                    },
                    down: function () {
                        if (this.sel < this.data.length)
                            this.sel++;
                        else return;
                        if (this.sel == this.data.length)
                            return "";
                        return this.data[this.sel];
                    }
                },
                onClose: function () {
                    this.hide();
                    //getApp().removeWindow(win);
                },
                log: function (type, object) {
                    var row = document.createElement("div");
                    var head = document.createElement("div");
                    var clear = document.createElement("div");
                    var d = document.createElement("div");
                    row.style.merge({
                        margin: "0 0 0 13px",
                    });
                    head.style.merge({
                        fontFamily: "Lucida Console, Monospace",
                        fontWeight: "bold",
                        float: "left",
                        margin: "0 0 0 -13px",
                        width: "13px",
                    });
                    d.style.merge({
                        whiteSpace: "pre-wrap",
                        float: "right",
                        fontFamily: "Lucida Console, Monospace",
                        border: "0",
                        width: "100%",
                    });
                    clear.style.merge({
                        clear: "both",
                    });
                    switch (type) {
                        case 'i':
                            d.innerText = object;
                            head.appendChild(document.createTextNode(">"));
                            head.style.color = "#88F";
                            d.style.paddingBottom = "3px";
                            break;
                        case 'o':
                            d.appendChild(objectRow(object));
                            d.style.borderBottom = "1px solid #EEE";
                            head.appendChild(document.createTextNode("<"));
                            head.style.color = "#DDD";
                            break;
                        case 'e':
                            d.appendChild(objectRow(object));
                            head.appendChild(document.createTextNode("!"));
                            head.style.color = "#F88";
                            d.style.background = "#FEE";
                            head.style.background = "#FEE";
                            break;
                    }
                    d.data = object;
                    row.appendChild(head);
                    row.appendChild(d);
                    row.appendChild(clear);
                    this.content.Hconsole.appendChild(row);
                    this.content.Hconsole.scrollTop = this.content.Hconsole.scrollHeight;
                },
                exec: function (code) {
                    if (code == null || typeof code != "string" || code.length < 1)
                        return;
                    this.conhis.add(code);
                    var obj;
                    this.log('i', code);
                    try {
                        obj = eval('(' + code + ')');
                    } catch (err) {
                        window.console.error(err);
                        return;
                    }
                    window.console.log(obj);
                },
                write: function () {
                    var k;
                    for (k in arguments)
                        this.log('o', arguments[k]);
                },
                writeError: function () {
                    var k;
                    for (k in arguments)
                        this.log('e', arguments[k]);
                },
                load: function () {
                    win.write("Inquirer " + VERSION + " console.");
                }
            });
            getApp().addWindow(win);
            win.load();
        }
        return win;
    }

    /** 
     * Open the console window
     */
    function openConsole() {
        var win = getConsole();
        win.show();
        return win;
    }

    /**
     * Open the properties window
     */
    function openProperties() {
        var wid, win, wwidth = 175, wheight = 100;
        wid = "preferences";
        win = getApp().windows[wid];
        if (!win) {
            win = merger.ui.window(wid, {
                title: "Preferences",
                width: wwidth,
                height: wheight,
                content: [
                    merger.ui.checkbox("pref_autoshow", {
                        top: 0,
                        left: 3,
                    }),
                    merger.ui.label("pref_autoshow_lbl", {
                        top: 0,
                        left: 20,
                        text: "Open Inquirer on error"
                    }),
                    merger.ui.checkbox("pref_erricon", {
                        top: 15,
                        left: 3,
                    }),
                    merger.ui.label("pref_erricon_lbl", {
                        top: 15,
                        left: 20,
                        text: "Show small error indicator"
                    }),
                    merger.ui.button("pref_save", {
                        top: wheight - 20,
                        left: wwidth - 27,
                        text: "Ok",
                        onClick: function () {
                            inq.autoShow = this.getWindow().content.pref_autoshow.checked;
                            inq.alertIcon = this.getWindow().content.pref_erricon.checked;
                            this.getWindow().close();
                        }
                    }),
                ],
                onShow: function () {
                    this.getWindow().content.pref_autoshow.checked = inq.autoShow;
                    this.getWindow().content.pref_erricon.checked = inq.alertIcon;
                }
            });
            getApp().addWindow(win);
        }
        win.show();
        return win;
    }

    /**
     * Open inspector window
     * @param {*} object Any object to inspect
     */
    function openInspector(object) {
        var wid, win, wwidth = 350, wheight = 400, panel;
        wid = "inspector_" + uuid();
        win = merger.ui.window(wid, {
            title: "Inspector",
            width: wwidth,
            height: wheight,
            resizable: true,
            content: [
                panel = merger.ui.html("panel", {
                    top: 0,
                    left: 0,
                    width: wwidth,
                    height: wheight - 25,
                    anchor: "TBRL",
                    style: {
                        overflow: "scroll",
                    },
                }),
                merger.ui.button("insp_close", {
                    top: wheight - 20,
                    left: wwidth - 27,
                    text: "Ok",
                    anchor: "BR",
                    onClick: function () {
                        this.getWindow().close();
                    }
                }),
            ],
            load: function () {
                panel.appendChild(objectRow(object, true, true));
            },
            onClose: function () {
                this.hide();
                getApp().removeWindow(win);
            }
        });
        getApp().addWindow(win);
        win.load();
        win.show();
        return win;
    }

    /**
     * Get Inquirer application
     */
    function getApp() {
        if (!inqapp)
            inqapp = merger.app("inquirer", {
                title: "Inquirer",
                icon: icon,
                appMenu: [
                    merger.ui.menuItem("app_preferences", {
                        text: "Preferences...",
                        icon: merger.media.createIcon('#EEE', '⚒'),
                        onClick: function () {
                            openProperties();
                        }
                    }),
                ],
                menu: [
                    merger.ui.menuItem("app_tools", {
                        text: "Tools",
                        items: [merger.ui.menuItem("tool_console", {
                            text: "Console",
                            onClick: function () {
                                this.getApp().showConsole();
                            }
                        })
                        ]
                    }),
                    merger.ui.menuItem("app_special", {
                        text: "Special",
                        items: [merger.ui.menuItem("special_reload", {
                            text: "Reload page",
                            onClick: function () {
                                location.reload(false);
                            }
                        }), merger.ui.menuItem("special_reload_full", {
                            text: "Reload page (ignore cache)",
                            onClick: function () {
                                location.reload(true);
                            }
                        }), merger.ui.menuItem("special_debugger", {
                            text: "Call browser debugger",
                            onClick: function () {
                                debugger;
                            }
                        })
                        ]
                    })
                ],
                windows: [
                ],
                onLoad: function () {
                },
                onAbout: function () {
                    merger.dialogs.messageBox(this, "Inquirer v" + VERSION + " over Merger UI " + merger.version + " ©2016-2018 XWolf Override.<br>Debugger application layer for web pages. Useful for embedded browser debugging", "About Inquirer", null, this.icon, 100);
                },
                onFocus: function () {
                    removeIcon();
                    if (!getApp().getFocusedWindow())
                        openConsole();
                },
                showError: function (err) {
                    if (err instanceof Error)
                        openErrorBox(err.message, err.stack);
                    else
                        openErrorBox(err.message, "File: " + err.source + "\r\n\r\nAt: " + err.at);
                },
                showConsole: function () {
                    openConsole();
                }
            });
        return inqapp;
    }

    /**
     * Show a small yellow mark to indicate some error has been happend
     */
    function showIcon() {
        if (!alertIcon) {
            alertIcon = document.createElement("DIV");
            alertIcon.style.merge({
                position: "absolute",
                top: "0px",
                right: "3px",
                width: "2px",
                height: "1px",
                background: "gold",
                borderBottom: "goldenRod",
            });
            document.body.appendChild(alertIcon);
        }
        alertIcon.style.display = "";
    }

    /**
     * Hides a small yellow mark to indicate some error has been happend
     */
    function removeIcon() {
        if (!alertIcon)
            return;
        alertIcon.style.display = "none";
    }

    // === Public members

    function show() {
        getApp().show();
    }

    function hide() {
        getApp().windows.Wmain.close();
    }

    // On error hook
    function hookOnError() {
        var formerOnError = window.onerror;
        window.onerror = function (message, source, lineno, colno, err) {
            inq.error(new BasicError({
                message: message,
                source: source,
                at: lineno + ":" + colno,
                error: err,
                raw: arguments
            }));
            if (formerOnError)
                formerOnError.apply(window, arguments);
        }
    }

    // Konami code hook
    function hookKonamiCode() {
        var kc = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65], kcindex = 0 // Konami code
        document.addEventListener("keydown", function (e) {
            if (e.keyCode == kc[kcindex])
                kcindex++;
            else
                kcindex = 0;
            if (kcindex == kc.length)
                inquirer.show();
        }, false);
    }

    // Console hook
    function hookConsole() {
        if (!window.console)
            window.console = {};
        function consoleOverride(method, funct) {
            var old = window.console[method];
            window.console[method] = function () {
                funct.apply(window.console, arguments);
                if (old)
                    old.apply(window.console, arguments);
            };
            window.console[method].old = old;
        }
        consoleOverride("log", function () {
            openConsole().write.apply(openConsole(), arguments);
        })
        consoleOverride("info", function () {
            openConsole().write.apply(openConsole(), arguments);
        })
        consoleOverride("debug", function () {
            openConsole().write.apply(openConsole(), arguments);
        })
        consoleOverride("error", function () {
            openConsole().writeError.apply(openConsole(), arguments);
        })
    }

    // Install hooks
    function hook() {
        hookOnError();
        hookKonamiCode();
        hookConsole();
    }

    function error(error) {
        getConsole().writeError(error);
        if (this.autoShow) {
            getApp().showError(error);
            show();
        }
        if (this.alertIcon) {
            showIcon();
        }
    }

    function inspect(object) {
        openInspector(object);
        show();
    }

    function console() {
        getApp().showConsole();
        show();
    }

    function log() {
        getApp().windows.Wconsole.write.apply(getApp().windows.Wconsole, arguments);
    }

    // Publish
    this.merge({
        version: VERSION,
        autoShow: false,    // Open Inquirer environment when a new unhandled error happen
        alertIcon: true,    // Small icon on screen to indicate if there is any new error
        show: show,         // Enters environment
        hide: hide,         // Exit environent
        hook: hook,         // Hook the webpage to control errors (Automatically hooked)
        error: error,       // Collect an error and if autoShow is true enters environment
        inspect: inspect,   // Enters environment and open variable inspector
        console: console,   // Enters environment and open inquirer console
        log: log,           // Log an object into the console
        config: config,     // Configuration object
    });

    // Hook the page now
    hook();
}();